Moved ProviderCollectionTest.cs from System assembly to System.Configuration.
[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 #ifdef DISABLE_JIT
223 /* Define this here, since many files reference it */
224 const guint8 mono_burg_arity [MBMAX_OPCODES] = {
225 };
226 #endif
227
228 gboolean
229 mono_running_on_valgrind (void)
230 {
231 #ifdef HAVE_VALGRIND_MEMCHECK_H
232                 if (RUNNING_ON_VALGRIND){
233 #ifdef VALGRIND_JIT_REGISTER_MAP
234                         valgrind_register = TRUE;
235 #endif
236                         return TRUE;
237                 } else
238                         return FALSE;
239 #else
240                 return FALSE;
241 #endif
242 }
243
244 typedef struct {
245         void *ip;
246         MonoMethod *method;
247 } FindTrampUserData;
248
249 static void
250 find_tramp (gpointer key, gpointer value, gpointer user_data)
251 {
252         FindTrampUserData *ud = (FindTrampUserData*)user_data;
253
254         if (value == ud->ip)
255                 ud->method = (MonoMethod*)key;
256 }
257
258 /* debug function */
259 G_GNUC_UNUSED static char*
260 get_method_from_ip (void *ip)
261 {
262         MonoJitInfo *ji;
263         char *method;
264         char *res;
265         MonoDomain *domain = mono_domain_get ();
266         MonoDebugSourceLocation *location;
267         FindTrampUserData user_data;
268         
269         ji = mono_jit_info_table_find (domain, ip);
270         if (!ji) {
271                 user_data.ip = ip;
272                 user_data.method = NULL;
273                 mono_domain_lock (domain);
274                 g_hash_table_foreach (domain->jit_trampoline_hash, find_tramp, &user_data);
275                 mono_domain_unlock (domain);
276                 if (user_data.method) {
277                         char *mname = mono_method_full_name (user_data.method, TRUE);
278                         res = g_strdup_printf ("<%p - JIT trampoline for %s>", ip, mname);
279                         g_free (mname);
280                         return res;
281                 }
282                 else
283                         return NULL;
284         }
285         method = mono_method_full_name (ji->method, TRUE);
286         /* FIXME: unused ? */
287         location = mono_debug_lookup_source_location (ji->method, (guint32)((guint8*)ip - (guint8*)ji->code_start), domain);
288
289         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);
290
291         mono_debug_free_source_location (location);
292         g_free (method);
293
294         return res;
295 }
296
297 /** 
298  * mono_pmip:
299  * @ip: an instruction pointer address
300  *
301  * This method is used from a debugger to get the name of the
302  * method at address @ip.   This routine is typically invoked from
303  * a debugger like this:
304  *
305  * (gdb) print mono_pmip ($pc)
306  *
307  * Returns: the name of the method at address @ip.
308  */
309 G_GNUC_UNUSED char *
310 mono_pmip (void *ip)
311 {
312         return get_method_from_ip (ip);
313 }
314
315 /** 
316  * mono_print_method_from_ip
317  * @ip: an instruction pointer address
318  *
319  * This method is used from a debugger to get the name of the
320  * method at address @ip.
321  *
322  * This prints the name of the method at address @ip in the standard
323  * output.  Unlike mono_pmip which returns a string, this routine
324  * prints the value on the standard output. 
325  */
326 void
327 mono_print_method_from_ip (void *ip)
328 {
329         MonoJitInfo *ji;
330         char *method;
331         MonoDebugSourceLocation *source;
332         MonoDomain *domain = mono_domain_get ();
333         FindTrampUserData user_data;
334         
335         ji = mono_jit_info_table_find (domain, ip);
336         if (!ji) {
337                 user_data.ip = ip;
338                 user_data.method = NULL;
339                 mono_domain_lock (domain);
340                 g_hash_table_foreach (domain->jit_trampoline_hash, find_tramp, &user_data);
341                 mono_domain_unlock (domain);
342                 if (user_data.method) {
343                         char *mname = mono_method_full_name (user_data.method, TRUE);
344                         printf ("IP %p is a JIT trampoline for %s\n", ip, mname);
345                         g_free (mname);
346                 }
347                 else
348                         g_print ("No method at %p\n", ip);
349                 return;
350         }
351         method = mono_method_full_name (ji->method, TRUE);
352         source = mono_debug_lookup_source_location (ji->method, (guint32)((guint8*)ip - (guint8*)ji->code_start), domain);
353
354         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);
355
356         if (source)
357                 g_print ("%s:%d\n", source->source_file, source->row);
358
359         mono_debug_free_source_location (source);
360         g_free (method);
361 }
362         
363 /* 
364  * mono_method_same_domain:
365  *
366  * Determine whenever two compiled methods are in the same domain, thus
367  * the address of the callee can be embedded in the caller.
368  */
369 gboolean mono_method_same_domain (MonoJitInfo *caller, MonoJitInfo *callee)
370 {
371         if (!caller || !callee)
372                 return FALSE;
373
374         /*
375          * If the call was made from domain-neutral to domain-specific 
376          * code, we can't patch the call site.
377          */
378         if (caller->domain_neutral && !callee->domain_neutral)
379                 return FALSE;
380
381         if ((caller->method->klass == mono_defaults.appdomain_class) &&
382                 (strstr (caller->method->name, "InvokeInDomain"))) {
383                  /* The InvokeInDomain methods change the current appdomain */
384                 return FALSE;
385         }
386
387         return TRUE;
388 }
389
390 /*
391  * mono_global_codeman_reserve:
392  *
393  *  Allocate code memory from the global code manager.
394  */
395 void *mono_global_codeman_reserve (int size)
396 {
397         void *ptr;
398
399         if (mono_aot_only)
400                 g_error ("Attempting to allocate from the global code manager while running with --aot-only.\n");
401
402         if (!global_codeman) {
403                 /* This can happen during startup */
404                 global_codeman = mono_code_manager_new ();
405                 return mono_code_manager_reserve (global_codeman, size);
406         }
407         else {
408                 mono_jit_lock ();
409                 ptr = mono_code_manager_reserve (global_codeman, size);
410                 mono_jit_unlock ();
411                 return ptr;
412         }
413 }
414
415 MonoJumpInfoToken *
416 mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
417 {
418         MonoJumpInfoToken *res = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoToken));
419         res->image = image;
420         res->token = token;
421
422         return res;
423 }
424
425 #define MONO_INIT_VARINFO(vi,id) do { \
426         (vi)->range.first_use.pos.bid = 0xffff; \
427         (vi)->reg = -1; \
428         (vi)->idx = (id); \
429 } while (0)
430
431 //#define UNVERIFIED do { G_BREAKPOINT (); goto unverified; } while (0)
432 #define UNVERIFIED do { if (debug_options.break_on_unverified) G_BREAKPOINT (); else goto unverified; } while (0)
433
434 /*
435  * Basic blocks have two numeric identifiers:
436  * dfn: Depth First Number
437  * block_num: unique ID assigned at bblock creation
438  */
439 #define NEW_BBLOCK(cfg) (mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock)))
440 #define ADD_BBLOCK(cfg,b) do {  \
441                 cfg->cil_offset_to_bb [(b)->cil_code - cfg->cil_start] = (b);   \
442                 (b)->block_num = cfg->num_bblocks++;    \
443                 (b)->real_offset = real_offset; \
444         } while (0)
445
446 #define GET_BBLOCK(cfg,tblock,ip) do {  \
447                 (tblock) = cfg->cil_offset_to_bb [(ip) - cfg->cil_start]; \
448                 if (!(tblock)) {        \
449                         if ((ip) >= end || (ip) < header->code) UNVERIFIED; \
450                         (tblock) = NEW_BBLOCK (cfg);    \
451                         (tblock)->cil_code = (ip);      \
452                         ADD_BBLOCK (cfg, (tblock));     \
453                 } \
454         } while (0)
455
456 #define CHECK_BBLOCK(target,ip,tblock) do {     \
457                 if ((target) < (ip) && !(tblock)->code) {       \
458                         bb_recheck = g_list_prepend (bb_recheck, (tblock));     \
459                         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));     \
460                 }       \
461         } while (0)
462
463 #define NEW_ICONST(cfg,dest,val) do {   \
464                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
465                 (dest)->opcode = OP_ICONST;     \
466                 (dest)->inst_c0 = (val);        \
467                 (dest)->type = STACK_I4;        \
468         } while (0)
469
470 #define NEW_PCONST(cfg,dest,val) do {   \
471                 MONO_INST_NEW ((cfg), (dest), OP_PCONST);       \
472                 (dest)->inst_p0 = (val);        \
473                 (dest)->type = STACK_PTR;       \
474         } while (0)
475
476
477 #ifdef MONO_ARCH_NEED_GOT_VAR
478
479 #define NEW_PATCH_INFO(cfg,dest,el1,el2) do {   \
480                 MONO_INST_NEW ((cfg), (dest), OP_PATCH_INFO);   \
481                 (dest)->inst_left = (gpointer)(el1);    \
482                 (dest)->inst_right = (gpointer)(el2);   \
483         } while (0)
484
485 #define NEW_AOTCONST(cfg,dest,patch_type,cons) do {                     \
486                 MONO_INST_NEW ((cfg), (dest), OP_NOP); \
487                 (dest)->opcode = cfg->compile_aot ? OP_GOT_ENTRY : OP_PCONST; \
488                 if (cfg->compile_aot) {                                 \
489                         MonoInst *group, *got_var, *got_loc;            \
490                         got_loc = mono_get_got_var (cfg);               \
491                         NEW_TEMPLOAD ((cfg), got_var, got_loc->inst_c0); \
492                         NEW_PATCH_INFO ((cfg), group, cons, patch_type); \
493                         (dest)->inst_p0 = got_var;                      \
494                         (dest)->inst_p1 = group;                        \
495                 } else {                                                \
496                         (dest)->inst_p0 = (cons);                       \
497                         (dest)->inst_i1 = (gpointer)(patch_type);       \
498                 }                                                       \
499                 (dest)->type = STACK_PTR;                               \
500         } while (0)
501
502 #define NEW_AOTCONST_TOKEN(cfg,dest,patch_type,image,token,stack_type,stack_class) do { \
503                 MonoInst *group, *got_var, *got_loc;                    \
504                 MONO_INST_NEW ((cfg), (dest), OP_GOT_ENTRY); \
505                 got_loc = mono_get_got_var (cfg);                       \
506                 NEW_TEMPLOAD ((cfg), got_var, got_loc->inst_c0);        \
507                 NEW_PATCH_INFO ((cfg), group, NULL, patch_type);        \
508                 group->inst_p0 = mono_jump_info_token_new ((cfg)->mempool, (image), (token)); \
509                 (dest)->inst_p0 = got_var;                              \
510                 (dest)->inst_p1 = group;                                \
511                 (dest)->type = (stack_type);                    \
512         (dest)->klass = (stack_class);          \
513         } while (0)
514
515 #else
516
517 #define NEW_AOTCONST(cfg,dest,patch_type,cons) do {    \
518                 MONO_INST_NEW ((cfg), (dest), OP_NOP);  \
519                 (dest)->opcode = cfg->compile_aot ? OP_AOTCONST : OP_PCONST;    \
520                 (dest)->inst_p0 = (cons);       \
521                 (dest)->inst_i1 = (gpointer)(patch_type); \
522                 (dest)->type = STACK_PTR;       \
523     } while (0)
524
525 #define NEW_AOTCONST_TOKEN(cfg,dest,patch_type,image,token,stack_type,stack_class) do { \
526                 MONO_INST_NEW ((cfg), (dest), OP_AOTCONST);     \
527                 (dest)->inst_p0 = mono_jump_info_token_new ((cfg)->mempool, (image), (token));  \
528                 (dest)->inst_p1 = (gpointer)(patch_type); \
529                 (dest)->type = (stack_type);    \
530         (dest)->klass = (stack_class);          \
531     } while (0)
532
533 #endif
534
535 #define NEW_CLASSCONST(cfg,dest,val) NEW_AOTCONST ((cfg), (dest), MONO_PATCH_INFO_CLASS, (val))
536
537 #define NEW_IMAGECONST(cfg,dest,val) NEW_AOTCONST ((cfg), (dest), MONO_PATCH_INFO_IMAGE, (val))
538
539 #define NEW_FIELDCONST(cfg,dest,val) NEW_AOTCONST ((cfg), (dest), MONO_PATCH_INFO_FIELD, (val))
540
541 #define NEW_METHODCONST(cfg,dest,val) NEW_AOTCONST ((cfg), (dest), MONO_PATCH_INFO_METHODCONST, (val))
542
543 #define NEW_VTABLECONST(cfg,dest,vtable) NEW_AOTCONST ((cfg), (dest), MONO_PATCH_INFO_VTABLE, cfg->compile_aot ? (gpointer)((vtable)->klass) : (vtable))
544
545 #define NEW_SFLDACONST(cfg,dest,val) NEW_AOTCONST ((cfg), (dest), MONO_PATCH_INFO_SFLDA, (val))
546
547 #define NEW_LDSTRCONST(cfg,dest,image,token) NEW_AOTCONST_TOKEN ((cfg), (dest), MONO_PATCH_INFO_LDSTR, (image), (token), STACK_OBJ, mono_defaults.string_class)
548
549 #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)
550
551 #define NEW_LDTOKENCONST(cfg,dest,image,token) NEW_AOTCONST_TOKEN ((cfg), (dest), MONO_PATCH_INFO_LDTOKEN, (image), (token), STACK_PTR, NULL)
552
553 #define NEW_DECLSECCONST(cfg,dest,image,entry) do { \
554                 if (cfg->compile_aot) { \
555                         NEW_AOTCONST_TOKEN (cfg, dest, MONO_PATCH_INFO_DECLSEC, image, (entry).index, STACK_OBJ, NULL); \
556                 } else { \
557                         NEW_PCONST (cfg, args [0], (entry).blob); \
558                 } \
559         } while (0)
560
561 #define NEW_DOMAINCONST(cfg,dest) do { \
562                 if (cfg->opt & MONO_OPT_SHARED) { \
563                         /* avoid depending on undefined C behavior in sequence points */ \
564                         MonoInst* __domain_var = mono_get_domainvar (cfg); \
565                         NEW_TEMPLOAD (cfg, dest, __domain_var->inst_c0); \
566                 } else { \
567                         NEW_PCONST (cfg, dest, (cfg)->domain); \
568                 } \
569         } while (0)
570
571 #define GET_VARINFO_INST(cfg,num) ((cfg)->varinfo [(num)]->inst)
572
573 #define NEW_ARGLOAD(cfg,dest,num) do {  \
574                 if (arg_array [(num)]->opcode == OP_ICONST) (dest) = arg_array [(num)]; else { \
575                 MONO_INST_NEW ((cfg), (dest), OP_NOP);  \
576                 (dest)->ssa_op = MONO_SSA_LOAD; \
577                 (dest)->inst_i0 = arg_array [(num)];    \
578                 (dest)->opcode = mini_type_to_ldind ((cfg), (dest)->inst_i0->inst_vtype); \
579                 type_to_eval_stack_type ((cfg), param_types [(num)], (dest));   \
580                 (dest)->klass = (dest)->inst_i0->klass; \
581         }} while (0)
582
583 #define NEW_LOCLOAD(cfg,dest,num) do {  \
584                 MONO_INST_NEW ((cfg), (dest), OP_NOP);  \
585                 (dest)->ssa_op = MONO_SSA_LOAD; \
586                 (dest)->inst_i0 = (cfg)->varinfo [locals_offset + (num)];       \
587                 (dest)->opcode = mini_type_to_ldind ((cfg), (dest)->inst_i0->inst_vtype); \
588                 type_to_eval_stack_type ((cfg), header->locals [(num)], (dest));        \
589                 (dest)->klass = (dest)->inst_i0->klass; \
590         } while (0)
591
592 #define NEW_LOCLOADA(cfg,dest,num) do { \
593                 MONO_INST_NEW ((cfg), (dest), OP_LDADDR);       \
594                 (dest)->ssa_op = MONO_SSA_ADDRESS_TAKEN;        \
595                 (dest)->inst_i0 = (cfg)->varinfo [locals_offset + (num)];       \
596                 (dest)->inst_i0->flags |= MONO_INST_INDIRECT;   \
597                 (dest)->type = STACK_MP;        \
598                 (dest)->klass = (dest)->inst_i0->klass; \
599         if (!MONO_TYPE_ISSTRUCT (header->locals [(num)])) \
600            (cfg)->disable_ssa = TRUE; \
601         } while (0)
602
603 #define NEW_RETLOADA(cfg,dest) do {     \
604         if (cfg->vret_addr) { \
605                     MONO_INST_NEW ((cfg), (dest), OP_NOP);      \
606                     (dest)->ssa_op = MONO_SSA_LOAD;     \
607                     (dest)->inst_i0 = cfg->vret_addr; \
608                     (dest)->opcode = mini_type_to_ldind ((cfg), (dest)->inst_i0->inst_vtype); \
609             (dest)->type = STACK_MP; \
610                     (dest)->klass = (dest)->inst_i0->klass;     \
611         } else { \
612                         MONO_INST_NEW ((cfg), (dest), OP_NOP);  \
613                     (dest)->ssa_op = MONO_SSA_ADDRESS_TAKEN;    \
614                     (dest)->inst_i0 = (cfg)->ret;       \
615                     (dest)->inst_i0->flags |= MONO_INST_INDIRECT;       \
616                     (dest)->opcode = cfg->ret_var_is_local ? OP_LDADDR : CEE_LDIND_I;   \
617                     (dest)->type = STACK_MP;    \
618                     (dest)->klass = (dest)->inst_i0->klass;     \
619             (cfg)->disable_ssa = TRUE; \
620         } \
621         } while (0)
622
623 #define NEW_ARGLOADA(cfg,dest,num) do { \
624                 if (arg_array [(num)]->opcode == OP_ICONST) goto inline_failure; \
625                 MONO_INST_NEW ((cfg), (dest), OP_LDADDR);       \
626                 (dest)->ssa_op = MONO_SSA_ADDRESS_TAKEN;        \
627                 (dest)->inst_i0 = arg_array [(num)];    \
628                 (dest)->inst_i0->flags |= MONO_INST_INDIRECT;   \
629                 (dest)->type = STACK_MP;        \
630                 (dest)->klass = (dest)->inst_i0->klass; \
631                 (cfg)->disable_ssa = TRUE; \
632         } while (0)
633
634 #define NEW_TEMPLOAD(cfg,dest,num) do { \
635                 MONO_INST_NEW ((cfg), (dest), OP_NOP);  \
636                 (dest)->ssa_op = MONO_SSA_LOAD; \
637                 (dest)->inst_i0 = (cfg)->varinfo [(num)];       \
638                 (dest)->opcode = mini_type_to_ldind ((cfg), (dest)->inst_i0->inst_vtype); \
639                 type_to_eval_stack_type ((cfg), (dest)->inst_i0->inst_vtype, (dest));   \
640                 (dest)->klass = (dest)->inst_i0->klass; \
641         } while (0)
642
643 #define NEW_TEMPLOADA(cfg,dest,num) do {        \
644                 MONO_INST_NEW ((cfg), (dest), OP_LDADDR);       \
645                 (dest)->ssa_op = MONO_SSA_ADDRESS_TAKEN;        \
646                 (dest)->inst_i0 = (cfg)->varinfo [(num)];       \
647                 (dest)->inst_i0->flags |= MONO_INST_INDIRECT;   \
648                 (dest)->type = STACK_MP;        \
649                 (dest)->klass = (dest)->inst_i0->klass; \
650         if (!MONO_TYPE_ISSTRUCT (cfg->varinfo [(num)]->inst_vtype)) \
651            (cfg)->disable_ssa = TRUE; \
652         } while (0)
653
654 #define NEW_INDLOAD(cfg,dest,addr,vtype) do {   \
655                 MONO_INST_NEW ((cfg), (dest), OP_NOP);  \
656                 (dest)->inst_left = addr;       \
657                 (dest)->opcode = mini_type_to_ldind ((cfg), vtype);     \
658                 type_to_eval_stack_type ((cfg), vtype, (dest)); \
659                 /* FIXME: (dest)->klass = (dest)->inst_i0->klass;*/     \
660         } while (0)
661
662 #define NEW_INDSTORE(cfg,dest,addr,value,vtype) do {    \
663                 MONO_INST_NEW ((cfg), (dest), OP_NOP);  \
664                 (dest)->inst_i0 = addr; \
665                 (dest)->opcode = mini_type_to_stind ((cfg), vtype);     \
666                 (dest)->inst_i1 = (value);      \
667                 /* FIXME: (dest)->klass = (dest)->inst_i0->klass;*/     \
668         } while (0)
669
670 #define NEW_TEMPSTORE(cfg,dest,num,inst) do {   \
671                 MONO_INST_NEW ((cfg), (dest), OP_NOP);  \
672                 (dest)->ssa_op = MONO_SSA_STORE;        \
673                 (dest)->inst_i0 = (cfg)->varinfo [(num)];       \
674                 (dest)->opcode = mini_type_to_stind ((cfg), (dest)->inst_i0->inst_vtype); \
675                 (dest)->inst_i1 = (inst);       \
676                 (dest)->klass = (dest)->inst_i0->klass; \
677         } while (0)
678
679 #define NEW_LOCSTORE(cfg,dest,num,inst) do {    \
680                 MONO_INST_NEW ((cfg), (dest), OP_NOP);  \
681                 (dest)->opcode = mini_type_to_stind ((cfg), header->locals [(num)]); \
682                 (dest)->ssa_op = MONO_SSA_STORE;        \
683                 (dest)->inst_i0 = (cfg)->varinfo [locals_offset + (num)];       \
684                 (dest)->inst_i1 = (inst);       \
685                 (dest)->klass = (dest)->inst_i0->klass; \
686         } while (0)
687
688 #define NEW_ARGSTORE(cfg,dest,num,inst) do {    \
689                 if (arg_array [(num)]->opcode == OP_ICONST) goto inline_failure; \
690                 MONO_INST_NEW ((cfg), (dest), OP_NOP);  \
691                 (dest)->opcode = mini_type_to_stind ((cfg), param_types [(num)]); \
692                 (dest)->ssa_op = MONO_SSA_STORE;        \
693                 (dest)->inst_i0 = arg_array [(num)];    \
694                 (dest)->inst_i1 = (inst);       \
695                 (dest)->klass = (dest)->inst_i0->klass; \
696         } while (0)
697
698 #define NEW_MEMCPY(cfg,dest,dst,src,memcpy_size,memcpy_align) do { \
699                 MONO_INST_NEW (cfg, dest, OP_MEMCPY); \
700         (dest)->inst_left = (dst); \
701                 (dest)->inst_right = (src); \
702         (dest)->backend.memcpy_args = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoMemcpyArgs)); \
703                 (dest)->backend.memcpy_args->size = (memcpy_size); \
704                 (dest)->backend.memcpy_args->align = (memcpy_align); \
705     } while (0)
706
707 #define NEW_MEMSET(cfg,dest,dst,imm,memcpy_size,memcpy_align) do { \
708                 MONO_INST_NEW (cfg, dest, OP_MEMSET); \
709         (dest)->inst_left = (dst); \
710                 (dest)->inst_imm = (imm); \
711         (dest)->backend.memcpy_args = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoMemcpyArgs)); \
712                 (dest)->backend.memcpy_args->size = (memcpy_size); \
713                 (dest)->backend.memcpy_args->align = (memcpy_align); \
714     } while (0)
715
716 #define NEW_DUMMY_USE(cfg,dest,load) do { \
717                 MONO_INST_NEW ((cfg), (dest), OP_DUMMY_USE);    \
718                 (dest)->inst_left = (load); \
719     } while (0)
720
721 #define NEW_DUMMY_STORE(cfg,dest,num) do { \
722                 MONO_INST_NEW ((cfg), (dest), OP_DUMMY_STORE);  \
723                 (dest)->inst_i0 = (cfg)->varinfo [(num)];       \
724                 (dest)->klass = (dest)->inst_i0->klass; \
725         } while (0)
726
727 #define ADD_BINOP(op) do {      \
728                 MONO_INST_NEW (cfg, ins, (op)); \
729                 sp -= 2;        \
730                 ins->inst_i0 = sp [0];  \
731                 ins->inst_i1 = sp [1];  \
732                 *sp++ = ins;    \
733                 type_from_op (ins);     \
734                 CHECK_TYPE (ins);       \
735                 /* Have to insert a widening op */               \
736                 /* FIXME: Need to add many more cases */ \
737                 if (ins->inst_i0->type == STACK_PTR && ins->inst_i1->type == STACK_I4) { \
738                         MonoInst *widen;  \
739                         MONO_INST_NEW (cfg, widen, CEE_CONV_I); \
740             widen->inst_i0 = ins->inst_i1; \
741                         ins->inst_i1 = widen; \
742                 } \
743         } while (0)
744
745 #define ADD_UNOP(op) do {       \
746                 MONO_INST_NEW (cfg, ins, (op)); \
747                 sp--;   \
748                 ins->inst_i0 = sp [0];  \
749                 *sp++ = ins;    \
750                 type_from_op (ins);     \
751                 CHECK_TYPE (ins);       \
752         } while (0)
753
754 #define ADD_BINCOND(next_block) do {    \
755                 MonoInst *cmp;  \
756                 sp -= 2;                \
757                 MONO_INST_NEW(cfg, cmp, OP_COMPARE);    \
758                 cmp->inst_i0 = sp [0];  \
759                 cmp->inst_i1 = sp [1];  \
760                 cmp->cil_code = ins->cil_code;  \
761                 type_from_op (cmp);     \
762                 CHECK_TYPE (cmp);       \
763                 ins->inst_i0 = cmp;     \
764                 MONO_ADD_INS (bblock, ins);     \
765                 ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);      \
766                 GET_BBLOCK (cfg, tblock, target);               \
767                 link_bblock (cfg, bblock, tblock);      \
768                 ins->inst_true_bb = tblock;     \
769                 CHECK_BBLOCK (target, ip, tblock);      \
770                 if ((next_block)) {     \
771                         link_bblock (cfg, bblock, (next_block));        \
772                         ins->inst_false_bb = (next_block);      \
773                         start_new_bblock = 1;   \
774                 } else {        \
775                         GET_BBLOCK (cfg, tblock, ip);           \
776                         link_bblock (cfg, bblock, tblock);      \
777                         ins->inst_false_bb = tblock;    \
778                         start_new_bblock = 2;   \
779                 }       \
780         } while (0)
781
782 /* FIXME: handle float, long ... */
783 #define ADD_UNCOND(istrue) do { \
784                 MonoInst *cmp;  \
785                 sp--;           \
786                 MONO_INST_NEW(cfg, cmp, OP_COMPARE);    \
787                 cmp->inst_i0 = sp [0];  \
788                 switch (cmp->inst_i0->type) { \
789                 case STACK_I8: \
790                         cmp->inst_i1 = zero_int64; break; \
791                 case STACK_R8: \
792                         cmp->inst_i1 = zero_r8; break; \
793                 case STACK_PTR: \
794                 case STACK_MP: \
795                         cmp->inst_i1 = zero_ptr; break; \
796                 case STACK_OBJ: \
797                         cmp->inst_i1 = zero_obj; break; \
798                 default: \
799                         cmp->inst_i1 = zero_int32;  \
800                 }  \
801                 cmp->cil_code = ins->cil_code;  \
802                 type_from_op (cmp);     \
803                 CHECK_TYPE (cmp);       \
804                 ins->inst_i0 = cmp;     \
805                 ins->opcode = (istrue)? CEE_BNE_UN: CEE_BEQ;    \
806                 MONO_ADD_INS (bblock, ins);     \
807                 ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);      \
808                 GET_BBLOCK (cfg, tblock, target);               \
809                 link_bblock (cfg, bblock, tblock);      \
810                 ins->inst_true_bb = tblock;     \
811                 CHECK_BBLOCK (target, ip, tblock);      \
812                 GET_BBLOCK (cfg, tblock, ip);           \
813                 link_bblock (cfg, bblock, tblock);      \
814                 ins->inst_false_bb = tblock;    \
815                 start_new_bblock = 2;   \
816         } while (0)
817
818 #define NEW_LDELEMA(cfg,dest,sp,k) do { \
819                 MONO_INST_NEW ((cfg), (dest), CEE_LDELEMA);     \
820                 (dest)->inst_left = (sp) [0];   \
821                 (dest)->inst_right = (sp) [1];  \
822                 (dest)->type = STACK_MP;        \
823                 (dest)->klass = (k);    \
824                 (cfg)->flags |= MONO_CFG_HAS_LDELEMA; \
825         } while (0)
826
827 #define NEW_GROUP(cfg,dest,el1,el2) do {        \
828                 MONO_INST_NEW ((cfg), (dest), OP_GROUP);        \
829                 (dest)->inst_left = (el1);      \
830                 (dest)->inst_right = (el2);     \
831         } while (0)
832
833 #if 0
834 static gint
835 compare_bblock (gconstpointer a, gconstpointer b)
836 {
837         const MonoBasicBlock *b1 = a;
838         const MonoBasicBlock *b2 = b;
839
840         return b2->cil_code - b1->cil_code;
841 }
842 #endif
843
844 /* *
845  * link_bblock: Links two basic blocks
846  *
847  * links two basic blocks in the control flow graph, the 'from'
848  * argument is the starting block and the 'to' argument is the block
849  * the control flow ends to after 'from'.
850  */
851 static void
852 link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
853 {
854         MonoBasicBlock **newa;
855         int i, found;
856
857 #if 0
858         if (from->cil_code) {
859                 if (to->cil_code)
860                         g_print ("edge from IL%04x to IL_%04x\n", from->cil_code - cfg->cil_code, to->cil_code - cfg->cil_code);
861                 else
862                         g_print ("edge from IL%04x to exit\n", from->cil_code - cfg->cil_code);
863         } else {
864                 if (to->cil_code)
865                         g_print ("edge from entry to IL_%04x\n", to->cil_code - cfg->cil_code);
866                 else
867                         g_print ("edge from entry to exit\n");
868         }
869 #endif
870         found = FALSE;
871         for (i = 0; i < from->out_count; ++i) {
872                 if (to == from->out_bb [i]) {
873                         found = TRUE;
874                         break;
875                 }
876         }
877         if (!found) {
878                 newa = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (from->out_count + 1));
879                 for (i = 0; i < from->out_count; ++i) {
880                         newa [i] = from->out_bb [i];
881                 }
882                 newa [i] = to;
883                 from->out_count++;
884                 from->out_bb = newa;
885         }
886
887         found = FALSE;
888         for (i = 0; i < to->in_count; ++i) {
889                 if (from == to->in_bb [i]) {
890                         found = TRUE;
891                         break;
892                 }
893         }
894         if (!found) {
895                 newa = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (to->in_count + 1));
896                 for (i = 0; i < to->in_count; ++i) {
897                         newa [i] = to->in_bb [i];
898                 }
899                 newa [i] = from;
900                 to->in_count++;
901                 to->in_bb = newa;
902         }
903 }
904
905 /**
906  * mono_unlink_bblock:
907  *
908  *   Unlink two basic blocks.
909  */
910 void
911 mono_unlink_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
912 {
913         int i, pos;
914         gboolean found;
915
916         found = FALSE;
917         for (i = 0; i < from->out_count; ++i) {
918                 if (to == from->out_bb [i]) {
919                         found = TRUE;
920                         break;
921                 }
922         }
923         if (found) {
924                 pos = 0;
925                 for (i = 0; i < from->out_count; ++i) {
926                         if (from->out_bb [i] != to)
927                                 from->out_bb [pos ++] = from->out_bb [i];
928                 }
929                 g_assert (pos == from->out_count - 1);
930                 from->out_count--;
931         }
932
933         found = FALSE;
934         for (i = 0; i < to->in_count; ++i) {
935                 if (from == to->in_bb [i]) {
936                         found = TRUE;
937                         break;
938                 }
939         }
940         if (found) {
941                 pos = 0;
942                 for (i = 0; i < to->in_count; ++i) {
943                         if (to->in_bb [i] != from)
944                                 to->in_bb [pos ++] = to->in_bb [i];
945                 }
946                 g_assert (pos == to->in_count - 1);
947                 to->in_count--;
948         }
949 }
950
951 /*
952  * mono_bblocks_linked:
953  *
954  *   Return whenever BB1 and BB2 are linked in the CFG.
955  */
956 gboolean
957 mono_bblocks_linked (MonoBasicBlock *bb1, MonoBasicBlock *bb2)
958 {
959         int i;
960
961         for (i = 0; i < bb1->out_count; ++i) {
962                 if (bb1->out_bb [i] == bb2)
963                         return TRUE;
964         }
965
966         return FALSE;
967 }
968
969 /**
970  * mono_find_block_region:
971  *
972  *   We mark each basic block with a region ID. We use that to avoid BB
973  *   optimizations when blocks are in different regions.
974  *
975  * Returns:
976  *   A region token that encodes where this region is, and information
977  *   about the clause owner for this block.
978  *
979  *   The region encodes the try/catch/filter clause that owns this block
980  *   as well as the type.  -1 is a special value that represents a block
981  *   that is in none of try/catch/filter.
982  */
983 static int
984 mono_find_block_region (MonoCompile *cfg, int offset)
985 {
986         MonoMethod *method = cfg->method;
987         MonoMethodHeader *header = mono_method_get_header (method);
988         MonoExceptionClause *clause;
989         int i;
990
991         /* first search for handlers and filters */
992         for (i = 0; i < header->num_clauses; ++i) {
993                 clause = &header->clauses [i];
994                 if ((clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) && (offset >= clause->data.filter_offset) &&
995                     (offset < (clause->handler_offset)))
996                         return ((i + 1) << 8) | MONO_REGION_FILTER | clause->flags;
997                            
998                 if (MONO_OFFSET_IN_HANDLER (clause, offset)) {
999                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY)
1000                                 return ((i + 1) << 8) | MONO_REGION_FINALLY | clause->flags;
1001                         else if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
1002                                 return ((i + 1) << 8) | MONO_REGION_FAULT | clause->flags;
1003                         else if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE)
1004                                 return ((i + 1) << 8) | MONO_REGION_CATCH | clause->flags;
1005                 }
1006         }
1007
1008         /* search the try blocks */
1009         for (i = 0; i < header->num_clauses; ++i) {
1010                 clause = &header->clauses [i];
1011                 if (MONO_OFFSET_IN_CLAUSE (clause, offset))
1012                         return ((i + 1) << 8) | clause->flags;
1013         }
1014
1015         return -1;
1016 }
1017
1018 static GList*
1019 mono_find_final_block (MonoCompile *cfg, unsigned char *ip, unsigned char *target, int type)
1020 {
1021         MonoMethod *method = cfg->method;
1022         MonoMethodHeader *header = mono_method_get_header (method);
1023         MonoExceptionClause *clause;
1024         MonoBasicBlock *handler;
1025         int i;
1026         GList *res = NULL;
1027
1028         for (i = 0; i < header->num_clauses; ++i) {
1029                 clause = &header->clauses [i];
1030                 if (MONO_OFFSET_IN_CLAUSE (clause, (ip - header->code)) && 
1031                     (!MONO_OFFSET_IN_CLAUSE (clause, (target - header->code)))) {
1032                         if (clause->flags == type) {
1033                                 handler = cfg->cil_offset_to_bb [clause->handler_offset];
1034                                 g_assert (handler);
1035                                 res = g_list_append (res, handler);
1036                         }
1037                 }
1038         }
1039         return res;
1040 }
1041
1042 MonoInst *
1043 mono_find_spvar_for_region (MonoCompile *cfg, int region)
1044 {
1045         return g_hash_table_lookup (cfg->spvars, GINT_TO_POINTER (region));
1046 }
1047
1048 static void
1049 mono_create_spvar_for_region (MonoCompile *cfg, int region)
1050 {
1051         MonoInst *var;
1052
1053         var = g_hash_table_lookup (cfg->spvars, GINT_TO_POINTER (region));
1054         if (var)
1055                 return;
1056
1057         var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1058         /* prevent it from being register allocated */
1059         var->flags |= MONO_INST_INDIRECT;
1060
1061         g_hash_table_insert (cfg->spvars, GINT_TO_POINTER (region), var);
1062 }
1063
1064 static MonoInst *
1065 mono_find_exvar_for_offset (MonoCompile *cfg, int offset)
1066 {
1067         return g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
1068 }
1069
1070 static MonoInst*
1071 mono_create_exvar_for_offset (MonoCompile *cfg, int offset)
1072 {
1073         MonoInst *var;
1074
1075         var = g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
1076         if (var)
1077                 return var;
1078
1079         var = mono_compile_create_var (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL);
1080         /* prevent it from being register allocated */
1081         var->flags |= MONO_INST_INDIRECT;
1082
1083         g_hash_table_insert (cfg->exvars, GINT_TO_POINTER (offset), var);
1084
1085         return var;
1086 }
1087
1088 static void
1089 df_visit (MonoBasicBlock *start, int *dfn, MonoBasicBlock **array)
1090 {
1091         int i;
1092
1093         array [*dfn] = start;
1094         /* g_print ("visit %d at %p (BB%ld)\n", *dfn, start->cil_code, start->block_num); */
1095         for (i = 0; i < start->out_count; ++i) {
1096                 if (start->out_bb [i]->dfn)
1097                         continue;
1098                 (*dfn)++;
1099                 start->out_bb [i]->dfn = *dfn;
1100                 start->out_bb [i]->df_parent = start;
1101                 array [*dfn] = start->out_bb [i];
1102                 df_visit (start->out_bb [i], dfn, array);
1103         }
1104 }
1105
1106 static MonoBasicBlock*
1107 find_previous (MonoBasicBlock **bblocks, guint32 n_bblocks, MonoBasicBlock *start, const guchar *code)
1108 {
1109         MonoBasicBlock *best = start;
1110         int i;
1111
1112         for (i = 0; i < n_bblocks; ++i) {
1113                 if (bblocks [i]) {
1114                         MonoBasicBlock *bb = bblocks [i];
1115
1116                         if (bb->cil_code && bb->cil_code < code && bb->cil_code > best->cil_code)
1117                                 best = bb;
1118                 }
1119         }
1120
1121         return best;
1122 }
1123
1124 static void
1125 split_bblock (MonoCompile *cfg, MonoBasicBlock *first, MonoBasicBlock *second) {
1126         int i, j;
1127         MonoInst *inst;
1128         MonoBasicBlock *bb;
1129
1130         if (second->code)
1131                 return;
1132         
1133         /* 
1134          * FIXME: take into account all the details:
1135          * second may have been the target of more than one bblock
1136          */
1137         second->out_count = first->out_count;
1138         second->out_bb = first->out_bb;
1139
1140         for (i = 0; i < first->out_count; ++i) {
1141                 bb = first->out_bb [i];
1142                 for (j = 0; j < bb->in_count; ++j) {
1143                         if (bb->in_bb [j] == first)
1144                                 bb->in_bb [j] = second;
1145                 }
1146         }
1147
1148         first->out_count = 0;
1149         first->out_bb = NULL;
1150         link_bblock (cfg, first, second);
1151
1152         second->last_ins = first->last_ins;
1153
1154         /*g_print ("start search at %p for %p\n", first->cil_code, second->cil_code);*/
1155         MONO_BB_FOR_EACH_INS (first, inst) {
1156                 /*char *code = mono_disasm_code_one (NULL, cfg->method, inst->next->cil_code, NULL);
1157                 g_print ("found %p: %s", inst->next->cil_code, code);
1158                 g_free (code);*/
1159                 if (inst->cil_code < second->cil_code && inst->next->cil_code >= second->cil_code) {
1160                         second->code = inst->next;
1161                         inst->next = NULL;
1162                         first->last_ins = inst;
1163                         second->next_bb = first->next_bb;
1164                         first->next_bb = second;
1165                         return;
1166                 }
1167         }
1168         if (!second->code) {
1169                 g_warning ("bblock split failed in %s::%s\n", cfg->method->klass->name, cfg->method->name);
1170                 //G_BREAKPOINT ();
1171         }
1172 }
1173
1174 guint32
1175 mono_reverse_branch_op (guint32 opcode)
1176 {
1177         static const int reverse_map [] = {
1178                 CEE_BNE_UN, CEE_BLT, CEE_BLE, CEE_BGT, CEE_BGE,
1179                 CEE_BEQ, CEE_BLT_UN, CEE_BLE_UN, CEE_BGT_UN, CEE_BGE_UN
1180         };
1181         static const int reverse_fmap [] = {
1182                 OP_FBNE_UN, OP_FBLT, OP_FBLE, OP_FBGT, OP_FBGE,
1183                 OP_FBEQ, OP_FBLT_UN, OP_FBLE_UN, OP_FBGT_UN, OP_FBGE_UN
1184         };
1185         static const int reverse_lmap [] = {
1186                 OP_LBNE_UN, OP_LBLT, OP_LBLE, OP_LBGT, OP_LBGE,
1187                 OP_LBEQ, OP_LBLT_UN, OP_LBLE_UN, OP_LBGT_UN, OP_LBGE_UN
1188         };
1189         static const int reverse_imap [] = {
1190                 OP_IBNE_UN, OP_IBLT, OP_IBLE, OP_IBGT, OP_IBGE,
1191                 OP_IBEQ, OP_IBLT_UN, OP_IBLE_UN, OP_IBGT_UN, OP_IBGE_UN
1192         };
1193                                 
1194         if (opcode >= CEE_BEQ && opcode <= CEE_BLT_UN) {
1195                 opcode = reverse_map [opcode - CEE_BEQ];
1196         } else if (opcode >= OP_FBEQ && opcode <= OP_FBLT_UN) {
1197                 opcode = reverse_fmap [opcode - OP_FBEQ];
1198         } else if (opcode >= OP_LBEQ && opcode <= OP_LBLT_UN) {
1199                 opcode = reverse_lmap [opcode - OP_LBEQ];
1200         } else if (opcode >= OP_IBEQ && opcode <= OP_IBLT_UN) {
1201                 opcode = reverse_imap [opcode - OP_IBEQ];
1202         } else
1203                 g_assert_not_reached ();
1204
1205         return opcode;
1206 }
1207
1208 guint
1209 mono_type_to_store_membase (MonoCompile *cfg, MonoType *type)
1210 {
1211         if (type->byref)
1212                 return OP_STORE_MEMBASE_REG;
1213
1214 handle_enum:
1215         switch (type->type) {
1216         case MONO_TYPE_I1:
1217         case MONO_TYPE_U1:
1218         case MONO_TYPE_BOOLEAN:
1219                 return OP_STOREI1_MEMBASE_REG;
1220         case MONO_TYPE_I2:
1221         case MONO_TYPE_U2:
1222         case MONO_TYPE_CHAR:
1223                 return OP_STOREI2_MEMBASE_REG;
1224         case MONO_TYPE_I4:
1225         case MONO_TYPE_U4:
1226                 return OP_STOREI4_MEMBASE_REG;
1227         case MONO_TYPE_I:
1228         case MONO_TYPE_U:
1229         case MONO_TYPE_PTR:
1230         case MONO_TYPE_FNPTR:
1231                 return OP_STORE_MEMBASE_REG;
1232         case MONO_TYPE_CLASS:
1233         case MONO_TYPE_STRING:
1234         case MONO_TYPE_OBJECT:
1235         case MONO_TYPE_SZARRAY:
1236         case MONO_TYPE_ARRAY:    
1237                 return OP_STORE_MEMBASE_REG;
1238         case MONO_TYPE_I8:
1239         case MONO_TYPE_U8:
1240                 return OP_STOREI8_MEMBASE_REG;
1241         case MONO_TYPE_R4:
1242                 return OP_STORER4_MEMBASE_REG;
1243         case MONO_TYPE_R8:
1244                 return OP_STORER8_MEMBASE_REG;
1245         case MONO_TYPE_VALUETYPE:
1246                 if (type->data.klass->enumtype) {
1247                         type = type->data.klass->enum_basetype;
1248                         goto handle_enum;
1249                 }
1250                 return OP_STOREV_MEMBASE;
1251         case MONO_TYPE_TYPEDBYREF:
1252                 return OP_STOREV_MEMBASE;
1253         case MONO_TYPE_GENERICINST:
1254                 type = &type->data.generic_class->container_class->byval_arg;
1255                 goto handle_enum;
1256         case MONO_TYPE_VAR:
1257         case MONO_TYPE_MVAR:
1258                 /* FIXME: all the arguments must be references for now,
1259                  * later look inside cfg and see if the arg num is
1260                  * really a reference
1261                  */
1262                 g_assert (cfg->generic_sharing_context);
1263                 return OP_STORE_MEMBASE_REG;
1264         default:
1265                 g_error ("unknown type 0x%02x in type_to_store_membase", type->type);
1266         }
1267         return -1;
1268 }
1269
1270 guint
1271 mono_type_to_load_membase (MonoCompile *cfg, MonoType *type)
1272 {
1273         if (type->byref)
1274                 return OP_LOAD_MEMBASE;
1275
1276         switch (mono_type_get_underlying_type (type)->type) {
1277         case MONO_TYPE_I1:
1278                 return OP_LOADI1_MEMBASE;
1279         case MONO_TYPE_U1:
1280         case MONO_TYPE_BOOLEAN:
1281                 return OP_LOADU1_MEMBASE;
1282         case MONO_TYPE_I2:
1283                 return OP_LOADI2_MEMBASE;
1284         case MONO_TYPE_U2:
1285         case MONO_TYPE_CHAR:
1286                 return OP_LOADU2_MEMBASE;
1287         case MONO_TYPE_I4:
1288                 return OP_LOADI4_MEMBASE;
1289         case MONO_TYPE_U4:
1290                 return OP_LOADU4_MEMBASE;
1291         case MONO_TYPE_I:
1292         case MONO_TYPE_U:
1293         case MONO_TYPE_PTR:
1294         case MONO_TYPE_FNPTR:
1295                 return OP_LOAD_MEMBASE;
1296         case MONO_TYPE_CLASS:
1297         case MONO_TYPE_STRING:
1298         case MONO_TYPE_OBJECT:
1299         case MONO_TYPE_SZARRAY:
1300         case MONO_TYPE_ARRAY:    
1301                 return OP_LOAD_MEMBASE;
1302         case MONO_TYPE_I8:
1303         case MONO_TYPE_U8:
1304                 return OP_LOADI8_MEMBASE;
1305         case MONO_TYPE_R4:
1306                 return OP_LOADR4_MEMBASE;
1307         case MONO_TYPE_R8:
1308                 return OP_LOADR8_MEMBASE;
1309         case MONO_TYPE_VALUETYPE:
1310         case MONO_TYPE_TYPEDBYREF:
1311                 return OP_LOADV_MEMBASE;
1312         case MONO_TYPE_GENERICINST:
1313                 if (mono_type_generic_inst_is_valuetype (type))
1314                         return OP_LOADV_MEMBASE;
1315                 else
1316                         return OP_LOAD_MEMBASE;
1317                 break;
1318         case MONO_TYPE_VAR:
1319         case MONO_TYPE_MVAR:
1320                 /* FIXME: all the arguments must be references for now,
1321                  * later look inside cfg and see if the arg num is
1322                  * really a reference
1323                  */
1324                 g_assert (cfg->generic_sharing_context);
1325                 return OP_LOAD_MEMBASE;
1326         default:
1327                 g_error ("unknown type 0x%02x in type_to_load_membase", type->type);
1328         }
1329         return -1;
1330 }
1331
1332 #ifdef MONO_ARCH_SOFT_FLOAT
1333 static int
1334 condbr_to_fp_br (int opcode)
1335 {
1336         switch (opcode) {
1337         case CEE_BEQ: return OP_FBEQ;
1338         case CEE_BGE: return OP_FBGE;
1339         case CEE_BGT: return OP_FBGT;
1340         case CEE_BLE: return OP_FBLE;
1341         case CEE_BLT: return OP_FBLT;
1342         case CEE_BNE_UN: return OP_FBNE_UN;
1343         case CEE_BGE_UN: return OP_FBGE_UN;
1344         case CEE_BGT_UN: return OP_FBGT_UN;
1345         case CEE_BLE_UN: return OP_FBLE_UN;
1346         case CEE_BLT_UN: return OP_FBLT_UN;
1347         }
1348         g_assert_not_reached ();
1349         return 0;
1350 }
1351 #endif
1352
1353 /*
1354  * Returns the type used in the eval stack when @type is loaded.
1355  * FIXME: return a MonoType/MonoClass for the byref and VALUETYPE cases.
1356  */
1357 static void
1358 type_to_eval_stack_type (MonoCompile *cfg, MonoType *type, MonoInst *inst)
1359 {
1360         MonoClass *klass;
1361
1362         inst->klass = klass = mono_class_from_mono_type (type);
1363         if (type->byref) {
1364                 inst->type = STACK_MP;
1365                 return;
1366         }
1367
1368 handle_enum:
1369         switch (type->type) {
1370         case MONO_TYPE_VOID:
1371                 inst->type = STACK_INV;
1372                 return;
1373         case MONO_TYPE_I1:
1374         case MONO_TYPE_U1:
1375         case MONO_TYPE_BOOLEAN:
1376         case MONO_TYPE_I2:
1377         case MONO_TYPE_U2:
1378         case MONO_TYPE_CHAR:
1379         case MONO_TYPE_I4:
1380         case MONO_TYPE_U4:
1381                 inst->type = STACK_I4;
1382                 return;
1383         case MONO_TYPE_I:
1384         case MONO_TYPE_U:
1385         case MONO_TYPE_PTR:
1386         case MONO_TYPE_FNPTR:
1387                 inst->type = STACK_PTR;
1388                 return;
1389         case MONO_TYPE_CLASS:
1390         case MONO_TYPE_STRING:
1391         case MONO_TYPE_OBJECT:
1392         case MONO_TYPE_SZARRAY:
1393         case MONO_TYPE_ARRAY:    
1394                 inst->type = STACK_OBJ;
1395                 return;
1396         case MONO_TYPE_I8:
1397         case MONO_TYPE_U8:
1398                 inst->type = STACK_I8;
1399                 return;
1400         case MONO_TYPE_R4:
1401         case MONO_TYPE_R8:
1402                 inst->type = STACK_R8;
1403                 return;
1404         case MONO_TYPE_VALUETYPE:
1405                 if (type->data.klass->enumtype) {
1406                         type = type->data.klass->enum_basetype;
1407                         goto handle_enum;
1408                 } else {
1409                         inst->klass = klass;
1410                         inst->type = STACK_VTYPE;
1411                         return;
1412                 }
1413         case MONO_TYPE_TYPEDBYREF:
1414                 inst->klass = mono_defaults.typed_reference_class;
1415                 inst->type = STACK_VTYPE;
1416                 return;
1417         case MONO_TYPE_GENERICINST:
1418                 type = &type->data.generic_class->container_class->byval_arg;
1419                 goto handle_enum;
1420         case MONO_TYPE_VAR :
1421         case MONO_TYPE_MVAR :
1422                 /* FIXME: all the arguments must be references for now,
1423                  * later look inside cfg and see if the arg num is
1424                  * really a reference
1425                  */
1426                 g_assert (cfg->generic_sharing_context);
1427                 inst->type = STACK_OBJ;
1428                 return;
1429         default:
1430                 g_error ("unknown type 0x%02x in eval stack type", type->type);
1431         }
1432 }
1433
1434 /*
1435  * The following tables are used to quickly validate the IL code in type_from_op ().
1436  */
1437 static const char
1438 bin_num_table [STACK_MAX] [STACK_MAX] = {
1439         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1440         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
1441         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1442         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
1443         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_R8,  STACK_INV, STACK_INV, STACK_INV},
1444         {STACK_INV, STACK_MP,  STACK_INV, STACK_MP,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV},
1445         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1446         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
1447 };
1448
1449 static const char 
1450 neg_table [] = {
1451         STACK_INV, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_INV, STACK_INV, STACK_INV
1452 };
1453
1454 /* reduce the size of this table */
1455 static const char
1456 bin_int_table [STACK_MAX] [STACK_MAX] = {
1457         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1458         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1459         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1460         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1461         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1462         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1463         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1464         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
1465 };
1466
1467 static const char
1468 bin_comp_table [STACK_MAX] [STACK_MAX] = {
1469 /*      Inv i  L  p  F  &  O  vt */
1470         {0},
1471         {0, 1, 0, 1, 0, 0, 0, 0}, /* i, int32 */
1472         {0, 0, 1, 0, 0, 0, 0, 0}, /* L, int64 */
1473         {0, 1, 0, 1, 0, 2, 4, 0}, /* p, ptr */
1474         {0, 0, 0, 0, 1, 0, 0, 0}, /* F, R8 */
1475         {0, 0, 0, 2, 0, 1, 0, 0}, /* &, managed pointer */
1476         {0, 0, 0, 4, 0, 0, 3, 0}, /* O, reference */
1477         {0, 0, 0, 0, 0, 0, 0, 0}, /* vt value type */
1478 };
1479
1480 /* reduce the size of this table */
1481 static const char
1482 shift_table [STACK_MAX] [STACK_MAX] = {
1483         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1484         {STACK_INV, STACK_I4,  STACK_INV, STACK_I4,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1485         {STACK_INV, STACK_I8,  STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1486         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1487         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1488         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1489         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1490         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
1491 };
1492
1493 /*
1494  * Tables to map from the non-specific opcode to the matching
1495  * type-specific opcode.
1496  */
1497 /* handles from CEE_ADD to CEE_SHR_UN (CEE_REM_UN for floats) */
1498 static const guint16
1499 binops_op_map [STACK_MAX] = {
1500         0, 0, OP_LADD-CEE_ADD, OP_PADD-CEE_ADD, OP_FADD-CEE_ADD, OP_PADD-CEE_ADD
1501 };
1502
1503 /* handles from CEE_NEG to CEE_CONV_U8 */
1504 static const guint16
1505 unops_op_map [STACK_MAX] = {
1506         0, 0, OP_LNEG-CEE_NEG, OP_PNEG-CEE_NEG, OP_FNEG-CEE_NEG, OP_PNEG-CEE_NEG
1507 };
1508
1509 /* handles from CEE_CONV_U2 to CEE_SUB_OVF_UN */
1510 static const guint16
1511 ovfops_op_map [STACK_MAX] = {
1512         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
1513 };
1514
1515 /* handles from CEE_CONV_OVF_I1_UN to CEE_CONV_OVF_U_UN */
1516 static const guint16
1517 ovf2ops_op_map [STACK_MAX] = {
1518         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
1519 };
1520
1521 /* handles from CEE_CONV_OVF_I1 to CEE_CONV_OVF_U8 */
1522 static const guint16
1523 ovf3ops_op_map [STACK_MAX] = {
1524         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
1525 };
1526
1527 /* handles from CEE_CEQ to CEE_CLT_UN */
1528 static const guint16
1529 ceqops_op_map [STACK_MAX] = {
1530         0, 0, OP_LCEQ-OP_CEQ, OP_PCEQ-OP_CEQ, OP_FCEQ-OP_CEQ, OP_LCEQ-OP_CEQ
1531 };
1532
1533 /*
1534  * Sets ins->type (the type on the eval stack) according to the
1535  * type of the opcode and the arguments to it.
1536  * Invalid IL code is marked by setting ins->type to the invalid value STACK_INV.
1537  *
1538  * FIXME: this function sets ins->type unconditionally in some cases, but
1539  * it should set it to invalid for some types (a conv.x on an object)
1540  */
1541 static void
1542 type_from_op (MonoInst *ins) {
1543         switch (ins->opcode) {
1544         /* binops */
1545         case CEE_ADD:
1546         case CEE_SUB:
1547         case CEE_MUL:
1548         case CEE_DIV:
1549         case CEE_REM:
1550                 /* FIXME: check unverifiable args for STACK_MP */
1551                 ins->type = bin_num_table [ins->inst_i0->type] [ins->inst_i1->type];
1552                 ins->opcode += binops_op_map [ins->type];
1553                 return;
1554         case CEE_DIV_UN:
1555         case CEE_REM_UN:
1556         case CEE_AND:
1557         case CEE_OR:
1558         case CEE_XOR:
1559                 ins->type = bin_int_table [ins->inst_i0->type] [ins->inst_i1->type];
1560                 ins->opcode += binops_op_map [ins->type];
1561                 return;
1562         case CEE_SHL:
1563         case CEE_SHR:
1564         case CEE_SHR_UN:
1565                 ins->type = shift_table [ins->inst_i0->type] [ins->inst_i1->type];
1566                 ins->opcode += binops_op_map [ins->type];
1567                 return;
1568         case OP_COMPARE:
1569         case OP_LCOMPARE:
1570                 /* FIXME: handle some specifics with ins->next->type */
1571                 ins->type = bin_comp_table [ins->inst_i0->type] [ins->inst_i1->type] ? STACK_I4: STACK_INV;
1572                 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))))
1573                         ins->opcode = OP_LCOMPARE;
1574                 return;
1575         case OP_CEQ:
1576                 ins->type = bin_comp_table [ins->inst_i0->type] [ins->inst_i1->type] ? STACK_I4: STACK_INV;
1577                 ins->opcode += ceqops_op_map [ins->inst_i0->type];
1578                 return;
1579                 
1580         case OP_CGT:
1581         case OP_CGT_UN:
1582         case OP_CLT:
1583         case OP_CLT_UN:
1584                 ins->type = (bin_comp_table [ins->inst_i0->type] [ins->inst_i1->type] & 1) ? STACK_I4: STACK_INV;
1585                 ins->opcode += ceqops_op_map [ins->inst_i0->type];
1586                 return;
1587         /* unops */
1588         case CEE_NEG:
1589                 ins->type = neg_table [ins->inst_i0->type];
1590                 ins->opcode += unops_op_map [ins->type];
1591                 return;
1592         case CEE_NOT:
1593                 if (ins->inst_i0->type >= STACK_I4 && ins->inst_i0->type <= STACK_PTR)
1594                         ins->type = ins->inst_i0->type;
1595                 else
1596                         ins->type = STACK_INV;
1597                 ins->opcode += unops_op_map [ins->type];
1598                 return;
1599         case CEE_CONV_I1:
1600         case CEE_CONV_I2:
1601         case CEE_CONV_I4:
1602         case CEE_CONV_U4:
1603                 ins->type = STACK_I4;
1604                 ins->opcode += unops_op_map [ins->inst_i0->type];
1605                 return;
1606         case CEE_CONV_R_UN:
1607                 ins->type = STACK_R8;
1608                 switch (ins->inst_i0->type) {
1609                 case STACK_I4:
1610                 case STACK_PTR:
1611                         break;
1612                 case STACK_I8:
1613                         ins->opcode = OP_LCONV_TO_R_UN; 
1614                         break;
1615                 }
1616                 return;
1617         case CEE_CONV_OVF_I1:
1618         case CEE_CONV_OVF_U1:
1619         case CEE_CONV_OVF_I2:
1620         case CEE_CONV_OVF_U2:
1621         case CEE_CONV_OVF_I4:
1622         case CEE_CONV_OVF_U4:
1623                 ins->type = STACK_I4;
1624                 ins->opcode += ovf3ops_op_map [ins->inst_i0->type];
1625                 return;
1626         case CEE_CONV_OVF_I_UN:
1627         case CEE_CONV_OVF_U_UN:
1628                 ins->type = STACK_PTR;
1629                 ins->opcode += ovf2ops_op_map [ins->inst_i0->type];
1630                 return;
1631         case CEE_CONV_OVF_I1_UN:
1632         case CEE_CONV_OVF_I2_UN:
1633         case CEE_CONV_OVF_I4_UN:
1634         case CEE_CONV_OVF_U1_UN:
1635         case CEE_CONV_OVF_U2_UN:
1636         case CEE_CONV_OVF_U4_UN:
1637                 ins->type = STACK_I4;
1638                 ins->opcode += ovf2ops_op_map [ins->inst_i0->type];
1639                 return;
1640         case CEE_CONV_U:
1641                 ins->type = STACK_PTR;
1642                 switch (ins->inst_i0->type) {
1643                 case STACK_I4:
1644                         break;
1645                 case STACK_PTR:
1646                 case STACK_MP:
1647 #if SIZEOF_VOID_P == 8
1648                         ins->opcode = OP_LCONV_TO_U;
1649 #endif
1650                         break;
1651                 case STACK_I8:
1652                         ins->opcode = OP_LCONV_TO_U;
1653                         break;
1654                 case STACK_R8:
1655                         ins->opcode = OP_FCONV_TO_U;
1656                         break;
1657                 }
1658                 return;
1659         case CEE_CONV_I8:
1660         case CEE_CONV_U8:
1661                 ins->type = STACK_I8;
1662                 ins->opcode += unops_op_map [ins->inst_i0->type];
1663                 return;
1664         case CEE_CONV_OVF_I8:
1665         case CEE_CONV_OVF_U8:
1666                 ins->type = STACK_I8;
1667                 ins->opcode += ovf3ops_op_map [ins->inst_i0->type];
1668                 return;
1669         case CEE_CONV_OVF_U8_UN:
1670         case CEE_CONV_OVF_I8_UN:
1671                 ins->type = STACK_I8;
1672                 ins->opcode += ovf2ops_op_map [ins->inst_i0->type];
1673                 return;
1674         case CEE_CONV_R4:
1675         case CEE_CONV_R8:
1676                 ins->type = STACK_R8;
1677                 ins->opcode += unops_op_map [ins->inst_i0->type];
1678                 return;
1679         case OP_CKFINITE:
1680                 ins->type = STACK_R8;           
1681                 return;
1682         case CEE_CONV_U2:
1683         case CEE_CONV_U1:
1684                 ins->type = STACK_I4;
1685                 ins->opcode += ovfops_op_map [ins->inst_i0->type];
1686                 break;
1687         case CEE_CONV_I:
1688         case CEE_CONV_OVF_I:
1689         case CEE_CONV_OVF_U:
1690                 ins->type = STACK_PTR;
1691                 ins->opcode += ovfops_op_map [ins->inst_i0->type];
1692                 return;
1693         case CEE_ADD_OVF:
1694         case CEE_ADD_OVF_UN:
1695         case CEE_MUL_OVF:
1696         case CEE_MUL_OVF_UN:
1697         case CEE_SUB_OVF:
1698         case CEE_SUB_OVF_UN:
1699                 ins->type = bin_num_table [ins->inst_i0->type] [ins->inst_i1->type];
1700                 ins->opcode += ovfops_op_map [ins->inst_i0->type];
1701                 if (ins->type == STACK_R8)
1702                         ins->type = STACK_INV;
1703                 return;
1704         default:
1705                 g_error ("opcode 0x%04x not handled in type from op", ins->opcode);
1706                 break;
1707         }
1708 }
1709
1710 static const char 
1711 ldind_type [] = {
1712         STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_R8, STACK_OBJ
1713 };
1714
1715 /* map ldelem.x to the matching ldind.x opcode */
1716 static const guchar
1717 ldelem_to_ldind [] = {
1718         CEE_LDIND_I1,
1719         CEE_LDIND_U1,
1720         CEE_LDIND_I2,
1721         CEE_LDIND_U2,
1722         CEE_LDIND_I4,
1723         CEE_LDIND_U4,
1724         CEE_LDIND_I8,
1725         CEE_LDIND_I,
1726         CEE_LDIND_R4,
1727         CEE_LDIND_R8,
1728         CEE_LDIND_REF
1729 };
1730
1731 /* map stelem.x to the matching stind.x opcode */
1732 static const guchar
1733 stelem_to_stind [] = {
1734         CEE_STIND_I,
1735         CEE_STIND_I1,
1736         CEE_STIND_I2,
1737         CEE_STIND_I4,
1738         CEE_STIND_I8,
1739         CEE_STIND_R4,
1740         CEE_STIND_R8,
1741         CEE_STIND_REF
1742 };
1743
1744
1745 #ifdef MONO_ARCH_SOFT_FLOAT
1746 static void
1747 handle_store_float (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *ptr, MonoInst *val, const unsigned char *ip)
1748 {
1749         MonoInst *iargs [2];
1750         iargs [0] = val;
1751         iargs [1] = ptr;
1752
1753         mono_emit_jit_icall (cfg, bblock, mono_fstore_r4, iargs, ip);
1754 }
1755
1756 static int
1757 handle_load_float (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *ptr, const unsigned char *ip)
1758 {
1759         MonoInst *iargs [1];
1760         iargs [0] = ptr;
1761
1762         return mono_emit_jit_icall (cfg, bblock, mono_fload_r4, iargs, ip);
1763 }
1764
1765 #define LDLOC_SOFT_FLOAT(cfg,ins,idx,ip) do {\
1766                 if (header->locals [(idx)]->type == MONO_TYPE_R4 && !header->locals [(idx)]->byref) {   \
1767                         int temp;       \
1768                         NEW_LOCLOADA (cfg, (ins), (idx));       \
1769                         temp = handle_load_float (cfg, bblock, (ins), (ip));    \
1770                         NEW_TEMPLOAD (cfg, (ins), temp);        \
1771                 }       \
1772         } while (0)
1773 #define STLOC_SOFT_FLOAT(cfg,ins,idx,ip) do {\
1774                 if (header->locals [(idx)]->type == MONO_TYPE_R4 && !header->locals [(idx)]->byref) {   \
1775                         NEW_LOCLOADA (cfg, (ins), (idx));       \
1776                         handle_store_float (cfg, bblock, (ins), *sp, (ip));     \
1777                         MONO_INST_NEW (cfg, (ins), OP_NOP);     \
1778                 }       \
1779         } while (0)
1780 #define LDARG_SOFT_FLOAT(cfg,ins,idx,ip) do {\
1781                 if (param_types [(idx)]->type == MONO_TYPE_R4 && !param_types [(idx)]->byref) { \
1782                         int temp;       \
1783                         NEW_ARGLOADA (cfg, (ins), (idx));       \
1784                         temp = handle_load_float (cfg, bblock, (ins), (ip));    \
1785                         NEW_TEMPLOAD (cfg, (ins), temp);        \
1786                 }       \
1787         } while (0)
1788 #define STARG_SOFT_FLOAT(cfg,ins,idx,ip) do {\
1789                 if (param_types [(idx)]->type == MONO_TYPE_R4 && !param_types [(idx)]->byref) { \
1790                         NEW_ARGLOADA (cfg, (ins), (idx));       \
1791                         handle_store_float (cfg, bblock, (ins), *sp, (ip));     \
1792                         MONO_INST_NEW (cfg, (ins), OP_NOP);     \
1793                 }       \
1794         } while (0)
1795
1796 #define NEW_TEMPLOAD_SOFT_FLOAT(cfg,bblock,ins,num,ip) do {             \
1797         if ((ins)->opcode == CEE_LDIND_R4) {                                            \
1798             int idx = (num);                                                                            \
1799             int temp;                                                                                   \
1800             NEW_TEMPLOADA (cfg, (ins), (idx));                                                  \
1801                 temp = handle_load_float (cfg, (bblock), (ins), ip);            \
1802                 NEW_TEMPLOAD (cfg, (ins), (temp));                                                      \
1803         }                                                                                                                               \
1804         } while (0)
1805
1806 #define NEW_TEMPSTORE_SOFT_FLOAT(cfg,bblock,ins,num,val,ip) do {                \
1807         if ((ins)->opcode == CEE_STIND_R4) {                                                            \
1808             int idx = (num);                                                                            \
1809                 NEW_TEMPLOADA (cfg, (ins), (idx)); \
1810                 handle_store_float ((cfg), (bblock), (ins), (val), (ip));       \
1811         } \
1812         } while (0)
1813
1814 #else
1815
1816 #define LDLOC_SOFT_FLOAT(cfg,ins,idx,ip)
1817 #define STLOC_SOFT_FLOAT(cfg,ins,idx,ip)
1818 #define LDARG_SOFT_FLOAT(cfg,ins,idx,ip)
1819 #define STARG_SOFT_FLOAT(cfg,ins,idx,ip)
1820 #define NEW_TEMPLOAD_SOFT_FLOAT(cfg,bblock,ins,num,ip)
1821 #define NEW_TEMPSTORE_SOFT_FLOAT(cfg,bblock,ins,num,val,ip)
1822 #endif
1823
1824 #if 0
1825
1826 static const char
1827 param_table [STACK_MAX] [STACK_MAX] = {
1828         {0},
1829 };
1830
1831 static int
1832 check_values_to_signature (MonoInst *args, MonoType *this, MonoMethodSignature *sig)
1833 {
1834         int i;
1835
1836         if (sig->hasthis) {
1837                 switch (args->type) {
1838                 case STACK_I4:
1839                 case STACK_I8:
1840                 case STACK_R8:
1841                 case STACK_VTYPE:
1842                 case STACK_INV:
1843                         return 0;
1844                 }
1845                 args++;
1846         }
1847         for (i = 0; i < sig->param_count; ++i) {
1848                 switch (args [i].type) {
1849                 case STACK_INV:
1850                         return 0;
1851                 case STACK_MP:
1852                         if (!sig->params [i]->byref)
1853                                 return 0;
1854                         continue;
1855                 case STACK_OBJ:
1856                         if (sig->params [i]->byref)
1857                                 return 0;
1858                         switch (sig->params [i]->type) {
1859                         case MONO_TYPE_CLASS:
1860                         case MONO_TYPE_STRING:
1861                         case MONO_TYPE_OBJECT:
1862                         case MONO_TYPE_SZARRAY:
1863                         case MONO_TYPE_ARRAY:
1864                                 break;
1865                         default:
1866                                 return 0;
1867                         }
1868                         continue;
1869                 case STACK_R8:
1870                         if (sig->params [i]->byref)
1871                                 return 0;
1872                         if (sig->params [i]->type != MONO_TYPE_R4 && sig->params [i]->type != MONO_TYPE_R8)
1873                                 return 0;
1874                         continue;
1875                 case STACK_PTR:
1876                 case STACK_I4:
1877                 case STACK_I8:
1878                 case STACK_VTYPE:
1879                         break;
1880                 }
1881                 /*if (!param_table [args [i].type] [sig->params [i]->type])
1882                         return 0;*/
1883         }
1884         return 1;
1885 }
1886 #endif
1887
1888 static guint
1889 mini_type_to_ldind (MonoCompile* cfg, MonoType *type)
1890 {
1891         if (cfg->generic_sharing_context && !type->byref) {
1892                 /* FIXME: all the arguments must be references for now,
1893                  * later look inside cfg and see if the arg num is
1894                  * really a reference
1895                  */
1896                 if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)
1897                         return CEE_LDIND_REF;
1898         }
1899         return mono_type_to_ldind (type);
1900 }
1901
1902 guint
1903 mini_type_to_stind (MonoCompile* cfg, MonoType *type)
1904 {
1905         if (cfg->generic_sharing_context && !type->byref) {
1906                 /* FIXME: all the arguments must be references for now,
1907                  * later look inside cfg and see if the arg num is
1908                  * really a reference
1909                  */
1910                 if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)
1911                         return CEE_STIND_REF;
1912         }
1913         return mono_type_to_stind (type);
1914 }
1915
1916 int
1917 mono_op_imm_to_op (int opcode)
1918 {
1919         switch (opcode) {
1920         case OP_ADD_IMM:
1921 #if SIZEOF_VOID_P == 4
1922                 return OP_IADD;
1923 #else
1924                 return OP_LADD;
1925 #endif
1926         case OP_IADD_IMM:
1927                 return OP_IADD;
1928         case OP_LADD_IMM:
1929                 return OP_LADD;
1930         case OP_ISUB_IMM:
1931                 return OP_ISUB;
1932         case OP_LSUB_IMM:
1933                 return OP_LSUB;
1934         case OP_IMUL_IMM:
1935                 return OP_IMUL;
1936         case OP_AND_IMM:
1937 #if SIZEOF_VOID_P == 4
1938                 return OP_IAND;
1939 #else
1940                 return OP_LAND;
1941 #endif
1942         case OP_IAND_IMM:
1943                 return OP_IAND;
1944         case OP_LAND_IMM:
1945                 return OP_LAND;
1946         case OP_IOR_IMM:
1947                 return OP_IOR;
1948         case OP_LOR_IMM:
1949                 return OP_LOR;
1950         case OP_IXOR_IMM:
1951                 return OP_IXOR;
1952         case OP_LXOR_IMM:
1953                 return OP_LXOR;
1954         case OP_ISHL_IMM:
1955                 return OP_ISHL;
1956         case OP_LSHL_IMM:
1957                 return OP_LSHL;
1958         case OP_ISHR_IMM:
1959                 return OP_ISHR;
1960         case OP_LSHR_IMM:
1961                 return OP_LSHR;
1962         case OP_ISHR_UN_IMM:
1963                 return OP_ISHR_UN;
1964         case OP_LSHR_UN_IMM:
1965                 return OP_LSHR_UN;
1966         case OP_IDIV_IMM:
1967                 return OP_IDIV;
1968         case OP_IDIV_UN_IMM:
1969                 return OP_IDIV_UN;
1970         case OP_IREM_UN_IMM:
1971                 return OP_IREM_UN;
1972         case OP_IREM_IMM:
1973                 return OP_IREM;
1974         case OP_DIV_IMM:
1975 #if SIZEOF_VOID_P == 4
1976                 return OP_IDIV;
1977 #else
1978                 return OP_LDIV;
1979 #endif
1980         case OP_REM_IMM:
1981 #if SIZEOF_VOID_P == 4
1982                 return OP_IREM;
1983 #else
1984                 return OP_LREM;
1985 #endif
1986         case OP_ADDCC_IMM:
1987                 return OP_ADDCC;
1988         case OP_ADC_IMM:
1989                 return OP_ADC;
1990         case OP_SUBCC_IMM:
1991                 return OP_SUBCC;
1992         case OP_SBB_IMM:
1993                 return OP_SBB;
1994         case OP_IADC_IMM:
1995                 return OP_IADC;
1996         case OP_ISBB_IMM:
1997                 return OP_ISBB;
1998         case OP_COMPARE_IMM:
1999                 return OP_COMPARE;
2000         case OP_ICOMPARE_IMM:
2001                 return OP_ICOMPARE;
2002         case OP_LOCALLOC_IMM:
2003                 return OP_LOCALLOC;
2004         default:
2005                 printf ("%s\n", mono_inst_name (opcode));
2006                 g_assert_not_reached ();
2007                 return -1;
2008         }
2009 }
2010
2011 /*
2012  * mono_decompose_op_imm:
2013  *
2014  *   Replace the OP_.._IMM INS with its non IMM variant.
2015  */
2016 void
2017 mono_decompose_op_imm (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *ins)
2018 {
2019         MonoInst *temp;
2020
2021         MONO_INST_NEW (cfg, temp, OP_ICONST);
2022         temp->inst_c0 = ins->inst_imm;
2023         temp->dreg = mono_regstate_next_int (cfg->rs);
2024         mono_bblock_insert_before_ins (bb, ins, temp);
2025         ins->opcode = mono_op_imm_to_op (ins->opcode);
2026         if (ins->opcode == OP_LOCALLOC)
2027                 ins->sreg1 = temp->dreg;
2028         else
2029                 ins->sreg2 = temp->dreg;
2030
2031         bb->max_vreg = MAX (bb->max_vreg, cfg->rs->next_vreg);
2032 }
2033
2034 /*
2035  * When we need a pointer to the current domain many times in a method, we
2036  * call mono_domain_get() once and we store the result in a local variable.
2037  * This function returns the variable that represents the MonoDomain*.
2038  */
2039 inline static MonoInst *
2040 mono_get_domainvar (MonoCompile *cfg)
2041 {
2042         if (!cfg->domainvar)
2043                 cfg->domainvar = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2044         return cfg->domainvar;
2045 }
2046
2047 /*
2048  * The got_var contains the address of the Global Offset Table when AOT 
2049  * compiling.
2050  */
2051 inline static MonoInst *
2052 mono_get_got_var (MonoCompile *cfg)
2053 {
2054 #ifdef MONO_ARCH_NEED_GOT_VAR
2055         if (!cfg->compile_aot)
2056                 return NULL;
2057         if (!cfg->got_var) {
2058                 cfg->got_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2059         }
2060         return cfg->got_var;
2061 #else
2062         return NULL;
2063 #endif
2064 }
2065
2066 static MonoInst *
2067 mono_get_vtable_var (MonoCompile *cfg)
2068 {
2069         g_assert (cfg->generic_sharing_context);
2070
2071         if (!cfg->rgctx_var) {
2072                 cfg->rgctx_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2073                 /* force the var to be stack allocated */
2074                 cfg->rgctx_var->flags |= MONO_INST_INDIRECT;
2075         }
2076
2077         return cfg->rgctx_var;
2078 }
2079
2080 static void
2081 set_vreg_to_inst (MonoCompile *cfg, int vreg, MonoInst *inst)
2082 {
2083         if (vreg >= cfg->vreg_to_inst_len) {
2084                 MonoInst **tmp = cfg->vreg_to_inst;
2085                 int size = cfg->vreg_to_inst_len;
2086
2087                 while (vreg >= cfg->vreg_to_inst_len)
2088                         cfg->vreg_to_inst_len = cfg->vreg_to_inst_len ? cfg->vreg_to_inst_len * 2 : 32;
2089                 cfg->vreg_to_inst = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * cfg->vreg_to_inst_len);
2090                 if (size)
2091                         memcpy (cfg->vreg_to_inst, tmp, size * sizeof (MonoInst*));
2092         }
2093         cfg->vreg_to_inst [vreg] = inst;
2094 }
2095
2096 #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)))
2097 #define mono_type_is_float(type) (!(type)->byref && (((type)->type == MONO_TYPE_R8) || ((type)->type == MONO_TYPE_R4)))
2098
2099 MonoInst*
2100 mono_compile_create_var_for_vreg (MonoCompile *cfg, MonoType *type, int opcode, int vreg)
2101 {
2102         MonoInst *inst;
2103         int num = cfg->num_varinfo;
2104         gboolean regpair;
2105
2106         if ((num + 1) >= cfg->varinfo_count) {
2107                 int orig_count = cfg->varinfo_count;
2108                 cfg->varinfo_count = cfg->varinfo_count ? (cfg->varinfo_count * 2) : 64;
2109                 cfg->varinfo = (MonoInst **)g_realloc (cfg->varinfo, sizeof (MonoInst*) * cfg->varinfo_count);
2110                 cfg->vars = (MonoMethodVar *)g_realloc (cfg->vars, sizeof (MonoMethodVar) * cfg->varinfo_count);
2111                 memset (&cfg->vars [orig_count], 0, (cfg->varinfo_count - orig_count) * sizeof (MonoMethodVar));
2112         }
2113
2114         mono_jit_stats.allocate_var++;
2115
2116         MONO_INST_NEW (cfg, inst, opcode);
2117         inst->inst_c0 = num;
2118         inst->inst_vtype = type;
2119         inst->klass = mono_class_from_mono_type (type);
2120         type_to_eval_stack_type (cfg, type, inst);
2121         /* if set to 1 the variable is native */
2122         inst->backend.is_pinvoke = 0;
2123         inst->dreg = vreg;
2124
2125         cfg->varinfo [num] = inst;
2126
2127         MONO_INIT_VARINFO (&cfg->vars [num], num);
2128
2129         if (vreg != -1)
2130                 set_vreg_to_inst (cfg, vreg, inst);
2131
2132 #if SIZEOF_VOID_P == 4
2133 #ifdef MONO_ARCH_SOFT_FLOAT
2134         regpair = mono_type_is_long (type) || mono_type_is_float (type);
2135 #else
2136         regpair = mono_type_is_long (type);
2137 #endif
2138 #else
2139         regpair = FALSE;
2140 #endif
2141
2142         if (regpair) {
2143                 MonoInst *tree;
2144
2145                 /* 
2146                  * These two cannot be allocated using create_var_for_vreg since that would
2147                  * put it into the cfg->varinfo array, confusing many parts of the JIT.
2148                  */
2149
2150                 /* 
2151                  * Set flags to VOLATILE so SSA skips it.
2152                  */
2153
2154                 if (cfg->verbose_level >= 4) {
2155                         printf ("  Create LVAR R%d (R%d, R%d)\n", inst->dreg, inst->dreg + 1, inst->dreg + 2);
2156                 }
2157
2158 #ifdef MONO_ARCH_SOFT_FLOAT
2159                 if (cfg->opt & MONO_OPT_SSA) {
2160                         if (mono_type_is_float (type))
2161                                 inst->flags = MONO_INST_VOLATILE;
2162                 }
2163 #endif
2164
2165                 /* Allocate a dummy MonoInst for the first vreg */
2166                 MONO_INST_NEW (cfg, tree, OP_LOCAL);
2167                 tree->dreg = inst->dreg + 1;
2168                 if (cfg->opt & MONO_OPT_SSA)
2169                         tree->flags = MONO_INST_VOLATILE;
2170                 tree->inst_c0 = num;
2171                 tree->type = STACK_I4;
2172                 tree->inst_vtype = &mono_defaults.int32_class->byval_arg;
2173                 tree->klass = mono_class_from_mono_type (tree->inst_vtype);
2174
2175                 set_vreg_to_inst (cfg, inst->dreg + 1, tree);
2176
2177                 /* Allocate a dummy MonoInst for the second vreg */
2178                 MONO_INST_NEW (cfg, tree, OP_LOCAL);
2179                 tree->dreg = inst->dreg + 2;
2180                 if (cfg->opt & MONO_OPT_SSA)
2181                         tree->flags = MONO_INST_VOLATILE;
2182                 tree->inst_c0 = num;
2183                 tree->type = STACK_I4;
2184                 tree->inst_vtype = &mono_defaults.int32_class->byval_arg;
2185                 tree->klass = mono_class_from_mono_type (tree->inst_vtype);
2186
2187                 set_vreg_to_inst (cfg, inst->dreg + 2, tree);
2188         }
2189
2190         cfg->num_varinfo++;
2191         if (cfg->verbose_level > 2)
2192                 g_print ("created temp %d (R%d) of type %s\n", num, vreg, mono_type_get_name (type));
2193         return inst;
2194 }
2195
2196 MonoInst*
2197 mono_compile_create_var (MonoCompile *cfg, MonoType *type, int opcode)
2198 {
2199         int dreg;
2200
2201         if (mono_type_is_long (type))
2202                 dreg = mono_alloc_dreg (cfg, STACK_I8);
2203 #ifdef MONO_ARCH_SOFT_FLOAT
2204         else if (mono_type_is_float (type))
2205                 dreg = mono_alloc_dreg (cfg, STACK_R8);
2206 #endif
2207         else
2208                 /* All the others are unified */
2209                 dreg = mono_alloc_preg (cfg);
2210
2211         return mono_compile_create_var_for_vreg (cfg, type, opcode, dreg);
2212 }
2213
2214 /*
2215  * Transform a MonoInst into a load from the variable of index var_index.
2216  */
2217 void
2218 mono_compile_make_var_load (MonoCompile *cfg, MonoInst *dest, gssize var_index) {
2219         memset (dest, 0, sizeof (MonoInst));
2220         dest->ssa_op = MONO_SSA_LOAD;
2221         dest->inst_i0 = cfg->varinfo [var_index];
2222         dest->opcode = mini_type_to_ldind (cfg, dest->inst_i0->inst_vtype);
2223         type_to_eval_stack_type (cfg, dest->inst_i0->inst_vtype, dest);
2224         dest->klass = dest->inst_i0->klass;
2225 }
2226
2227 /*
2228  * Create a MonoInst that is a load from the variable of index var_index.
2229  */
2230 MonoInst*
2231 mono_compile_create_var_load (MonoCompile *cfg, gssize var_index) {
2232         MonoInst *dest;
2233         NEW_TEMPLOAD (cfg,dest,var_index);
2234         return dest;
2235 }
2236
2237 /*
2238  * Create a MonoInst that is a store of the given value into the variable of index var_index.
2239  */
2240 MonoInst*
2241 mono_compile_create_var_store (MonoCompile *cfg, gssize var_index, MonoInst *value) {
2242         MonoInst *dest;
2243         NEW_TEMPSTORE (cfg, dest, var_index, value);
2244         return dest;
2245 }
2246
2247 static MonoType*
2248 type_from_stack_type (MonoInst *ins) {
2249         switch (ins->type) {
2250         case STACK_I4: return &mono_defaults.int32_class->byval_arg;
2251         case STACK_I8: return &mono_defaults.int64_class->byval_arg;
2252         case STACK_PTR: return &mono_defaults.int_class->byval_arg;
2253         case STACK_R8: return &mono_defaults.double_class->byval_arg;
2254         case STACK_MP:
2255                 /* 
2256                  * this if used to be commented without any specific reason, but
2257                  * it breaks #80235 when commented
2258                  */
2259                 if (ins->klass)
2260                         return &ins->klass->this_arg;
2261                 else
2262                         return &mono_defaults.object_class->this_arg;
2263         case STACK_OBJ:
2264                 /* ins->klass may not be set for ldnull.
2265                  * Also, if we have a boxed valuetype, we want an object lass,
2266                  * not the valuetype class
2267                  */
2268                 if (ins->klass && !ins->klass->valuetype)
2269                         return &ins->klass->byval_arg;
2270                 return &mono_defaults.object_class->byval_arg;
2271         case STACK_VTYPE: return &ins->klass->byval_arg;
2272         default:
2273                 g_error ("stack type %d to montype not handled\n", ins->type);
2274         }
2275         return NULL;
2276 }
2277
2278 MonoType*
2279 mono_type_from_stack_type (MonoInst *ins) {
2280         return type_from_stack_type (ins);
2281 }
2282
2283 static MonoClass*
2284 array_access_to_klass (int opcode, MonoInst *array_obj)
2285 {
2286         switch (opcode) {
2287         case CEE_LDELEM_U1:
2288                 return mono_defaults.byte_class;
2289         case CEE_LDELEM_U2:
2290                 return mono_defaults.uint16_class;
2291         case CEE_LDELEM_I:
2292         case CEE_STELEM_I:
2293                 return mono_defaults.int_class;
2294         case CEE_LDELEM_I1:
2295         case CEE_STELEM_I1:
2296                 return mono_defaults.sbyte_class;
2297         case CEE_LDELEM_I2:
2298         case CEE_STELEM_I2:
2299                 return mono_defaults.int16_class;
2300         case CEE_LDELEM_I4:
2301         case CEE_STELEM_I4:
2302                 return mono_defaults.int32_class;
2303         case CEE_LDELEM_U4:
2304                 return mono_defaults.uint32_class;
2305         case CEE_LDELEM_I8:
2306         case CEE_STELEM_I8:
2307                 return mono_defaults.int64_class;
2308         case CEE_LDELEM_R4:
2309         case CEE_STELEM_R4:
2310                 return mono_defaults.single_class;
2311         case CEE_LDELEM_R8:
2312         case CEE_STELEM_R8:
2313                 return mono_defaults.double_class;
2314         case CEE_LDELEM_REF:
2315         case CEE_STELEM_REF: {
2316                 MonoClass *klass = array_obj->klass;
2317                 /* FIXME: add assert */
2318                 if (klass && klass->rank)
2319                         return klass->element_class;
2320                 return mono_defaults.object_class;
2321         }
2322         default:
2323                 g_assert_not_reached ();
2324         }
2325         return NULL;
2326 }
2327
2328 /*
2329  * mono_add_ins_to_end:
2330  *
2331  *   Same as MONO_ADD_INS, but add INST before any branches at the end of BB.
2332  */
2333 void
2334 mono_add_ins_to_end (MonoBasicBlock *bb, MonoInst *inst)
2335 {
2336         int opcode;
2337
2338         if (!bb->code) {
2339                 MONO_ADD_INS (bb, inst);
2340                 return;
2341         }
2342
2343         switch (bb->last_ins->opcode) {
2344         case OP_BR:
2345         case OP_BR_REG:
2346         case CEE_BEQ:
2347         case CEE_BGE:
2348         case CEE_BGT:
2349         case CEE_BLE:
2350         case CEE_BLT:
2351         case CEE_BNE_UN:
2352         case CEE_BGE_UN:
2353         case CEE_BGT_UN:
2354         case CEE_BLE_UN:
2355         case CEE_BLT_UN:
2356         case OP_SWITCH:
2357                 mono_bblock_insert_before_ins (bb, bb->last_ins, inst);
2358                 break;
2359         default:
2360                 if (MONO_IS_COND_BRANCH_OP (bb->last_ins)) {
2361                         /* Need to insert the ins before the compare */
2362                         if (bb->code == bb->last_ins) {
2363                                 mono_bblock_insert_before_ins (bb, bb->last_ins, inst);
2364                                 return;
2365                         }
2366
2367                         if (bb->code->next == bb->last_ins) {
2368                                 /* Only two instructions */
2369                                 opcode = bb->code->opcode;
2370
2371                                 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)) {
2372                                         /* NEW IR */
2373                                         mono_bblock_insert_before_ins (bb, bb->code, inst);
2374                                 } else {
2375                                         mono_bblock_insert_before_ins (bb, bb->last_ins, inst);
2376                                 }
2377                         } else {
2378                                 opcode = bb->last_ins->prev->opcode;
2379
2380                                 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)) {
2381                                         /* NEW IR */
2382                                         mono_bblock_insert_before_ins (bb, bb->last_ins->prev, inst);
2383                                 } else {
2384                                         mono_bblock_insert_before_ins (bb, bb->last_ins, inst);
2385                                 }                                       
2386                         }
2387                 }
2388                 else
2389                         MONO_ADD_INS (bb, inst);
2390                 break;
2391         }
2392 }
2393
2394 /**
2395  * mono_replace_ins:
2396  *
2397  *   Replace INS with its decomposition which is stored in a series of bblocks starting
2398  * at FIRST_BB and ending at LAST_BB. On enter, PREV points to the predecessor of INS. 
2399  * On return, it will be set to the last ins of the decomposition.
2400  */
2401 void
2402 mono_replace_ins (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *ins, MonoInst **prev, MonoBasicBlock *first_bb, MonoBasicBlock *last_bb)
2403 {
2404         MonoInst *next = ins->next;
2405
2406         if (next && next->opcode == OP_NOP) {
2407                 /* Avoid NOPs following branches */
2408                 ins->next = next->next;
2409                 next = next->next;
2410         }
2411
2412         if (first_bb == last_bb) {
2413                 /* 
2414                  * Only one replacement bb, merge the code into
2415                  * the current bb.
2416                  */
2417
2418                 /* Delete links between the first_bb and its successors */
2419                 while (first_bb->out_count)
2420                         mono_unlink_bblock (cfg, first_bb, first_bb->out_bb [0]);
2421
2422                 /* Head */
2423                 if (*prev) {
2424                         (*prev)->next = first_bb->code;
2425                         first_bb->code->prev = (*prev);
2426                 } else {
2427                         bb->code = first_bb->code;
2428                 }
2429
2430                 /* Tail */
2431                 last_bb->last_ins->next = next;
2432                 if (next)
2433                         next->prev = last_bb->last_ins;
2434                 else
2435                         bb->last_ins = last_bb->last_ins;
2436                 *prev = last_bb->last_ins;
2437         } else {
2438                 int i, count;
2439                 MonoBasicBlock **tmp_bblocks, *tmp;
2440                 MonoInst *last;
2441
2442                 /* Multiple BBs */
2443
2444                 /* Set region */
2445                 for (tmp = first_bb; tmp; tmp = tmp->next_bb)
2446                         tmp->region = bb->region;
2447
2448                 /* Split the original bb */
2449                 if (ins->next)
2450                         ins->next->prev = NULL;
2451                 ins->next = NULL;
2452                 bb->last_ins = ins;
2453
2454                 /* Merge the second part of the original bb into the last bb */
2455                 if (last_bb->last_ins) {
2456                         last_bb->last_ins->next = next;
2457                         if (next)
2458                                 next->prev = last_bb->last_ins;
2459                 } else {
2460                         last_bb->code = next;
2461                 }
2462
2463                 if (next) {
2464                         for (last = next; last->next != NULL; last = last->next)
2465                                 ;
2466                         last_bb->last_ins = last;
2467                 }
2468
2469                 for (i = 0; i < bb->out_count; ++i)
2470                         link_bblock (cfg, last_bb, bb->out_bb [i]);
2471
2472                 /* Merge the first (dummy) bb to the original bb */
2473                 if (*prev) {
2474                         (*prev)->next = first_bb->code;
2475                         first_bb->code->prev = (*prev);
2476                 } else {
2477                         bb->code = first_bb->code;
2478                 }
2479                 bb->last_ins = first_bb->last_ins;
2480
2481                 /* Delete the links between the original bb and its successors */
2482                 tmp_bblocks = bb->out_bb;
2483                 count = bb->out_count;
2484                 for (i = 0; i < count; ++i)
2485                         mono_unlink_bblock (cfg, bb, tmp_bblocks [i]);
2486
2487                 /* Add links between the original bb and the first_bb's successors */
2488                 for (i = 0; i < first_bb->out_count; ++i) {
2489                         MonoBasicBlock *out_bb = first_bb->out_bb [i];
2490
2491                         link_bblock (cfg, bb, out_bb);
2492                 }
2493                 /* Delete links between the first_bb and its successors */
2494                 for (i = 0; i < bb->out_count; ++i) {
2495                         MonoBasicBlock *out_bb = bb->out_bb [i];
2496
2497                         mono_unlink_bblock (cfg, first_bb, out_bb);
2498                 }
2499                 last_bb->next_bb = bb->next_bb;
2500                 bb->next_bb = first_bb->next_bb;
2501
2502                 *prev = NULL;
2503         }
2504 }
2505
2506 void
2507 mono_add_varcopy_to_end (MonoCompile *cfg, MonoBasicBlock *bb, int src, int dest)
2508 {
2509         MonoInst *inst, *load;
2510
2511         NEW_TEMPLOAD (cfg, load, src);
2512
2513         NEW_TEMPSTORE (cfg, inst, dest, load);
2514         /* FIXME: handle CEE_STIND_R4 */
2515         if (inst->opcode == CEE_STOBJ) {
2516                 NEW_TEMPLOADA (cfg, inst, dest);
2517                 handle_stobj (cfg, bb, inst, load, NULL, inst->klass, TRUE, FALSE, FALSE);
2518         } else {
2519                 inst->cil_code = NULL;
2520                 mono_add_ins_to_end (bb, inst);
2521         }
2522 }
2523
2524 /*
2525  * This function is called to handle items that are left on the evaluation stack
2526  * at basic block boundaries. What happens is that we save the values to local variables
2527  * and we reload them later when first entering the target basic block (with the
2528  * handle_loaded_temps () function).
2529  * It is also used to handle items on the stack in store opcodes, since it is
2530  * possible that the variable to be stored into is already on the stack, in
2531  * which case its old value should be used.
2532  * A single joint point will use the same variables (stored in the array bb->out_stack or
2533  * bb->in_stack, if the basic block is before or after the joint point).
2534  * If the stack merge fails at a join point, cfg->unverifiable is set.
2535  */
2536 static void
2537 handle_stack_args (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst **sp, int count)
2538 {
2539         int i, bindex;
2540         MonoBasicBlock *outb;
2541         MonoInst *inst, **locals;
2542         gboolean found;
2543
2544         if (!count)
2545                 return;
2546         if (cfg->verbose_level > 3)
2547                 g_print ("%d item(s) on exit from B%d\n", count, bb->block_num);
2548
2549         if (!bb->out_scount) {
2550                 bb->out_scount = count;
2551                 //g_print ("bblock %d has out:", bb->block_num);
2552                 found = FALSE;
2553                 for (i = 0; i < bb->out_count; ++i) {
2554                         outb = bb->out_bb [i];
2555                         /* exception handlers are linked, but they should not be considered for stack args */
2556                         if (outb->flags & BB_EXCEPTION_HANDLER)
2557                                 continue;
2558                         //g_print (" %d", outb->block_num);
2559                         if (outb->in_stack) {
2560                                 found = TRUE;
2561                                 bb->out_stack = outb->in_stack;
2562                                 break;
2563                         }
2564                 }
2565                 //g_print ("\n");
2566                 if (!found) {
2567                         bb->out_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * count);
2568                         for (i = 0; i < count; ++i) {
2569                                 /* 
2570                                  * try to reuse temps already allocated for this purpouse, if they occupy the same
2571                                  * stack slot and if they are of the same type.
2572                                  * This won't cause conflicts since if 'local' is used to 
2573                                  * store one of the values in the in_stack of a bblock, then
2574                                  * the same variable will be used for the same outgoing stack 
2575                                  * slot as well. 
2576                                  * This doesn't work when inlining methods, since the bblocks
2577                                  * in the inlined methods do not inherit their in_stack from
2578                                  * the bblock they are inlined to. See bug #58863 for an
2579                                  * example.
2580                                  * This hack is disabled since it also prevents proper tracking of types.
2581                                  */
2582 #if 1
2583                                 bb->out_stack [i] = mono_compile_create_var (cfg, type_from_stack_type (sp [i]), OP_LOCAL);
2584 #else
2585                                 if (cfg->inlined_method)
2586                                         bb->out_stack [i] = mono_compile_create_var (cfg, type_from_stack_type (sp [i]), OP_LOCAL);
2587                                 else
2588                                         bb->out_stack [i] = mono_compile_get_interface_var (cfg, i, sp [i]);
2589 #endif
2590                         }
2591                 }
2592         }
2593
2594         for (i = 0; i < bb->out_count; ++i) {
2595                 outb = bb->out_bb [i];
2596                 /* exception handlers are linked, but they should not be considered for stack args */
2597                 if (outb->flags & BB_EXCEPTION_HANDLER)
2598                         continue;
2599                 if (outb->in_scount) {
2600                         if (outb->in_scount != bb->out_scount) {
2601                                 cfg->unverifiable = TRUE;
2602                                 return;
2603                         }
2604                         continue; /* check they are the same locals */
2605                 }
2606                 outb->in_scount = count;
2607                 outb->in_stack = bb->out_stack;
2608         }
2609
2610         locals = bb->out_stack;
2611         for (i = 0; i < count; ++i) {
2612                 /* add store ops at the end of the bb, before the branch */
2613                 NEW_TEMPSTORE (cfg, inst, locals [i]->inst_c0, sp [i]);
2614                 if (inst->opcode == CEE_STOBJ) {
2615                         NEW_TEMPLOADA (cfg, inst, locals [i]->inst_c0);
2616                         handle_stobj (cfg, bb, inst, sp [i], sp [i]->cil_code, inst->klass, TRUE, FALSE, FALSE);
2617                 } else {
2618                         inst->cil_code = sp [i]->cil_code;
2619                         mono_add_ins_to_end (bb, inst);
2620                 }
2621                 if (cfg->verbose_level > 3)
2622                         g_print ("storing %d to temp %d\n", i, (int)locals [i]->inst_c0);
2623         }
2624
2625         /*
2626          * It is possible that the out bblocks already have in_stack assigned, and
2627          * the in_stacks differ. In this case, we will store to all the different 
2628          * in_stacks.
2629          */
2630
2631         found = TRUE;
2632         bindex = 0;
2633         while (found) {
2634                 /* Find a bblock which has a different in_stack */
2635                 found = FALSE;
2636                 while (bindex < bb->out_count) {
2637                         outb = bb->out_bb [bindex];
2638                         /* exception handlers are linked, but they should not be considered for stack args */
2639                         if (outb->flags & BB_EXCEPTION_HANDLER) {
2640                                 bindex++;
2641                                 continue;
2642                         }
2643                         if (outb->in_stack != locals) {
2644                                 /* 
2645                                  * Instead of storing sp [i] to locals [i], we need to store
2646                                  * locals [i] to <new locals>[i], since the sp [i] tree can't
2647                                  * be shared between trees.
2648                                  */
2649                                 for (i = 0; i < count; ++i)
2650                                         mono_add_varcopy_to_end (cfg, bb, locals [i]->inst_c0, outb->in_stack [i]->inst_c0);
2651                                 locals = outb->in_stack;
2652                                 found = TRUE;
2653                                 break;
2654                         }
2655                         bindex ++;
2656                 }
2657         }
2658 }
2659
2660 static int
2661 ret_type_to_call_opcode (MonoType *type, int calli, int virt, MonoGenericSharingContext *gsctx)
2662 {
2663         if (type->byref)
2664                 return calli? OP_CALL_REG: virt? OP_CALLVIRT: OP_CALL;
2665
2666 handle_enum:
2667         type = mini_get_basic_type_from_generic (gsctx, type);
2668         switch (type->type) {
2669         case MONO_TYPE_VOID:
2670                 return calli? OP_VOIDCALL_REG: virt? OP_VOIDCALLVIRT: OP_VOIDCALL;
2671         case MONO_TYPE_I1:
2672         case MONO_TYPE_U1:
2673         case MONO_TYPE_BOOLEAN:
2674         case MONO_TYPE_I2:
2675         case MONO_TYPE_U2:
2676         case MONO_TYPE_CHAR:
2677         case MONO_TYPE_I4:
2678         case MONO_TYPE_U4:
2679                 return calli? OP_CALL_REG: virt? OP_CALLVIRT: OP_CALL;
2680         case MONO_TYPE_I:
2681         case MONO_TYPE_U:
2682         case MONO_TYPE_PTR:
2683         case MONO_TYPE_FNPTR:
2684                 return calli? OP_CALL_REG: virt? OP_CALLVIRT: OP_CALL;
2685         case MONO_TYPE_CLASS:
2686         case MONO_TYPE_STRING:
2687         case MONO_TYPE_OBJECT:
2688         case MONO_TYPE_SZARRAY:
2689         case MONO_TYPE_ARRAY:    
2690                 return calli? OP_CALL_REG: virt? OP_CALLVIRT: OP_CALL;
2691         case MONO_TYPE_I8:
2692         case MONO_TYPE_U8:
2693                 return calli? OP_LCALL_REG: virt? OP_LCALLVIRT: OP_LCALL;
2694         case MONO_TYPE_R4:
2695         case MONO_TYPE_R8:
2696                 return calli? OP_FCALL_REG: virt? OP_FCALLVIRT: OP_FCALL;
2697         case MONO_TYPE_VALUETYPE:
2698                 if (type->data.klass->enumtype) {
2699                         type = type->data.klass->enum_basetype;
2700                         goto handle_enum;
2701                 } else
2702                         return calli? OP_VCALL_REG: virt? OP_VCALLVIRT: OP_VCALL;
2703         case MONO_TYPE_TYPEDBYREF:
2704                 return calli? OP_VCALL_REG: virt? OP_VCALLVIRT: OP_VCALL;
2705         case MONO_TYPE_GENERICINST:
2706                 type = &type->data.generic_class->container_class->byval_arg;
2707                 goto handle_enum;
2708         default:
2709                 g_error ("unknown type 0x%02x in ret_type_to_call_opcode", type->type);
2710         }
2711         return -1;
2712 }
2713
2714 void
2715 mono_create_jump_table (MonoCompile *cfg, MonoInst *label, MonoBasicBlock **bbs, int num_blocks)
2716 {
2717         MonoJumpInfo *ji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo));
2718         MonoJumpInfoBBTable *table;
2719
2720         table = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfoBBTable));
2721         table->table = bbs;
2722         table->table_size = num_blocks;
2723         
2724         ji->ip.label = label;
2725         ji->type = MONO_PATCH_INFO_SWITCH;
2726         ji->data.table = table;
2727         ji->next = cfg->patch_info;
2728         cfg->patch_info = ji;
2729 }
2730
2731 static void
2732 mono_save_token_info (MonoCompile *cfg, MonoImage *image, guint32 token, gpointer key)
2733 {
2734         if (cfg->compile_aot) {
2735                 MonoJumpInfoToken *jump_info_token = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoToken));
2736                 jump_info_token->image = image;
2737                 jump_info_token->token = token;
2738                 g_hash_table_insert (cfg->token_info_hash, key, jump_info_token);
2739         }
2740 }
2741
2742 /*
2743  * When we add a tree of instructions, we need to ensure the instructions currently
2744  * on the stack are executed before (like, if we load a value from a local).
2745  * We ensure this by saving the currently loaded values to temps and rewriting the
2746  * instructions to load the values.
2747  * This is not done for opcodes that terminate a basic block (because it's handled already
2748  * by handle_stack_args ()) and for opcodes that can't change values, like POP.
2749  */
2750 static void
2751 handle_loaded_temps (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst **stack, MonoInst **sp)
2752 {
2753         MonoInst *load, *store, *temp, *ins;
2754
2755         while (stack < sp) {
2756                 ins = *stack;
2757                 /* handle also other constants */
2758                 if ((ins->opcode != OP_ICONST) &&
2759                     /* temps never get written to again, so we can safely avoid duplicating them */
2760                     !(ins->ssa_op == MONO_SSA_LOAD && ins->inst_i0->opcode == OP_LOCAL && ins->inst_i0->flags & MONO_INST_IS_TEMP)) {
2761                         temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
2762                         temp->flags |= MONO_INST_IS_TEMP;
2763                         NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
2764                         store->cil_code = ins->cil_code;
2765                         if (store->opcode == CEE_STOBJ) {
2766                                 NEW_TEMPLOADA (cfg, store, temp->inst_c0);
2767                                 handle_stobj (cfg, bblock, store, ins, ins->cil_code, temp->klass, FALSE, FALSE, FALSE);
2768                         } else
2769                                 MONO_ADD_INS (bblock, store);
2770                         NEW_TEMPLOAD (cfg, load, temp->inst_c0);
2771                         load->cil_code = ins->cil_code;
2772                         *stack = load;
2773                 }
2774                 stack++;
2775         }
2776 }
2777
2778 /*
2779  * target_type_is_incompatible:
2780  * @cfg: MonoCompile context
2781  *
2782  * Check that the item @arg on the evaluation stack can be stored
2783  * in the target type (can be a local, or field, etc).
2784  * The cfg arg can be used to check if we need verification or just
2785  * validity checks.
2786  *
2787  * Returns: non-0 value if arg can't be stored on a target.
2788  */
2789 static int
2790 target_type_is_incompatible (MonoCompile *cfg, MonoType *target, MonoInst *arg)
2791 {
2792         MonoType *simple_type;
2793         MonoClass *klass;
2794
2795         if (target->byref) {
2796                 /* FIXME: check that the pointed to types match */
2797                 if (arg->type == STACK_MP)
2798                         return arg->klass != mono_class_from_mono_type (target);
2799                 if (arg->type == STACK_PTR)
2800                         return 0;
2801                 return 1;
2802         }
2803         simple_type = mono_type_get_underlying_type (target);
2804         switch (simple_type->type) {
2805         case MONO_TYPE_VOID:
2806                 return 1;
2807         case MONO_TYPE_I1:
2808         case MONO_TYPE_U1:
2809         case MONO_TYPE_BOOLEAN:
2810         case MONO_TYPE_I2:
2811         case MONO_TYPE_U2:
2812         case MONO_TYPE_CHAR:
2813         case MONO_TYPE_I4:
2814         case MONO_TYPE_U4:
2815                 if (arg->type != STACK_I4 && arg->type != STACK_PTR)
2816                         return 1;
2817                 return 0;
2818         case MONO_TYPE_PTR:
2819                 /* STACK_MP is needed when setting pinned locals */
2820                 if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
2821                         return 1;
2822                 return 0;
2823         case MONO_TYPE_I:
2824         case MONO_TYPE_U:
2825         case MONO_TYPE_FNPTR:
2826                 if (arg->type != STACK_I4 && arg->type != STACK_PTR)
2827                         return 1;
2828                 return 0;
2829         case MONO_TYPE_OBJECT:
2830                 if (arg->type != STACK_OBJ)
2831                         return 1;
2832                 return 0;
2833         case MONO_TYPE_STRING:
2834                 if (arg->type != STACK_OBJ)
2835                         return 1;
2836                 /* ldnull has arg->klass unset */
2837                 /*if (arg->klass && arg->klass != mono_defaults.string_class) {
2838                         G_BREAKPOINT ();
2839                         return 1;
2840                 }*/
2841                 return 0;
2842         case MONO_TYPE_CLASS:
2843         case MONO_TYPE_SZARRAY:
2844         case MONO_TYPE_ARRAY:    
2845                 if (arg->type != STACK_OBJ)
2846                         return 1;
2847                 /* FIXME: check type compatibility */
2848                 return 0;
2849         case MONO_TYPE_I8:
2850         case MONO_TYPE_U8:
2851                 if (arg->type != STACK_I8)
2852                         return 1;
2853                 return 0;
2854         case MONO_TYPE_R4:
2855         case MONO_TYPE_R8:
2856                 if (arg->type != STACK_R8)
2857                         return 1;
2858                 return 0;
2859         case MONO_TYPE_VALUETYPE:
2860                 if (arg->type != STACK_VTYPE)
2861                         return 1;
2862                 klass = mono_class_from_mono_type (simple_type);
2863                 if (klass != arg->klass)
2864                         return 1;
2865                 return 0;
2866         case MONO_TYPE_TYPEDBYREF:
2867                 if (arg->type != STACK_VTYPE)
2868                         return 1;
2869                 klass = mono_class_from_mono_type (simple_type);
2870                 if (klass != arg->klass)
2871                         return 1;
2872                 return 0;
2873         case MONO_TYPE_GENERICINST:
2874                 if (mono_type_generic_inst_is_valuetype (simple_type)) {
2875                         klass = mono_class_from_mono_type (simple_type);
2876                         if (klass->enumtype)
2877                                 return target_type_is_incompatible (cfg, klass->enum_basetype, arg);
2878                         if (arg->type != STACK_VTYPE)
2879                                 return 1;
2880                         if (klass != arg->klass)
2881                                 return 1;
2882                         return 0;
2883                 } else {
2884                         if (arg->type != STACK_OBJ)
2885                                 return 1;
2886                         /* FIXME: check type compatibility */
2887                         return 0;
2888                 }
2889         case MONO_TYPE_VAR:
2890         case MONO_TYPE_MVAR:
2891                 /* FIXME: all the arguments must be references for now,
2892                  * later look inside cfg and see if the arg num is
2893                  * really a reference
2894                  */
2895                 g_assert (cfg->generic_sharing_context);
2896                 if (arg->type != STACK_OBJ)
2897                         return 1;
2898                 return 0;
2899         default:
2900                 g_error ("unknown type 0x%02x in target_type_is_incompatible", simple_type->type);
2901         }
2902         return 1;
2903 }
2904
2905 /*
2906  * Prepare arguments for passing to a function call.
2907  * Return a non-zero value if the arguments can't be passed to the given
2908  * signature.
2909  * The type checks are not yet complete and some conversions may need
2910  * casts on 32 or 64 bit architectures.
2911  *
2912  * FIXME: implement this using target_type_is_incompatible ()
2913  */
2914 static int
2915 check_call_signature (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args)
2916 {
2917         MonoType *simple_type;
2918         int i;
2919
2920         if (sig->hasthis) {
2921                 if (args [0]->type != STACK_OBJ && args [0]->type != STACK_MP && args [0]->type != STACK_PTR)
2922                         return 1;
2923                 args++;
2924         }
2925         for (i = 0; i < sig->param_count; ++i) {
2926                 if (sig->params [i]->byref) {
2927                         if (args [i]->type != STACK_MP && args [i]->type != STACK_PTR)
2928                                 return 1;
2929                         continue;
2930                 }
2931                 simple_type = sig->params [i];
2932                 simple_type = mini_get_basic_type_from_generic (cfg->generic_sharing_context, simple_type);
2933 handle_enum:
2934                 switch (simple_type->type) {
2935                 case MONO_TYPE_VOID:
2936                         return 1;
2937                         continue;
2938                 case MONO_TYPE_I1:
2939                 case MONO_TYPE_U1:
2940                 case MONO_TYPE_BOOLEAN:
2941                 case MONO_TYPE_I2:
2942                 case MONO_TYPE_U2:
2943                 case MONO_TYPE_CHAR:
2944                 case MONO_TYPE_I4:
2945                 case MONO_TYPE_U4:
2946                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR)
2947                                 return 1;
2948                         continue;
2949                 case MONO_TYPE_I:
2950                 case MONO_TYPE_U:
2951                 case MONO_TYPE_PTR:
2952                 case MONO_TYPE_FNPTR:
2953                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR && args [i]->type != STACK_MP && args [i]->type != STACK_OBJ)
2954                                 return 1;
2955                         continue;
2956                 case MONO_TYPE_CLASS:
2957                 case MONO_TYPE_STRING:
2958                 case MONO_TYPE_OBJECT:
2959                 case MONO_TYPE_SZARRAY:
2960                 case MONO_TYPE_ARRAY:    
2961                         if (args [i]->type != STACK_OBJ)
2962                                 return 1;
2963                         continue;
2964                 case MONO_TYPE_I8:
2965                 case MONO_TYPE_U8:
2966                         if (args [i]->type != STACK_I8)
2967                                 return 1;
2968                         continue;
2969                 case MONO_TYPE_R4:
2970                 case MONO_TYPE_R8:
2971                         if (args [i]->type != STACK_R8)
2972                                 return 1;
2973                         continue;
2974                 case MONO_TYPE_VALUETYPE:
2975                         if (simple_type->data.klass->enumtype) {
2976                                 simple_type = simple_type->data.klass->enum_basetype;
2977                                 goto handle_enum;
2978                         }
2979                         if (args [i]->type != STACK_VTYPE)
2980                                 return 1;
2981                         continue;
2982                 case MONO_TYPE_TYPEDBYREF:
2983                         if (args [i]->type != STACK_VTYPE)
2984                                 return 1;
2985                         continue;
2986                 case MONO_TYPE_GENERICINST:
2987                         simple_type = &simple_type->data.generic_class->container_class->byval_arg;
2988                         goto handle_enum;
2989
2990                 default:
2991                         g_error ("unknown type 0x%02x in check_call_signature",
2992                                  simple_type->type);
2993                 }
2994         }
2995         return 0;
2996 }
2997
2998 inline static int
2999 mono_spill_call (MonoCompile *cfg, MonoBasicBlock *bblock, MonoCallInst *call, MonoMethodSignature *sig, gboolean ret_object, 
3000                  const guint8 *ip, gboolean to_end)
3001 {
3002         MonoInst *temp, *store, *ins = (MonoInst*)call;
3003         MonoType *ret = sig->ret;
3004
3005         if (!MONO_TYPE_IS_VOID (ret) || ret_object) {
3006                 if (ret_object) {
3007                         call->inst.type = STACK_OBJ;
3008                         call->inst.opcode = OP_CALL;
3009                         temp = mono_compile_create_var (cfg, &mono_defaults.string_class->byval_arg, OP_LOCAL);
3010                 } else {
3011                         type_to_eval_stack_type (cfg, ret, ins);
3012                         temp = mono_compile_create_var (cfg, ret, OP_LOCAL);
3013                 }
3014                 
3015                 temp->flags |= MONO_INST_IS_TEMP;
3016
3017                 if (MONO_TYPE_ISSTRUCT (ret)) {
3018                         MonoInst *loada, *dummy_store;
3019
3020                         /* 
3021                          * Emit a dummy store to the local holding the result so the
3022                          * liveness info remains correct.
3023                          */
3024                         NEW_DUMMY_STORE (cfg, dummy_store, temp->inst_c0);
3025                         if (to_end)
3026                                 mono_add_ins_to_end (bblock, dummy_store);
3027                         else
3028                                 MONO_ADD_INS (bblock, dummy_store);
3029
3030                         /* we use this to allocate native sized structs */
3031                         temp->backend.is_pinvoke = sig->pinvoke;
3032
3033                         NEW_TEMPLOADA (cfg, loada, temp->inst_c0);
3034                         if (call->inst.opcode == OP_VCALL || call->inst.opcode == OP_VCALL_RGCTX)
3035                                 ins->inst_left = loada;
3036                         else
3037                                 ins->inst_right = loada; /* a virtual or indirect call */
3038
3039                         if (to_end)
3040                                 mono_add_ins_to_end (bblock, ins);
3041                         else
3042                                 MONO_ADD_INS (bblock, ins);
3043                 } else {
3044                         NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
3045                         store->cil_code = ip;
3046                         
3047 #ifdef MONO_ARCH_SOFT_FLOAT
3048                         if (store->opcode == CEE_STIND_R4) {
3049                                 /*FIXME implement proper support for to_end*/
3050                                 g_assert (!to_end);
3051                                 NEW_TEMPLOADA (cfg, store, temp->inst_c0);
3052                                 handle_store_float (cfg, bblock, store, ins, ip);
3053                         } else
3054 #endif
3055                         if (to_end)
3056                                 mono_add_ins_to_end (bblock, store);
3057                         else
3058                                 MONO_ADD_INS (bblock, store);
3059                 }
3060                 return temp->inst_c0;
3061         } else {
3062                 if (to_end)
3063                         mono_add_ins_to_end (bblock, ins);
3064                 else
3065                         MONO_ADD_INS (bblock, ins);
3066                 return -1;
3067         }
3068 }
3069
3070 inline static MonoCallInst *
3071 mono_emit_call_args (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethodSignature *sig, 
3072                      MonoInst **args, int calli, int virtual, const guint8 *ip, gboolean to_end)
3073 {
3074         MonoCallInst *call;
3075         MonoInst *arg;
3076
3077         MONO_INST_NEW_CALL (cfg, call, ret_type_to_call_opcode (sig->ret, calli, virtual, cfg->generic_sharing_context));
3078
3079 #ifdef MONO_ARCH_SOFT_FLOAT
3080         /* we need to convert the r4 value to an int value */
3081         {
3082                 int i;
3083                 for (i = 0; i < sig->param_count; ++i) {
3084                         if (!sig->params [i]->byref && sig->params [i]->type == MONO_TYPE_R4) {
3085                                 MonoInst *iargs [1];
3086                                 int temp;
3087                                 iargs [0] = args [i + sig->hasthis];
3088
3089                                 temp = mono_emit_jit_icall (cfg, bblock, mono_fload_r4_arg, iargs, ip);
3090                                 NEW_TEMPLOAD (cfg, arg, temp);
3091                                 args [i + sig->hasthis] = arg;
3092                         }
3093                 }
3094         }
3095 #endif
3096
3097         call->inst.cil_code = ip;
3098         call->args = args;
3099         call->signature = sig;
3100         call = mono_arch_call_opcode (cfg, bblock, call, virtual);
3101         type_to_eval_stack_type (cfg, sig->ret, &call->inst);
3102
3103         for (arg = call->out_args; arg;) {
3104                 MonoInst *narg = arg->next;
3105                 arg->next = NULL;
3106                 if (!arg->cil_code)
3107                         arg->cil_code = ip;
3108                 if (to_end)
3109                         mono_add_ins_to_end (bblock, arg);
3110                 else
3111                         MONO_ADD_INS (bblock, arg);
3112                 arg = narg;
3113         }
3114         return call;
3115 }
3116
3117 inline static MonoCallInst*
3118 mono_emit_calli (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethodSignature *sig, 
3119                  MonoInst **args, MonoInst *addr, const guint8 *ip)
3120 {
3121         MonoCallInst *call = mono_emit_call_args (cfg, bblock, sig, args, TRUE, FALSE, ip, FALSE);
3122
3123         call->inst.inst_i0 = addr;
3124
3125         return call;
3126 }
3127
3128 inline static MonoCallInst*
3129 mono_emit_rgctx_calli (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethodSignature *sig,
3130         MonoInst **args, MonoInst *addr, MonoInst *rgctx_arg, const guint8 *ip)
3131 {
3132         MonoCallInst *call = mono_emit_calli (cfg, bblock, sig, args, addr, ip);
3133
3134         if (rgctx_arg) {
3135                 switch (call->inst.opcode) {
3136                 case OP_CALL_REG: call->inst.opcode = OP_CALL_REG_RGCTX; break;
3137                 case OP_VOIDCALL_REG: call->inst.opcode = OP_VOIDCALL_REG_RGCTX; break;
3138                 case OP_FCALL_REG: call->inst.opcode = OP_FCALL_REG_RGCTX; break;
3139                 case OP_LCALL_REG: call->inst.opcode = OP_LCALL_REG_RGCTX; break;
3140                 case OP_VCALL_REG: {
3141                         MonoInst *group;
3142
3143                         NEW_GROUP (cfg, group, call->inst.inst_left, NULL);
3144                         call->inst.inst_left = group;
3145                         call->inst.opcode = OP_VCALL_REG_RGCTX;
3146                         break;
3147                 }
3148                 default: g_assert_not_reached ();
3149                 }
3150
3151                 if (call->inst.opcode != OP_VCALL_REG_RGCTX) {
3152                         g_assert (!call->inst.inst_right);
3153                         call->inst.inst_right = rgctx_arg;
3154                 } else {
3155                         g_assert (!call->inst.inst_left->inst_right);
3156                         call->inst.inst_left->inst_right = rgctx_arg;
3157                 }
3158         }
3159
3160         return call;
3161 }
3162
3163 inline static int
3164 mono_emit_calli_spilled (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethodSignature *sig, 
3165                                                  MonoInst **args, MonoInst *addr, const guint8 *ip)
3166 {
3167         MonoCallInst *call = mono_emit_calli (cfg, bblock, sig, args, addr, ip);
3168
3169         return mono_spill_call (cfg, bblock, call, sig, FALSE, ip, FALSE);
3170 }
3171
3172 static int
3173 mono_emit_rgctx_calli_spilled (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethodSignature *sig,
3174         MonoInst **args, MonoInst *addr, MonoInst *rgctx_arg, const guint8 *ip)
3175 {
3176         MonoCallInst *call = mono_emit_rgctx_calli (cfg, bblock, sig, args, addr, rgctx_arg, ip);
3177
3178         return mono_spill_call (cfg, bblock, call, sig, FALSE, ip, FALSE);
3179 }
3180
3181 static MonoCallInst*
3182 mono_emit_method_call_full (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *method, MonoMethodSignature *sig,
3183                        MonoInst **args, const guint8 *ip, MonoInst *this, gboolean to_end)
3184 {
3185         gboolean virtual = this != NULL;
3186         MonoCallInst *call;
3187
3188         call = mono_emit_call_args (cfg, bblock, sig, args, FALSE, virtual, ip, to_end);
3189
3190         if (this && sig->hasthis && 
3191             (method->klass->marshalbyref || method->klass == mono_defaults.object_class) && 
3192             !(method->flags & METHOD_ATTRIBUTE_VIRTUAL) && !MONO_CHECK_THIS (this)) {
3193                 call->method = mono_marshal_get_remoting_invoke_with_check (method);
3194         } else {
3195                 call->method = method;
3196         }
3197         call->inst.flags |= MONO_INST_HAS_METHOD;
3198         call->inst.inst_left = this;
3199
3200         if (call->method->klass->flags & TYPE_ATTRIBUTE_INTERFACE)
3201                 /* Needed by the code generated in inssel.brg */
3202                 mono_get_got_var (cfg);
3203
3204         return call;
3205 }
3206
3207 static MonoCallInst*
3208 mono_emit_method_call (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *method, MonoMethodSignature *sig,
3209                        MonoInst **args, const guint8 *ip, MonoInst *this)
3210 {
3211         return mono_emit_method_call_full (cfg, bblock, method, sig, args, ip, this, FALSE);
3212 }
3213
3214 inline static int
3215 mono_emit_method_call_spilled (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *method,  
3216                        MonoMethodSignature *signature, MonoInst **args, const guint8 *ip, MonoInst *this)
3217 {
3218         MonoCallInst *call = mono_emit_method_call (cfg, bblock, method, signature, args, ip, this);
3219
3220         return mono_spill_call (cfg, bblock, call, signature, method->string_ctor, ip, FALSE);
3221 }
3222
3223 inline static int
3224 mono_emit_method_call_spilled_full (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *method,  
3225                        MonoMethodSignature *signature, MonoInst **args, const guint8 *ip, MonoInst *this,
3226                        gboolean ret_object, gboolean to_end)
3227 {
3228         MonoCallInst *call = mono_emit_method_call_full (cfg, bblock, method, signature, args, ip, this, to_end);
3229
3230         return mono_spill_call (cfg, bblock, call, signature, ret_object, ip, to_end);
3231 }
3232
3233 inline static int
3234 mono_emit_native_call (MonoCompile *cfg, MonoBasicBlock *bblock, gconstpointer func, MonoMethodSignature *sig,
3235                        MonoInst **args, const guint8 *ip, gboolean ret_object, gboolean to_end)
3236 {
3237         MonoCallInst *call;
3238
3239         g_assert (sig);
3240
3241         call = mono_emit_call_args (cfg, bblock, sig, args, FALSE, FALSE, ip, to_end);
3242         call->fptr = func;
3243
3244         return mono_spill_call (cfg, bblock, call, sig, ret_object, ip, to_end);
3245 }
3246
3247 inline static int
3248 mono_emit_jit_icall (MonoCompile *cfg, MonoBasicBlock *bblock, gconstpointer func, MonoInst **args, const guint8 *ip)
3249 {
3250         MonoJitICallInfo *info = mono_find_jit_icall_by_addr (func);
3251         
3252         if (!info) {
3253                 g_warning ("unregistered JIT ICall");
3254                 g_assert_not_reached ();
3255         }
3256
3257         return mono_emit_native_call (cfg, bblock, mono_icall_get_wrapper (info), info->sig, args, ip, FALSE, FALSE);
3258 }
3259
3260 static MonoCallInst*
3261 mono_emit_rgctx_method_call (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *method, MonoMethodSignature *sig,
3262                 MonoInst **args, MonoInst *rgctx_arg, MonoInst *imt_arg, const guint8 *ip, MonoInst *this)
3263 {
3264         MonoCallInst *call = mono_emit_method_call_full (cfg, bblock, method, sig, args, ip, this, FALSE);
3265
3266         g_assert (!(rgctx_arg && imt_arg));
3267
3268         if (rgctx_arg) {
3269                 switch (call->inst.opcode) {
3270                 case OP_CALL: call->inst.opcode = OP_CALL_RGCTX; break;
3271                 case OP_VOIDCALL: call->inst.opcode = OP_VOIDCALL_RGCTX; break;
3272                 case OP_FCALL: call->inst.opcode = OP_FCALL_RGCTX; break;
3273                 case OP_LCALL: call->inst.opcode = OP_LCALL_RGCTX; break;
3274                 case OP_VCALL: call->inst.opcode = OP_VCALL_RGCTX; break;
3275                 default: g_assert_not_reached ();
3276                 }
3277
3278                 if (call->inst.opcode != OP_VCALL_RGCTX) {
3279                         g_assert (!call->inst.inst_left);
3280                         call->inst.inst_left = rgctx_arg;
3281                 } else {
3282                         g_assert (!call->inst.inst_right);
3283                         call->inst.inst_right = rgctx_arg;
3284                 }
3285         } else if (imt_arg) {
3286                 switch (call->inst.opcode) {
3287                 case OP_CALLVIRT: call->inst.opcode = OP_CALLVIRT_IMT; break;
3288                 case OP_VOIDCALLVIRT: call->inst.opcode = OP_VOIDCALLVIRT_IMT; break;
3289                 case OP_FCALLVIRT: call->inst.opcode = OP_FCALLVIRT_IMT; break;
3290                 case OP_LCALLVIRT: call->inst.opcode = OP_LCALLVIRT_IMT; break;
3291                 case OP_VCALLVIRT: {
3292                         MonoInst *group;
3293
3294                         NEW_GROUP (cfg, group, call->inst.inst_left, NULL);
3295                         call->inst.inst_left = group;
3296                         call->inst.opcode = OP_VCALLVIRT_IMT;
3297                         break;
3298                 }
3299                 default: g_assert_not_reached ();
3300                 }
3301
3302                 if (call->inst.opcode != OP_VCALLVIRT_IMT) {
3303                         g_assert (!call->inst.inst_right);
3304                         call->inst.inst_right = imt_arg;
3305                 } else {
3306                         g_assert (!call->inst.inst_left->inst_right);
3307                         call->inst.inst_left->inst_right = imt_arg;
3308                 }
3309         }
3310
3311         return call;
3312 }
3313
3314 inline static int
3315 mono_emit_rgctx_method_call_spilled (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *method,  
3316                 MonoMethodSignature *signature, MonoInst **args, MonoInst *rgctx_arg, MonoInst *imt_arg,
3317                 const guint8 *ip, MonoInst *this)
3318 {
3319         MonoCallInst *call = mono_emit_rgctx_method_call (cfg, bblock, method, signature, args, rgctx_arg, imt_arg, ip, this);
3320
3321         return mono_spill_call (cfg, bblock, call, signature, method->string_ctor, ip, FALSE);
3322 }
3323
3324 static void
3325 mono_emulate_opcode (MonoCompile *cfg, MonoInst *tree, MonoInst **iargs, MonoJitICallInfo *info)
3326 {
3327         MonoInst *ins, *temp = NULL, *store, *load, *begin;
3328         MonoInst *last_arg = NULL;
3329         int nargs;
3330         MonoCallInst *call;
3331
3332         //g_print ("emulating: ");
3333         //mono_print_tree_nl (tree);
3334         MONO_INST_NEW_CALL (cfg, call, ret_type_to_call_opcode (info->sig->ret, FALSE, FALSE, cfg->generic_sharing_context));
3335         ins = (MonoInst*)call;
3336         
3337         call->inst.cil_code = tree->cil_code;
3338         call->args = iargs;
3339         call->signature = info->sig;
3340
3341         call = mono_arch_call_opcode (cfg, cfg->cbb, call, FALSE);
3342
3343         if (!MONO_TYPE_IS_VOID (info->sig->ret)) {
3344                 temp = mono_compile_create_var (cfg, info->sig->ret, OP_LOCAL);
3345                 temp->flags |= MONO_INST_IS_TEMP;
3346                 NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
3347                 /* FIXME: handle CEE_STIND_R4 */
3348                 store->cil_code = tree->cil_code;
3349         } else {
3350                 store = ins;
3351         }
3352
3353         nargs = info->sig->param_count + info->sig->hasthis;
3354
3355         for (last_arg = call->out_args; last_arg && last_arg->next; last_arg = last_arg->next) ;
3356
3357         if (nargs)
3358                 last_arg->next = store;
3359
3360         if (nargs)
3361                 begin = call->out_args;
3362         else
3363                 begin = store;
3364
3365         if (cfg->prev_ins) {
3366                 /* 
3367                  * This assumes that that in a tree, emulate_opcode is called for a
3368                  * node before it is called for its children. dec_foreach needs to
3369                  * take this into account.
3370                  */
3371                 store->next = cfg->prev_ins->next;
3372                 cfg->prev_ins->next = begin;
3373         } else {
3374                 store->next = cfg->cbb->code;
3375                 cfg->cbb->code = begin;
3376         }
3377
3378         call->fptr = mono_icall_get_wrapper (info);
3379
3380         if (!MONO_TYPE_IS_VOID (info->sig->ret)) {
3381                 NEW_TEMPLOAD (cfg, load, temp->inst_c0);
3382                 *tree = *load;
3383         }
3384 }
3385
3386 /*
3387  * This entry point could be used later for arbitrary method
3388  * redirection.
3389  */
3390 inline static int
3391 mini_redirect_call (int *temp, MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *method,  
3392                        MonoMethodSignature *signature, MonoInst **args, const guint8 *ip, MonoInst *this)
3393 {
3394
3395         if (method->klass == mono_defaults.string_class) {
3396                 /* managed string allocation support */
3397                 if (strcmp (method->name, "InternalAllocateStr") == 0) {
3398                         MonoInst *iargs [2];
3399                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
3400                         MonoMethod *managed_alloc = mono_gc_get_managed_allocator (vtable, FALSE);
3401                         if (!managed_alloc)
3402                                 return FALSE;
3403                         NEW_VTABLECONST (cfg, iargs [0], vtable);
3404                         iargs [1] = args [0];
3405                         *temp = mono_emit_method_call_spilled (cfg, bblock, managed_alloc, mono_method_signature (managed_alloc), iargs, ip, this);
3406                         return TRUE;
3407                 }
3408         }
3409         return FALSE;
3410 }
3411
3412 static MonoMethodSignature *
3413 mono_get_array_new_va_signature (int arity)
3414 {
3415         static GHashTable *sighash = NULL;
3416         MonoMethodSignature *res;
3417         int i;
3418
3419         mono_jit_lock ();
3420         if (!sighash) {
3421                 sighash = g_hash_table_new (NULL, NULL);
3422         }
3423         else if ((res = g_hash_table_lookup (sighash, GINT_TO_POINTER (arity)))) {
3424                 mono_jit_unlock ();
3425                 return res;
3426         }
3427
3428         res = mono_metadata_signature_alloc (mono_defaults.corlib, arity + 1);
3429
3430         res->pinvoke = 1;
3431 #ifdef MONO_ARCH_VARARG_ICALLS
3432         /* Only set this only some archs since not all backends can handle varargs+pinvoke */
3433         res->call_convention = MONO_CALL_VARARG;
3434 #endif
3435
3436 #ifdef PLATFORM_WIN32
3437         res->call_convention = MONO_CALL_C;
3438 #endif
3439
3440         res->params [0] = &mono_defaults.int_class->byval_arg;  
3441         for (i = 0; i < arity; i++)
3442                 res->params [i + 1] = &mono_defaults.int_class->byval_arg;
3443
3444         res->ret = &mono_defaults.object_class->byval_arg;
3445
3446         g_hash_table_insert (sighash, GINT_TO_POINTER (arity), res);
3447         mono_jit_unlock ();
3448
3449         return res;
3450 }
3451
3452 MonoJitICallInfo *
3453 mono_get_array_new_va_icall (int rank)
3454 {
3455         MonoMethodSignature *esig;
3456         char icall_name [256];
3457         char *name;
3458         MonoJitICallInfo *info;
3459
3460         /* Need to register the icall so it gets an icall wrapper */
3461         sprintf (icall_name, "ves_array_new_va_%d", rank);
3462
3463         mono_jit_lock ();
3464         info = mono_find_jit_icall_by_name (icall_name);
3465         if (info == NULL) {
3466                 esig = mono_get_array_new_va_signature (rank);
3467                 name = g_strdup (icall_name);
3468                 info = mono_register_jit_icall (mono_array_new_va, name, esig, FALSE);
3469
3470                 g_hash_table_insert (jit_icall_name_hash, name, name);
3471         }
3472         mono_jit_unlock ();
3473
3474         return info;
3475 }
3476
3477 static MonoMethod*
3478 get_memcpy_method (void)
3479 {
3480         static MonoMethod *memcpy_method = NULL;
3481         if (!memcpy_method) {
3482                 memcpy_method = mono_class_get_method_from_name (mono_defaults.string_class, "memcpy", 3);
3483                 if (!memcpy_method)
3484                         g_error ("Old corlib found. Install a new one");
3485         }
3486         return memcpy_method;
3487 }
3488
3489 static void
3490 handle_stobj (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *dest, MonoInst *src, const unsigned char *ip, MonoClass *klass, gboolean to_end, gboolean native, gboolean write_barrier) {
3491         MonoInst *iargs [3];
3492         int n;
3493         guint32 align = 0;
3494         MonoMethod *memcpy_method;
3495
3496         g_assert (klass);
3497         /*
3498          * This check breaks with spilled vars... need to handle it during verification anyway.
3499          * g_assert (klass && klass == src->klass && klass == dest->klass);
3500          */
3501
3502         if (native)
3503                 n = mono_class_native_size (klass, &align);
3504         else
3505                 n = mono_class_value_size (klass, &align);
3506
3507 #if HAVE_WRITE_BARRIERS
3508         /* if native is true there should be no references in the struct */
3509         if (write_barrier && klass->has_references && !native) {
3510                 iargs [0] = dest;
3511                 iargs [1] = src;
3512                 NEW_PCONST (cfg, iargs [2], klass);
3513
3514                 mono_emit_jit_icall (cfg, bblock, mono_value_copy, iargs, ip);
3515                 return;
3516         }
3517 #endif
3518
3519         /* FIXME: add write barrier handling */
3520         if ((cfg->opt & MONO_OPT_INTRINS) && !to_end && n <= sizeof (gpointer) * 5) {
3521                 MonoInst *inst;
3522                 if (dest->opcode == OP_LDADDR) {
3523                         /* Keep liveness info correct */
3524                         NEW_DUMMY_STORE (cfg, inst, dest->inst_i0->inst_c0);
3525                         MONO_ADD_INS (bblock, inst);
3526                 }
3527                 NEW_MEMCPY (cfg, inst, dest, src, n, align);
3528                 MONO_ADD_INS (bblock, inst);
3529                 return;
3530         }
3531         iargs [0] = dest;
3532         iargs [1] = src;
3533         NEW_ICONST (cfg, iargs [2], n);
3534
3535         memcpy_method = get_memcpy_method ();
3536         mono_emit_method_call_spilled_full (cfg, bblock, memcpy_method, memcpy_method->signature, iargs, ip, NULL, FALSE, to_end);
3537 }
3538
3539 static MonoMethod*
3540 get_memset_method (void)
3541 {
3542         static MonoMethod *memset_method = NULL;
3543         if (!memset_method) {
3544                 memset_method = mono_class_get_method_from_name (mono_defaults.string_class, "memset", 3);
3545                 if (!memset_method)
3546                         g_error ("Old corlib found. Install a new one");
3547         }
3548         return memset_method;
3549 }
3550
3551 static void
3552 handle_initobj (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *dest, const guchar *ip, MonoClass *klass, MonoInst **stack_start, MonoInst **sp)
3553 {
3554         MonoInst *iargs [3];
3555         MonoInst *ins, *zero_int32;
3556         int n;
3557         guint32 align;
3558         MonoMethod *memset_method;
3559
3560         NEW_ICONST (cfg, zero_int32, 0);
3561
3562         mono_class_init (klass);
3563         n = mono_class_value_size (klass, &align);
3564         MONO_INST_NEW (cfg, ins, 0);
3565         ins->cil_code = ip;
3566         ins->inst_left = dest;
3567         ins->inst_right = zero_int32;
3568         if (n == 1) {
3569                 ins->opcode = CEE_STIND_I1;
3570                 MONO_ADD_INS (bblock, ins);
3571         } else if ((n == 2) && (align >= 2)) {
3572                 ins->opcode = CEE_STIND_I2;
3573                 MONO_ADD_INS (bblock, ins);
3574         } else if ((n == 2) && (align >= 4)) {
3575                 ins->opcode = CEE_STIND_I4;
3576                 MONO_ADD_INS (bblock, ins);
3577         } else if (n <= sizeof (gpointer) * 5) {
3578                 NEW_MEMSET (cfg, ins, dest, 0, n, align);
3579                 MONO_ADD_INS (bblock, ins);
3580         } else {
3581                 memset_method = get_memset_method ();
3582                 handle_loaded_temps (cfg, bblock, stack_start, sp);
3583                 iargs [0] = dest;
3584                 NEW_ICONST (cfg, iargs [1], 0);
3585                 NEW_ICONST (cfg, iargs [2], n);
3586                 mono_emit_method_call_spilled (cfg, bblock, memset_method, memset_method->signature, iargs, ip, NULL);
3587         }
3588 }
3589
3590 static int
3591 handle_alloc (MonoCompile *cfg, MonoBasicBlock *bblock, MonoClass *klass, gboolean for_box, const guchar *ip)
3592 {
3593         MonoInst *iargs [2];
3594         void *alloc_ftn;
3595
3596         if (cfg->opt & MONO_OPT_SHARED) {
3597                 NEW_DOMAINCONST (cfg, iargs [0]);
3598                 NEW_CLASSCONST (cfg, iargs [1], klass);
3599
3600                 alloc_ftn = mono_object_new;
3601         } else if (cfg->compile_aot && bblock->out_of_line && klass->type_token && klass->image == mono_defaults.corlib) {
3602                 /* This happens often in argument checking code, eg. throw new FooException... */
3603                 /* Avoid relocations by calling a helper function specialized to mscorlib */
3604                 NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (klass->type_token));
3605                 return mono_emit_jit_icall (cfg, bblock, mono_helper_newobj_mscorlib, iargs, ip);
3606         } else {
3607                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
3608                 MonoMethod *managed_alloc = mono_gc_get_managed_allocator (vtable, for_box);
3609                 gboolean pass_lw;
3610
3611                 if (managed_alloc) {
3612                         NEW_VTABLECONST (cfg, iargs [0], vtable);
3613                         return mono_emit_method_call_spilled (cfg, bblock, managed_alloc, mono_method_signature (managed_alloc), iargs, ip, NULL);
3614                 }
3615                 alloc_ftn = mono_class_get_allocation_ftn (vtable, for_box, &pass_lw);
3616                 if (pass_lw) {
3617                         guint32 lw = vtable->klass->instance_size;
3618                         lw = ((lw + (sizeof (gpointer) - 1)) & ~(sizeof (gpointer) - 1)) / sizeof (gpointer);
3619                         NEW_ICONST (cfg, iargs [0], lw);
3620                         NEW_VTABLECONST (cfg, iargs [1], vtable);
3621                 }
3622                 else
3623                         NEW_VTABLECONST (cfg, iargs [0], vtable);
3624         }
3625
3626         return mono_emit_jit_icall (cfg, bblock, alloc_ftn, iargs, ip);
3627 }
3628
3629 static int
3630 handle_alloc_from_inst (MonoCompile *cfg, MonoBasicBlock *bblock, MonoClass *klass, MonoInst *data_inst,
3631                 gboolean for_box, const guchar *ip)
3632 {
3633         MonoInst *iargs [2];
3634         MonoMethod *managed_alloc = NULL;
3635         void *alloc_ftn;
3636         /*
3637           FIXME: we cannot get managed_alloc here because we can't get
3638           the class's vtable (because it's not a closed class)
3639
3640         MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
3641         MonoMethod *managed_alloc = mono_gc_get_managed_allocator (vtable, for_box);
3642         */
3643
3644         if (cfg->opt & MONO_OPT_SHARED) {
3645                 NEW_DOMAINCONST (cfg, iargs [0]);
3646                 iargs [1] = data_inst;
3647                 alloc_ftn = mono_object_new;
3648         } else {
3649                 g_assert (!cfg->compile_aot);
3650
3651                 if (managed_alloc) {
3652                         iargs [0] = data_inst;
3653                         return mono_emit_method_call_spilled (cfg, bblock, managed_alloc,
3654                                 mono_method_signature (managed_alloc), iargs, ip, NULL);
3655                 }
3656
3657                 iargs [0] = data_inst;
3658                 alloc_ftn = mono_object_new_specific;
3659         }
3660
3661         return mono_emit_jit_icall (cfg, bblock, alloc_ftn, iargs, ip);
3662 }
3663
3664 static MonoInst*
3665 handle_box_copy (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *val, const guchar *ip, MonoClass *klass, int temp)
3666 {
3667         MonoInst *dest, *vtoffset, *add, *vstore;
3668
3669         NEW_TEMPLOAD (cfg, dest, temp);
3670         NEW_ICONST (cfg, vtoffset, sizeof (MonoObject));
3671         MONO_INST_NEW (cfg, add, OP_PADD);
3672         add->inst_left = dest;
3673         add->inst_right = vtoffset;
3674         add->cil_code = ip;
3675         add->klass = klass;
3676         MONO_INST_NEW (cfg, vstore, CEE_STIND_I);
3677         vstore->opcode = mini_type_to_stind (cfg, &klass->byval_arg);
3678         vstore->cil_code = ip;
3679         vstore->inst_left = add;
3680         vstore->inst_right = val;
3681
3682 #ifdef MONO_ARCH_SOFT_FLOAT
3683         if (vstore->opcode == CEE_STIND_R4) {
3684                 handle_store_float (cfg, bblock, add, val, ip);
3685         } else
3686 #endif
3687         if (vstore->opcode == CEE_STOBJ) {
3688                 handle_stobj (cfg, bblock, add, val, ip, klass, FALSE, FALSE, TRUE);
3689         } else
3690                 MONO_ADD_INS (bblock, vstore);
3691
3692         NEW_TEMPLOAD (cfg, dest, temp);
3693         return dest;
3694 }
3695
3696 static MonoInst *
3697 handle_box (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *val, const guchar *ip, MonoClass *klass)
3698 {
3699         MonoInst *dest;
3700         int temp;
3701
3702         if (mono_class_is_nullable (klass)) {
3703                 MonoMethod* method = mono_class_get_method_from_name (klass, "Box", 1);
3704                 temp = mono_emit_method_call_spilled (cfg, bblock, method, mono_method_signature (method), &val, ip, NULL);
3705                 NEW_TEMPLOAD (cfg, dest, temp);
3706                 return dest;
3707         }
3708
3709         temp = handle_alloc (cfg, bblock, klass, TRUE, ip);
3710
3711         return handle_box_copy (cfg, bblock, val, ip, klass, temp);
3712 }
3713
3714 static MonoInst *
3715 handle_box_from_inst (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *val, const guchar *ip,
3716                 MonoClass *klass, MonoInst *data_inst)
3717 {
3718         int temp;
3719
3720         g_assert (!mono_class_is_nullable (klass));
3721
3722         temp = handle_alloc_from_inst (cfg, bblock, klass, data_inst, TRUE, ip);
3723
3724         return handle_box_copy (cfg, bblock, val, ip, klass, temp);
3725 }
3726
3727 static MonoInst*
3728 handle_delegate_ctor (MonoCompile *cfg, MonoBasicBlock *bblock, MonoClass *klass, MonoInst *target, MonoMethod *method, unsigned char *ip)
3729 {
3730         gpointer *trampoline;
3731         MonoInst *obj, *ins, *store, *offset_ins, *method_ins, *tramp_ins;
3732         int temp;
3733
3734         temp = handle_alloc (cfg, bblock, klass, FALSE, ip);
3735
3736         /* Inline the contents of mono_delegate_ctor */
3737
3738         /* Set target field */
3739         /* Optimize away setting of NULL target */
3740         if (!(target->opcode == OP_PCONST && target->inst_p0 == 0)) {
3741                 NEW_TEMPLOAD (cfg, obj, temp);
3742                 NEW_ICONST (cfg, offset_ins, G_STRUCT_OFFSET (MonoDelegate, target));
3743                 MONO_INST_NEW (cfg, ins, OP_PADD);
3744                 ins->inst_left = obj;
3745                 ins->inst_right = offset_ins;
3746
3747                 MONO_INST_NEW (cfg, store, CEE_STIND_REF);
3748                 store->inst_left = ins;
3749                 store->inst_right = target;
3750                 mono_bblock_add_inst (bblock, store);
3751         }
3752
3753         /* Set method field */
3754         NEW_TEMPLOAD (cfg, obj, temp);
3755         NEW_ICONST (cfg, offset_ins, G_STRUCT_OFFSET (MonoDelegate, method));
3756         MONO_INST_NEW (cfg, ins, OP_PADD);
3757         ins->inst_left = obj;
3758         ins->inst_right = offset_ins;
3759
3760         NEW_METHODCONST (cfg, method_ins, method);
3761
3762         MONO_INST_NEW (cfg, store, CEE_STIND_I);
3763         store->inst_left = ins;
3764         store->inst_right = method_ins;
3765         mono_bblock_add_inst (bblock, store);
3766
3767         /* Set invoke_impl field */
3768         NEW_TEMPLOAD (cfg, obj, temp);
3769         NEW_ICONST (cfg, offset_ins, G_STRUCT_OFFSET (MonoDelegate, invoke_impl));
3770         MONO_INST_NEW (cfg, ins, OP_PADD);
3771         ins->inst_left = obj;
3772         ins->inst_right = offset_ins;
3773
3774         trampoline = mono_create_delegate_trampoline (klass);
3775         NEW_AOTCONST (cfg, tramp_ins, MONO_PATCH_INFO_ABS, trampoline);
3776
3777         MONO_INST_NEW (cfg, store, CEE_STIND_I);
3778         store->inst_left = ins;
3779         store->inst_right = tramp_ins;
3780         mono_bblock_add_inst (bblock, store);
3781
3782         /* All the checks which are in mono_delegate_ctor () are done by the delegate trampoline */
3783
3784         NEW_TEMPLOAD (cfg, obj, temp);
3785
3786         return obj;
3787 }
3788
3789 static int
3790 handle_array_new (MonoCompile *cfg, MonoBasicBlock *bblock, int rank, MonoInst **sp, unsigned char *ip)
3791 {
3792         MonoJitICallInfo *info;
3793
3794         info = mono_get_array_new_va_icall (rank);
3795
3796         cfg->flags |= MONO_CFG_HAS_VARARGS;
3797
3798         /* FIXME: This uses info->sig, but it should use the signature of the wrapper */
3799         return mono_emit_native_call (cfg, bblock, mono_icall_get_wrapper (info), info->sig, sp, ip, TRUE, FALSE);
3800 }
3801
3802 static void
3803 mono_emit_load_got_addr (MonoCompile *cfg)
3804 {
3805         MonoInst *load, *store, *dummy_use;
3806         MonoInst *get_got;
3807
3808         if (!cfg->got_var || cfg->got_var_allocated)
3809                 return;
3810
3811         MONO_INST_NEW (cfg, get_got, OP_LOAD_GOTADDR);
3812         NEW_TEMPSTORE (cfg, store, cfg->got_var->inst_c0, get_got);
3813
3814         /* Add it to the start of the first bblock */
3815         if (cfg->bb_entry->code) {
3816                 store->next = cfg->bb_entry->code;
3817                 cfg->bb_entry->code = store;
3818         }
3819         else
3820                 MONO_ADD_INS (cfg->bb_entry, store);
3821
3822         cfg->got_var_allocated = TRUE;
3823
3824         /* 
3825          * Add a dummy use to keep the got_var alive, since real uses might
3826          * only be generated in the decompose or instruction selection phases.
3827          * Add it to end_bblock, so the variable's lifetime covers the whole
3828          * method.
3829          */
3830         NEW_TEMPLOAD (cfg, load, cfg->got_var->inst_c0);
3831         NEW_DUMMY_USE (cfg, dummy_use, load);
3832         MONO_ADD_INS (cfg->bb_exit, dummy_use);
3833 }
3834
3835 #define CODE_IS_STLOC(ip) (((ip) [0] >= CEE_STLOC_0 && (ip) [0] <= CEE_STLOC_3) || ((ip) [0] == CEE_STLOC_S))
3836
3837 gboolean
3838 mini_class_is_system_array (MonoClass *klass)
3839 {
3840         if (klass->parent == mono_defaults.array_class)
3841                 return TRUE;
3842         else
3843                 return FALSE;
3844 }
3845
3846 static gboolean
3847 mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method)
3848 {
3849         MonoMethodHeader *header = mono_method_get_header (method);
3850         MonoMethodSignature *signature = mono_method_signature (method);
3851         MonoVTable *vtable;
3852         int i;
3853
3854         if (cfg->generic_sharing_context)
3855                 return FALSE;
3856
3857         if (method->inline_failure)
3858                 return FALSE;
3859
3860 #ifdef MONO_ARCH_HAVE_LMF_OPS
3861         if (((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
3862                  (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) &&
3863             !MONO_TYPE_ISSTRUCT (signature->ret) && !mini_class_is_system_array (method->klass))
3864                 return TRUE;
3865 #endif
3866
3867         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
3868             (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
3869             (method->iflags & METHOD_IMPL_ATTRIBUTE_NOINLINING) ||
3870             (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) ||
3871             (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
3872             (method->klass->marshalbyref) ||
3873             !header || header->num_clauses ||
3874             /* fixme: why cant we inline valuetype returns? */
3875             MONO_TYPE_ISSTRUCT (signature->ret))
3876                 return FALSE;
3877
3878 #ifdef MONO_ARCH_SOFT_FLOAT
3879         /* this complicates things, fix later */
3880         if (signature->ret->type == MONO_TYPE_R4)
3881                 return FALSE;
3882 #endif
3883         /* its not worth to inline methods with valuetype arguments?? */
3884         for (i = 0; i < signature->param_count; i++) {
3885                 if (MONO_TYPE_ISSTRUCT (signature->params [i])) {
3886                         return FALSE;
3887                 }
3888 #ifdef MONO_ARCH_SOFT_FLOAT
3889                 /* this complicates things, fix later */
3890                 if (!signature->params [i]->byref && signature->params [i]->type == MONO_TYPE_R4)
3891                         return FALSE;
3892 #endif
3893         }
3894
3895         /* also consider num_locals? */
3896         /* Do the size check early to avoid creating vtables */
3897         if (getenv ("MONO_INLINELIMIT")) {
3898                 if (header->code_size >= atoi (getenv ("MONO_INLINELIMIT"))) {
3899                         return FALSE;
3900                 }
3901         } else if (header->code_size >= INLINE_LENGTH_LIMIT)
3902                 return FALSE;
3903
3904         /*
3905          * if we can initialize the class of the method right away, we do,
3906          * otherwise we don't allow inlining if the class needs initialization,
3907          * since it would mean inserting a call to mono_runtime_class_init()
3908          * inside the inlined code
3909          */
3910         if (!(cfg->opt & MONO_OPT_SHARED)) {
3911                 if (method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) {
3912                         if (cfg->run_cctors && method->klass->has_cctor) {
3913                                 if (!method->klass->runtime_info)
3914                                         /* No vtable created yet */
3915                                         return FALSE;
3916                                 vtable = mono_class_vtable (cfg->domain, method->klass);
3917                                 if (!vtable)
3918                                         return FALSE;
3919                                 /* This makes so that inline cannot trigger */
3920                                 /* .cctors: too many apps depend on them */
3921                                 /* running with a specific order... */
3922                                 if (! vtable->initialized)
3923                                         return FALSE;
3924                                 mono_runtime_class_init (vtable);
3925                         }
3926                 } else if (mono_class_needs_cctor_run (method->klass, NULL)) {
3927                         if (!method->klass->runtime_info)
3928                                 /* No vtable created yet */
3929                                 return FALSE;
3930                         vtable = mono_class_vtable (cfg->domain, method->klass);
3931                         if (!vtable)
3932                                 return FALSE;
3933                         if (!vtable->initialized)
3934                                 return FALSE;
3935                 }
3936         } else {
3937                 /* 
3938                  * If we're compiling for shared code
3939                  * the cctor will need to be run at aot method load time, for example,
3940                  * or at the end of the compilation of the inlining method.
3941                  */
3942                 if (mono_class_needs_cctor_run (method->klass, NULL) && !((method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT)))
3943                         return FALSE;
3944         }
3945         //if (!MONO_TYPE_IS_VOID (signature->ret)) return FALSE;
3946
3947         /*
3948          * CAS - do not inline methods with declarative security
3949          * Note: this has to be before any possible return TRUE;
3950          */
3951         if (mono_method_has_declsec (method))
3952                 return FALSE;
3953
3954         return TRUE;
3955 }
3956
3957 static gboolean
3958 mini_field_access_needs_cctor_run (MonoCompile *cfg, MonoMethod *method, MonoVTable *vtable)
3959 {
3960         if (vtable->initialized && !cfg->compile_aot)
3961                 return FALSE;
3962
3963         if (vtable->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT)
3964                 return FALSE;
3965
3966         if (!mono_class_needs_cctor_run (vtable->klass, method))
3967                 return FALSE;
3968
3969         if (! (method->flags & METHOD_ATTRIBUTE_STATIC) && (vtable->klass == method->klass))
3970                 /* The initialization is already done before the method is called */
3971                 return FALSE;
3972
3973         return TRUE;
3974 }
3975
3976 static MonoInst*
3977 mini_get_ldelema_ins (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *cmethod, MonoInst **sp, unsigned char *ip, gboolean is_set)
3978 {
3979         int temp, rank;
3980         MonoInst *addr;
3981         MonoMethod *addr_method;
3982         int element_size;
3983
3984         rank = mono_method_signature (cmethod)->param_count - (is_set? 1: 0);
3985
3986         if (rank == 1) {
3987                 MONO_INST_NEW (cfg, addr, CEE_LDELEMA);
3988                 addr->inst_left = sp [0];
3989                 addr->inst_right = sp [1];
3990                 addr->type = STACK_MP;
3991                 addr->klass = cmethod->klass->element_class;
3992                 return addr;
3993         }
3994
3995         if (rank == 2 && (cfg->opt & MONO_OPT_INTRINS)) {
3996 #if defined(MONO_ARCH_EMULATE_MUL_DIV) && !defined(MONO_ARCH_NO_EMULATE_MUL)
3997                 /* OP_LDELEMA2D depends on OP_LMUL */
3998 #else
3999                 MonoInst *indexes;
4000                 NEW_GROUP (cfg, indexes, sp [1], sp [2]);
4001                 MONO_INST_NEW (cfg, addr, OP_LDELEMA2D);
4002                 addr->inst_left = sp [0];
4003                 addr->inst_right = indexes;
4004                 addr->type = STACK_MP;
4005                 addr->klass = cmethod->klass->element_class;
4006                 return addr;
4007 #endif
4008         }
4009
4010         element_size = mono_class_array_element_size (cmethod->klass->element_class);
4011         addr_method = mono_marshal_get_array_address (rank, element_size);
4012         temp = mono_emit_method_call_spilled (cfg, bblock, addr_method, addr_method->signature, sp, ip, NULL);
4013         NEW_TEMPLOAD (cfg, addr, temp);
4014         return addr;
4015
4016 }
4017
4018 static MonoJitICallInfo **emul_opcode_map = NULL;
4019
4020 MonoJitICallInfo *
4021 mono_find_jit_opcode_emulation (int opcode)
4022 {
4023         g_assert (opcode >= 0 && opcode <= OP_LAST);
4024         if  (emul_opcode_map)
4025                 return emul_opcode_map [opcode];
4026         else
4027                 return NULL;
4028 }
4029
4030 static MonoInst*
4031 mini_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
4032 {
4033         MonoInst *ins = NULL;
4034         
4035         static MonoClass *runtime_helpers_class = NULL;
4036         if (! runtime_helpers_class)
4037                 runtime_helpers_class = mono_class_from_name (mono_defaults.corlib,
4038                         "System.Runtime.CompilerServices", "RuntimeHelpers");
4039
4040         if (cmethod->klass == mono_defaults.string_class) {
4041                 if (strcmp (cmethod->name, "get_Chars") == 0) {
4042                         MONO_INST_NEW (cfg, ins, OP_GETCHR);
4043                         ins->inst_i0 = args [0];
4044                         ins->inst_i1 = args [1];
4045                         return ins;
4046                 } else if (strcmp (cmethod->name, "get_Length") == 0) {
4047                         MONO_INST_NEW (cfg, ins, OP_STRLEN);
4048                         ins->inst_i0 = args [0];
4049                         return ins;
4050                 } else if (strcmp (cmethod->name, "InternalSetChar") == 0) {
4051                         MonoInst *get_addr;
4052                         MONO_INST_NEW (cfg, get_addr, OP_STR_CHAR_ADDR);
4053                         get_addr->inst_i0 = args [0];
4054                         get_addr->inst_i1 = args [1];
4055                         MONO_INST_NEW (cfg, ins, CEE_STIND_I2);
4056                         ins->inst_i0 = get_addr;
4057                         ins->inst_i1 = args [2];
4058                         return ins;
4059                 } else 
4060                         return NULL;
4061         } else if (cmethod->klass == mono_defaults.object_class) {
4062                 if (strcmp (cmethod->name, "GetType") == 0) {
4063                         MONO_INST_NEW (cfg, ins, OP_GETTYPE);
4064                         ins->inst_i0 = args [0];
4065                         return ins;
4066                 /* The OP_GETHASHCODE rule depends on OP_MUL */
4067 #if !defined(MONO_ARCH_EMULATE_MUL_DIV) && !defined(HAVE_MOVING_COLLECTOR)
4068                 } else if (strcmp (cmethod->name, "InternalGetHashCode") == 0) {
4069                         MONO_INST_NEW (cfg, ins, OP_GETHASHCODE);
4070                         ins->inst_i0 = args [0];
4071                         return ins;
4072 #endif
4073                 } else if (strcmp (cmethod->name, ".ctor") == 0) {
4074                         MONO_INST_NEW (cfg, ins, OP_NOP);
4075                         return ins;
4076                 } else
4077                         return NULL;
4078         } else if (cmethod->klass == mono_defaults.array_class) {
4079                 if (cmethod->name [0] != 'g')
4080                         return NULL;
4081
4082                 if (strcmp (cmethod->name, "get_Rank") == 0) {
4083                         MONO_INST_NEW (cfg, ins, OP_ARRAY_RANK);
4084                         ins->inst_i0 = args [0];
4085                         return ins;
4086                 } else if (strcmp (cmethod->name, "get_Length") == 0) {
4087                         MONO_INST_NEW (cfg, ins, CEE_LDLEN);
4088                         ins->inst_i0 = args [0];
4089                         return ins;
4090                 } else
4091                         return NULL;
4092         } else if (cmethod->klass == runtime_helpers_class) {
4093                 if (strcmp (cmethod->name, "get_OffsetToStringData") == 0) {
4094                         NEW_ICONST (cfg, ins, G_STRUCT_OFFSET (MonoString, chars));
4095                         return ins;
4096                 } else
4097                         return NULL;
4098         } else if (cmethod->klass == mono_defaults.thread_class) {
4099                 if (strcmp (cmethod->name, "get_CurrentThread") == 0 && (ins = mono_arch_get_thread_intrinsic (cfg)))
4100                         return ins;
4101                 if (strcmp (cmethod->name, "MemoryBarrier") == 0) {
4102                         MONO_INST_NEW (cfg, ins, OP_MEMORY_BARRIER);
4103                         return ins;
4104                 }
4105         } else if (mini_class_is_system_array (cmethod->klass) &&
4106                         strcmp (cmethod->name, "GetGenericValueImpl") == 0) {
4107                 MonoInst *sp [2];
4108                 MonoInst *ldelem, *store, *load;
4109                 MonoClass *eklass = mono_class_from_mono_type (fsig->params [1]);
4110                 int n;
4111                 n = mini_type_to_stind (cfg, &eklass->byval_arg);
4112                 if (n == CEE_STOBJ)
4113                         return NULL;
4114                 sp [0] = args [0];
4115                 sp [1] = args [1];
4116                 NEW_LDELEMA (cfg, ldelem, sp, eklass);
4117                 ldelem->flags |= MONO_INST_NORANGECHECK;
4118                 MONO_INST_NEW (cfg, store, n);
4119                 MONO_INST_NEW (cfg, load, mini_type_to_ldind (cfg, &eklass->byval_arg));
4120                 type_to_eval_stack_type (cfg, &eklass->byval_arg, load);
4121                 load->inst_left = ldelem;
4122                 store->inst_left = args [2];
4123                 store->inst_right = load;
4124                 return store;
4125         } else if (cmethod->klass == mono_defaults.math_class) {
4126                 /* 
4127                  * There is general branches code for Min/Max, but it does not work for 
4128                  * all inputs:
4129                  * http://everything2.com/?node_id=1051618
4130                  */
4131         } else if (cmethod->klass->image == mono_defaults.corlib &&
4132                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
4133                            (strcmp (cmethod->klass->name, "Interlocked") == 0)) {
4134                 ins = NULL;
4135
4136 #if SIZEOF_VOID_P == 8
4137                 if (strcmp (cmethod->name, "Read") == 0 && (fsig->params [0]->type == MONO_TYPE_I8)) {
4138                         /* 64 bit reads are already atomic */
4139                         MONO_INST_NEW (cfg, ins, CEE_LDIND_I8);
4140                         ins->inst_i0 = args [0];
4141                 }
4142 #endif
4143
4144 #ifdef MONO_ARCH_HAVE_ATOMIC_ADD
4145                 if (strcmp (cmethod->name, "Increment") == 0) {
4146                         MonoInst *ins_iconst;
4147                         guint32 opcode;
4148
4149                         if (fsig->params [0]->type == MONO_TYPE_I4)
4150                                 opcode = OP_ATOMIC_ADD_NEW_I4;
4151                         else if (fsig->params [0]->type == MONO_TYPE_I8)
4152                                 opcode = OP_ATOMIC_ADD_NEW_I8;
4153                         else
4154                                 g_assert_not_reached ();
4155
4156 #if SIZEOF_VOID_P == 4
4157                         if (opcode == OP_ATOMIC_ADD_NEW_I8)
4158                                 return NULL;
4159 #endif
4160
4161                         MONO_INST_NEW (cfg, ins, opcode);
4162                         MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
4163                         ins_iconst->inst_c0 = 1;
4164
4165                         ins->inst_i0 = args [0];
4166                         ins->inst_i1 = ins_iconst;
4167                 } else if (strcmp (cmethod->name, "Decrement") == 0) {
4168                         MonoInst *ins_iconst;
4169                         guint32 opcode;
4170
4171                         if (fsig->params [0]->type == MONO_TYPE_I4)
4172                                 opcode = OP_ATOMIC_ADD_NEW_I4;
4173                         else if (fsig->params [0]->type == MONO_TYPE_I8)
4174                                 opcode = OP_ATOMIC_ADD_NEW_I8;
4175                         else
4176                                 g_assert_not_reached ();
4177
4178 #if SIZEOF_VOID_P == 4
4179                         if (opcode == OP_ATOMIC_ADD_NEW_I8)
4180                                 return NULL;
4181 #endif
4182
4183                         MONO_INST_NEW (cfg, ins, opcode);
4184                         MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
4185                         ins_iconst->inst_c0 = -1;
4186
4187                         ins->inst_i0 = args [0];
4188                         ins->inst_i1 = ins_iconst;
4189                 } else if (strcmp (cmethod->name, "Add") == 0) {
4190                         guint32 opcode;
4191
4192                         if (fsig->params [0]->type == MONO_TYPE_I4)
4193                                 opcode = OP_ATOMIC_ADD_NEW_I4;
4194                         else if (fsig->params [0]->type == MONO_TYPE_I8)
4195                                 opcode = OP_ATOMIC_ADD_NEW_I8;
4196                         else
4197                                 g_assert_not_reached ();
4198
4199 #if SIZEOF_VOID_P == 4
4200                         if (opcode == OP_ATOMIC_ADD_NEW_I8)
4201                                 return NULL;
4202 #endif
4203                         
4204                         MONO_INST_NEW (cfg, ins, opcode);
4205
4206                         ins->inst_i0 = args [0];
4207                         ins->inst_i1 = args [1];
4208                 }
4209 #endif /* MONO_ARCH_HAVE_ATOMIC_ADD */
4210
4211 #ifdef MONO_ARCH_HAVE_ATOMIC_EXCHANGE
4212                 if (strcmp (cmethod->name, "Exchange") == 0) {
4213                         guint32 opcode;
4214
4215                         if (fsig->params [0]->type == MONO_TYPE_I4)
4216                                 opcode = OP_ATOMIC_EXCHANGE_I4;
4217 #if SIZEOF_VOID_P == 8
4218                         else if ((fsig->params [0]->type == MONO_TYPE_I8) ||
4219                                          (fsig->params [0]->type == MONO_TYPE_I) ||
4220                                          (fsig->params [0]->type == MONO_TYPE_OBJECT))
4221                                 opcode = OP_ATOMIC_EXCHANGE_I8;
4222 #else
4223                         else if ((fsig->params [0]->type == MONO_TYPE_I) ||
4224                                          (fsig->params [0]->type == MONO_TYPE_OBJECT))
4225                                 opcode = OP_ATOMIC_EXCHANGE_I4;
4226 #endif
4227                         else
4228                                 return NULL;
4229
4230 #if SIZEOF_VOID_P == 4
4231                         if (opcode == OP_ATOMIC_EXCHANGE_I8)
4232                                 return NULL;
4233 #endif
4234
4235                         MONO_INST_NEW (cfg, ins, opcode);
4236
4237                         ins->inst_i0 = args [0];
4238                         ins->inst_i1 = args [1];
4239                 }
4240 #endif /* MONO_ARCH_HAVE_ATOMIC_EXCHANGE */
4241
4242 #ifdef MONO_ARCH_HAVE_ATOMIC_CAS_IMM
4243                 /* 
4244                  * Can't implement CompareExchange methods this way since they have
4245                  * three arguments. We can implement one of the common cases, where the new
4246                  * value is a constant.
4247                  */
4248                 if ((strcmp (cmethod->name, "CompareExchange") == 0)) {
4249                         if (fsig->params [1]->type == MONO_TYPE_I4 && args [2]->opcode == OP_ICONST) {
4250                                 MONO_INST_NEW (cfg, ins, OP_ATOMIC_CAS_IMM_I4);
4251                                 ins->inst_i0 = args [0];
4252                                 ins->inst_i1 = args [1];
4253                                 ins->backend.data = GINT_TO_POINTER (args [2]->inst_c0);
4254                         }
4255                         /* The I8 case is hard to detect, since the arg might be a conv.i8 (iconst) tree */
4256                 }
4257 #endif /* MONO_ARCH_HAVE_ATOMIC_CAS_IMM */
4258
4259                 if (ins)
4260                         return ins;
4261         } else if (cmethod->klass->image == mono_defaults.corlib) {
4262                 if (cmethod->name [0] == 'B' && strcmp (cmethod->name, "Break") == 0
4263                                 && strcmp (cmethod->klass->name, "Debugger") == 0) {
4264                         MONO_INST_NEW (cfg, ins, OP_BREAK);
4265                         return ins;
4266                 }
4267                 if (cmethod->name [0] == 'g' && strcmp (cmethod->name, "get_IsRunningOnWindows") == 0
4268                                 && strcmp (cmethod->klass->name, "Environment") == 0) {
4269 #ifdef PLATFORM_WIN32
4270                         NEW_ICONST (cfg, ins, 1);
4271 #else
4272                         NEW_ICONST (cfg, ins, 0);
4273 #endif
4274                         return ins;
4275                 }
4276         }
4277
4278         return mono_arch_get_inst_for_method (cfg, cmethod, fsig, args);
4279 }
4280
4281 static void
4282 mono_save_args (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethodSignature *sig, MonoInst **sp, MonoInst **args)
4283 {
4284         MonoInst *store, *temp;
4285         int i;
4286
4287         g_assert (!MONO_TYPE_ISSTRUCT (sig->ret));
4288
4289         if (!sig->hasthis && sig->param_count == 0) 
4290                 return;
4291
4292         if (sig->hasthis) {
4293                 if (sp [0]->opcode == OP_ICONST) {
4294                         *args++ = sp [0];
4295                 } else {
4296                         temp = mono_compile_create_var (cfg, type_from_stack_type (*sp), OP_LOCAL);
4297                         *args++ = temp;
4298                         NEW_TEMPSTORE (cfg, store, temp->inst_c0, *sp);
4299                         /* FIXME: handle CEE_STIND_R4 */
4300                         store->cil_code = sp [0]->cil_code;
4301                         MONO_ADD_INS (bblock, store);
4302                 }
4303                 sp++;
4304         }
4305
4306         for (i = 0; i < sig->param_count; ++i) {
4307                 if (sp [0]->opcode == OP_ICONST) {
4308                         *args++ = sp [0];
4309                 } else {
4310                         temp = mono_compile_create_var (cfg, sig->params [i], OP_LOCAL);
4311                         *args++ = temp;
4312                         NEW_TEMPSTORE (cfg, store, temp->inst_c0, *sp);
4313                         store->cil_code = sp [0]->cil_code;
4314                         /* FIXME: handle CEE_STIND_R4 */
4315                         if (store->opcode == CEE_STOBJ) {
4316                                 NEW_TEMPLOADA (cfg, store, temp->inst_c0);
4317                                 handle_stobj (cfg, bblock, store, *sp, sp [0]->cil_code, temp->klass, FALSE, FALSE, FALSE);
4318 #ifdef MONO_ARCH_SOFT_FLOAT
4319                         } else if (store->opcode == CEE_STIND_R4) {
4320                                 NEW_TEMPLOADA (cfg, store, temp->inst_c0);
4321                                 handle_store_float (cfg, bblock, store, *sp, sp [0]->cil_code);
4322 #endif
4323                         } else {
4324                                 MONO_ADD_INS (bblock, store);
4325                         } 
4326                 }
4327                 sp++;
4328         }
4329 }
4330 #define MONO_INLINE_CALLED_LIMITED_METHODS 0
4331 #define MONO_INLINE_CALLER_LIMITED_METHODS 0
4332
4333 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
4334 static char*
4335 mono_inline_called_method_name_limit = NULL;
4336 static gboolean check_inline_called_method_name_limit (MonoMethod *called_method) {
4337         char *called_method_name = mono_method_full_name (called_method, TRUE);
4338         int strncmp_result;
4339         
4340         if (mono_inline_called_method_name_limit == NULL) {
4341                 char *limit_string = getenv ("MONO_INLINE_CALLED_METHOD_NAME_LIMIT");
4342                 if (limit_string != NULL) {
4343                         mono_inline_called_method_name_limit = limit_string;
4344                 } else {
4345                         mono_inline_called_method_name_limit = (char *) "";
4346                 }
4347         }
4348         
4349         strncmp_result = strncmp (called_method_name, mono_inline_called_method_name_limit, strlen (mono_inline_called_method_name_limit));
4350         g_free (called_method_name);
4351         
4352         //return (strncmp_result <= 0);
4353         return (strncmp_result == 0);
4354 }
4355 #endif
4356
4357 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
4358 static char*
4359 mono_inline_caller_method_name_limit = NULL;
4360 static gboolean check_inline_caller_method_name_limit (MonoMethod *caller_method) {
4361         char *caller_method_name = mono_method_full_name (caller_method, TRUE);
4362         int strncmp_result;
4363         
4364         if (mono_inline_caller_method_name_limit == NULL) {
4365                 char *limit_string = getenv ("MONO_INLINE_CALLER_METHOD_NAME_LIMIT");
4366                 if (limit_string != NULL) {
4367                         mono_inline_caller_method_name_limit = limit_string;
4368                 } else {
4369                         mono_inline_caller_method_name_limit = (char *) "";
4370                 }
4371         }
4372         
4373         strncmp_result = strncmp (caller_method_name, mono_inline_caller_method_name_limit, strlen (mono_inline_caller_method_name_limit));
4374         g_free (caller_method_name);
4375         
4376         //return (strncmp_result <= 0);
4377         return (strncmp_result == 0);
4378 }
4379 #endif
4380
4381 static int
4382 inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoBasicBlock *bblock, MonoInst **sp,
4383                 guchar *ip, guint real_offset, GList *dont_inline, MonoBasicBlock **last_b, gboolean inline_allways)
4384 {
4385         MonoInst *ins, *rvar = NULL;
4386         MonoMethodHeader *cheader;
4387         MonoBasicBlock *ebblock, *sbblock;
4388         int i, costs, new_locals_offset;
4389         MonoMethod *prev_inlined_method;
4390         MonoBasicBlock **prev_cil_offset_to_bb;
4391         unsigned char* prev_cil_start;
4392         guint32 prev_cil_offset_to_bb_len;
4393
4394         g_assert (cfg->exception_type == MONO_EXCEPTION_NONE);
4395
4396 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
4397         if ((! inline_allways) && ! check_inline_called_method_name_limit (cmethod))
4398                 return 0;
4399 #endif
4400 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
4401         if ((! inline_allways) && ! check_inline_caller_method_name_limit (cfg->method))
4402                 return 0;
4403 #endif
4404
4405         if (bblock->out_of_line && !inline_allways)
4406                 return 0;
4407
4408         if (cfg->verbose_level > 2)
4409                 g_print ("INLINE START %p %s -> %s\n", cmethod,  mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
4410
4411         if (!cmethod->inline_info) {
4412                 mono_jit_stats.inlineable_methods++;
4413                 cmethod->inline_info = 1;
4414         }
4415         /* allocate space to store the return value */
4416         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
4417                 rvar =  mono_compile_create_var (cfg, fsig->ret, OP_LOCAL);
4418         }
4419
4420         /* allocate local variables */
4421         cheader = mono_method_get_header (cmethod);
4422         new_locals_offset = cfg->num_varinfo;
4423         for (i = 0; i < cheader->num_locals; ++i)
4424                 mono_compile_create_var (cfg, cheader->locals [i], OP_LOCAL);
4425
4426         /* allocate starte and end blocks */
4427         sbblock = NEW_BBLOCK (cfg);
4428         sbblock->block_num = cfg->num_bblocks++;
4429         sbblock->real_offset = real_offset;
4430
4431         ebblock = NEW_BBLOCK (cfg);
4432         ebblock->block_num = cfg->num_bblocks++;
4433         ebblock->real_offset = real_offset;
4434
4435         prev_inlined_method = cfg->inlined_method;
4436         cfg->inlined_method = cmethod;
4437         prev_cil_offset_to_bb = cfg->cil_offset_to_bb;
4438         prev_cil_offset_to_bb_len = cfg->cil_offset_to_bb_len;
4439         prev_cil_start = cfg->cil_start;
4440
4441         costs = mono_method_to_ir (cfg, cmethod, sbblock, ebblock, new_locals_offset, rvar, dont_inline, sp, real_offset, *ip == CEE_CALLVIRT);
4442
4443         cfg->inlined_method = prev_inlined_method;
4444         cfg->cil_offset_to_bb = prev_cil_offset_to_bb;
4445         cfg->cil_offset_to_bb_len = prev_cil_offset_to_bb_len;
4446         cfg->cil_start = prev_cil_start;
4447
4448         if ((costs >= 0 && costs < 60) || inline_allways) {
4449                 if (cfg->verbose_level > 2)
4450                         g_print ("INLINE END %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
4451                 
4452                 mono_jit_stats.inlined_methods++;
4453
4454                 /* always add some code to avoid block split failures */
4455                 MONO_INST_NEW (cfg, ins, OP_NOP);
4456                 MONO_ADD_INS (bblock, ins);
4457                 ins->cil_code = ip;
4458
4459                 bblock->next_bb = sbblock;
4460                 link_bblock (cfg, bblock, sbblock);
4461
4462                 if (rvar) {
4463                         NEW_TEMPLOAD (cfg, ins, rvar->inst_c0);
4464                         NEW_TEMPLOAD_SOFT_FLOAT (cfg, ebblock, ins, rvar->inst_c0, ip);
4465                         *sp++ = ins;
4466                 }
4467                 *last_b = ebblock;
4468                 return costs + 1;
4469         } else {
4470                 if (cfg->verbose_level > 2)
4471                         g_print ("INLINE ABORTED %s\n", mono_method_full_name (cmethod, TRUE));
4472                 cfg->exception_type = MONO_EXCEPTION_NONE;
4473                 mono_loader_clear_error ();
4474                 cmethod->inline_failure = TRUE;
4475         }
4476         return 0;
4477 }
4478
4479 /*
4480  * Some of these comments may well be out-of-date.
4481  * Design decisions: we do a single pass over the IL code (and we do bblock 
4482  * splitting/merging in the few cases when it's required: a back jump to an IL
4483  * address that was not already seen as bblock starting point).
4484  * Code is validated as we go (full verification is still better left to metadata/verify.c).
4485  * Complex operations are decomposed in simpler ones right away. We need to let the 
4486  * arch-specific code peek and poke inside this process somehow (except when the 
4487  * optimizations can take advantage of the full semantic info of coarse opcodes).
4488  * All the opcodes of the form opcode.s are 'normalized' to opcode.
4489  * MonoInst->opcode initially is the IL opcode or some simplification of that 
4490  * (OP_LOAD, OP_STORE). The arch-specific code may rearrange it to an arch-specific 
4491  * opcode with value bigger than OP_LAST.
4492  * At this point the IR can be handed over to an interpreter, a dumb code generator
4493  * or to the optimizing code generator that will translate it to SSA form.
4494  *
4495  * Profiling directed optimizations.
4496  * We may compile by default with few or no optimizations and instrument the code
4497  * or the user may indicate what methods to optimize the most either in a config file
4498  * or through repeated runs where the compiler applies offline the optimizations to 
4499  * each method and then decides if it was worth it.
4500  *
4501  */
4502
4503 #define CHECK_TYPE(ins) if (!(ins)->type) UNVERIFIED
4504 #define CHECK_STACK(num) if ((sp - stack_start) < (num)) UNVERIFIED
4505 #define CHECK_STACK_OVF(num) if (((sp - stack_start) + (num)) > header->max_stack) UNVERIFIED
4506 #define CHECK_ARG(num) if ((unsigned)(num) >= (unsigned)num_args) UNVERIFIED
4507 #define CHECK_LOCAL(num) if ((unsigned)(num) >= (unsigned)header->num_locals) UNVERIFIED
4508 #define CHECK_OPSIZE(size) if (ip + size > end) UNVERIFIED
4509 #define CHECK_UNVERIFIABLE(cfg) if (cfg->unverifiable) UNVERIFIED
4510 #define CHECK_TYPELOAD(klass) if (!(klass) || (klass)->exception_type) {cfg->exception_ptr = klass; goto load_error;}
4511
4512 /* offset from br.s -> br like opcodes */
4513 #define BIG_BRANCH_OFFSET 13
4514
4515 static inline gboolean
4516 ip_in_bb (MonoCompile *cfg, MonoBasicBlock *bb, const guint8* ip)
4517 {
4518         MonoBasicBlock *b = cfg->cil_offset_to_bb [ip - cfg->cil_start];
4519         
4520         return b == NULL || b == bb;
4521 }
4522
4523 static int
4524 get_basic_blocks (MonoCompile *cfg, MonoMethodHeader* header, guint real_offset, unsigned char *start, unsigned char *end, unsigned char **pos)
4525 {
4526         unsigned char *ip = start;
4527         unsigned char *target;
4528         int i;
4529         guint cli_addr;
4530         MonoBasicBlock *bblock;
4531         const MonoOpcode *opcode;
4532
4533         while (ip < end) {
4534                 cli_addr = ip - start;
4535                 i = mono_opcode_value ((const guint8 **)&ip, end);
4536                 if (i < 0)
4537                         UNVERIFIED;
4538                 opcode = &mono_opcodes [i];
4539                 switch (opcode->argument) {
4540                 case MonoInlineNone:
4541                         ip++; 
4542                         break;
4543                 case MonoInlineString:
4544                 case MonoInlineType:
4545                 case MonoInlineField:
4546                 case MonoInlineMethod:
4547                 case MonoInlineTok:
4548                 case MonoInlineSig:
4549                 case MonoShortInlineR:
4550                 case MonoInlineI:
4551                         ip += 5;
4552                         break;
4553                 case MonoInlineVar:
4554                         ip += 3;
4555                         break;
4556                 case MonoShortInlineVar:
4557                 case MonoShortInlineI:
4558                         ip += 2;
4559                         break;
4560                 case MonoShortInlineBrTarget:
4561                         target = start + cli_addr + 2 + (signed char)ip [1];
4562                         GET_BBLOCK (cfg, bblock, target);
4563                         ip += 2;
4564                         if (ip < end)
4565                                 GET_BBLOCK (cfg, bblock, ip);
4566                         break;
4567                 case MonoInlineBrTarget:
4568                         target = start + cli_addr + 5 + (gint32)read32 (ip + 1);
4569                         GET_BBLOCK (cfg, bblock, target);
4570                         ip += 5;
4571                         if (ip < end)
4572                                 GET_BBLOCK (cfg, bblock, ip);
4573                         break;
4574                 case MonoInlineSwitch: {
4575                         guint32 n = read32 (ip + 1);
4576                         guint32 j;
4577                         ip += 5;
4578                         cli_addr += 5 + 4 * n;
4579                         target = start + cli_addr;
4580                         GET_BBLOCK (cfg, bblock, target);
4581                         
4582                         for (j = 0; j < n; ++j) {
4583                                 target = start + cli_addr + (gint32)read32 (ip);
4584                                 GET_BBLOCK (cfg, bblock, target);
4585                                 ip += 4;
4586                         }
4587                         break;
4588                 }
4589                 case MonoInlineR:
4590                 case MonoInlineI8:
4591                         ip += 9;
4592                         break;
4593                 default:
4594                         g_assert_not_reached ();
4595                 }
4596
4597                 if (i == CEE_THROW) {
4598                         unsigned char *bb_start = ip - 1;
4599                         
4600                         /* Find the start of the bblock containing the throw */
4601                         bblock = NULL;
4602                         while ((bb_start >= start) && !bblock) {
4603                                 bblock = cfg->cil_offset_to_bb [(bb_start) - start];
4604                                 bb_start --;
4605                         }
4606                         if (bblock)
4607                                 bblock->out_of_line = 1;
4608                 }
4609         }
4610         return 0;
4611 unverified:
4612         *pos = ip;
4613         return 1;
4614 }
4615
4616 static MonoInst*
4617 emit_tree (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *ins, const guint8* ip_next)
4618 {
4619         MonoInst *store, *temp, *load;
4620         
4621         if (ip_in_bb (cfg, bblock, ip_next) &&
4622                 (CODE_IS_STLOC (ip_next) || *ip_next == CEE_RET))
4623                         return ins;
4624         
4625         temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
4626         temp->flags |= MONO_INST_IS_TEMP;
4627         NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
4628         /* FIXME: handle CEE_STIND_R4 */
4629         store->cil_code = ins->cil_code;
4630         MONO_ADD_INS (bblock, store);
4631         NEW_TEMPLOAD (cfg, load, temp->inst_c0);
4632         load->cil_code = ins->cil_code;
4633         return load;
4634 }
4635
4636 static inline MonoMethod *
4637 mini_get_method_allow_open (MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
4638 {
4639         MonoMethod *method;
4640
4641         if (m->wrapper_type != MONO_WRAPPER_NONE)
4642                 return mono_method_get_wrapper_data (m, token);
4643
4644         method = mono_get_method_full (m->klass->image, token, klass, context);
4645
4646         return method;
4647 }
4648
4649 static inline MonoMethod *
4650 mini_get_method (MonoCompile *cfg, MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
4651 {
4652         MonoMethod *method = mini_get_method_allow_open (m, token, klass, context);
4653
4654         if (method && cfg && !cfg->generic_sharing_context && mono_class_is_open_constructed_type (&method->klass->byval_arg))
4655                 return NULL;
4656
4657         return method;
4658 }
4659
4660 static inline MonoClass*
4661 mini_get_class (MonoMethod *method, guint32 token, MonoGenericContext *context)
4662 {
4663         MonoClass *klass;
4664
4665         if (method->wrapper_type != MONO_WRAPPER_NONE)
4666                 klass = mono_method_get_wrapper_data (method, token);
4667         else
4668                 klass = mono_class_get_full (method->klass->image, token, context);
4669         if (klass)
4670                 mono_class_init (klass);
4671         return klass;
4672 }
4673
4674 /*
4675  * Returns TRUE if the JIT should abort inlining because "callee"
4676  * is influenced by security attributes.
4677  */
4678 static
4679 gboolean check_linkdemand (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee, MonoBasicBlock *bblock, unsigned char *ip)
4680 {
4681         guint32 result;
4682         
4683         if ((cfg->method != caller) && mono_method_has_declsec (callee)) {
4684                 return TRUE;
4685         }
4686         
4687         result = mono_declsec_linkdemand (cfg->domain, caller, callee);
4688         if (result == MONO_JIT_SECURITY_OK)
4689                 return FALSE;
4690
4691         if (result == MONO_JIT_LINKDEMAND_ECMA) {
4692                 /* Generate code to throw a SecurityException before the actual call/link */
4693                 MonoSecurityManager *secman = mono_security_manager_get_methods ();
4694                 MonoInst *args [2];
4695
4696                 NEW_ICONST (cfg, args [0], 4);
4697                 NEW_METHODCONST (cfg, args [1], caller);
4698                 mono_emit_method_call_spilled (cfg, bblock, secman->linkdemandsecurityexception, mono_method_signature (secman->linkdemandsecurityexception), args, ip, NULL);
4699         } else if (cfg->exception_type == MONO_EXCEPTION_NONE) {
4700                  /* don't hide previous results */
4701                 cfg->exception_type = MONO_EXCEPTION_SECURITY_LINKDEMAND;
4702                 cfg->exception_data = result;
4703                 return TRUE;
4704         }
4705         
4706         return FALSE;
4707 }
4708
4709 static MonoMethod*
4710 method_access_exception (void)
4711 {
4712         static MonoMethod *method = NULL;
4713
4714         if (!method) {
4715                 MonoSecurityManager *secman = mono_security_manager_get_methods ();
4716                 method = mono_class_get_method_from_name (secman->securitymanager,
4717                                                           "MethodAccessException", 2);
4718         }
4719         g_assert (method);
4720         return method;
4721 }
4722
4723 static void
4724 emit_throw_method_access_exception (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee,
4725                                     MonoBasicBlock *bblock, unsigned char *ip)
4726 {
4727         MonoMethod *thrower = method_access_exception ();
4728         MonoInst *args [2];
4729
4730         NEW_METHODCONST (cfg, args [0], caller);
4731         NEW_METHODCONST (cfg, args [1], callee);
4732         mono_emit_method_call_spilled (cfg, bblock, thrower,
4733                 mono_method_signature (thrower), args, ip, NULL);
4734 }
4735
4736 static MonoMethod*
4737 verification_exception (void)
4738 {
4739         static MonoMethod *method = NULL;
4740
4741         if (!method) {
4742                 MonoSecurityManager *secman = mono_security_manager_get_methods ();
4743                 method = mono_class_get_method_from_name (secman->securitymanager,
4744                                                           "VerificationException", 0);
4745         }
4746         g_assert (method);
4747         return method;
4748 }
4749
4750 static void
4751 emit_throw_verification_exception (MonoCompile *cfg, MonoBasicBlock *bblock, unsigned char *ip)
4752 {
4753         MonoMethod *thrower = verification_exception ();
4754
4755         mono_emit_method_call_spilled (cfg, bblock, thrower,
4756                 mono_method_signature (thrower),
4757                 NULL, ip, NULL);
4758 }
4759
4760 static void
4761 ensure_method_is_allowed_to_call_method (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee,
4762                                          MonoBasicBlock *bblock, unsigned char *ip)
4763 {
4764         MonoSecurityCoreCLRLevel caller_level = mono_security_core_clr_method_level (caller, TRUE);
4765         MonoSecurityCoreCLRLevel callee_level = mono_security_core_clr_method_level (callee, TRUE);
4766         gboolean is_safe = TRUE;
4767
4768         if (!(caller_level >= callee_level ||
4769                         caller_level == MONO_SECURITY_CORE_CLR_SAFE_CRITICAL ||
4770                         callee_level == MONO_SECURITY_CORE_CLR_SAFE_CRITICAL)) {
4771                 is_safe = FALSE;
4772         }
4773
4774         if (!is_safe)
4775                 emit_throw_method_access_exception (cfg, caller, callee, bblock, ip);
4776 }
4777
4778 static gboolean
4779 method_is_safe (MonoMethod *method)
4780 {
4781         /*
4782         if (strcmp (method->name, "unsafeMethod") == 0)
4783                 return FALSE;
4784         */
4785         return TRUE;
4786 }
4787
4788 /*
4789  * Check that the IL instructions at ip are the array initialization
4790  * sequence and return the pointer to the data and the size.
4791  */
4792 static const char*
4793 initialize_array_data (MonoMethod *method, gboolean aot, unsigned char *ip, MonoInst *newarr, int *out_size)
4794 {
4795         /*
4796          * newarr[System.Int32]
4797          * dup
4798          * ldtoken field valuetype ...
4799          * call void class [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype [mscorlib]System.RuntimeFieldHandle)
4800          */
4801         if (ip [0] == CEE_DUP && ip [1] == CEE_LDTOKEN && ip [5] == 0x4 && ip [6] == CEE_CALL) {
4802                 MonoClass *klass = newarr->inst_newa_class;
4803                 guint32 field_token = read32 (ip + 2);
4804                 guint32 field_index = field_token & 0xffffff;
4805                 guint32 token = read32 (ip + 7);
4806                 guint32 rva;
4807                 const char *data_ptr;
4808                 int size = 0;
4809                 MonoMethod *cmethod;
4810                 MonoClass *dummy_class;
4811                 MonoClassField *field = mono_field_from_token (method->klass->image, field_token, &dummy_class, NULL);
4812                 int dummy_align;
4813
4814                 if (!field)
4815                         return NULL;
4816
4817                 if (newarr->inst_newa_len->opcode != OP_ICONST)
4818                         return NULL;
4819                 cmethod = mini_get_method (NULL, method, token, NULL, NULL);
4820                 if (!cmethod)
4821                         return NULL;
4822                 if (strcmp (cmethod->name, "InitializeArray") || strcmp (cmethod->klass->name, "RuntimeHelpers") || cmethod->klass->image != mono_defaults.corlib)
4823                         return NULL;
4824                 switch (mono_type_get_underlying_type (&klass->byval_arg)->type) {
4825                 case MONO_TYPE_BOOLEAN:
4826                 case MONO_TYPE_I1:
4827                 case MONO_TYPE_U1:
4828                         size = 1; break;
4829                 /* we need to swap on big endian, so punt. Should we handle R4 and R8 as well? */
4830 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
4831                 case MONO_TYPE_CHAR:
4832                 case MONO_TYPE_I2:
4833                 case MONO_TYPE_U2:
4834                         size = 2; break;
4835                 case MONO_TYPE_I4:
4836                 case MONO_TYPE_U4:
4837                 case MONO_TYPE_R4:
4838                         size = 4; break;
4839                 case MONO_TYPE_R8:
4840 #ifdef ARM_FPU_FPA
4841                         return NULL; /* stupid ARM FP swapped format */
4842 #endif
4843                 case MONO_TYPE_I8:
4844                 case MONO_TYPE_U8:
4845                         size = 8; break;
4846 #endif
4847                 default:
4848                         return NULL;
4849                 }
4850                 size *= newarr->inst_newa_len->inst_c0;
4851                 if (size > mono_type_size (field->type, &dummy_align))
4852                     return NULL;
4853                 *out_size = size;
4854                 /*g_print ("optimized in %s: size: %d, numelems: %d\n", method->name, size, newarr->inst_newa_len->inst_c0);*/
4855                 field_index = read32 (ip + 2) & 0xffffff;
4856                 mono_metadata_field_info (method->klass->image, field_index - 1, NULL, &rva, NULL);
4857                 data_ptr = mono_image_rva_map (method->klass->image, rva);
4858                 /*g_print ("field: 0x%08x, rva: %d, rva_ptr: %p\n", read32 (ip + 2), rva, data_ptr);*/
4859                 /* for aot code we do the lookup on load */
4860                 if (aot && data_ptr)
4861                         return GUINT_TO_POINTER (rva);
4862                 return data_ptr;
4863         }
4864         return NULL;
4865 }
4866
4867 static void
4868 set_exception_type_from_invalid_il (MonoCompile *cfg, MonoMethod *method, unsigned char *ip)
4869 {
4870         char *method_fname = mono_method_full_name (method, TRUE);
4871         char *method_code;
4872
4873         if (mono_method_get_header (method)->code_size == 0)
4874                 method_code = g_strdup ("method body is empty.");
4875         else
4876                 method_code = mono_disasm_code_one (NULL, method, ip, NULL);
4877         cfg->exception_type = MONO_EXCEPTION_INVALID_PROGRAM;
4878         cfg->exception_message = g_strdup_printf ("Invalid IL code in %s: %s\n", method_fname, method_code);
4879         g_free (method_fname);
4880         g_free (method_code);
4881 }
4882
4883 static void
4884 set_exception_object (MonoCompile *cfg, MonoException *exception)
4885 {
4886         cfg->exception_type = MONO_EXCEPTION_OBJECT_SUPPLIED;
4887         MONO_GC_REGISTER_ROOT (cfg->exception_ptr);
4888         cfg->exception_ptr = exception;
4889 }
4890
4891 static MonoInst*
4892 get_runtime_generic_context (MonoCompile *cfg, MonoMethod *method, int context_used, MonoInst *this, unsigned char *ip)
4893 {
4894         g_assert (!method->klass->valuetype);
4895
4896         if (context_used & MONO_GENERIC_CONTEXT_USED_METHOD) {
4897                 MonoInst *mrgctx_loc, *mrgctx_var;
4898
4899                 g_assert (!this);
4900                 g_assert (method->is_inflated && mono_method_get_context (method)->method_inst);
4901
4902                 mrgctx_loc = mono_get_vtable_var (cfg);
4903                 NEW_TEMPLOAD (cfg, mrgctx_var, mrgctx_loc->inst_c0);
4904
4905                 return mrgctx_var;
4906         } else if (method->flags & METHOD_ATTRIBUTE_STATIC) {
4907                 MonoInst *vtable_loc, *vtable_var;
4908
4909                 g_assert (!this);
4910
4911                 vtable_loc = mono_get_vtable_var (cfg);
4912                 NEW_TEMPLOAD (cfg, vtable_var, vtable_loc->inst_c0);
4913
4914                 if (method->is_inflated && mono_method_get_context (method)->method_inst) {
4915                         MonoInst *mrgctx_var = vtable_var;
4916
4917                         g_assert (G_STRUCT_OFFSET (MonoMethodRuntimeGenericContext, class_vtable) == 0);
4918
4919                         MONO_INST_NEW (cfg, vtable_var, CEE_LDIND_I);
4920                         vtable_var->cil_code = ip;
4921                         vtable_var->inst_left = mrgctx_var;
4922                         vtable_var->type = STACK_PTR;
4923                 }
4924
4925                 return vtable_var;
4926         } else {
4927                 MonoInst *vtable;
4928
4929                 g_assert (this);
4930
4931                 MONO_INST_NEW (cfg, vtable, CEE_LDIND_I);
4932                 vtable->inst_left = this;
4933                 vtable->type = STACK_PTR;
4934
4935                 return vtable;
4936         }
4937 }
4938
4939 static MonoInst*
4940 get_runtime_generic_context_other_table_ptr (MonoCompile *cfg, MonoBasicBlock *bblock,
4941         MonoInst *rgc_ptr, guint32 slot, const unsigned char *ip)
4942 {
4943         MonoMethodSignature *sig = helper_sig_rgctx_lazy_fetch_trampoline;
4944         guint8 *tramp = mono_create_rgctx_lazy_fetch_trampoline (slot);
4945         int temp;
4946         MonoInst *field;
4947
4948         temp = mono_emit_native_call (cfg, bblock, tramp, sig, &rgc_ptr, ip, FALSE, FALSE);
4949
4950         NEW_TEMPLOAD (cfg, field, temp);
4951
4952         return field;
4953 }
4954
4955 static MonoInst*
4956 get_runtime_generic_context_ptr (MonoCompile *cfg, MonoMethod *method, int context_used, MonoBasicBlock *bblock,
4957         MonoClass *klass, MonoGenericContext *generic_context, MonoInst *rgctx, int rgctx_type, unsigned char *ip)
4958 {
4959         guint32 slot = mono_method_lookup_or_register_other_info (method,
4960                 context_used & MONO_GENERIC_CONTEXT_USED_METHOD, &klass->byval_arg, rgctx_type, generic_context);
4961
4962         return get_runtime_generic_context_other_table_ptr (cfg, bblock, rgctx, slot, ip);
4963 }
4964
4965 static MonoInst*
4966 get_runtime_generic_context_method (MonoCompile *cfg, MonoMethod *method, int context_used, MonoBasicBlock *bblock,
4967         MonoMethod *cmethod, MonoGenericContext *generic_context, MonoInst *rgctx, int rgctx_type, const unsigned char *ip)
4968 {
4969         guint32 slot = mono_method_lookup_or_register_other_info (method,
4970                 context_used & MONO_GENERIC_CONTEXT_USED_METHOD, cmethod, rgctx_type, generic_context);
4971
4972         return get_runtime_generic_context_other_table_ptr (cfg, bblock, rgctx, slot, ip);
4973 }
4974
4975 static MonoInst*
4976 get_runtime_generic_context_field (MonoCompile *cfg, MonoMethod *method, int context_used, MonoBasicBlock *bblock,
4977         MonoClassField *field, MonoGenericContext *generic_context, MonoInst *rgctx, int rgctx_type,
4978         const unsigned char *ip)
4979 {
4980         guint32 slot = mono_method_lookup_or_register_other_info (method,
4981                 context_used & MONO_GENERIC_CONTEXT_USED_METHOD, field, rgctx_type, generic_context);
4982
4983         return get_runtime_generic_context_other_table_ptr (cfg, bblock, rgctx, slot, ip);
4984 }
4985
4986 static MonoInst*
4987 get_runtime_generic_context_method_rgctx (MonoCompile *cfg, MonoMethod *method, int context_used, MonoBasicBlock *bblock,
4988         MonoMethod *rgctx_method, MonoGenericContext *generic_context, MonoInst *rgctx, const unsigned char *ip)
4989 {
4990         guint32 slot = mono_method_lookup_or_register_other_info (method,
4991                 context_used & MONO_GENERIC_CONTEXT_USED_METHOD, rgctx_method,
4992                 MONO_RGCTX_INFO_METHOD_RGCTX, generic_context);
4993
4994         return get_runtime_generic_context_other_table_ptr (cfg, bblock, rgctx, slot, ip);
4995 }
4996
4997 static gboolean
4998 generic_class_is_reference_type (MonoCompile *cfg, MonoClass *klass)
4999 {
5000         MonoType *type;
5001
5002         if (cfg->generic_sharing_context)
5003                 type = mini_get_basic_type_from_generic (cfg->generic_sharing_context, &klass->byval_arg);
5004         else
5005                 type = &klass->byval_arg;
5006         return MONO_TYPE_IS_REFERENCE (type);
5007 }
5008
5009 /**
5010  * Handles unbox of a Nullable<T>, returning a temp variable where the
5011  * result is stored.  If a rgctx is passed, then shared generic code
5012  * is generated.
5013  */
5014 static int
5015 handle_unbox_nullable (MonoCompile* cfg, MonoMethod *caller_method, int context_used, MonoBasicBlock* bblock,
5016         MonoInst* val, const guchar *ip, MonoClass* klass, MonoGenericContext *generic_context, MonoInst *rgctx)
5017 {
5018         MonoMethod* method = mono_class_get_method_from_name (klass, "Unbox", 1);
5019         MonoMethodSignature *signature = mono_method_signature (method);
5020
5021         if (rgctx) {
5022                 MonoInst *addr = get_runtime_generic_context_method (cfg, caller_method, context_used, bblock, method,
5023                         generic_context, rgctx, MONO_RGCTX_INFO_GENERIC_METHOD_CODE, ip);
5024
5025                 return mono_emit_rgctx_calli_spilled (cfg, bblock, signature, &val, addr, NULL, ip);
5026         } else {
5027                 return mono_emit_method_call_spilled (cfg, bblock, method, signature, &val, ip, NULL);
5028         }
5029 }
5030
5031 static MonoInst*
5032 handle_box_nullable_from_inst (MonoCompile *cfg, MonoMethod *caller_method, int context_used, MonoBasicBlock *bblock,
5033         MonoInst *val, const guchar *ip, MonoClass *klass, MonoGenericContext *generic_context, MonoInst *rgctx)
5034 {
5035         MonoMethod* method = mono_class_get_method_from_name (klass, "Box", 1);
5036         MonoInst *dest, *method_addr;
5037         int temp;
5038
5039         g_assert (mono_class_is_nullable (klass));
5040
5041         method_addr = get_runtime_generic_context_method (cfg, caller_method, context_used, bblock, method,
5042                         generic_context, rgctx, MONO_RGCTX_INFO_GENERIC_METHOD_CODE, ip);
5043         temp = mono_emit_rgctx_calli_spilled (cfg, bblock, mono_method_signature (method), &val,
5044                         method_addr, NULL, ip);
5045         NEW_TEMPLOAD (cfg, dest, temp);
5046         return dest;
5047 }
5048
5049 static int
5050 emit_castclass (MonoClass *klass, guint32 token, int context_used, gboolean inst_is_castclass, MonoCompile *cfg,
5051                 MonoMethod *method, MonoInst **arg_array, MonoType **param_types, GList *dont_inline,
5052                 unsigned char *end, MonoMethodHeader *header, MonoGenericContext *generic_context,
5053                 MonoBasicBlock **_bblock, unsigned char **_ip, MonoInst ***_sp, int *_inline_costs, guint *_real_offset)
5054 {
5055         MonoBasicBlock *bblock = *_bblock;
5056         unsigned char *ip = *_ip;
5057         MonoInst **sp = *_sp;
5058         int inline_costs = *_inline_costs;
5059         guint real_offset = *_real_offset;
5060         int return_value = 0;
5061
5062         if (context_used) {
5063                 MonoInst *rgctx, *args [2];
5064                 int temp;
5065
5066                 g_assert (!method->klass->valuetype);
5067
5068                 /* obj */
5069                 args [0] = *sp;
5070
5071                 /* klass */
5072                 GET_RGCTX (rgctx, context_used);
5073                 args [1] = get_runtime_generic_context_ptr (cfg, method, context_used, bblock, klass,
5074                                 generic_context, rgctx, MONO_RGCTX_INFO_KLASS, ip);
5075
5076                 temp = mono_emit_jit_icall (cfg, bblock, mono_object_castclass, args, ip);
5077                 NEW_TEMPLOAD (cfg, *sp, temp);
5078
5079                 sp++;
5080                 ip += 5;
5081                 inline_costs += 2;
5082         } else if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
5083
5084                 MonoMethod *mono_castclass;
5085                 MonoInst *iargs [1];
5086                 MonoBasicBlock *ebblock;
5087                 int costs;
5088                 int temp;
5089
5090                 mono_castclass = mono_marshal_get_castclass (klass);
5091                 iargs [0] = sp [0];
5092
5093                 costs = inline_method (cfg, mono_castclass, mono_method_signature (mono_castclass), bblock,
5094                                 iargs, ip, real_offset, dont_inline, &ebblock, TRUE);
5095
5096                 g_assert (costs > 0);
5097
5098                 ip += 5;
5099                 real_offset += 5;
5100
5101                 GET_BBLOCK (cfg, bblock, ip);
5102                 ebblock->next_bb = bblock;
5103                 link_bblock (cfg, ebblock, bblock);
5104
5105                 temp = iargs [0]->inst_i0->inst_c0;
5106                 NEW_TEMPLOAD (cfg, *sp, temp);
5107
5108                 sp++;
5109                 bblock = ebblock;
5110                 inline_costs += costs;
5111         } else {
5112                 MonoInst *ins;
5113
5114                 /* Needed by the code generated in inssel.brg */
5115                 mono_get_got_var (cfg);
5116
5117                 MONO_INST_NEW (cfg, ins, CEE_CASTCLASS);
5118                 ins->type = STACK_OBJ;
5119                 ins->inst_left = *sp;
5120                 ins->klass = klass;
5121                 ins->inst_newa_class = klass;
5122                 if (inst_is_castclass)
5123                         ins->backend.record_cast_details = debug_options.better_cast_details;
5124                 if (inst_is_castclass)
5125                         *sp++ = emit_tree (cfg, bblock, ins, ip + 5);
5126                 else
5127                         *sp++ = ins;
5128                 ip += 5;
5129         }
5130
5131 do_return:
5132         *_bblock = bblock;
5133         *_ip = ip;
5134         *_sp = sp;
5135         *_inline_costs = inline_costs;
5136         *_real_offset = real_offset;
5137         return return_value;
5138 exception_exit:
5139         return_value = -2;
5140         goto do_return;
5141 unverified:
5142         return_value = -1;
5143         goto do_return;
5144 }
5145
5146 static int
5147 emit_unbox (MonoClass *klass, guint32 token, int context_used,
5148                 MonoCompile *cfg, MonoMethod *method, MonoInst **arg_array, MonoType **param_types, GList *dont_inline,
5149                 unsigned char *end, MonoMethodHeader *header, MonoGenericContext *generic_context,
5150                 MonoBasicBlock **_bblock, unsigned char **_ip, MonoInst ***_sp, int *_inline_costs, guint *_real_offset)
5151 {
5152         MonoBasicBlock *bblock = *_bblock;
5153         unsigned char *ip = *_ip;
5154         MonoInst **sp = *_sp;
5155         int inline_costs = *_inline_costs;
5156         guint real_offset = *_real_offset;
5157         int return_value = 0;
5158
5159         MonoInst *add, *vtoffset, *ins;
5160
5161         /* Needed by the code generated in inssel.brg */
5162         mono_get_got_var (cfg);
5163
5164         if (context_used) {
5165                 MonoInst *rgctx, *element_class;
5166
5167                 /* This assertion is from the unboxcast insn */
5168                 g_assert (klass->rank == 0);
5169
5170                 GET_RGCTX (rgctx, context_used);
5171                 element_class = get_runtime_generic_context_ptr (cfg, method, context_used, bblock,
5172                                 klass->element_class, generic_context, rgctx, MONO_RGCTX_INFO_KLASS, ip);
5173
5174                 MONO_INST_NEW (cfg, ins, OP_UNBOXCAST_REG);
5175                 ins->type = STACK_OBJ;
5176                 ins->inst_left = *sp;
5177                 ins->inst_right = element_class;
5178                 ins->klass = klass;
5179                 ins->cil_code = ip;
5180         } else {
5181                 MONO_INST_NEW (cfg, ins, OP_UNBOXCAST);
5182                 ins->type = STACK_OBJ;
5183                 ins->inst_left = *sp;
5184                 ins->klass = klass;
5185                 ins->inst_newa_class = klass;
5186                 ins->cil_code = ip;
5187         }
5188
5189         MONO_INST_NEW (cfg, add, OP_PADD);
5190         NEW_ICONST (cfg, vtoffset, sizeof (MonoObject));
5191         add->inst_left = ins;
5192         add->inst_right = vtoffset;
5193         add->type = STACK_MP;
5194         add->klass = klass;
5195         *sp = add;
5196
5197 do_return:
5198         *_bblock = bblock;
5199         *_ip = ip;
5200         *_sp = sp;
5201         *_inline_costs = inline_costs;
5202         *_real_offset = real_offset;
5203         return return_value;
5204 exception_exit:
5205         return_value = -2;
5206         goto do_return;
5207 }
5208
5209 gboolean
5210 mini_assembly_can_skip_verification (MonoDomain *domain, MonoMethod *method)
5211 {
5212         MonoAssembly *assembly = method->klass->image->assembly;
5213         if (method->wrapper_type != MONO_WRAPPER_NONE)
5214                 return FALSE;
5215         if (assembly->in_gac || assembly->image == mono_defaults.corlib)
5216                 return FALSE;
5217         if (mono_security_get_mode () != MONO_SECURITY_MODE_NONE)
5218                 return FALSE;
5219         return mono_assembly_has_skip_verification (assembly);
5220 }
5221
5222 /*
5223  * mini_method_verify:
5224  * 
5225  * Verify the method using the new verfier.
5226  * 
5227  * Returns true if the method is invalid. 
5228  */
5229 gboolean
5230 mini_method_verify (MonoCompile *cfg, MonoMethod *method)
5231 {
5232         GSList *tmp, *res;
5233         gboolean is_fulltrust;
5234         MonoLoaderError *error;
5235
5236         if (method->verification_success)
5237                 return FALSE;
5238
5239         is_fulltrust = mono_verifier_is_method_full_trust (method);
5240
5241         if (!mono_verifier_is_enabled_for_method (method))
5242                 return FALSE;
5243
5244         res = mono_method_verify_with_current_settings (method, cfg->skip_visibility);
5245
5246         if ((error = mono_loader_get_last_error ())) {
5247                 cfg->exception_type = error->exception_type;
5248                 if (res)
5249                         mono_free_verify_list (res);
5250                 return TRUE;
5251         }
5252
5253         if (res) { 
5254                 for (tmp = res; tmp; tmp = tmp->next) {
5255                         MonoVerifyInfoExtended *info = (MonoVerifyInfoExtended *)tmp->data;
5256                         if (info->info.status == MONO_VERIFY_ERROR) {
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                         if (info->info.status == MONO_VERIFY_NOT_VERIFIABLE && !is_fulltrust) {
5263                                 cfg->exception_type = info->exception_type;
5264                                 cfg->exception_message = g_strdup (info->info.message);
5265                                 mono_free_verify_list (res);
5266                                 return TRUE;
5267                         }
5268                 }
5269                 mono_free_verify_list (res);
5270         }
5271         method->verification_success = 1;
5272         return FALSE;
5273 }
5274
5275 /*
5276  * mono_method_to_ir: translates IL into basic blocks containing trees
5277  */
5278 static int
5279 mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock, 
5280                    int locals_offset, MonoInst *return_var, GList *dont_inline, MonoInst **inline_args, 
5281                    guint inline_offset, gboolean is_virtual_call)
5282 {
5283         MonoInst *zero_int32, *zero_int64, *zero_ptr, *zero_obj, *zero_r8;
5284         MonoInst *ins, **sp, **stack_start;
5285         MonoBasicBlock *bblock, *tblock = NULL, *init_localsbb = NULL;
5286         MonoMethod *cmethod, *method_definition;
5287         MonoInst **arg_array;
5288         MonoMethodHeader *header;
5289         MonoImage *image;
5290         guint32 token, ins_flag;
5291         MonoClass *klass;
5292         MonoClass *constrained_call = NULL;
5293         unsigned char *ip, *end, *target, *err_pos;
5294         static double r8_0 = 0.0;
5295         MonoMethodSignature *sig;
5296         MonoGenericContext *generic_context = NULL;
5297         MonoGenericContainer *generic_container = NULL;
5298         MonoType **param_types;
5299         GList *bb_recheck = NULL, *tmp;
5300         int i, n, start_new_bblock, ialign;
5301         int num_calls = 0, inline_costs = 0;
5302         int breakpoint_id = 0;
5303         guint32 align;
5304         guint real_offset, num_args;
5305         MonoBoolean security, pinvoke;
5306         MonoSecurityManager* secman = NULL;
5307         MonoDeclSecurityActions actions;
5308         GSList *class_inits = NULL;
5309         gboolean dont_verify, dont_verify_stloc, readonly = FALSE;
5310         int context_used;
5311
5312         /* serialization and xdomain stuff may need access to private fields and methods */
5313         dont_verify = method->klass->image->assembly->corlib_internal? TRUE: FALSE;
5314         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE;
5315         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH;
5316         dont_verify |= method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE; /* bug #77896 */
5317         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP;
5318         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP_INVOKE;
5319
5320         /* turn off visibility checks for smcs */
5321         dont_verify |= mono_security_get_mode () == MONO_SECURITY_MODE_SMCS_HACK;
5322
5323         /* still some type unsafety issues in marshal wrappers... (unknown is PtrToStructure) */
5324         dont_verify_stloc = method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE;
5325         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_UNKNOWN;
5326         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED;
5327
5328         image = method->klass->image;
5329         header = mono_method_get_header (method);
5330         generic_container = mono_method_get_generic_container (method);
5331         sig = mono_method_signature (method);
5332         num_args = sig->hasthis + sig->param_count;
5333         ip = (unsigned char*)header->code;
5334         cfg->cil_start = ip;
5335         end = ip + header->code_size;
5336         mono_jit_stats.cil_code_size += header->code_size;
5337
5338         method_definition = method;
5339         while (method_definition->is_inflated) {
5340                 MonoMethodInflated *imethod = (MonoMethodInflated *) method_definition;
5341                 method_definition = imethod->declaring;
5342         }
5343
5344         /* SkipVerification is not allowed if core-clr is enabled */
5345         if (!dont_verify && mini_assembly_can_skip_verification (cfg->domain, method)) {
5346                 dont_verify = TRUE;
5347                 dont_verify_stloc = TRUE;
5348         }
5349
5350         if (!dont_verify && mini_method_verify (cfg, method_definition))
5351                 goto exception_exit;
5352
5353         if (sig->is_inflated)
5354                 generic_context = mono_method_get_context (method);
5355         else if (generic_container)
5356                 generic_context = &generic_container->context;
5357
5358         if (!cfg->generic_sharing_context)
5359                 g_assert (!sig->has_type_parameters);
5360
5361         if (sig->generic_param_count && method->wrapper_type == MONO_WRAPPER_NONE) {
5362                 g_assert (method->is_inflated);
5363                 g_assert (mono_method_get_context (method)->method_inst);
5364         }
5365         if (method->is_inflated && mono_method_get_context (method)->method_inst)
5366                 g_assert (sig->generic_param_count);
5367
5368         if (cfg->method == method)
5369                 real_offset = 0;
5370         else
5371                 real_offset = inline_offset;
5372
5373         cfg->cil_offset_to_bb = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoBasicBlock*) * header->code_size);
5374         cfg->cil_offset_to_bb_len = header->code_size;
5375
5376         if (cfg->verbose_level > 2)
5377                 g_print ("method to IR %s\n", mono_method_full_name (method, TRUE));
5378
5379         dont_inline = g_list_prepend (dont_inline, method);
5380         if (cfg->method == method) {
5381
5382                 if (cfg->prof_options & MONO_PROFILE_INS_COVERAGE)
5383                         cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, header->code_size);
5384
5385                 /* ENTRY BLOCK */
5386                 cfg->bb_entry = start_bblock = NEW_BBLOCK (cfg);
5387                 start_bblock->cil_code = NULL;
5388                 start_bblock->cil_length = 0;
5389                 start_bblock->block_num = cfg->num_bblocks++;
5390
5391                 /* EXIT BLOCK */
5392                 cfg->bb_exit = end_bblock = NEW_BBLOCK (cfg);
5393                 end_bblock->cil_code = NULL;
5394                 end_bblock->cil_length = 0;
5395                 end_bblock->block_num = cfg->num_bblocks++;
5396                 g_assert (cfg->num_bblocks == 2);
5397
5398                 arg_array = alloca (sizeof (MonoInst *) * num_args);
5399                 for (i = num_args - 1; i >= 0; i--)
5400                         arg_array [i] = cfg->varinfo [i];
5401
5402                 if (header->num_clauses) {
5403                         cfg->spvars = g_hash_table_new (NULL, NULL);
5404                         cfg->exvars = g_hash_table_new (NULL, NULL);
5405                 }
5406                 /* handle exception clauses */
5407                 for (i = 0; i < header->num_clauses; ++i) {
5408                         MonoBasicBlock *try_bb;
5409                         MonoExceptionClause *clause = &header->clauses [i];
5410
5411                         GET_BBLOCK (cfg, try_bb, ip + clause->try_offset);
5412                         try_bb->real_offset = clause->try_offset;
5413                         GET_BBLOCK (cfg, tblock, ip + clause->handler_offset);
5414                         tblock->real_offset = clause->handler_offset;
5415                         tblock->flags |= BB_EXCEPTION_HANDLER;
5416
5417                         link_bblock (cfg, try_bb, tblock);
5418
5419                         if (*(ip + clause->handler_offset) == CEE_POP)
5420                                 tblock->flags |= BB_EXCEPTION_DEAD_OBJ;
5421
5422                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY ||
5423                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER ||
5424                             clause->flags == MONO_EXCEPTION_CLAUSE_FAULT) {
5425                                 MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
5426                                 MONO_ADD_INS (tblock, ins);
5427
5428                                 /* todo: is a fault block unsafe to optimize? */
5429                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
5430                                         tblock->flags |= BB_EXCEPTION_UNSAFE;
5431                         }
5432
5433
5434                         /*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);
5435                           while (p < end) {
5436                           g_print ("%s", mono_disasm_code_one (NULL, method, p, &p));
5437                           }*/
5438                         /* catch and filter blocks get the exception object on the stack */
5439                         if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE ||
5440                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
5441                                 MonoInst *load, *dummy_use;
5442
5443                                 /* mostly like handle_stack_args (), but just sets the input args */
5444                                 /* g_print ("handling clause at IL_%04x\n", clause->handler_offset); */
5445                                 tblock->in_scount = 1;
5446                                 tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
5447                                 tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
5448
5449                                 /* 
5450                                  * Add a dummy use for the exvar so its liveness info will be
5451                                  * correct.
5452                                  */
5453                                 NEW_TEMPLOAD (cfg, load, tblock->in_stack [0]->inst_c0);
5454                                 NEW_DUMMY_USE (cfg, dummy_use, load);
5455                                 MONO_ADD_INS (tblock, dummy_use);
5456                                 
5457                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
5458                                         GET_BBLOCK (cfg, tblock, ip + clause->data.filter_offset);
5459                                         tblock->real_offset = clause->data.filter_offset;
5460                                         tblock->in_scount = 1;
5461                                         tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
5462                                         /* The filter block shares the exvar with the handler block */
5463                                         tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
5464                                         MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
5465                                         MONO_ADD_INS (tblock, ins);
5466                                 }
5467                         }
5468
5469                         if (clause->flags != MONO_EXCEPTION_CLAUSE_FILTER &&
5470                                         clause->data.catch_class &&
5471                                         cfg->generic_sharing_context &&
5472                                         mono_class_check_context_used (clause->data.catch_class)) {
5473                                 if (mono_method_get_context (method)->method_inst)
5474                                         GENERIC_SHARING_FAILURE (CEE_NOP);
5475
5476                                 /*
5477                                  * In shared generic code with catch
5478                                  * clauses containing type variables
5479                                  * the exception handling code has to
5480                                  * be able to get to the rgctx.
5481                                  * Therefore we have to make sure that
5482                                  * the vtable/mrgctx argument (for
5483                                  * static or generic methods) or the
5484                                  * "this" argument (for non-static
5485                                  * methods) are live.
5486                                  */
5487                                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
5488                                                 mini_method_get_context (method)->method_inst) {
5489                                         mono_get_vtable_var (cfg);
5490                                 } else {
5491                                         MonoInst *this, *dummy_use;
5492                                         MonoType *this_type;
5493
5494                                         if (method->klass->valuetype)
5495                                                 this_type = &method->klass->this_arg;
5496                                         else
5497                                                 this_type = &method->klass->byval_arg;
5498
5499                                         if (arg_array [0]->opcode == OP_ICONST) {
5500                                                 this = arg_array [0];
5501                                         } else {
5502                                                 this = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));
5503                                                 this->ssa_op = MONO_SSA_LOAD;
5504                                                 this->inst_i0 = arg_array [0];
5505                                                 this->opcode = mini_type_to_ldind ((cfg), this->inst_i0->inst_vtype);
5506                                                 type_to_eval_stack_type ((cfg), this_type, this);
5507                                                 this->klass = this->inst_i0->klass;
5508                                         }
5509
5510                                         NEW_DUMMY_USE (cfg, dummy_use, this);
5511                                         MONO_ADD_INS (tblock, dummy_use);
5512                                 }
5513                         }
5514                 }
5515         } else {
5516                 arg_array = alloca (sizeof (MonoInst *) * num_args);
5517                 mono_save_args (cfg, start_bblock, sig, inline_args, arg_array);
5518         }
5519
5520         /* FIRST CODE BLOCK */
5521         bblock = NEW_BBLOCK (cfg);
5522         bblock->cil_code = ip;
5523
5524         ADD_BBLOCK (cfg, bblock);
5525
5526         if (cfg->method == method) {
5527                 breakpoint_id = mono_debugger_method_has_breakpoint (method);
5528                 if (breakpoint_id && (mono_debug_format != MONO_DEBUG_FORMAT_DEBUGGER)) {
5529                         MONO_INST_NEW (cfg, ins, OP_BREAK);
5530                         MONO_ADD_INS (bblock, ins);
5531                 }
5532         }
5533
5534         if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS)
5535                 secman = mono_security_manager_get_methods ();
5536
5537         security = (secman && mono_method_has_declsec (method));
5538         /* at this point having security doesn't mean we have any code to generate */
5539         if (security && (cfg->method == method)) {
5540                 /* Only Demand, NonCasDemand and DemandChoice requires code generation.
5541                  * And we do not want to enter the next section (with allocation) if we
5542                  * have nothing to generate */
5543                 security = mono_declsec_get_demands (method, &actions);
5544         }
5545
5546         /* we must Demand SecurityPermission.Unmanaged before P/Invoking */
5547         pinvoke = (secman && (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE));
5548         if (pinvoke) {
5549                 MonoMethod *wrapped = mono_marshal_method_from_wrapper (method);
5550                 if (wrapped && (wrapped->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
5551                         MonoCustomAttrInfo* custom = mono_custom_attrs_from_method (wrapped);
5552
5553                         /* unless the method or it's class has the [SuppressUnmanagedCodeSecurity] attribute */
5554                         if (custom && mono_custom_attrs_has_attr (custom, secman->suppressunmanagedcodesecurity)) {
5555                                 pinvoke = FALSE;
5556                         }
5557                         if (custom)
5558                                 mono_custom_attrs_free (custom);
5559
5560                         if (pinvoke) {
5561                                 custom = mono_custom_attrs_from_class (wrapped->klass);
5562                                 if (custom && mono_custom_attrs_has_attr (custom, secman->suppressunmanagedcodesecurity)) {
5563                                         pinvoke = FALSE;
5564                                 }
5565                                 if (custom)
5566                                         mono_custom_attrs_free (custom);
5567                         }
5568                 } else {
5569                         /* not a P/Invoke after all */
5570                         pinvoke = FALSE;
5571                 }
5572         }
5573         
5574         if ((header->init_locals || (cfg->method == method && (cfg->opt & MONO_OPT_SHARED))) || cfg->compile_aot || security || pinvoke) {
5575                 /* we use a separate basic block for the initialization code */
5576                 cfg->bb_init = init_localsbb = NEW_BBLOCK (cfg);
5577                 init_localsbb->real_offset = real_offset;
5578                 start_bblock->next_bb = init_localsbb;
5579                 init_localsbb->next_bb = bblock;
5580                 link_bblock (cfg, start_bblock, init_localsbb);
5581                 link_bblock (cfg, init_localsbb, bblock);
5582                 init_localsbb->block_num = cfg->num_bblocks++;
5583         } else {
5584                 start_bblock->next_bb = bblock;
5585                 link_bblock (cfg, start_bblock, bblock);
5586         }
5587
5588         /* at this point we know, if security is TRUE, that some code needs to be generated */
5589         if (security && (cfg->method == method)) {
5590                 MonoInst *args [2];
5591
5592                 mono_jit_stats.cas_demand_generation++;
5593
5594                 if (actions.demand.blob) {
5595                         /* Add code for SecurityAction.Demand */
5596                         NEW_DECLSECCONST (cfg, args[0], image, actions.demand);
5597                         NEW_ICONST (cfg, args [1], actions.demand.size);
5598                         /* Calls static void SecurityManager.InternalDemand (byte* permissions, int size); */
5599                         mono_emit_method_call_spilled (cfg, init_localsbb, secman->demand, mono_method_signature (secman->demand), args, ip, NULL);
5600                 }
5601                 if (actions.noncasdemand.blob) {
5602                         /* CLR 1.x uses a .noncasdemand (but 2.x doesn't) */
5603                         /* For Mono we re-route non-CAS Demand to Demand (as the managed code must deal with it anyway) */
5604                         NEW_DECLSECCONST (cfg, args[0], image, actions.noncasdemand);
5605                         NEW_ICONST (cfg, args [1], actions.noncasdemand.size);
5606                         /* Calls static void SecurityManager.InternalDemand (byte* permissions, int size); */
5607                         mono_emit_method_call_spilled (cfg, init_localsbb, secman->demand, mono_method_signature (secman->demand), args, ip, NULL);
5608                 }
5609                 if (actions.demandchoice.blob) {
5610                         /* New in 2.0, Demand must succeed for one of the permissions (i.e. not all) */
5611                         NEW_DECLSECCONST (cfg, args[0], image, actions.demandchoice);
5612                         NEW_ICONST (cfg, args [1], actions.demandchoice.size);
5613                         /* Calls static void SecurityManager.InternalDemandChoice (byte* permissions, int size); */
5614                         mono_emit_method_call_spilled (cfg, init_localsbb, secman->demandchoice, mono_method_signature (secman->demandchoice), args, ip, NULL);
5615                 }
5616         }
5617
5618         /* we must Demand SecurityPermission.Unmanaged before p/invoking */
5619         if (pinvoke) {
5620                 mono_emit_method_call_spilled (cfg, init_localsbb, secman->demandunmanaged, mono_method_signature (secman->demandunmanaged), NULL, ip, NULL);
5621         }
5622
5623         if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR) {
5624                 if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
5625                         MonoMethod *wrapped = mono_marshal_method_from_wrapper (method);
5626                         if (wrapped && (wrapped->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
5627                                 if (!(method->klass && method->klass->image &&
5628                                                 mono_security_core_clr_is_platform_image (method->klass->image))) {
5629                                         emit_throw_method_access_exception (cfg, method, wrapped, bblock, ip);
5630                                 }
5631                         }
5632                 }
5633                 if (!method_is_safe (method))
5634                         emit_throw_verification_exception (cfg, bblock, ip);
5635         }
5636
5637         if (header->code_size == 0)
5638                 UNVERIFIED;
5639
5640         if (get_basic_blocks (cfg, header, real_offset, ip, end, &err_pos)) {
5641                 ip = err_pos;
5642                 UNVERIFIED;
5643         }
5644
5645         if (cfg->method == method)
5646                 mono_debug_init_method (cfg, bblock, breakpoint_id);
5647
5648         param_types = mono_mempool_alloc (cfg->mempool, sizeof (MonoType*) * num_args);
5649         if (sig->hasthis)
5650                 param_types [0] = method->klass->valuetype?&method->klass->this_arg:&method->klass->byval_arg;
5651         for (n = 0; n < sig->param_count; ++n)
5652                 param_types [n + sig->hasthis] = sig->params [n];
5653         for (n = 0; n < header->num_locals; ++n) {
5654                 if (header->locals [n]->type == MONO_TYPE_VOID && !header->locals [n]->byref)
5655                         UNVERIFIED;
5656         }
5657         class_inits = NULL;
5658
5659         /* do this somewhere outside - not here */
5660         NEW_ICONST (cfg, zero_int32, 0);
5661         NEW_ICONST (cfg, zero_int64, 0);
5662         zero_int64->type = STACK_I8;
5663         NEW_PCONST (cfg, zero_ptr, 0);
5664         NEW_PCONST (cfg, zero_obj, 0);
5665         zero_obj->type = STACK_OBJ;
5666
5667         MONO_INST_NEW (cfg, zero_r8, OP_R8CONST);
5668         zero_r8->type = STACK_R8;
5669         zero_r8->inst_p0 = &r8_0;
5670
5671         /* add a check for this != NULL to inlined methods */
5672         if (is_virtual_call) {
5673                 MONO_INST_NEW (cfg, ins, OP_CHECK_THIS);
5674                 NEW_ARGLOAD (cfg, ins->inst_left, 0);
5675                 ins->cil_code = ip;
5676                 MONO_ADD_INS (bblock, ins);
5677         }
5678
5679         /* we use a spare stack slot in SWITCH and NEWOBJ and others */
5680         stack_start = sp = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (header->max_stack + 1));
5681
5682         ins_flag = 0;
5683         start_new_bblock = 0;
5684         while (ip < end) {
5685
5686                 if (cfg->method == method)
5687                         real_offset = ip - header->code;
5688                 else
5689                         real_offset = inline_offset;
5690                 cfg->ip = ip;
5691
5692                 context_used = 0;
5693
5694                 if (start_new_bblock) {
5695                         bblock->cil_length = ip - bblock->cil_code;
5696                         if (start_new_bblock == 2) {
5697                                 g_assert (ip == tblock->cil_code);
5698                         } else {
5699                                 GET_BBLOCK (cfg, tblock, ip);
5700                         }
5701                         bblock->next_bb = tblock;
5702                         bblock = tblock;
5703                         start_new_bblock = 0;
5704                         for (i = 0; i < bblock->in_scount; ++i) {
5705                                 if (cfg->verbose_level > 3)
5706                                         g_print ("loading %d from temp %d\n", i, (int)bblock->in_stack [i]->inst_c0);                                           
5707                                 NEW_TEMPLOAD (cfg, ins, bblock->in_stack [i]->inst_c0);
5708                                 *sp++ = ins;
5709                         }
5710                         g_slist_free (class_inits);
5711                         class_inits = NULL;
5712                 } else {
5713                         if ((tblock = cfg->cil_offset_to_bb [ip - cfg->cil_start]) && (tblock != bblock)) {
5714                                 link_bblock (cfg, bblock, tblock);
5715                                 if (sp != stack_start) {
5716                                         handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
5717                                         sp = stack_start;
5718                                         CHECK_UNVERIFIABLE (cfg);
5719                                 }
5720                                 bblock->next_bb = tblock;
5721                                 bblock = tblock;
5722                                 for (i = 0; i < bblock->in_scount; ++i) {
5723                                         if (cfg->verbose_level > 3)
5724                                                 g_print ("loading %d from temp %d\n", i, (int)bblock->in_stack [i]->inst_c0);                                           
5725                                         NEW_TEMPLOAD (cfg, ins, bblock->in_stack [i]->inst_c0);
5726                                         *sp++ = ins;
5727                                 }
5728                                 g_slist_free (class_inits);
5729                                 class_inits = NULL;
5730                         }
5731                 }
5732
5733                 bblock->real_offset = real_offset;
5734
5735                 if ((cfg->method == method) && cfg->coverage_info) {
5736                         MonoInst *store, *one;
5737                         guint32 cil_offset = ip - header->code;
5738                         cfg->coverage_info->data [cil_offset].cil_code = ip;
5739
5740                         /* TODO: Use an increment here */
5741                         NEW_ICONST (cfg, one, 1);
5742                         one->cil_code = ip;
5743
5744                         NEW_PCONST (cfg, ins, &(cfg->coverage_info->data [cil_offset].count));
5745                         ins->cil_code = ip;
5746
5747                         MONO_INST_NEW (cfg, store, CEE_STIND_I);
5748                         store->inst_left = ins;
5749                         store->inst_right = one;
5750
5751                         MONO_ADD_INS (bblock, store);
5752                 }
5753
5754                 if (cfg->verbose_level > 3)
5755                         g_print ("converting (in B%d: stack: %d) %s", bblock->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
5756
5757                 switch (*ip) {
5758                 case CEE_NOP:
5759                         MONO_INST_NEW (cfg, ins, OP_NOP);
5760                         ip++;
5761                         MONO_ADD_INS (bblock, ins);
5762                         break;
5763                 case CEE_BREAK:
5764                         MONO_INST_NEW (cfg, ins, OP_BREAK);
5765                         ip++;
5766                         MONO_ADD_INS (bblock, ins);
5767                         break;
5768                 case CEE_LDARG_0:
5769                 case CEE_LDARG_1:
5770                 case CEE_LDARG_2:
5771                 case CEE_LDARG_3:
5772                         CHECK_STACK_OVF (1);
5773                         n = (*ip)-CEE_LDARG_0;
5774                         CHECK_ARG (n);
5775                         NEW_ARGLOAD (cfg, ins, n);
5776                         LDARG_SOFT_FLOAT (cfg, ins, n, ip);
5777                         ip++;
5778                         *sp++ = ins;
5779                         break;
5780                 case CEE_LDLOC_0:
5781                 case CEE_LDLOC_1:
5782                 case CEE_LDLOC_2:
5783                 case CEE_LDLOC_3:
5784                         CHECK_STACK_OVF (1);
5785                         n = (*ip)-CEE_LDLOC_0;
5786                         CHECK_LOCAL (n);
5787                         NEW_LOCLOAD (cfg, ins, n);
5788                         LDLOC_SOFT_FLOAT (cfg, ins, n, ip);
5789                         ip++;
5790                         *sp++ = ins;
5791                         break;
5792                 case CEE_STLOC_0:
5793                 case CEE_STLOC_1:
5794                 case CEE_STLOC_2:
5795                 case CEE_STLOC_3:
5796                         CHECK_STACK (1);
5797                         n = (*ip)-CEE_STLOC_0;
5798                         CHECK_LOCAL (n);
5799                         --sp;
5800                         handle_loaded_temps (cfg, bblock, stack_start, sp);
5801                         NEW_LOCSTORE (cfg, ins, n, *sp);
5802                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
5803                                 UNVERIFIED;
5804                         STLOC_SOFT_FLOAT (cfg, ins, n, ip);
5805                         if (ins->opcode == CEE_STOBJ) {
5806                                 NEW_LOCLOADA (cfg, ins, n);
5807                                 handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE, FALSE);
5808                         } else
5809                                 MONO_ADD_INS (bblock, ins);
5810                         ++ip;
5811                         inline_costs += 1;
5812                         break;
5813                 case CEE_LDARG_S:
5814                         CHECK_OPSIZE (2);
5815                         CHECK_STACK_OVF (1);
5816                         CHECK_ARG (ip [1]);
5817                         NEW_ARGLOAD (cfg, ins, ip [1]);
5818                         LDARG_SOFT_FLOAT (cfg, ins, ip [1], ip);
5819                         *sp++ = ins;
5820                         ip += 2;
5821                         break;
5822                 case CEE_LDARGA_S:
5823                         CHECK_OPSIZE (2);
5824                         CHECK_STACK_OVF (1);
5825                         CHECK_ARG (ip [1]);
5826                         NEW_ARGLOADA (cfg, ins, ip [1]);
5827                         *sp++ = ins;
5828                         ip += 2;
5829                         break;
5830                 case CEE_STARG_S:
5831                         CHECK_OPSIZE (2);
5832                         CHECK_STACK (1);
5833                         --sp;
5834                         CHECK_ARG (ip [1]);
5835                         NEW_ARGSTORE (cfg, ins, ip [1], *sp);
5836                         handle_loaded_temps (cfg, bblock, stack_start, sp);
5837                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [ip [1]], *sp))
5838                                 UNVERIFIED;
5839                         STARG_SOFT_FLOAT (cfg, ins, ip [1], ip);
5840                         if (ins->opcode == CEE_STOBJ) {
5841                                 NEW_ARGLOADA (cfg, ins, ip [1]);
5842                                 handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE, FALSE);
5843                         } else
5844                                 MONO_ADD_INS (bblock, ins);
5845                         ip += 2;
5846                         break;
5847                 case CEE_LDLOC_S:
5848                         CHECK_OPSIZE (2);
5849                         CHECK_STACK_OVF (1);
5850                         CHECK_LOCAL (ip [1]);
5851                         NEW_LOCLOAD (cfg, ins, ip [1]);
5852                         LDLOC_SOFT_FLOAT (cfg, ins, ip [1], ip);
5853                         *sp++ = ins;
5854                         ip += 2;
5855                         break;
5856                 case CEE_LDLOCA_S:
5857                         CHECK_OPSIZE (2);
5858                         CHECK_STACK_OVF (1);
5859                         CHECK_LOCAL (ip [1]);
5860                         NEW_LOCLOADA (cfg, ins, ip [1]);
5861                         *sp++ = ins;
5862                         ip += 2;
5863                         break;
5864                 case CEE_STLOC_S:
5865                         CHECK_OPSIZE (2);
5866                         CHECK_STACK (1);
5867                         --sp;
5868                         handle_loaded_temps (cfg, bblock, stack_start, sp);
5869                         CHECK_LOCAL (ip [1]);
5870                         NEW_LOCSTORE (cfg, ins, ip [1], *sp);
5871                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [ip [1]], *sp))
5872                                 UNVERIFIED;
5873                         STLOC_SOFT_FLOAT (cfg, ins, ip [1], ip);
5874                         if (ins->opcode == CEE_STOBJ) {
5875                                 NEW_LOCLOADA (cfg, ins, ip [1]);
5876                                 handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE, FALSE);
5877                         } else
5878                                 MONO_ADD_INS (bblock, ins);
5879                         ip += 2;
5880                         inline_costs += 1;
5881                         break;
5882                 case CEE_LDNULL:
5883                         CHECK_STACK_OVF (1);
5884                         NEW_PCONST (cfg, ins, NULL);
5885                         ins->type = STACK_OBJ;
5886                         ++ip;
5887                         *sp++ = ins;
5888                         break;
5889                 case CEE_LDC_I4_M1:
5890                         CHECK_STACK_OVF (1);
5891                         NEW_ICONST (cfg, ins, -1);
5892                         ++ip;
5893                         *sp++ = ins;
5894                         break;
5895                 case CEE_LDC_I4_0:
5896                 case CEE_LDC_I4_1:
5897                 case CEE_LDC_I4_2:
5898                 case CEE_LDC_I4_3:
5899                 case CEE_LDC_I4_4:
5900                 case CEE_LDC_I4_5:
5901                 case CEE_LDC_I4_6:
5902                 case CEE_LDC_I4_7:
5903                 case CEE_LDC_I4_8:
5904                         CHECK_STACK_OVF (1);
5905                         NEW_ICONST (cfg, ins, (*ip) - CEE_LDC_I4_0);
5906                         ++ip;
5907                         *sp++ = ins;
5908                         break;
5909                 case CEE_LDC_I4_S:
5910                         CHECK_OPSIZE (2);
5911                         CHECK_STACK_OVF (1);
5912                         ++ip;
5913                         NEW_ICONST (cfg, ins, *((signed char*)ip));
5914                         ++ip;
5915                         *sp++ = ins;
5916                         break;
5917                 case CEE_LDC_I4:
5918                         CHECK_OPSIZE (5);
5919                         CHECK_STACK_OVF (1);
5920                         NEW_ICONST (cfg, ins, (gint32)read32 (ip + 1));
5921                         ip += 5;
5922                         *sp++ = ins;
5923                         break;
5924                 case CEE_LDC_I8:
5925                         CHECK_OPSIZE (9);
5926                         CHECK_STACK_OVF (1);
5927                         MONO_INST_NEW (cfg, ins, OP_I8CONST);
5928                         ins->type = STACK_I8;
5929                         ++ip;
5930                         ins->inst_l = (gint64)read64 (ip);
5931                         ip += 8;
5932                         *sp++ = ins;
5933                         break;
5934                 case CEE_LDC_R4: {
5935                         float *f;
5936                         /* we should really allocate this only late in the compilation process */
5937                         mono_domain_lock (cfg->domain);
5938                         f = mono_mempool_alloc (cfg->domain->mp, sizeof (float));
5939                         mono_domain_unlock (cfg->domain);
5940                         CHECK_OPSIZE (5);
5941                         CHECK_STACK_OVF (1);
5942                         MONO_INST_NEW (cfg, ins, OP_R4CONST);
5943                         ins->type = STACK_R8;
5944                         ++ip;
5945                         readr4 (ip, f);
5946                         ins->inst_p0 = f;
5947
5948                         ip += 4;
5949                         *sp++ = ins;                    
5950                         break;
5951                 }
5952                 case CEE_LDC_R8: {
5953                         double *d;
5954                         mono_domain_lock (cfg->domain);
5955                         d = mono_mempool_alloc (cfg->domain->mp, sizeof (double));
5956                         mono_domain_unlock (cfg->domain);
5957                         CHECK_OPSIZE (9);
5958                         CHECK_STACK_OVF (1);
5959                         MONO_INST_NEW (cfg, ins, OP_R8CONST);
5960                         ins->type = STACK_R8;
5961                         ++ip;
5962                         readr8 (ip, d);
5963                         ins->inst_p0 = d;
5964
5965                         ip += 8;
5966                         *sp++ = ins;                    
5967                         break;
5968                 }
5969                 case CEE_DUP: {
5970                         MonoInst *temp, *store;
5971                         CHECK_STACK (1);
5972                         CHECK_STACK_OVF (1);
5973                         sp--;
5974                         ins = *sp;
5975                 
5976                         /* 
5977                          * small optimization: if the loaded value was from a local already,
5978                          * just load it twice.
5979                          */
5980                         if (ins->ssa_op == MONO_SSA_LOAD && 
5981                             (ins->inst_i0->opcode == OP_LOCAL || ins->inst_i0->opcode == OP_ARG)) {
5982                                 sp++;
5983                                 MONO_INST_NEW (cfg, temp, 0);
5984                                 *temp = *ins;
5985                                 *sp++ = temp;
5986                         } else {
5987                                 temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
5988                                 temp->flags |= MONO_INST_IS_TEMP;
5989                                 NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
5990                                 /* FIXME: handle CEE_STIND_R4 */
5991                                 if (store->opcode == CEE_STOBJ) {
5992                                         NEW_TEMPLOADA (cfg, store, temp->inst_c0);
5993                                         handle_stobj (cfg, bblock, store, sp [0], sp [0]->cil_code, store->klass, TRUE, FALSE, FALSE);
5994                                 } else {
5995                                         MONO_ADD_INS (bblock, store);
5996                                 }
5997                                 NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
5998                                 *sp++ = ins;
5999                                 NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
6000                                 *sp++ = ins;
6001                         }
6002                         ++ip;
6003                         inline_costs += 2;
6004                         break;
6005                 }
6006                 case CEE_POP:
6007                         CHECK_STACK (1);
6008                         MONO_INST_NEW (cfg, ins, CEE_POP);
6009                         MONO_ADD_INS (bblock, ins);
6010                         ip++;
6011                         --sp;
6012                         ins->inst_i0 = *sp;
6013                         break;
6014                 case CEE_JMP:
6015                         CHECK_OPSIZE (5);
6016                         if (stack_start != sp)
6017                                 UNVERIFIED;
6018                         MONO_INST_NEW (cfg, ins, OP_JMP);
6019                         token = read32 (ip + 1);
6020                         /* FIXME: check the signature matches */
6021                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
6022
6023                         if (!cmethod)
6024                                 goto load_error;
6025
6026                         if (cfg->generic_sharing_context && mono_method_check_context_used (cmethod))
6027                                 GENERIC_SHARING_FAILURE (CEE_JMP);
6028
6029                         if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS) {
6030                                 if (check_linkdemand (cfg, method, cmethod, bblock, ip))
6031                                         INLINE_FAILURE;
6032                                 CHECK_CFG_EXCEPTION;
6033                         }
6034
6035                         ins->inst_p0 = cmethod;
6036                         MONO_ADD_INS (bblock, ins);
6037                         ip += 5;
6038                         start_new_bblock = 1;
6039                         break;
6040                 case CEE_CALLI:
6041                 case CEE_CALL:
6042                 case CEE_CALLVIRT: {
6043                         MonoInst *addr = NULL;
6044                         MonoMethodSignature *fsig = NULL;
6045                         int temp, array_rank = 0;
6046                         int virtual = *ip == CEE_CALLVIRT;
6047                         gboolean no_spill;
6048                         gboolean pass_imt_from_rgctx = FALSE;
6049                         MonoInst *imt_arg = NULL;
6050                         gboolean pass_vtable = FALSE;
6051                         gboolean pass_mrgctx = FALSE;
6052                         MonoInst *vtable_arg = NULL;
6053                         gboolean check_this = FALSE;
6054
6055                         CHECK_OPSIZE (5);
6056                         token = read32 (ip + 1);
6057
6058                         if (*ip == CEE_CALLI) {
6059                                 cmethod = NULL;
6060                                 CHECK_STACK (1);
6061                                 --sp;
6062                                 addr = *sp;
6063                                 if (method->wrapper_type != MONO_WRAPPER_NONE)
6064                                         fsig = (MonoMethodSignature *)mono_method_get_wrapper_data (method, token);
6065                                 else
6066                                         fsig = mono_metadata_parse_signature (image, token);
6067
6068                                 n = fsig->param_count + fsig->hasthis;
6069                         } else {
6070                                 MonoMethod *cil_method;
6071                                 
6072                                 if (method->wrapper_type != MONO_WRAPPER_NONE) {
6073                                         cmethod =  (MonoMethod *)mono_method_get_wrapper_data (method, token);
6074                                         cil_method = cmethod;
6075                                 } else if (constrained_call) {
6076                                         cmethod = mono_get_method_constrained (image, token, constrained_call, generic_context, &cil_method);
6077                                         cil_method = cmethod;
6078                                 } else {
6079                                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
6080                                         cil_method = cmethod;
6081                                 }
6082
6083                                 if (!cmethod)
6084                                         goto load_error;
6085                                 if (!dont_verify && !cfg->skip_visibility) {
6086                                         MonoMethod *target_method = cil_method;
6087                                         if (method->is_inflated) {
6088                                                 target_method = mini_get_method_allow_open (method, token, NULL, &(mono_method_get_generic_container (method_definition)->context));
6089                                         }
6090                                         if (!mono_method_can_access_method (method_definition, target_method) &&
6091                                                 !mono_method_can_access_method (method, cil_method))
6092                                                 METHOD_ACCESS_FAILURE;
6093                                 }
6094
6095                                 if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR)
6096                                         ensure_method_is_allowed_to_call_method (cfg, method, cil_method, bblock, ip);
6097
6098                                 if (!virtual && (cmethod->flags & METHOD_ATTRIBUTE_ABSTRACT))
6099                                         /* MS.NET seems to silently convert this to a callvirt */
6100                                         virtual = 1;
6101
6102                                 if (!cmethod->klass->inited){
6103                                         if (!mono_class_init (cmethod->klass))
6104                                                 goto load_error;
6105                                 }
6106
6107                                 if (mono_method_signature (cmethod)->pinvoke) {
6108                                         MonoMethod *wrapper = mono_marshal_get_native_wrapper (cmethod, check_for_pending_exc, FALSE);
6109                                         fsig = mono_method_signature (wrapper);
6110                                 } else if (constrained_call) {
6111                                         fsig = mono_method_signature (cmethod);
6112                                 } else {
6113                                         fsig = mono_method_get_signature_full (cmethod, image, token, generic_context);
6114                                 }
6115
6116                                 mono_save_token_info (cfg, image, token, cmethod);
6117
6118                                 n = fsig->param_count + fsig->hasthis;
6119
6120                                 if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS) {
6121                                         if (check_linkdemand (cfg, method, cmethod, bblock, ip))
6122                                                 INLINE_FAILURE;
6123                                         CHECK_CFG_EXCEPTION;
6124                                 }
6125
6126                                 if (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL &&
6127                                     mini_class_is_system_array (cmethod->klass)) {
6128                                         array_rank = cmethod->klass->rank;
6129                                 }
6130
6131                                 if (cmethod->string_ctor)
6132                                         g_assert_not_reached ();
6133
6134                         }
6135
6136                         if (!cfg->generic_sharing_context && cmethod && cmethod->klass->generic_container)
6137                                 UNVERIFIED;
6138
6139                         if (!cfg->generic_sharing_context && cmethod)
6140                                 g_assert (!mono_method_check_context_used (cmethod));
6141
6142                         CHECK_STACK (n);
6143
6144                         //g_assert (!virtual || fsig->hasthis);
6145
6146                         sp -= n;
6147
6148                         if (constrained_call) {
6149                                 /*
6150                                  * We have the `constrained.' prefix opcode.
6151                                  */
6152                                 if (constrained_call->valuetype && !cmethod->klass->valuetype) {
6153                                         MonoInst *load;
6154                                         /*
6155                                          * The type parameter is instantiated as a valuetype,
6156                                          * but that type doesn't override the method we're
6157                                          * calling, so we need to box `this'.
6158                                          * sp [0] is a pointer to the data: we need the value
6159                                          * in handle_box (), so load it here.
6160                                          */
6161                                         MONO_INST_NEW (cfg, load, mini_type_to_ldind (cfg, &constrained_call->byval_arg));
6162                                         type_to_eval_stack_type (cfg, &constrained_call->byval_arg, load);
6163                                         load->inst_left = sp [0];
6164                                         sp [0] = handle_box (cfg, bblock, load, ip, constrained_call);
6165                                 } else if (!constrained_call->valuetype) {
6166                                         MonoInst *ins;
6167
6168                                         /*
6169                                          * The type parameter is instantiated as a reference
6170                                          * type.  We have a managed pointer on the stack, so
6171                                          * we need to dereference it here.
6172                                          */
6173
6174                                         MONO_INST_NEW (cfg, ins, CEE_LDIND_REF);
6175                                         ins->inst_i0 = sp [0];
6176                                         ins->type = STACK_OBJ;
6177                                         ins->klass = mono_class_from_mono_type (&constrained_call->byval_arg);
6178                                         sp [0] = ins;
6179                                 } else if (cmethod->klass->valuetype)
6180                                         virtual = 0;
6181                                 constrained_call = NULL;
6182                         }
6183
6184                         if (*ip != CEE_CALLI && check_call_signature (cfg, fsig, sp))
6185                                 UNVERIFIED;
6186
6187                         if (cmethod && (cmethod->flags & METHOD_ATTRIBUTE_STATIC) &&
6188                                         (cmethod->klass->generic_class || cmethod->klass->generic_container)) {
6189                                 gboolean sharing_enabled = mono_class_generic_sharing_enabled (cmethod->klass);
6190                                 MonoGenericContext *context = mini_class_get_context (cmethod->klass);
6191                                 gboolean context_sharable = mono_generic_context_is_sharable (context, TRUE);
6192
6193                                 /*
6194                                  * Pass vtable iff target method might
6195                                  * be shared, which means that sharing
6196                                  * is enabled for its class and its
6197                                  * context is sharable (and it's not a
6198                                  * generic method).
6199                                  */
6200                                 if (sharing_enabled && context_sharable &&
6201                                         !(mini_method_get_context (cmethod) && mini_method_get_context (cmethod)->method_inst))
6202                                         pass_vtable = TRUE;
6203                         }
6204
6205                         if (cmethod && mini_method_get_context (cmethod) &&
6206                                         mini_method_get_context (cmethod)->method_inst) {
6207                                 gboolean sharing_enabled = mono_class_generic_sharing_enabled (cmethod->klass);
6208                                 MonoGenericContext *context = mini_method_get_context (cmethod);
6209                                 gboolean context_sharable = mono_generic_context_is_sharable (context, TRUE);
6210
6211                                 g_assert (!pass_vtable);
6212
6213                                 if (sharing_enabled && context_sharable)
6214                                         pass_mrgctx = TRUE;
6215                         }
6216
6217                         if (cfg->generic_sharing_context && cmethod) {
6218                                 MonoGenericContext *cmethod_context = mono_method_get_context (cmethod);
6219
6220                                 context_used = mono_method_check_context_used (cmethod);
6221
6222                                 if (context_used && (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
6223                                         /* Generic method interface
6224                                            calls are resolved via a
6225                                            helper function and don't
6226                                            need an imt. */
6227                                         if (!cmethod_context || !cmethod_context->method_inst)
6228                                                 pass_imt_from_rgctx = TRUE;
6229                                 }
6230
6231                                 /*
6232                                  * If a shared method calls another
6233                                  * shared method then the caller must
6234                                  * have a generic sharing context
6235                                  * because the magic trampoline
6236                                  * requires it.  FIXME: We shouldn't
6237                                  * have to force the vtable/mrgctx
6238                                  * variable here.  Instead there
6239                                  * should be a flag in the cfg to
6240                                  * request a generic sharing context.
6241                                  */
6242                                 if (context_used && method->flags & METHOD_ATTRIBUTE_STATIC)
6243                                         mono_get_vtable_var (cfg);
6244                         }
6245
6246                         if (pass_vtable) {
6247                                 if (context_used) {
6248                                         MonoInst *rgctx;
6249
6250                                         GET_RGCTX (rgctx, context_used);
6251                                         vtable_arg = get_runtime_generic_context_ptr (cfg, method, context_used,
6252                                                 bblock, cmethod->klass, generic_context, rgctx, MONO_RGCTX_INFO_VTABLE, ip);
6253                                 } else {
6254                                         MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
6255                                         
6256                                         CHECK_TYPELOAD (cmethod->klass);
6257                                         NEW_VTABLECONST (cfg, vtable_arg, vtable);
6258                                 }
6259                         }
6260
6261                         if (pass_mrgctx) {
6262                                 g_assert (!vtable_arg);
6263
6264                                 if (context_used) {
6265                                         MonoInst *rgctx;
6266
6267                                         GET_RGCTX (rgctx, context_used);
6268                                         vtable_arg = get_runtime_generic_context_method_rgctx (cfg, method,
6269                                                 context_used, bblock, cmethod, generic_context, rgctx, ip);
6270                                 } else {
6271                                         MonoMethodRuntimeGenericContext *mrgctx;
6272
6273                                         mrgctx = mono_method_lookup_rgctx (mono_class_vtable (cfg->domain, cmethod->klass),
6274                                                 mini_method_get_context (cmethod)->method_inst);
6275
6276                                         cfg->disable_aot = TRUE;
6277                                         NEW_PCONST (cfg, vtable_arg, mrgctx);
6278                                 }
6279
6280                                 if (!(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
6281                                                 (cmethod->flags & METHOD_ATTRIBUTE_FINAL)) {
6282                                         if (virtual)
6283                                                 check_this = TRUE;
6284                                         virtual = 0;
6285                                 }
6286                         }
6287
6288                         if (pass_imt_from_rgctx) {
6289                                 MonoInst *rgctx;
6290
6291                                 g_assert (!pass_vtable);
6292                                 g_assert (cmethod);
6293
6294                                 GET_RGCTX (rgctx, context_used);
6295                                 imt_arg = get_runtime_generic_context_method (cfg, method, context_used, bblock, cmethod,
6296                                                 generic_context, rgctx, MONO_RGCTX_INFO_METHOD, ip);
6297                         }
6298
6299                         if (check_this) {
6300                                 MonoInst *check;
6301
6302                                 MONO_INST_NEW (cfg, check, OP_CHECK_THIS_PASSTHROUGH);
6303                                 check->cil_code = ip;
6304                                 check->inst_left = sp [0];
6305                                 check->type = sp [0]->type;
6306                                 sp [0] = check;
6307                         }
6308
6309                         if (cmethod && virtual && 
6310                             (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) && 
6311                             !((cmethod->flags & METHOD_ATTRIBUTE_FINAL) && 
6312                               cmethod->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK) &&
6313                             mono_method_signature (cmethod)->generic_param_count) {
6314                                 MonoInst *this_temp, *this_arg_temp, *store;
6315                                 MonoInst *iargs [4];
6316
6317                                 g_assert (mono_method_signature (cmethod)->is_inflated);
6318                                 /* Prevent inlining of methods that contain indirect calls */
6319                                 INLINE_FAILURE;
6320
6321                                 this_temp = mono_compile_create_var (cfg, type_from_stack_type (sp [0]), OP_LOCAL);
6322                                 NEW_TEMPSTORE (cfg, store, this_temp->inst_c0, sp [0]);
6323                                 MONO_ADD_INS (bblock, store);
6324
6325                                 /* FIXME: This should be a managed pointer */
6326                                 this_arg_temp = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
6327
6328                                 /* Because of the PCONST below */
6329                                 cfg->disable_aot = TRUE;
6330                                 NEW_TEMPLOAD (cfg, iargs [0], this_temp->inst_c0);
6331                                 if (context_used) {
6332                                         MonoInst *rgctx;
6333
6334                                         GET_RGCTX (rgctx, context_used);
6335                                         iargs [1] = get_runtime_generic_context_method (cfg, method, context_used,
6336                                                         bblock, cmethod,
6337                                                         generic_context, rgctx, MONO_RGCTX_INFO_METHOD, ip);
6338                                         NEW_TEMPLOADA (cfg, iargs [2], this_arg_temp->inst_c0);
6339                                         temp = mono_emit_jit_icall (cfg, bblock,
6340                                                 mono_helper_compile_generic_method, iargs, ip);
6341                                 } else {
6342                                         NEW_METHODCONST (cfg, iargs [1], cmethod);
6343                                         NEW_TEMPLOADA (cfg, iargs [2], this_arg_temp->inst_c0);
6344                                         temp = mono_emit_jit_icall (cfg, bblock, mono_helper_compile_generic_method,
6345                                                 iargs, ip);
6346                                 }
6347
6348                                 NEW_TEMPLOAD (cfg, addr, temp);
6349                                 NEW_TEMPLOAD (cfg, sp [0], this_arg_temp->inst_c0);
6350
6351                                 if ((temp = mono_emit_calli_spilled (cfg, bblock, fsig, sp, addr, ip)) != -1) {
6352                                         NEW_TEMPLOAD (cfg, *sp, temp);
6353                                         sp++;
6354                                 }
6355
6356                                 ip += 5;
6357                                 ins_flag = 0;
6358                                 break;
6359                         }
6360
6361                         /* FIXME: runtime generic context pointer for jumps? */
6362                         /* FIXME: handle this for generic sharing eventually */
6363                         if ((ins_flag & MONO_INST_TAILCALL) && !cfg->generic_sharing_context && !vtable_arg && cmethod && (*ip == CEE_CALL) &&
6364                                  (mono_metadata_signature_equal (mono_method_signature (method), mono_method_signature (cmethod)))) {
6365                                 int i;
6366
6367                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
6368                                 INLINE_FAILURE;
6369                                 /* FIXME: This assumes the two methods has the same number and type of arguments */
6370                                 /*
6371                                  * We implement tail calls by storing the actual arguments into the 
6372                                  * argument variables, then emitting a OP_JMP. Since the actual arguments
6373                                  * can refer to the arg variables, we have to spill them.
6374                                  */
6375                                 handle_loaded_temps (cfg, bblock, sp, sp + n);
6376                                 for (i = 0; i < n; ++i) {
6377                                         /* Prevent argument from being register allocated */
6378                                         arg_array [i]->flags |= MONO_INST_VOLATILE;
6379
6380                                         /* Check if argument is the same */
6381                                         /* 
6382                                          * FIXME: This loses liveness info, so it can only be done if the
6383                                          * argument is not register allocated.
6384                                          */
6385                                         NEW_ARGLOAD (cfg, ins, i);
6386                                         if ((ins->opcode == sp [i]->opcode) && (ins->inst_i0 == sp [i]->inst_i0))
6387                                                 continue;
6388
6389                                         NEW_ARGSTORE (cfg, ins, i, sp [i]);
6390                                         /* FIXME: handle CEE_STIND_R4 */
6391                                         if (ins->opcode == CEE_STOBJ) {
6392                                                 NEW_ARGLOADA (cfg, ins, i);
6393                                                 handle_stobj (cfg, bblock, ins, sp [i], sp [i]->cil_code, ins->klass, FALSE, FALSE, FALSE);
6394                                         }
6395                                         else
6396                                                 MONO_ADD_INS (bblock, ins);
6397                                 }
6398                                 MONO_INST_NEW (cfg, ins, OP_JMP);
6399                                 ins->inst_p0 = cmethod;
6400                                 ins->inst_p1 = arg_array [0];
6401                                 MONO_ADD_INS (bblock, ins);
6402                                 link_bblock (cfg, bblock, end_bblock);                  
6403                                 start_new_bblock = 1;
6404                                 /* skip CEE_RET as well */
6405                                 ip += 6;
6406                                 ins_flag = 0;
6407                                 break;
6408                         }
6409                         if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_get_inst_for_method (cfg, cmethod, fsig, sp))) {
6410                                 if (MONO_TYPE_IS_VOID (fsig->ret)) {
6411                                         MONO_ADD_INS (bblock, ins);
6412                                 } else {
6413                                         type_to_eval_stack_type (cfg, fsig->ret, ins);
6414                                         *sp = ins;
6415                                         sp++;
6416                                 }
6417
6418                                 ip += 5;
6419                                 ins_flag = 0;
6420                                 break;
6421                         }
6422
6423                         handle_loaded_temps (cfg, bblock, stack_start, sp);
6424
6425                         if ((cfg->opt & MONO_OPT_INLINE) && cmethod && //!check_this &&
6426                             (!virtual || !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) || (cmethod->flags & METHOD_ATTRIBUTE_FINAL)) && 
6427                             mono_method_check_inlining (cfg, cmethod) &&
6428                                  !g_list_find (dont_inline, cmethod)) {
6429                                 int costs;
6430                                 MonoBasicBlock *ebblock;
6431                                 gboolean allways = FALSE;
6432
6433                                 if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
6434                                         (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
6435                                         /* Prevent inlining of methods that call wrappers */
6436                                         INLINE_FAILURE;
6437                                         cmethod = mono_marshal_get_native_wrapper (cmethod, check_for_pending_exc, FALSE);
6438                                         allways = TRUE;
6439                                 }
6440
6441                                 if ((costs = inline_method (cfg, cmethod, fsig, bblock, sp, ip, real_offset, dont_inline, &ebblock, allways))) {
6442                                         ip += 5;
6443                                         real_offset += 5;
6444
6445                                         GET_BBLOCK (cfg, bblock, ip);
6446                                         ebblock->next_bb = bblock;
6447                                         link_bblock (cfg, ebblock, bblock);
6448
6449                                         if (!MONO_TYPE_IS_VOID (fsig->ret))
6450                                                 sp++;
6451
6452                                         /* indicates start of a new block, and triggers a load of all 
6453                                            stack arguments at bb boundarie */
6454                                         bblock = ebblock;
6455
6456                                         inline_costs += costs;
6457                                         ins_flag = 0;
6458                                         break;
6459                                 }
6460                         }
6461                         
6462                         inline_costs += 10 * num_calls++;
6463
6464                         /* tail recursion elimination */
6465                         if ((cfg->opt & MONO_OPT_TAILC) && *ip == CEE_CALL && cmethod == method && ip [5] == CEE_RET &&
6466                                         !vtable_arg) {
6467                                 gboolean has_vtargs = FALSE;
6468                                 int i;
6469                                 
6470                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
6471                                 INLINE_FAILURE;
6472                                 /* keep it simple */
6473                                 for (i =  fsig->param_count - 1; i >= 0; i--) {
6474                                         if (MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->params [i])) 
6475                                                 has_vtargs = TRUE;
6476                                 }
6477
6478                                 if (!has_vtargs) {
6479                                         for (i = 0; i < n; ++i) {
6480                                                 /* FIXME: handle CEE_STIND_R4 */
6481                                                 NEW_ARGSTORE (cfg, ins, i, sp [i]);
6482                                                 MONO_ADD_INS (bblock, ins);
6483                                         }
6484                                         MONO_INST_NEW (cfg, ins, OP_BR);
6485                                         MONO_ADD_INS (bblock, ins);
6486                                         tblock = start_bblock->out_bb [0];
6487                                         link_bblock (cfg, bblock, tblock);
6488                                         ins->inst_target_bb = tblock;
6489                                         start_new_bblock = 1;
6490
6491                                         /* skip the CEE_RET, too */
6492                                         if (ip_in_bb (cfg, bblock, ip + 5))
6493                                                 ip += 6;
6494                                         else
6495                                                 ip += 5;
6496                                         ins_flag = 0;
6497                                         break;
6498                                 }
6499                         }
6500
6501                         if (ip_in_bb (cfg, bblock, ip + 5) 
6502                                 && (!MONO_TYPE_ISSTRUCT (fsig->ret))
6503                                 && (!MONO_TYPE_IS_VOID (fsig->ret) || (cmethod && cmethod->string_ctor))
6504                                 && (CODE_IS_STLOC (ip + 5) || ip [5] == CEE_POP || ip [5] == CEE_RET))
6505                                 /* No need to spill */
6506                                 no_spill = TRUE;
6507                         else
6508                                 no_spill = FALSE;
6509
6510                         /* FIXME: only do this for generic methods if
6511                            they are not shared! */
6512                         if (context_used &&
6513                                         (cmethod->klass->valuetype ||
6514                                         (cmethod->is_inflated && mono_method_get_context (cmethod)->method_inst && !pass_mrgctx) ||
6515                                         ((cmethod->flags & METHOD_ATTRIBUTE_STATIC) &&
6516                                                 mono_class_generic_sharing_enabled (cmethod->klass)) ||
6517                                         (!imt_arg && !mono_method_is_generic_sharable_impl (cmethod, TRUE) &&
6518                                                 (!virtual || cmethod->flags & METHOD_ATTRIBUTE_FINAL ||
6519                                                 !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))))) {
6520                                 MonoInst *rgctx;
6521
6522                                 INLINE_FAILURE;
6523
6524                                 g_assert (cfg->generic_sharing_context && cmethod);
6525                                 g_assert (!addr);
6526
6527                                 /*
6528                                  * We are compiling a call to
6529                                  * non-shared generic code from shared
6530                                  * code, which means that we have to
6531                                  * look up the method in the rgctx and
6532                                  * do an indirect call.
6533                                  */
6534                                 GET_RGCTX (rgctx, context_used);
6535                                 addr = get_runtime_generic_context_method (cfg, method, context_used, bblock, cmethod,
6536                                                 generic_context, rgctx, MONO_RGCTX_INFO_GENERIC_METHOD_CODE, ip);
6537
6538                         }
6539
6540                         if (addr) {
6541                                 g_assert (!imt_arg);
6542
6543                                 if (*ip == CEE_CALL) {
6544                                         g_assert (context_used);
6545                                 } else if (*ip == CEE_CALLI) {
6546                                         g_assert (!vtable_arg);
6547                                 } else {
6548                                         g_assert (cmethod->flags & METHOD_ATTRIBUTE_FINAL ||
6549                                                         !(cmethod->flags & METHOD_ATTRIBUTE_FINAL));
6550                                 }
6551
6552                                 /* Prevent inlining of methods with indirect calls */
6553                                 INLINE_FAILURE;
6554                                 if (no_spill) {
6555                                         ins = (MonoInst*)mono_emit_rgctx_calli (cfg, bblock, fsig, sp, addr, vtable_arg, ip);
6556                                         *sp++ = ins;                                    
6557                                 } else {
6558                                         temp = mono_emit_rgctx_calli_spilled (cfg, bblock, fsig, sp, addr, vtable_arg, ip);
6559                                         if (temp != -1) {
6560                                                 NEW_TEMPLOAD (cfg, *sp, temp);
6561                                                 NEW_TEMPLOAD_SOFT_FLOAT (cfg, bblock, *sp, temp, ip);
6562                                                 sp++;
6563                                         }
6564                                 }                       
6565                         } else if (array_rank) {
6566                                 MonoInst *addr;
6567
6568                                 if (strcmp (cmethod->name, "Set") == 0) { /* array Set */ 
6569                                         if (sp [fsig->param_count]->type == STACK_OBJ) {
6570                                                 MonoInst *iargs [2];
6571                                                 MonoInst *array, *to_store, *store;
6572
6573                                                 handle_loaded_temps (cfg, bblock, stack_start, sp);
6574                                                 
6575                                                 array = mono_compile_create_var (cfg, type_from_stack_type (sp [0]), OP_LOCAL);
6576                                                 NEW_TEMPSTORE (cfg, store, array->inst_c0, sp [0]);
6577                                                 MONO_ADD_INS (bblock, store);
6578                                                 NEW_TEMPLOAD (cfg, iargs [0], array->inst_c0);
6579
6580                                                 to_store = mono_compile_create_var (cfg, type_from_stack_type (sp [fsig->param_count]), OP_LOCAL);
6581                                                 NEW_TEMPSTORE (cfg, store, to_store->inst_c0, sp [fsig->param_count]);
6582                                                 /* FIXME: handle CEE_STIND_R4 */
6583                                                 MONO_ADD_INS (bblock, store);
6584                                                 NEW_TEMPLOAD (cfg, iargs [1], to_store->inst_c0);
6585
6586                                                 /*
6587                                                  * We first save the args for the call so that the args are copied to the stack
6588                                                  * and a new instruction tree for them is created. If we don't do this,
6589                                                  * the same MonoInst is added to two different trees and this is not 
6590                                                  * allowed by burg.
6591                                                  */
6592                                                 mono_emit_jit_icall (cfg, bblock, mono_helper_stelem_ref_check, iargs, ip);
6593
6594                                                 NEW_TEMPLOAD (cfg, sp [0], array->inst_c0);
6595                                                 NEW_TEMPLOAD (cfg, sp [fsig->param_count], to_store->inst_c0);
6596                                         }
6597
6598                                         addr = mini_get_ldelema_ins (cfg, bblock, cmethod, sp, ip, TRUE);
6599                                         NEW_INDSTORE (cfg, ins, addr, sp [fsig->param_count], fsig->params [fsig->param_count - 1]);
6600                                         /* FIXME: handle CEE_STIND_R4 */
6601                                         if (ins->opcode == CEE_STOBJ) {
6602                                                 handle_stobj (cfg, bblock, addr, sp [fsig->param_count], ip, mono_class_from_mono_type (fsig->params [fsig->param_count-1]), FALSE, FALSE, TRUE);
6603                                         } else {
6604                                                 MONO_ADD_INS (bblock, ins);
6605                                         }
6606
6607                                 } else if (strcmp (cmethod->name, "Get") == 0) { /* array Get */
6608                                         addr = mini_get_ldelema_ins (cfg, bblock, cmethod, sp, ip, FALSE);
6609                                         NEW_INDLOAD (cfg, ins, addr, fsig->ret);
6610
6611                                         *sp++ = ins;
6612                                 } else if (strcmp (cmethod->name, "Address") == 0) { /* array Address */
6613                                         if (!cmethod->klass->element_class->valuetype && !readonly) {
6614                                                 MonoInst* check;
6615                                                 //* Needed by the code generated in inssel.brg * /
6616                                                 mono_get_got_var (cfg);
6617
6618                                                 MONO_INST_NEW (cfg, check, OP_CHECK_ARRAY_TYPE);
6619                                                 check->klass = cmethod->klass;
6620                                                 check->inst_left = sp [0];
6621                                                 check->type = STACK_OBJ;
6622                                                 sp [0] = check;
6623                                         }
6624
6625                                         readonly = FALSE;
6626                                         addr = mini_get_ldelema_ins (cfg, bblock, cmethod, sp, ip, FALSE);
6627                                         *sp++ = addr;
6628                                 } else {
6629                                         g_assert_not_reached ();
6630                                 }
6631
6632                         } else {
6633                                 /* Prevent inlining of methods which call other methods */
6634                                 INLINE_FAILURE;
6635                                 if (mini_redirect_call (&temp, cfg, bblock, cmethod, fsig, sp, ip, virtual ? sp [0] : NULL)) {
6636                                         if (temp != -1) {
6637                                                 NEW_TEMPLOAD (cfg, *sp, temp);
6638                                                 sp++;
6639                                         }
6640                                 } else if (no_spill) {
6641                                         ins = (MonoInst*)mono_emit_rgctx_method_call (cfg, bblock, cmethod, fsig, sp,
6642                                                         vtable_arg, imt_arg, ip, virtual ? sp [0] : NULL);
6643                                         *sp++ = ins;
6644                                 } else {
6645                                         if ((temp = mono_emit_rgctx_method_call_spilled (cfg, bblock, cmethod, fsig, sp,
6646                                                         vtable_arg, imt_arg, ip, virtual ? sp [0] : NULL)) != -1) {
6647                                                 MonoInst *load;
6648                                                 NEW_TEMPLOAD (cfg, load, temp);
6649
6650 #ifdef MONO_ARCH_SOFT_FLOAT
6651                                                 if (load->opcode == CEE_LDIND_R4) {
6652                                                         NEW_TEMPLOADA (cfg, load, temp);
6653                                                         temp = handle_load_float (cfg, bblock, load, ip);
6654                                                         NEW_TEMPLOAD (cfg, load, temp);
6655                                                 }
6656 #endif
6657                                                 *sp++ = load;
6658                                         }
6659                                 }
6660                         }
6661
6662                         ip += 5;
6663                         ins_flag = 0;
6664                         break;
6665                 }
6666                 case CEE_RET:
6667                         if (cfg->method != method) {
6668                                 /* return from inlined method */
6669                                 if (return_var) {
6670                                         MonoInst *store;
6671                                         CHECK_STACK (1);
6672                                         --sp;
6673                                         //g_assert (returnvar != -1);
6674                                         NEW_TEMPSTORE (cfg, store, return_var->inst_c0, *sp);
6675                                         store->cil_code = sp [0]->cil_code;
6676                                         if (store->opcode == CEE_STOBJ) {
6677                                                 g_assert_not_reached ();
6678                                                 NEW_TEMPLOADA (cfg, store, return_var->inst_c0);
6679                                                 /* FIXME: it is possible some optimization will pass the a heap pointer for the struct address, so we'll need the write barrier */
6680                                                 handle_stobj (cfg, bblock, store, *sp, sp [0]->cil_code, return_var->klass, FALSE, FALSE, FALSE);
6681 #ifdef MONO_ARCH_SOFT_FLOAT
6682                                         } else if (store->opcode == CEE_STIND_R4) {
6683                                                 NEW_TEMPLOADA (cfg, store, return_var->inst_c0);
6684                                                 handle_store_float (cfg, bblock, store, *sp, sp [0]->cil_code);
6685 #endif
6686                                         } else
6687                                                 MONO_ADD_INS (bblock, store);
6688                                 } 
6689                         } else {
6690                                 if (cfg->ret) {
6691                                         g_assert (!return_var);
6692                                         CHECK_STACK (1);
6693                                         --sp;
6694                                         MONO_INST_NEW (cfg, ins, OP_NOP);
6695                                         ins->opcode = mini_type_to_stind (cfg, mono_method_signature (method)->ret);
6696                                         if (ins->opcode == CEE_STOBJ) {
6697                                                 NEW_RETLOADA (cfg, ins);
6698                                                 /* FIXME: it is possible some optimization will pass the a heap pointer for the struct address, so we'll need the write barrier */
6699                                                 handle_stobj (cfg, bblock, ins, *sp, ip, cfg->ret->klass, FALSE, FALSE, FALSE);
6700                                         } else {
6701                                                 ins->opcode = OP_SETRET;
6702                                                 ins->inst_i0 = *sp;;
6703                                                 ins->inst_i1 = NULL;
6704                                                 MONO_ADD_INS (bblock, ins);
6705                                         }
6706                                 }
6707                         }
6708                         if (sp != stack_start)
6709                                 UNVERIFIED;
6710                         MONO_INST_NEW (cfg, ins, OP_BR);
6711                         ip++;
6712                         ins->inst_target_bb = end_bblock;
6713                         MONO_ADD_INS (bblock, ins);
6714                         link_bblock (cfg, bblock, end_bblock);
6715                         start_new_bblock = 1;
6716                         break;
6717                 case CEE_BR_S:
6718                         CHECK_OPSIZE (2);
6719                         MONO_INST_NEW (cfg, ins, OP_BR);
6720                         ip++;
6721                         MONO_ADD_INS (bblock, ins);
6722                         target = ip + 1 + (signed char)(*ip);
6723                         ++ip;
6724                         GET_BBLOCK (cfg, tblock, target);
6725                         link_bblock (cfg, bblock, tblock);
6726                         CHECK_BBLOCK (target, ip, tblock);
6727                         ins->inst_target_bb = tblock;
6728                         if (sp != stack_start) {
6729                                 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
6730                                 sp = stack_start;
6731                                 CHECK_UNVERIFIABLE (cfg);
6732                         }
6733                         start_new_bblock = 1;
6734                         inline_costs += BRANCH_COST;
6735                         break;
6736                 case CEE_BRFALSE_S:
6737                 case CEE_BRTRUE_S:
6738                         CHECK_OPSIZE (2);
6739                         CHECK_STACK (1);
6740                         if (sp [-1]->type == STACK_VTYPE || sp [-1]->type == STACK_R8)
6741                                 UNVERIFIED;
6742                         MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
6743                         ip++;
6744                         target = ip + 1 + *(signed char*)ip;
6745                         ip++;
6746                         ADD_UNCOND (ins->opcode == CEE_BRTRUE);
6747                         if (sp != stack_start) {
6748                                 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
6749                                 sp = stack_start;
6750                                 CHECK_UNVERIFIABLE (cfg);
6751                         }
6752                         inline_costs += BRANCH_COST;
6753                         break;
6754                 case CEE_BEQ_S:
6755                 case CEE_BGE_S:
6756                 case CEE_BGT_S:
6757                 case CEE_BLE_S:
6758                 case CEE_BLT_S:
6759                 case CEE_BNE_UN_S:
6760                 case CEE_BGE_UN_S:
6761                 case CEE_BGT_UN_S:
6762                 case CEE_BLE_UN_S:
6763                 case CEE_BLT_UN_S:
6764                         CHECK_OPSIZE (2);
6765                         CHECK_STACK (2);
6766                         MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
6767                         ip++;
6768                         target = ip + 1 + *(signed char*)ip;
6769                         ip++;
6770 #ifdef MONO_ARCH_SOFT_FLOAT
6771                         if (sp [-1]->type == STACK_R8 || sp [-2]->type == STACK_R8) {
6772                                 ins->opcode = condbr_to_fp_br (ins->opcode);
6773                                 sp -= 2;
6774                                 ins->inst_left = sp [0];
6775                                 ins->inst_right = sp [1];
6776                                 ins->type = STACK_I4;
6777                                 *sp++ = emit_tree (cfg, bblock, ins, ins->cil_code);
6778                                 MONO_INST_NEW (cfg, ins, CEE_BRTRUE);
6779                                 ADD_UNCOND (TRUE);
6780                         } else {
6781                                 ADD_BINCOND (NULL);
6782                         }
6783 #else
6784                         ADD_BINCOND (NULL);
6785 #endif
6786                         if (sp != stack_start) {
6787                                 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
6788                                 sp = stack_start;
6789                                 CHECK_UNVERIFIABLE (cfg);
6790                         }
6791                         inline_costs += BRANCH_COST;
6792                         break;
6793                 case CEE_BR:
6794                         CHECK_OPSIZE (5);
6795                         MONO_INST_NEW (cfg, ins, OP_BR);
6796                         ip++;
6797                         MONO_ADD_INS (bblock, ins);
6798                         target = ip + 4 + (gint32)read32(ip);
6799                         ip += 4;
6800                         GET_BBLOCK (cfg, tblock, target);
6801                         link_bblock (cfg, bblock, tblock);
6802                         CHECK_BBLOCK (target, ip, tblock);
6803                         ins->inst_target_bb = tblock;
6804                         if (sp != stack_start) {
6805                                 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
6806                                 sp = stack_start;
6807                                 CHECK_UNVERIFIABLE (cfg);
6808                         }
6809                         start_new_bblock = 1;
6810                         inline_costs += BRANCH_COST;
6811                         break;
6812                 case CEE_BRFALSE:
6813                 case CEE_BRTRUE:
6814                         CHECK_OPSIZE (5);
6815                         CHECK_STACK (1);
6816                         if (sp [-1]->type == STACK_VTYPE || sp [-1]->type == STACK_R8)
6817                                 UNVERIFIED;
6818                         MONO_INST_NEW (cfg, ins, *ip);
6819                         ip++;
6820                         target = ip + 4 + (gint32)read32(ip);
6821                         ip += 4;
6822                         ADD_UNCOND(ins->opcode == CEE_BRTRUE);
6823                         if (sp != stack_start) {
6824                                 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
6825                                 sp = stack_start;
6826                                 CHECK_UNVERIFIABLE (cfg);
6827                         }
6828                         inline_costs += BRANCH_COST;
6829                         break;
6830                 case CEE_BEQ:
6831                 case CEE_BGE:
6832                 case CEE_BGT:
6833                 case CEE_BLE:
6834                 case CEE_BLT:
6835                 case CEE_BNE_UN:
6836                 case CEE_BGE_UN:
6837                 case CEE_BGT_UN:
6838                 case CEE_BLE_UN:
6839                 case CEE_BLT_UN:
6840                         CHECK_OPSIZE (5);
6841                         CHECK_STACK (2);
6842                         MONO_INST_NEW (cfg, ins, *ip);
6843                         ip++;
6844                         target = ip + 4 + (gint32)read32(ip);
6845                         ip += 4;
6846 #ifdef MONO_ARCH_SOFT_FLOAT
6847                         if (sp [-1]->type == STACK_R8 || sp [-2]->type == STACK_R8) {
6848                                 ins->opcode = condbr_to_fp_br (ins->opcode);
6849                                 sp -= 2;
6850                                 ins->inst_left = sp [0];
6851                                 ins->inst_right = sp [1];
6852                                 ins->type = STACK_I4;
6853                                 *sp++ = emit_tree (cfg, bblock, ins, ins->cil_code);
6854                                 MONO_INST_NEW (cfg, ins, CEE_BRTRUE);
6855                                 ADD_UNCOND (TRUE);
6856                         } else {
6857                                 ADD_BINCOND (NULL);
6858                         }
6859 #else
6860                         ADD_BINCOND (NULL);
6861 #endif
6862                         if (sp != stack_start) {
6863                                 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
6864                                 sp = stack_start;
6865                                 CHECK_UNVERIFIABLE (cfg);
6866                         }
6867                         inline_costs += BRANCH_COST;
6868                         break;
6869                 case CEE_SWITCH:
6870                         CHECK_OPSIZE (5);
6871                         CHECK_STACK (1);
6872                         n = read32 (ip + 1);
6873                         MONO_INST_NEW (cfg, ins, OP_SWITCH);
6874                         --sp;
6875                         ins->inst_left = *sp;
6876                         if ((ins->inst_left->type != STACK_I4) && (ins->inst_left->type != STACK_PTR)) 
6877                                 UNVERIFIED;
6878                         ip += 5;
6879                         CHECK_OPSIZE (n * sizeof (guint32));
6880                         target = ip + n * sizeof (guint32);
6881                         MONO_ADD_INS (bblock, ins);
6882                         GET_BBLOCK (cfg, tblock, target);
6883                         link_bblock (cfg, bblock, tblock);
6884                         ins->klass = GUINT_TO_POINTER (n);
6885                         ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * (n + 1));
6886                         ins->inst_many_bb [n] = tblock;
6887
6888                         for (i = 0; i < n; ++i) {
6889                                 GET_BBLOCK (cfg, tblock, target + (gint32)read32(ip));
6890                                 link_bblock (cfg, bblock, tblock);
6891                                 ins->inst_many_bb [i] = tblock;
6892                                 ip += 4;
6893                         }
6894                         if (sp != stack_start) {
6895                                 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
6896                                 sp = stack_start;
6897                                 CHECK_UNVERIFIABLE (cfg);
6898                         }
6899                         /* Needed by the code generated in inssel.brg */
6900                         mono_get_got_var (cfg);
6901                         inline_costs += (BRANCH_COST * 2);
6902                         break;
6903                 case CEE_LDIND_I1:
6904                 case CEE_LDIND_U1:
6905                 case CEE_LDIND_I2:
6906                 case CEE_LDIND_U2:
6907                 case CEE_LDIND_I4:
6908                 case CEE_LDIND_U4:
6909                 case CEE_LDIND_I8:
6910                 case CEE_LDIND_I:
6911                 case CEE_LDIND_R4:
6912                 case CEE_LDIND_R8:
6913                 case CEE_LDIND_REF:
6914                         CHECK_STACK (1);
6915                         MONO_INST_NEW (cfg, ins, *ip);
6916                         --sp;
6917                         ins->inst_i0 = *sp;
6918                         *sp++ = ins;
6919                         ins->type = ldind_type [*ip - CEE_LDIND_I1];
6920                         ins->flags |= ins_flag;
6921                         ins_flag = 0;
6922                         if (ins->type == STACK_OBJ)
6923                                 ins->klass = mono_defaults.object_class;
6924 #ifdef MONO_ARCH_SOFT_FLOAT
6925                         if (*ip == CEE_LDIND_R4) {
6926                                 int temp;
6927                                 --sp;
6928                                 temp = handle_load_float (cfg, bblock, ins->inst_i0, ip);
6929                                 NEW_TEMPLOAD (cfg, *sp, temp);
6930                                 sp++;
6931                         }
6932 #endif
6933                         ++ip;
6934                         break;
6935                 case CEE_STIND_REF:
6936                 case CEE_STIND_I1:
6937                 case CEE_STIND_I2:
6938                 case CEE_STIND_I4:
6939                 case CEE_STIND_I8:
6940                 case CEE_STIND_R4:
6941                 case CEE_STIND_R8:
6942                         CHECK_STACK (2);
6943 #ifdef MONO_ARCH_SOFT_FLOAT
6944                         if (*ip == CEE_STIND_R4) {
6945                                 sp -= 2;
6946                                 handle_store_float (cfg, bblock, sp [0], sp [1], ip);
6947                                 ip++;
6948                                 break;
6949                         }
6950 #endif
6951 #if HAVE_WRITE_BARRIERS
6952                         if (*ip == CEE_STIND_REF && method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER && !((sp [-1]->opcode == OP_PCONST) && (sp [-1]->inst_p0 == 0))) {
6953                                 /* insert call to write barrier */
6954                                 MonoMethod *write_barrier = mono_marshal_get_write_barrier ();
6955                                 sp -= 2;
6956                                 mono_emit_method_call_spilled (cfg, bblock, write_barrier, mono_method_signature (write_barrier), sp, ip, NULL);
6957                                 ip++;
6958                                 break;
6959                         }
6960 #endif
6961                         MONO_INST_NEW (cfg, ins, *ip);
6962                         ip++;
6963                         sp -= 2;
6964                         handle_loaded_temps (cfg, bblock, stack_start, sp);
6965                         MONO_ADD_INS (bblock, ins);
6966                         ins->inst_i0 = sp [0];
6967                         ins->inst_i1 = sp [1];
6968                         ins->flags |= ins_flag;
6969                         ins_flag = 0;
6970                         inline_costs += 1;
6971                         break;
6972                 case CEE_MUL:
6973                         CHECK_STACK (2);
6974                         ADD_BINOP (*ip);
6975
6976 #ifdef MONO_ARCH_NO_EMULATE_MUL_IMM
6977                         /* FIXME: This breaks with ssapre (mono -O=ssapre loader.exe) */
6978                         if ((ins->inst_right->opcode == OP_ICONST) && !(cfg->opt & MONO_OPT_SSAPRE)) {
6979                                 switch (ins->opcode) {
6980                                 case CEE_MUL:
6981                                         ins->opcode = OP_IMUL_IMM;
6982                                         ins->inst_imm = ins->inst_right->inst_c0;
6983                                         break;
6984                                 case OP_LMUL:
6985                                         ins->opcode = OP_LMUL_IMM;
6986                                         ins->inst_imm = ins->inst_right->inst_c0;
6987                                         break;
6988                                 default:
6989                                         g_assert_not_reached ();
6990                                 }
6991                         }
6992 #endif
6993
6994                         if (mono_find_jit_opcode_emulation (ins->opcode)) {
6995                                 --sp;
6996                                 *sp++ = emit_tree (cfg, bblock, ins, ip + 1);
6997                         }
6998                         ip++;
6999                         break;
7000                 case CEE_ADD:
7001                 case CEE_SUB:
7002                 case CEE_DIV:
7003                 case CEE_DIV_UN:
7004                 case CEE_REM:
7005                 case CEE_REM_UN:
7006                 case CEE_AND:
7007                 case CEE_OR:
7008                 case CEE_XOR:
7009                 case CEE_SHL:
7010                 case CEE_SHR:
7011                 case CEE_SHR_UN:
7012                         CHECK_STACK (2);
7013                         ADD_BINOP (*ip);
7014                         /* special case that gives a nice speedup and happens to workaorund a ppc jit but (for the release)
7015                          * later apply the speedup to the left shift as well
7016                          * See BUG# 57957.
7017                          */
7018                         if ((ins->opcode == OP_LSHR_UN) && (ins->type == STACK_I8) 
7019                                         && (ins->inst_right->opcode == OP_ICONST) && (ins->inst_right->inst_c0 == 32)) {
7020                                 ins->opcode = OP_LSHR_UN_32;
7021                                 /*g_print ("applied long shr speedup to %s\n", cfg->method->name);*/
7022                                 ip++;
7023                                 break;
7024                         }
7025                         if (mono_find_jit_opcode_emulation (ins->opcode)) {
7026                                 --sp;
7027                                 *sp++ = emit_tree (cfg, bblock, ins, ip + 1);
7028                         }
7029                         ip++;
7030                         break;
7031                 case CEE_NEG:
7032                 case CEE_NOT:
7033                 case CEE_CONV_I1:
7034                 case CEE_CONV_I2:
7035                 case CEE_CONV_I4:
7036                 case CEE_CONV_R4:
7037                 case CEE_CONV_R8:
7038                 case CEE_CONV_U4:
7039                 case CEE_CONV_I8:
7040                 case CEE_CONV_U8:
7041                 case CEE_CONV_OVF_I8:
7042                 case CEE_CONV_OVF_U8:
7043                 case CEE_CONV_R_UN:
7044                         CHECK_STACK (1);
7045                         ADD_UNOP (*ip);
7046
7047 #ifdef MONO_ARCH_SOFT_FLOAT
7048                         /*
7049                          * Its rather hard to emit the soft float code during the decompose
7050                          * pass, so avoid it in some specific cases.
7051                          */
7052                         if (ins->opcode == OP_LCONV_TO_R4) {
7053                                 MonoInst *conv;
7054
7055                                 ins->opcode = OP_LCONV_TO_R8;
7056                                 ins->type = STACK_R8;
7057
7058                                 --sp;
7059                                 *sp++ = emit_tree (cfg, bblock, ins, ip + 1);
7060
7061                                 MONO_INST_NEW (cfg, conv, CEE_CONV_R4);
7062                                 conv->inst_left = sp [-1];
7063                                 conv->type = STACK_R8;
7064                                 sp [-1] = ins;
7065
7066                                 ip++;
7067                                 break;
7068                         }
7069 #endif
7070
7071                         if (mono_find_jit_opcode_emulation (ins->opcode)) {
7072                                 --sp;
7073                                 *sp++ = emit_tree (cfg, bblock, ins, ip + 1);
7074                         }
7075                         ip++;                   
7076                         break;
7077                 case CEE_CONV_OVF_I4:
7078                 case CEE_CONV_OVF_I1:
7079                 case CEE_CONV_OVF_I2:
7080                 case CEE_CONV_OVF_I:
7081                 case CEE_CONV_OVF_U:
7082                         CHECK_STACK (1);
7083
7084                         if (sp [-1]->type == STACK_R8) {
7085                                 ADD_UNOP (CEE_CONV_OVF_I8);
7086                                 ADD_UNOP (*ip);
7087                         } else {
7088                                 ADD_UNOP (*ip);
7089                         }
7090
7091                         ip++;
7092                         break;
7093                 case CEE_CONV_OVF_U1:
7094                 case CEE_CONV_OVF_U2:
7095                 case CEE_CONV_OVF_U4:
7096                         CHECK_STACK (1);
7097
7098                         if (sp [-1]->type == STACK_R8) {
7099                                 ADD_UNOP (CEE_CONV_OVF_U8);
7100                                 ADD_UNOP (*ip);
7101                         } else {
7102                                 ADD_UNOP (*ip);
7103                         }
7104
7105                         ip++;
7106                         break;
7107                 case CEE_CONV_OVF_I1_UN:
7108                 case CEE_CONV_OVF_I2_UN:
7109                 case CEE_CONV_OVF_I4_UN:
7110                 case CEE_CONV_OVF_I8_UN:
7111                 case CEE_CONV_OVF_U1_UN:
7112                 case CEE_CONV_OVF_U2_UN:
7113                 case CEE_CONV_OVF_U4_UN:
7114                 case CEE_CONV_OVF_U8_UN:
7115                 case CEE_CONV_OVF_I_UN:
7116                 case CEE_CONV_OVF_U_UN:
7117                         CHECK_STACK (1);
7118                         ADD_UNOP (*ip);
7119                         ip++;
7120                         break;
7121                 case CEE_CPOBJ:
7122                         CHECK_OPSIZE (5);
7123                         CHECK_STACK (2);
7124                         token = read32 (ip + 1);
7125                         klass = mini_get_class (method, token, generic_context);
7126                         CHECK_TYPELOAD (klass);
7127                         sp -= 2;
7128                         if (generic_class_is_reference_type (cfg, klass)) {
7129                                 MonoInst *store, *load;
7130                                 MONO_INST_NEW (cfg, load, CEE_LDIND_REF);
7131                                 load->inst_i0 = sp [1];
7132                                 load->type = STACK_OBJ;
7133                                 load->klass = klass;
7134                                 load->flags |= ins_flag;
7135                                 MONO_INST_NEW (cfg, store, CEE_STIND_REF);
7136                                 handle_loaded_temps (cfg, bblock, stack_start, sp);
7137                                 MONO_ADD_INS (bblock, store);
7138                                 store->inst_i0 = sp [0];
7139                                 store->inst_i1 = load;
7140                                 store->flags |= ins_flag;
7141                         } else {
7142                                 guint32 align;
7143
7144                                 n = mono_class_value_size (klass, &align);
7145                                 if ((cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 5) {
7146                                         MonoInst *copy;
7147                                         NEW_MEMCPY (cfg, copy, sp [0], sp [1], n, align);
7148                                         MONO_ADD_INS (bblock, copy);
7149                                 } else {
7150                                         MonoMethod *memcpy_method = get_memcpy_method ();
7151                                         MonoInst *iargs [3];
7152                                         iargs [0] = sp [0];
7153                                         iargs [1] = sp [1];
7154                                         NEW_ICONST (cfg, iargs [2], n);
7155
7156                                         mono_emit_method_call_spilled (cfg, bblock, memcpy_method, memcpy_method->signature, iargs, ip, NULL);
7157                                 }
7158                         }
7159                         ins_flag = 0;
7160                         ip += 5;
7161                         break;
7162                 case CEE_LDOBJ: {
7163                         MonoInst *iargs [3];
7164                         int loc_index = -1;
7165                         int stloc_len = 0;
7166                         guint32 align;
7167
7168                         CHECK_OPSIZE (5);
7169                         CHECK_STACK (1);
7170                         --sp;
7171                         token = read32 (ip + 1);
7172                         klass = mini_get_class (method, token, generic_context);
7173                         CHECK_TYPELOAD (klass);
7174                         if (generic_class_is_reference_type (cfg, klass)) {
7175                                 MONO_INST_NEW (cfg, ins, CEE_LDIND_REF);
7176                                 ins->inst_i0 = sp [0];
7177                                 ins->type = STACK_OBJ;
7178                                 ins->klass = klass;
7179                                 ins->flags |= ins_flag;
7180                                 ins_flag = 0;
7181                                 *sp++ = ins;
7182                                 ip += 5;
7183                                 break;
7184                         }
7185
7186                         /* Optimize the common ldobj+stloc combination */
7187                         switch (ip [5]) {
7188                         case CEE_STLOC_S:
7189                                 loc_index = ip [6];
7190                                 stloc_len = 2;
7191                                 break;
7192                         case CEE_STLOC_0:
7193                         case CEE_STLOC_1:
7194                         case CEE_STLOC_2:
7195                         case CEE_STLOC_3:
7196                                 loc_index = ip [5] - CEE_STLOC_0;
7197                                 stloc_len = 1;
7198                                 break;
7199                         default:
7200                                 break;
7201                         }
7202
7203                         if ((loc_index != -1) && ip_in_bb (cfg, bblock, ip + 5)) {
7204                                 CHECK_LOCAL (loc_index);
7205                                 NEW_LOCSTORE (cfg, ins, loc_index, *sp);
7206
7207                                 /* FIXME: handle CEE_STIND_R4 */
7208                                 if (ins->opcode == CEE_STOBJ) {
7209                                         handle_loaded_temps (cfg, bblock, stack_start, sp);
7210                                         g_assert (ins->opcode == CEE_STOBJ);
7211                                         NEW_LOCLOADA (cfg, ins, loc_index);
7212                                         handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE, FALSE);
7213                                         ip += 5;
7214                                         ip += stloc_len;
7215                                         break;
7216                                 }
7217                         }
7218
7219                         n = mono_class_value_size (klass, &align);
7220                         ins = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
7221                         NEW_TEMPLOADA (cfg, iargs [0], ins->inst_c0);
7222                         if ((cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 5) {
7223                                 MonoInst *copy;
7224                                 NEW_MEMCPY (cfg, copy, iargs [0], *sp, n, align);
7225                                 MONO_ADD_INS (bblock, copy);
7226                         } else {
7227                                 MonoMethod *memcpy_method = get_memcpy_method ();
7228                                 iargs [1] = *sp;
7229                                 NEW_ICONST (cfg, iargs [2], n);
7230
7231                                 mono_emit_method_call_spilled (cfg, bblock, memcpy_method, memcpy_method->signature, iargs, ip, NULL);
7232                         }
7233                         NEW_TEMPLOAD (cfg, *sp, ins->inst_c0);
7234                         ++sp;
7235                         ip += 5;
7236                         ins_flag = 0;
7237                         inline_costs += 1;
7238                         break;
7239                 }
7240                 case CEE_LDSTR:
7241                         CHECK_STACK_OVF (1);
7242                         CHECK_OPSIZE (5);
7243                         n = read32 (ip + 1);
7244
7245                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
7246                                 /* FIXME: moving GC */
7247                                 NEW_PCONST (cfg, ins, mono_method_get_wrapper_data (method, n));
7248                                 ins->type = STACK_OBJ;
7249                                 ins->klass = mono_defaults.string_class;
7250                                 *sp = ins;
7251                         }
7252                         else if (method->wrapper_type != MONO_WRAPPER_NONE) {
7253                                 int temp;
7254                                 MonoInst *iargs [1];
7255
7256                                 NEW_PCONST (cfg, iargs [0], mono_method_get_wrapper_data (method, n));                          
7257                                 temp = mono_emit_jit_icall (cfg, bblock, mono_string_new_wrapper, iargs, ip);
7258                                 NEW_TEMPLOAD (cfg, *sp, temp);
7259
7260                         } else {
7261
7262                                 if (cfg->opt & MONO_OPT_SHARED) {
7263                                         int temp;
7264                                         MonoInst *iargs [3];
7265                                         MonoInst* domain_var;
7266                                         
7267                                         if (cfg->compile_aot) {
7268                                                 /* FIXME: bug when inlining methods from different assemblies (n is a token valid just in one). */
7269                                                 cfg->ldstr_list = g_list_prepend (cfg->ldstr_list, GINT_TO_POINTER (n));
7270                                         }
7271                                         /* avoid depending on undefined C behavior in sequence points */
7272                                         domain_var = mono_get_domainvar (cfg);
7273                                         NEW_TEMPLOAD (cfg, iargs [0], domain_var->inst_c0);
7274                                         NEW_IMAGECONST (cfg, iargs [1], image);
7275                                         NEW_ICONST (cfg, iargs [2], mono_metadata_token_index (n));
7276                                         temp = mono_emit_jit_icall (cfg, bblock, mono_ldstr, iargs, ip);
7277                                         NEW_TEMPLOAD (cfg, *sp, temp);
7278                                         mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
7279                                 } else {
7280                                         if (bblock->out_of_line) {
7281                                                 MonoInst *iargs [2];
7282                                                 int temp;
7283
7284                                                 if (cfg->method->klass->image == mono_defaults.corlib) {
7285                                                         /* 
7286                                                          * Avoid relocations and save some code size by using a 
7287                                                          * version of helper_ldstr specialized to mscorlib.
7288                                                          */
7289                                                         NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (n));
7290                                                         temp = mono_emit_jit_icall (cfg, bblock, mono_helper_ldstr_mscorlib, iargs, ip);
7291                                                 } else {
7292                                                         /* Avoid creating the string object */
7293                                                         NEW_IMAGECONST (cfg, iargs [0], image);
7294                                                         NEW_ICONST (cfg, iargs [1], mono_metadata_token_index (n));
7295                                                         temp = mono_emit_jit_icall (cfg, bblock, mono_helper_ldstr, iargs, ip);
7296                                                 }
7297                                                 NEW_TEMPLOAD (cfg, *sp, temp);
7298                                         } 
7299                                         else
7300                                         if (cfg->compile_aot) {
7301                                                 NEW_LDSTRCONST (cfg, ins, image, n);
7302                                                 *sp = ins;
7303                                         } 
7304                                         else {
7305                                                 NEW_PCONST (cfg, ins, NULL);
7306                                                 ins->type = STACK_OBJ;
7307                                                 ins->inst_p0 = mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
7308                                                 ins->klass = mono_defaults.string_class;
7309                                                 *sp = ins;
7310                                         }
7311                                 }
7312                         }
7313
7314                         sp++;
7315                         ip += 5;
7316                         break;
7317                 case CEE_NEWOBJ: {
7318                         MonoInst *iargs [2];
7319                         MonoMethodSignature *fsig;
7320                         MonoInst this_ins;
7321                         int temp;
7322
7323                         CHECK_OPSIZE (5);
7324                         token = read32 (ip + 1);
7325                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
7326                         if (!cmethod)
7327                                 goto load_error;
7328                         fsig = mono_method_get_signature (cmethod, image, token);
7329
7330                         mono_save_token_info (cfg, image, token, cmethod);
7331
7332                         if (!mono_class_init (cmethod->klass))
7333                                 goto load_error;
7334
7335                         if (cfg->generic_sharing_context)
7336                                 context_used = mono_method_check_context_used (cmethod);
7337
7338                         if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS) {
7339                                 if (check_linkdemand (cfg, method, cmethod, bblock, ip))
7340                                         INLINE_FAILURE;
7341                                 CHECK_CFG_EXCEPTION;
7342                         } else if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR) {
7343                                 ensure_method_is_allowed_to_call_method (cfg, method, cmethod, bblock, ip);
7344                         }
7345
7346                         n = fsig->param_count;
7347                         CHECK_STACK (n);
7348  
7349                         /* 
7350                          * Generate smaller code for the common newobj <exception> instruction in
7351                          * argument checking code.
7352                          */
7353                         if (bblock->out_of_line && cmethod->klass->image == mono_defaults.corlib && n <= 2 && 
7354                                 ((n < 1) || (!fsig->params [0]->byref && fsig->params [0]->type == MONO_TYPE_STRING)) && 
7355                                 ((n < 2) || (!fsig->params [1]->byref && fsig->params [1]->type == MONO_TYPE_STRING))) {
7356                                 MonoInst *iargs [3];
7357                                 int temp;
7358                                 
7359                                 sp -= n;
7360
7361                                 NEW_ICONST (cfg, iargs [0], cmethod->klass->type_token);
7362                                 switch (n) {
7363                                 case 0:
7364                                         temp = mono_emit_jit_icall (cfg, bblock, mono_create_corlib_exception_0, iargs, ip);
7365                                         break;
7366                                 case 1:
7367                                         iargs [1] = sp [0];
7368                                         temp = mono_emit_jit_icall (cfg, bblock, mono_create_corlib_exception_1, iargs, ip);
7369                                         break;
7370                                 case 2:
7371                                         iargs [1] = sp [0];
7372                                         iargs [2] = sp [1];
7373                                         temp = mono_emit_jit_icall (cfg, bblock, mono_create_corlib_exception_2, iargs, ip);
7374                                         break;
7375                                 default:
7376                                         g_assert_not_reached ();
7377                                 }
7378                                 NEW_TEMPLOAD (cfg, ins, temp);
7379                                 *sp ++ = ins;
7380
7381                                 ip += 5;
7382                                 inline_costs += 5;
7383                                 break;
7384                         }
7385
7386                         /* move the args to allow room for 'this' in the first position */
7387                         while (n--) {
7388                                 --sp;
7389                                 sp [1] = sp [0];
7390                         }
7391
7392                         /* check_call_signature () requires sp[0] to be set */
7393                         this_ins.type = STACK_OBJ;
7394                         sp [0] = &this_ins;
7395                         if (check_call_signature (cfg, fsig, sp))
7396                                 UNVERIFIED;
7397
7398                         handle_loaded_temps (cfg, bblock, stack_start, sp);
7399
7400                         if (mini_class_is_system_array (cmethod->klass)) {
7401                                 g_assert (!context_used);
7402
7403                                 NEW_METHODCONST (cfg, *sp, cmethod);
7404
7405                                 if (fsig->param_count == 2)
7406                                         /* Avoid varargs in the common case */
7407                                         temp = mono_emit_jit_icall (cfg, bblock, mono_array_new_2, sp, ip);
7408                                 else
7409                                         temp = handle_array_new (cfg, bblock, fsig->param_count, sp, ip);
7410                         } else if (cmethod->string_ctor) {
7411                                 g_assert (!context_used);
7412
7413                                 /* we simply pass a null pointer */
7414                                 NEW_PCONST (cfg, *sp, NULL); 
7415                                 /* now call the string ctor */
7416                                 temp = mono_emit_method_call_spilled (cfg, bblock, cmethod, fsig, sp, ip, NULL);
7417                         } else {
7418                                 MonoInst* callvirt_this_arg = NULL;
7419                                 
7420                                 if (cmethod->klass->valuetype) {
7421                                         iargs [0] = mono_compile_create_var (cfg, &cmethod->klass->byval_arg, OP_LOCAL);
7422                                         temp = iargs [0]->inst_c0;
7423
7424                                         NEW_TEMPLOADA (cfg, *sp, temp);
7425
7426                                         handle_initobj (cfg, bblock, *sp, NULL, cmethod->klass, stack_start, sp);
7427
7428                                         NEW_TEMPLOADA (cfg, *sp, temp);
7429
7430                                         /* 
7431                                          * The code generated by mini_emit_virtual_call () expects
7432                                          * iargs [0] to be a boxed instance, but luckily the vcall
7433                                          * will be transformed into a normal call there.
7434                                          */
7435                                 } else if (context_used) {
7436                                         MonoInst *rgctx, *data;
7437                                         int rgctx_info;
7438
7439                                         GET_RGCTX (rgctx, context_used);
7440                                         if (cfg->opt & MONO_OPT_SHARED)
7441                                                 rgctx_info = MONO_RGCTX_INFO_KLASS;
7442                                         else
7443                                                 rgctx_info = MONO_RGCTX_INFO_VTABLE;
7444                                         data = get_runtime_generic_context_ptr (cfg, method, context_used, bblock,
7445                                                 cmethod->klass, generic_context, rgctx, rgctx_info, ip);
7446
7447                                         temp = handle_alloc_from_inst (cfg, bblock, cmethod->klass, data, FALSE, ip);
7448                                         NEW_TEMPLOAD (cfg, *sp, temp);
7449                                 } else {
7450                                         MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
7451
7452                                         CHECK_TYPELOAD (cmethod->klass);
7453                                         if (mini_field_access_needs_cctor_run (cfg, method, vtable) && !(g_slist_find (class_inits, vtable))) {
7454                                                 guint8 *tramp = mono_create_class_init_trampoline (vtable);
7455                                                 mono_emit_native_call (cfg, bblock, tramp, 
7456                                                                                            helper_sig_class_init_trampoline,
7457                                                                                            NULL, ip, FALSE, FALSE);
7458                                                 if (cfg->verbose_level > 2)
7459                                                         g_print ("class %s.%s needs init call for ctor\n", cmethod->klass->name_space, cmethod->klass->name);
7460                                                 class_inits = g_slist_prepend (class_inits, vtable);
7461                                         }
7462                                         temp = handle_alloc (cfg, bblock, cmethod->klass, FALSE, ip);
7463                                         NEW_TEMPLOAD (cfg, *sp, temp);
7464                                 }
7465
7466                                 /* Avoid virtual calls to ctors if possible */
7467                                 if (cmethod->klass->marshalbyref)
7468                                         callvirt_this_arg = sp [0];
7469                                 
7470                                 if ((cfg->opt & MONO_OPT_INLINE) && cmethod && !context_used &&
7471                                     mono_method_check_inlining (cfg, cmethod) &&
7472                                     !mono_class_is_subclass_of (cmethod->klass, mono_defaults.exception_class, FALSE) &&
7473                                     !g_list_find (dont_inline, cmethod)) {
7474                                         int costs;
7475                                         MonoBasicBlock *ebblock;
7476                                         if ((costs = inline_method (cfg, cmethod, fsig, bblock, sp, ip, real_offset, dont_inline, &ebblock, FALSE))) {
7477
7478                                                 ip += 5;
7479                                                 real_offset += 5;
7480                                                 
7481                                                 GET_BBLOCK (cfg, bblock, ip);
7482                                                 ebblock->next_bb = bblock;
7483                                                 link_bblock (cfg, ebblock, bblock);
7484
7485                                                 NEW_TEMPLOAD (cfg, *sp, temp);
7486                                                 sp++;
7487
7488                                                 /* indicates start of a new block, and triggers a load 
7489                                                    of all stack arguments at bb boundarie */
7490                                                 bblock = ebblock;
7491
7492                                                 inline_costs += costs;
7493                                                 break;
7494                                                 
7495                                         } else {
7496                                                 /* Prevent inlining of methods which call other methods */
7497                                                 INLINE_FAILURE;
7498                                                 mono_emit_method_call_spilled (cfg, bblock, cmethod, fsig, sp, ip, callvirt_this_arg);
7499                                         }
7500                                 } else if (context_used &&
7501                                                 (cmethod->klass->valuetype ||
7502                                                 !mono_method_is_generic_sharable_impl (cmethod, TRUE))) {
7503                                         MonoInst *rgctx, *cmethod_addr;
7504
7505                                         g_assert (!callvirt_this_arg);
7506
7507                                         GET_RGCTX (rgctx, context_used);
7508                                         cmethod_addr = get_runtime_generic_context_method (cfg, method, context_used,
7509                                                         bblock, cmethod,
7510                                                         generic_context, rgctx, MONO_RGCTX_INFO_GENERIC_METHOD_CODE, ip);
7511
7512                                         mono_emit_calli_spilled (cfg, bblock, fsig, sp, cmethod_addr, ip);
7513                                 } else {
7514                                         /* Prevent inlining of methods which call other methods */
7515                                         INLINE_FAILURE;
7516                                         /* now call the actual ctor */
7517                                         mono_emit_method_call_spilled (cfg, bblock, cmethod, fsig, sp, ip, callvirt_this_arg);
7518                                 }
7519                         }
7520
7521                         NEW_TEMPLOAD (cfg, *sp, temp);
7522                         sp++;
7523                         
7524                         ip += 5;
7525                         inline_costs += 5;
7526                         break;
7527                 }
7528                 case CEE_ISINST:
7529                         CHECK_STACK (1);
7530                         --sp;
7531                         CHECK_OPSIZE (5);
7532                         token = read32 (ip + 1);
7533                         klass = mini_get_class (method, token, generic_context);
7534                         CHECK_TYPELOAD (klass);
7535                         if (sp [0]->type != STACK_OBJ)
7536                                 UNVERIFIED;
7537
7538                         if (cfg->generic_sharing_context)
7539                                 context_used = mono_class_check_context_used (klass);
7540
7541                         /* Needed by the code generated in inssel.brg */
7542                         if (!context_used)
7543                                 mono_get_got_var (cfg);
7544
7545                         if (context_used) {
7546                                 MonoInst *rgctx, *args [2];
7547                                 int temp;
7548
7549                                 /* obj */
7550                                 args [0] = *sp;
7551
7552                                 /* klass */
7553                                 GET_RGCTX (rgctx, context_used);
7554                                 args [1] = get_runtime_generic_context_ptr (cfg, method, context_used, bblock, klass,
7555                                         generic_context, rgctx, MONO_RGCTX_INFO_KLASS, ip);
7556
7557                                 temp = mono_emit_jit_icall (cfg, bblock, mono_object_isinst, args, ip);
7558                                 NEW_TEMPLOAD (cfg, *sp, temp);
7559
7560                                 sp++;
7561                                 ip += 5;
7562                                 inline_costs += 2;
7563                         } else if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
7564                         
7565                                 MonoMethod *mono_isinst;
7566                                 MonoInst *iargs [1];
7567                                 MonoBasicBlock *ebblock;
7568                                 int costs;
7569                                 int temp;
7570                                 
7571                                 mono_isinst = mono_marshal_get_isinst (klass); 
7572                                 iargs [0] = sp [0];
7573                                 
7574                                 costs = inline_method (cfg, mono_isinst, mono_method_signature (mono_isinst), bblock, 
7575                                                        iargs, ip, real_offset, dont_inline, &ebblock, TRUE);
7576                         
7577                                 g_assert (costs > 0);
7578                                 
7579                                 ip += 5;
7580                                 real_offset += 5;
7581                         
7582                                 GET_BBLOCK (cfg, bblock, ip);
7583                                 ebblock->next_bb = bblock;
7584                                 link_bblock (cfg, ebblock, bblock);
7585
7586                                 temp = iargs [0]->inst_i0->inst_c0;
7587                                 NEW_TEMPLOAD (cfg, *sp, temp);
7588                                 
7589                                 sp++;
7590                                 bblock = ebblock;
7591                                 inline_costs += costs;
7592                         } else {
7593                                 MONO_INST_NEW (cfg, ins, *ip);
7594                                 ins->type = STACK_OBJ;
7595                                 ins->inst_left = *sp;
7596                                 ins->inst_newa_class = klass;
7597                                 ins->klass = klass;
7598                                 *sp++ = emit_tree (cfg, bblock, ins, ip + 5);
7599                                 ip += 5;
7600                         }
7601                         break;
7602                 case CEE_UNBOX_ANY: {
7603                         MonoInst *iargs [3];
7604                         guint32 align;
7605
7606                         CHECK_STACK (1);
7607                         --sp;
7608                         CHECK_OPSIZE (5);
7609                         token = read32 (ip + 1);
7610                         klass = mini_get_class (method, token, generic_context);
7611                         CHECK_TYPELOAD (klass);
7612
7613                         if (cfg->generic_sharing_context)
7614                                 context_used = mono_class_check_context_used (klass);
7615
7616                         if (generic_class_is_reference_type (cfg, klass)) {
7617                                 switch (emit_castclass (klass, token, context_used, FALSE,
7618                                                 cfg, method, arg_array, param_types, dont_inline, end, header,
7619                                                 generic_context, &bblock, &ip, &sp, &inline_costs, &real_offset)) {
7620                                 case 0: break;
7621                                 case -1: goto unverified;
7622                                 case -2: goto exception_exit;
7623                                 default: g_assert_not_reached ();
7624                                 }
7625                                 break;
7626                         }
7627
7628                         if (mono_class_is_nullable (klass)) {
7629                                 int v;
7630                                 MonoInst *rgctx = NULL;
7631
7632                                 if (context_used)
7633                                         GET_RGCTX (rgctx, context_used);
7634
7635                                 v = handle_unbox_nullable (cfg, method, context_used, bblock, *sp, ip, klass,
7636                                         generic_context, rgctx);
7637                                 NEW_TEMPLOAD (cfg, *sp, v);
7638                                 sp ++;
7639                                 ip += 5;
7640                                 break;
7641                         }
7642
7643                         switch (emit_unbox (klass, token, context_used,
7644                                         cfg, method, arg_array, param_types, dont_inline, end, header,
7645                                         generic_context, &bblock, &ip, &sp, &inline_costs, &real_offset)) {
7646                         case 0: break;
7647                         case -1: goto unverified;
7648                         case -2: goto exception_exit;
7649                         default: g_assert_not_reached ();
7650                         }
7651                         ip += 5;
7652                         /* LDOBJ impl */
7653                         n = mono_class_value_size (klass, &align);
7654                         ins = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
7655                         NEW_TEMPLOADA (cfg, iargs [0], ins->inst_c0);
7656                         if ((cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 5) {
7657                                 MonoInst *copy;
7658                                 NEW_MEMCPY (cfg, copy, iargs [0], *sp, n, align);
7659                                 MONO_ADD_INS (bblock, copy);
7660                         } else {
7661                                 MonoMethod *memcpy_method = get_memcpy_method ();
7662                                 iargs [1] = *sp;
7663                                 NEW_ICONST (cfg, iargs [2], n);
7664
7665                                 mono_emit_method_call_spilled (cfg, bblock, memcpy_method, memcpy_method->signature, iargs, ip, NULL);
7666                         }
7667                         NEW_TEMPLOAD (cfg, *sp, ins->inst_c0);
7668                         ++sp;
7669                         inline_costs += 2;
7670                         break;
7671                 }
7672                 case CEE_UNBOX:
7673                         CHECK_STACK (1);
7674                         --sp;
7675                         CHECK_OPSIZE (5);
7676                         token = read32 (ip + 1);
7677                         klass = mini_get_class (method, token, generic_context);
7678                         CHECK_TYPELOAD (klass);
7679
7680                         if (cfg->generic_sharing_context)
7681                                 context_used = mono_class_check_context_used (klass);
7682
7683                         if (mono_class_is_nullable (klass)) {
7684                                 int v;
7685                                 MonoInst *rgctx = NULL;
7686
7687                                 if (context_used)
7688                                         GET_RGCTX (rgctx, context_used);
7689                                 v = handle_unbox_nullable (cfg, method, context_used, bblock, *sp, ip, klass,
7690                                         generic_context, rgctx);
7691                                 NEW_TEMPLOAD (cfg, *sp, v);
7692                                 sp ++;
7693                                 ip += 5;
7694                                 break;
7695                         }
7696
7697                         switch (emit_unbox (klass, token, context_used,
7698                                         cfg, method, arg_array, param_types, dont_inline, end, header,
7699                                         generic_context, &bblock, &ip, &sp, &inline_costs, &real_offset)) {
7700                         case 0: break;
7701                         case -1: goto unverified;
7702                         case -2: goto exception_exit;
7703                         default: g_assert_not_reached ();
7704                         }
7705
7706                         sp++;
7707                         ip += 5;
7708                         inline_costs += 2;
7709                         break;
7710                 case CEE_CASTCLASS:
7711                         CHECK_STACK (1);
7712                         --sp;
7713                         CHECK_OPSIZE (5);
7714                         token = read32 (ip + 1);
7715                         klass = mini_get_class (method, token, generic_context);
7716                         CHECK_TYPELOAD (klass);
7717                         if (sp [0]->type != STACK_OBJ)
7718                                 UNVERIFIED;
7719
7720                         if (cfg->generic_sharing_context)
7721                                 context_used = mono_class_check_context_used (klass);
7722
7723                         switch (emit_castclass (klass, token, context_used, TRUE,
7724                                         cfg, method, arg_array, param_types, dont_inline, end, header,
7725                                         generic_context, &bblock, &ip, &sp, &inline_costs, &real_offset)) {
7726                         case 0: break;
7727                         case -1: goto unverified;
7728                         case -2: goto exception_exit;
7729                         default: g_assert_not_reached ();
7730                         }
7731                         break;
7732                 case CEE_THROW:
7733                         CHECK_STACK (1);
7734                         MONO_INST_NEW (cfg, ins, OP_THROW);
7735                         --sp;
7736                         ins->inst_left = *sp;
7737                         ip++;
7738                         bblock->out_of_line = TRUE;
7739                         MONO_ADD_INS (bblock, ins);
7740                         MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
7741                         ins->cil_code = ip - 1;
7742                         MONO_ADD_INS (bblock, ins);
7743                         sp = stack_start;
7744                         
7745                         link_bblock (cfg, bblock, end_bblock);
7746                         start_new_bblock = 1;
7747                         break;
7748                 case CEE_LDFLD:
7749                 case CEE_LDFLDA:
7750                 case CEE_STFLD: {
7751                         MonoInst *offset_ins;
7752                         MonoClassField *field;
7753                         MonoBasicBlock *ebblock;
7754                         int costs;
7755                         guint foffset;
7756
7757                         if (*ip == CEE_STFLD) {
7758                                 CHECK_STACK (2);
7759                                 sp -= 2;
7760                         } else {
7761                                 CHECK_STACK (1);
7762                                 --sp;
7763                         }
7764                         if (sp [0]->type == STACK_I4 || sp [0]->type == STACK_I8 || sp [0]->type == STACK_R8)
7765                                 UNVERIFIED;
7766                         if (*ip != CEE_LDFLD && sp [0]->type == STACK_VTYPE)
7767                                 UNVERIFIED;
7768                         CHECK_OPSIZE (5);
7769                         token = read32 (ip + 1);
7770                         if (method->wrapper_type != MONO_WRAPPER_NONE) {
7771                                 field = mono_method_get_wrapper_data (method, token);
7772                                 klass = field->parent;
7773                         } else {
7774                                 field = mono_field_from_token (image, token, &klass, generic_context);
7775                         }
7776                         if (!field)
7777                                 goto load_error;
7778                         mono_class_init (klass);
7779                         if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_field (method, field))
7780                                 FIELD_ACCESS_FAILURE;
7781
7782                         foffset = klass->valuetype? field->offset - sizeof (MonoObject): field->offset;
7783                         /* FIXME: mark instructions for use in SSA */
7784                         if (*ip == CEE_STFLD) {
7785                                 if (target_type_is_incompatible (cfg, field->type, sp [1]))
7786                                         UNVERIFIED;
7787                                 if ((klass->marshalbyref && !MONO_CHECK_THIS (sp [0])) || klass->contextbound || klass == mono_defaults.marshalbyrefobject_class) {
7788                                         MonoMethod *stfld_wrapper = mono_marshal_get_stfld_wrapper (field->type); 
7789                                         MonoInst *iargs [5];
7790
7791                                         iargs [0] = sp [0];
7792                                         NEW_CLASSCONST (cfg, iargs [1], klass);
7793                                         NEW_FIELDCONST (cfg, iargs [2], field);
7794                                         NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : 
7795                                                     field->offset);
7796                                         iargs [4] = sp [1];
7797
7798                                         if (cfg->opt & MONO_OPT_INLINE) {
7799                                                 costs = inline_method (cfg, stfld_wrapper, mono_method_signature (stfld_wrapper), bblock, 
7800                                                                 iargs, ip, real_offset, dont_inline, &ebblock, TRUE);
7801                                                 g_assert (costs > 0);
7802                                                       
7803                                                 ip += 5;
7804                                                 real_offset += 5;
7805
7806                                                 GET_BBLOCK (cfg, bblock, ip);
7807                                                 ebblock->next_bb = bblock;
7808                                                 link_bblock (cfg, ebblock, bblock);
7809
7810                                                 /* indicates start of a new block, and triggers a load 
7811                                                    of all stack arguments at bb boundarie */
7812                                                 bblock = ebblock;
7813
7814                                                 inline_costs += costs;
7815                                                 break;
7816                                         } else {
7817                                                 mono_emit_method_call_spilled (cfg, bblock, stfld_wrapper, mono_method_signature (stfld_wrapper), iargs, ip, NULL);
7818                                         }
7819 #if HAVE_WRITE_BARRIERS
7820                                 } else if (mini_type_to_stind (cfg, field->type) == CEE_STIND_REF && !(sp [1]->opcode == OP_PCONST && sp [1]->inst_c0 == 0)) {
7821                                         /* insert call to write barrier */
7822                                         MonoMethod *write_barrier = mono_marshal_get_write_barrier ();
7823                                         MonoInst *iargs [2];
7824                                         NEW_ICONST (cfg, offset_ins, foffset);
7825                                         MONO_INST_NEW (cfg, ins, OP_PADD);
7826                                         ins->inst_left = *sp;
7827                                         ins->inst_right = offset_ins;
7828                                         ins->type = STACK_MP;
7829                                         ins->klass = mono_defaults.object_class;
7830                                         iargs [0] = ins;
7831                                         iargs [1] = sp [1];
7832                                         mono_emit_method_call_spilled (cfg, bblock, write_barrier, mono_method_signature (write_barrier), iargs, ip, NULL);
7833 #endif
7834 #ifdef MONO_ARCH_SOFT_FLOAT
7835                                 } else if (mini_type_to_stind (cfg, field->type) == CEE_STIND_R4) {
7836                                         NEW_ICONST (cfg, offset_ins, foffset);
7837                                         MONO_INST_NEW (cfg, ins, OP_PADD);
7838                                         ins->inst_left = *sp;
7839                                         ins->inst_right = offset_ins;
7840                                         ins->type = STACK_MP;
7841                                         ins->klass = mono_defaults.object_class;
7842                                         handle_store_float (cfg, bblock, ins, sp [1], ip);
7843 #endif
7844                                 } else {
7845                                         MonoInst *store;
7846                                         NEW_ICONST (cfg, offset_ins, foffset);
7847                                         MONO_INST_NEW (cfg, ins, OP_PADD);
7848                                         ins->inst_left = *sp;
7849                                         ins->inst_right = offset_ins;
7850                                         ins->type = STACK_MP;
7851
7852                                         MONO_INST_NEW (cfg, store, mini_type_to_stind (cfg, field->type));
7853                                         store->inst_left = ins;
7854                                         store->inst_right = sp [1];
7855                                         handle_loaded_temps (cfg, bblock, stack_start, sp);
7856                                         store->flags |= ins_flag;
7857                                         ins_flag = 0;
7858                                         if (store->opcode == CEE_STOBJ) {
7859                                                 handle_stobj (cfg, bblock, ins, sp [1], ip, 
7860                                                               mono_class_from_mono_type (field->type), FALSE, FALSE, TRUE);
7861                                         } else
7862                                                 MONO_ADD_INS (bblock, store);
7863                                 }
7864                         } else {
7865                                 if ((klass->marshalbyref && !MONO_CHECK_THIS (sp [0])) || klass->contextbound || klass == mono_defaults.marshalbyrefobject_class) {
7866                                         MonoMethod *wrapper = (*ip == CEE_LDFLDA) ? mono_marshal_get_ldflda_wrapper (field->type) : mono_marshal_get_ldfld_wrapper (field->type); 
7867                                         MonoInst *iargs [4];
7868                                         int temp;
7869                                         
7870                                         iargs [0] = sp [0];
7871                                         NEW_CLASSCONST (cfg, iargs [1], klass);
7872                                         NEW_FIELDCONST (cfg, iargs [2], field);
7873                                         NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset);
7874                                         if ((cfg->opt & MONO_OPT_INLINE) && !MONO_TYPE_ISSTRUCT (mono_method_signature (wrapper)->ret)) {
7875                                                 costs = inline_method (cfg, wrapper, mono_method_signature (wrapper), bblock, 
7876                                                                 iargs, ip, real_offset, dont_inline, &ebblock, TRUE);
7877                                                 g_assert (costs > 0);
7878                                                       
7879                                                 ip += 5;
7880                                                 real_offset += 5;
7881
7882                                                 GET_BBLOCK (cfg, bblock, ip);
7883                                                 ebblock->next_bb = bblock;
7884                                                 link_bblock (cfg, ebblock, bblock);
7885
7886                                                 temp = iargs [0]->inst_i0->inst_c0;
7887
7888                                                 NEW_TEMPLOAD (cfg, *sp, temp);
7889                                                 sp++;
7890
7891                                                 /* indicates start of a new block, and triggers a load of
7892                                                    all stack arguments at bb boundarie */
7893                                                 bblock = ebblock;
7894                                                 
7895                                                 inline_costs += costs;
7896                                                 break;
7897                                         } else {
7898                                                 temp = mono_emit_method_call_spilled (cfg, bblock, wrapper, mono_method_signature (wrapper), iargs, ip, NULL);
7899                                                 NEW_TEMPLOAD (cfg, *sp, temp);
7900                                                 NEW_TEMPLOAD_SOFT_FLOAT (cfg, bblock, *sp, temp, ip);
7901                                                 sp++;
7902                                         }
7903                                 } else {
7904                                         NEW_ICONST (cfg, offset_ins, foffset);
7905                                         MONO_INST_NEW (cfg, ins, OP_PADD);
7906                                         ins->inst_left = *sp;
7907                                         ins->inst_right = offset_ins;
7908                                         ins->type = STACK_MP;
7909
7910                                         if (*ip == CEE_LDFLDA) {
7911                                                 ins->klass = mono_class_from_mono_type (field->type);
7912                                                 *sp++ = ins;
7913                                         } else {
7914                                                 MonoInst *load;
7915                                                 MONO_INST_NEW (cfg, load, mini_type_to_ldind (cfg, field->type));
7916                                                 type_to_eval_stack_type (cfg, field->type, load);
7917                                                 load->inst_left = ins;
7918                                                 load->flags |= ins_flag;
7919                                                 ins_flag = 0;
7920 #ifdef MONO_ARCH_SOFT_FLOAT
7921                                                 if (mini_type_to_ldind (cfg, field->type) == CEE_LDIND_R4) {
7922                                                         int temp;
7923                                                         temp = handle_load_float (cfg, bblock, ins, ip);
7924                                                         NEW_TEMPLOAD (cfg, *sp, temp);
7925                                                         sp++;
7926                                                 } else
7927 #endif
7928                                                 *sp++ = load;
7929                                         }
7930                                 }
7931                         }
7932                         ip += 5;
7933                         break;
7934                 }
7935                 case CEE_LDSFLD:
7936                 case CEE_LDSFLDA:
7937                 case CEE_STSFLD: {
7938                         MonoClassField *field;
7939                         gboolean is_special_static;
7940                         gpointer addr = NULL;
7941
7942                         CHECK_OPSIZE (5);
7943                         token = read32 (ip + 1);
7944                         if (method->wrapper_type != MONO_WRAPPER_NONE) {
7945                                 field = mono_method_get_wrapper_data (method, token);
7946                                 klass = field->parent;
7947                         }
7948                         else
7949                                 field = mono_field_from_token (image, token, &klass, generic_context);
7950                         if (!field)
7951                                 goto load_error;
7952                         mono_class_init (klass);
7953                         if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_field (method, field))
7954                                 FIELD_ACCESS_FAILURE;
7955
7956                         /*
7957                          * We can only support shared generic static
7958                          * field access on architectures where the
7959                          * trampoline code has been extended to handle
7960                          * the generic class init.
7961                          */
7962 #ifndef MONO_ARCH_VTABLE_REG
7963                         GENERIC_SHARING_FAILURE (*ip);
7964 #endif
7965
7966                         if (cfg->generic_sharing_context)
7967                                 context_used = mono_class_check_context_used (klass);
7968
7969                         g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
7970
7971                         if ((*ip) == CEE_STSFLD)
7972                                 handle_loaded_temps (cfg, bblock, stack_start, sp);
7973
7974                         is_special_static = mono_class_field_is_special_static (field);
7975
7976                         if ((cfg->opt & MONO_OPT_SHARED) ||
7977                                         (cfg->compile_aot && is_special_static) ||
7978                                         (context_used && is_special_static)) {
7979                                 int temp;
7980                                 MonoInst *iargs [2];
7981
7982                                 g_assert (field->parent);
7983                                 if ((cfg->opt & MONO_OPT_SHARED) || cfg->compile_aot) {
7984                                         MonoInst *domain_var;
7985                                         /* avoid depending on undefined C behavior in sequence points */
7986                                         domain_var = mono_get_domainvar (cfg);
7987                                         NEW_TEMPLOAD (cfg, iargs [0], domain_var->inst_c0);
7988                                 } else {
7989                                         NEW_DOMAINCONST (cfg, iargs [0]);
7990                                 }
7991                                 if (context_used) {
7992                                         MonoInst *rgctx;
7993
7994                                         GET_RGCTX (rgctx, context_used);
7995                                         iargs [1] = get_runtime_generic_context_field (cfg, method, context_used,
7996                                                         bblock, field,
7997                                                         generic_context, rgctx, MONO_RGCTX_INFO_CLASS_FIELD, ip);
7998                                 } else {
7999                                         NEW_FIELDCONST (cfg, iargs [1], field);
8000                                 }
8001                                 temp = mono_emit_jit_icall (cfg, bblock, mono_class_static_field_address, iargs, ip);
8002                                 NEW_TEMPLOAD (cfg, ins, temp);
8003                         } else if (context_used) {
8004                                 MonoInst *rgctx, *static_data;
8005
8006                                 /*
8007                                 g_print ("sharing static field access in %s.%s.%s - depth %d offset %d\n",
8008                                         method->klass->name_space, method->klass->name, method->name,
8009                                         depth, field->offset);
8010                                 */
8011
8012                                 if (mono_class_needs_cctor_run (klass, method)) {
8013                                         MonoMethodSignature *sig = helper_sig_generic_class_init_trampoline;
8014                                         MonoCallInst *call;
8015                                         MonoInst *vtable, *rgctx;
8016
8017                                         GET_RGCTX (rgctx, context_used);
8018                                         vtable = get_runtime_generic_context_ptr (cfg, method, context_used, bblock, klass,
8019                                                         generic_context, rgctx, MONO_RGCTX_INFO_VTABLE, ip);
8020
8021                                         call = mono_emit_call_args (cfg, bblock, sig, NULL, FALSE, FALSE, ip, FALSE);
8022                                         call->inst.opcode = OP_TRAMPCALL_VTABLE;
8023                                         call->fptr = mono_create_generic_class_init_trampoline ();
8024
8025                                         call->inst.inst_left = vtable;
8026
8027                                         mono_spill_call (cfg, bblock, call, sig, FALSE, ip, FALSE);
8028                                 }
8029
8030                                 /*
8031                                  * The pointer we're computing here is
8032                                  *
8033                                  *   super_info.static_data + field->offset
8034                                  */
8035                                 GET_RGCTX (rgctx, context_used);
8036                                 static_data = get_runtime_generic_context_ptr (cfg, method, context_used, bblock, klass,
8037                                         generic_context, rgctx, MONO_RGCTX_INFO_STATIC_DATA, ip);
8038
8039                                 if (field->offset == 0) {
8040                                         ins = static_data;
8041                                 } else {
8042                                         MonoInst *field_offset;
8043
8044                                         NEW_ICONST (cfg, field_offset, field->offset);
8045
8046                                         MONO_INST_NEW (cfg, ins, OP_PADD);
8047                                         ins->inst_left = static_data;
8048                                         ins->inst_right = field_offset;
8049                                         ins->type = STACK_PTR;
8050                                         ins->klass = klass;
8051                                 }
8052                         } else {
8053                                 MonoVTable *vtable;
8054
8055                                 vtable = mono_class_vtable (cfg->domain, klass);
8056                                 CHECK_TYPELOAD (klass);
8057                                 if (!is_special_static) {
8058                                         if (mini_field_access_needs_cctor_run (cfg, method, vtable) && !(g_slist_find (class_inits, vtable))) {
8059                                                 guint8 *tramp = mono_create_class_init_trampoline (vtable);
8060                                                 mono_emit_native_call (cfg, bblock, tramp, 
8061                                                                                            helper_sig_class_init_trampoline,
8062                                                                                            NULL, ip, FALSE, FALSE);
8063                                                 if (cfg->verbose_level > 2)
8064                                                         g_print ("class %s.%s needs init call for %s\n", klass->name_space, klass->name, field->name);
8065                                                 class_inits = g_slist_prepend (class_inits, vtable);
8066                                         } else {
8067                                                 if (cfg->run_cctors) {
8068                                                         MonoException *ex;
8069                                                         /* This makes so that inline cannot trigger */
8070                                                         /* .cctors: too many apps depend on them */
8071                                                         /* running with a specific order... */
8072                                                         if (! vtable->initialized)
8073                                                                 INLINE_FAILURE;
8074                                                         ex = mono_runtime_class_init_full (vtable, FALSE);
8075                                                         if (ex) {
8076                                                                 set_exception_object (cfg, ex);
8077                                                                 goto exception_exit;
8078                                                         }                                       
8079                                                 }
8080                                         }
8081                                         addr = (char*)vtable->data + field->offset;
8082
8083                                         if (cfg->compile_aot)
8084                                                 NEW_SFLDACONST (cfg, ins, field);
8085                                         else
8086                                                 NEW_PCONST (cfg, ins, addr);
8087                                 } else {
8088                                         int temp;
8089                                         MonoInst *iargs [1];
8090
8091                                         /* The special_static_fields
8092                                          * field is init'd in
8093                                          * mono_class_vtable, so it
8094                                          * needs to be called here.
8095                                          */
8096                                         if (!(cfg->opt & MONO_OPT_SHARED)) {
8097                                                 mono_class_vtable (cfg->domain, klass);
8098                                                 CHECK_TYPELOAD (klass);
8099                                         }
8100                                         mono_domain_lock (cfg->domain);
8101                                         if (cfg->domain->special_static_fields)
8102                                                 addr = g_hash_table_lookup (cfg->domain->special_static_fields, field);
8103                                         mono_domain_unlock (cfg->domain);
8104
8105                                         /* 
8106                                          * insert call to mono_threads_get_static_data (GPOINTER_TO_UINT (addr)) 
8107                                          * This could be later optimized to do just a couple of
8108                                          * memory dereferences with constant offsets.
8109                                          */
8110                                         NEW_ICONST (cfg, iargs [0], GPOINTER_TO_UINT (addr));
8111                                         temp = mono_emit_jit_icall (cfg, bblock, mono_get_special_static_data, iargs, ip);
8112                                         NEW_TEMPLOAD (cfg, ins, temp);
8113                                 }
8114                         }
8115
8116                         /* FIXME: mark instructions for use in SSA */
8117                         if (*ip == CEE_LDSFLDA) {
8118                                 ins->klass = mono_class_from_mono_type (field->type);
8119                                 *sp++ = ins;
8120                         } else if (*ip == CEE_STSFLD) {
8121                                 MonoInst *store;
8122                                 CHECK_STACK (1);
8123                                 sp--;
8124                                 MONO_INST_NEW (cfg, store, mini_type_to_stind (cfg, field->type));
8125                                 store->inst_left = ins;
8126                                 store->inst_right = sp [0];
8127                                 store->flags |= ins_flag;
8128                                 ins_flag = 0;
8129
8130 #ifdef MONO_ARCH_SOFT_FLOAT
8131                                 if (store->opcode == CEE_STIND_R4)
8132                                         handle_store_float (cfg, bblock, ins, sp [0], ip);
8133                                 else
8134 #endif
8135                                 if (store->opcode == CEE_STOBJ) {
8136                                         handle_stobj (cfg, bblock, ins, sp [0], ip, mono_class_from_mono_type (field->type), FALSE, FALSE, FALSE);
8137                                 } else
8138                                         MONO_ADD_INS (bblock, store);
8139                         } else {
8140                                 gboolean is_const = FALSE;
8141                                 MonoVTable *vtable = NULL;
8142
8143                                 if (!context_used)
8144                                         vtable = mono_class_vtable (cfg->domain, klass);
8145
8146                                 CHECK_TYPELOAD (klass);
8147                                 if (!context_used && !((cfg->opt & MONO_OPT_SHARED) || cfg->compile_aot) && 
8148                                     vtable->initialized && (field->type->attrs & FIELD_ATTRIBUTE_INIT_ONLY)) {
8149                                         gpointer addr = (char*)vtable->data + field->offset;
8150                                         int ro_type = field->type->type;
8151                                         if (ro_type == MONO_TYPE_VALUETYPE && field->type->data.klass->enumtype) {
8152                                                 ro_type = field->type->data.klass->enum_basetype->type;
8153                                         }
8154                                         /* g_print ("RO-FIELD %s.%s:%s\n", klass->name_space, klass->name, field->name);*/
8155                                         is_const = TRUE;
8156                                         switch (ro_type) {
8157                                         case MONO_TYPE_BOOLEAN:
8158                                         case MONO_TYPE_U1:
8159                                                 NEW_ICONST (cfg, *sp, *((guint8 *)addr));
8160                                                 sp++;
8161                                                 break;
8162                                         case MONO_TYPE_I1:
8163                                                 NEW_ICONST (cfg, *sp, *((gint8 *)addr));
8164                                                 sp++;
8165                                                 break;                                          
8166                                         case MONO_TYPE_CHAR:
8167                                         case MONO_TYPE_U2:
8168                                                 NEW_ICONST (cfg, *sp, *((guint16 *)addr));
8169                                                 sp++;
8170                                                 break;
8171                                         case MONO_TYPE_I2:
8172                                                 NEW_ICONST (cfg, *sp, *((gint16 *)addr));
8173                                                 sp++;
8174                                                 break;
8175                                                 break;
8176                                         case MONO_TYPE_I4:
8177                                                 NEW_ICONST (cfg, *sp, *((gint32 *)addr));
8178                                                 sp++;
8179                                                 break;                                          
8180                                         case MONO_TYPE_U4:
8181                                                 NEW_ICONST (cfg, *sp, *((guint32 *)addr));
8182                                                 sp++;
8183                                                 break;
8184 #ifndef HAVE_MOVING_COLLECTOR
8185                                         case MONO_TYPE_I:
8186                                         case MONO_TYPE_U:
8187                                         case MONO_TYPE_STRING:
8188                                         case MONO_TYPE_OBJECT:
8189                                         case MONO_TYPE_CLASS:
8190                                         case MONO_TYPE_SZARRAY:
8191                                         case MONO_TYPE_PTR:
8192                                         case MONO_TYPE_FNPTR:
8193                                         case MONO_TYPE_ARRAY:
8194                                                 NEW_PCONST (cfg, *sp, *((gpointer *)addr));
8195                                                 type_to_eval_stack_type (cfg, field->type, *sp);
8196                                                 sp++;
8197                                                 break;
8198 #endif
8199                                         case MONO_TYPE_I8:
8200                                         case MONO_TYPE_U8:
8201                                                 MONO_INST_NEW (cfg, *sp, OP_I8CONST);
8202                                                 sp [0]->type = STACK_I8;
8203                                                 sp [0]->inst_l = *((gint64 *)addr);
8204                                                 sp++;
8205                                                 break;
8206                                         case MONO_TYPE_R4:
8207                                         case MONO_TYPE_R8:
8208                                         case MONO_TYPE_VALUETYPE:
8209                                         default:
8210                                                 is_const = FALSE;
8211                                                 break;
8212                                         }
8213                                 }
8214
8215                                 if (!is_const) {
8216                                         MonoInst *load;
8217                                         CHECK_STACK_OVF (1);
8218                                         MONO_INST_NEW (cfg, load, mini_type_to_ldind (cfg, field->type));
8219                                         type_to_eval_stack_type (cfg, field->type, load);
8220                                         load->inst_left = ins;
8221                                         load->flags |= ins_flag;
8222 #ifdef MONO_ARCH_SOFT_FLOAT
8223                                         if (load->opcode == CEE_LDIND_R4) {
8224                                                 int temp;
8225                                                 temp = handle_load_float (cfg, bblock, ins, ip);
8226                                                 NEW_TEMPLOAD (cfg, load, temp);
8227                                         }
8228 #endif
8229                                         *sp++ = load;
8230                                         ins_flag = 0;
8231                                 }
8232                         }
8233                         ip += 5;
8234                         break;
8235                 }
8236                 case CEE_STOBJ:
8237                         CHECK_STACK (2);
8238                         sp -= 2;
8239                         CHECK_OPSIZE (5);
8240                         token = read32 (ip + 1);
8241                         klass = mini_get_class (method, token, generic_context);
8242                         CHECK_TYPELOAD (klass);
8243                         n = mini_type_to_stind (cfg, &klass->byval_arg);
8244                         /* FIXME: handle CEE_STIND_R4 */
8245                         if (n == CEE_STOBJ) {
8246                                 handle_stobj (cfg, bblock, sp [0], sp [1], ip, klass, FALSE, FALSE, TRUE);
8247                         } else {
8248                                 /* FIXME: should check item at sp [1] is compatible with the type of the store. */
8249                                 MonoInst *store;
8250                                 MONO_INST_NEW (cfg, store, n);
8251                                 store->inst_left = sp [0];
8252                                 store->inst_right = sp [1];
8253                                 store->flags |= ins_flag;
8254                                 MONO_ADD_INS (bblock, store);
8255                         }
8256                         ins_flag = 0;
8257                         ip += 5;
8258                         inline_costs += 1;
8259                         break;
8260                 case CEE_BOX: {
8261                         MonoInst *val;
8262
8263                         CHECK_STACK (1);
8264                         --sp;
8265                         val = *sp;
8266                         CHECK_OPSIZE (5);
8267                         token = read32 (ip + 1);
8268                         klass = mini_get_class (method, token, generic_context);
8269                         CHECK_TYPELOAD (klass);
8270
8271                         if (cfg->generic_sharing_context)
8272                                 context_used =  mono_class_check_context_used (klass);
8273
8274                         if (generic_class_is_reference_type (cfg, klass)) {
8275                                 *sp++ = val;
8276                                 ip += 5;
8277                                 break;
8278                         }
8279                         if (klass == mono_defaults.void_class)
8280                                 UNVERIFIED;
8281                         if (target_type_is_incompatible (cfg, &klass->byval_arg, *sp))
8282                                 UNVERIFIED;
8283                         /* frequent check in generic code: box (struct), brtrue */
8284                         if (!mono_class_is_nullable (klass) &&
8285                             ip + 5 < end && ip_in_bb (cfg, bblock, ip + 5) && (ip [5] == CEE_BRTRUE || ip [5] == CEE_BRTRUE_S)) {
8286                                 /*g_print ("box-brtrue opt at 0x%04x in %s\n", real_offset, method->name);*/
8287                                 MONO_INST_NEW (cfg, ins, CEE_POP);
8288                                 MONO_ADD_INS (bblock, ins);
8289                                 ins->inst_i0 = *sp;
8290                                 ip += 5;
8291                                 cfg->ip = ip;
8292                                 MONO_INST_NEW (cfg, ins, OP_BR);
8293                                 MONO_ADD_INS (bblock, ins);
8294                                 if (*ip == CEE_BRTRUE_S) {
8295                                         CHECK_OPSIZE (2);
8296                                         ip++;
8297                                         target = ip + 1 + (signed char)(*ip);
8298                                         ip++;
8299                                 } else {
8300                                         CHECK_OPSIZE (5);
8301                                         ip++;
8302                                         target = ip + 4 + (gint)(read32 (ip));
8303                                         ip += 4;
8304                                 }
8305                                 GET_BBLOCK (cfg, tblock, target);
8306                                 link_bblock (cfg, bblock, tblock);
8307                                 CHECK_BBLOCK (target, ip, tblock);
8308                                 ins->inst_target_bb = tblock;
8309                                 GET_BBLOCK (cfg, tblock, ip);
8310                                 link_bblock (cfg, bblock, tblock);
8311                                 if (sp != stack_start) {
8312                                         handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
8313                                         sp = stack_start;
8314                                         CHECK_UNVERIFIABLE (cfg);
8315                                 }
8316                                 start_new_bblock = 1;
8317                                 break;
8318                         }
8319                         if (context_used) {
8320                                 MonoInst *rgctx;
8321
8322                                 if (mono_class_is_nullable (klass)) {
8323                                         GET_RGCTX (rgctx, context_used);
8324                                         *sp++ = handle_box_nullable_from_inst (cfg, method, context_used, bblock, val,
8325                                                         ip, klass, generic_context, rgctx);
8326                                 } else {
8327                                         MonoInst *data;
8328                                         int rgctx_info;
8329
8330                                         GET_RGCTX (rgctx, context_used);
8331                                         if (cfg->opt & MONO_OPT_SHARED)
8332                                                 rgctx_info = MONO_RGCTX_INFO_KLASS;
8333                                         else
8334                                                 rgctx_info = MONO_RGCTX_INFO_VTABLE;
8335                                         data = get_runtime_generic_context_ptr (cfg, method, context_used, bblock, klass,
8336                                                         generic_context, rgctx, rgctx_info, ip);
8337
8338                                         *sp++ = handle_box_from_inst (cfg, bblock, val, ip, klass, data);
8339                                 }
8340                         } else {
8341                                 *sp++ = handle_box (cfg, bblock, val, ip, klass);
8342                         }
8343                         ip += 5;
8344                         inline_costs += 1;
8345                         break;
8346                 }
8347                 case CEE_NEWARR:
8348                         CHECK_STACK (1);
8349                         --sp;
8350
8351                         CHECK_OPSIZE (5);
8352                         token = read32 (ip + 1);
8353
8354                         /* allocate the domainvar - becaus this is used in decompose_foreach */
8355                         if (cfg->opt & MONO_OPT_SHARED) {
8356                                 mono_get_domainvar (cfg);
8357                                 /* LAME-IR: Mark it as used since otherwise it will be optimized away */
8358                                 cfg->domainvar->flags |= MONO_INST_VOLATILE;
8359                         }
8360
8361                         /* Ditto */
8362                         mono_get_got_var (cfg);
8363
8364                         klass = mini_get_class (method, token, generic_context);
8365                         CHECK_TYPELOAD (klass);
8366
8367                         if (cfg->generic_sharing_context)
8368                                 context_used = mono_class_check_context_used (klass);
8369
8370                         if (context_used) {
8371                                 MonoInst *rgctx, *args [3];
8372                                 int temp;
8373
8374                                 /* domain */
8375                                 /* FIXME: what about domain-neutral code? */
8376                                 NEW_DOMAINCONST (cfg, args [0]);
8377
8378                                 /* klass */
8379                                 GET_RGCTX (rgctx, context_used);
8380                                 args [1] = get_runtime_generic_context_ptr (cfg, method, context_used, bblock, klass,
8381                                         generic_context, rgctx, MONO_RGCTX_INFO_KLASS, ip);
8382
8383                                 /* array len */
8384                                 args [2] = *sp;
8385
8386                                 temp = mono_emit_jit_icall (cfg, bblock, mono_array_new, args, ip);
8387                                 NEW_TEMPLOAD (cfg, ins, temp);
8388                         } else {
8389                                 MONO_INST_NEW (cfg, ins, *ip);
8390                                 ins->inst_newa_class = klass;
8391                                 ins->inst_newa_len = *sp;
8392                                 ins->type = STACK_OBJ;
8393                                 ins->klass = mono_array_class_get (klass, 1);
8394                         }
8395
8396                         ip += 5;
8397                         *sp++ = ins;
8398                         /* 
8399                          * we store the object so calls to create the array are not interleaved
8400                          * with the arguments of other calls.
8401                          */
8402                         if (1) {
8403                                 MonoInst *store, *temp, *load;
8404                                 const char *data_ptr;
8405                                 int data_size = 0;
8406                                 --sp;
8407                                 temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
8408                                 NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
8409                                 store->cil_code = ins->cil_code;
8410                                 MONO_ADD_INS (bblock, store);
8411                                 /* 
8412                                  * we inline/optimize the initialization sequence if possible.
8413                                  * we should also allocate the array as not cleared, since we spend as much time clearing to 0 as initializing
8414                                  * for small sizes open code the memcpy
8415                                  * ensure the rva field is big enough
8416                                  */
8417                                 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))) {
8418                                         MonoMethod *memcpy_method = get_memcpy_method ();
8419                                         MonoInst *data_offset, *add;
8420                                         MonoInst *iargs [3];
8421                                         NEW_ICONST (cfg, iargs [2], data_size);
8422                                         NEW_TEMPLOAD (cfg, load, temp->inst_c0);
8423                                         load->cil_code = ins->cil_code;
8424                                         NEW_ICONST (cfg, data_offset, G_STRUCT_OFFSET (MonoArray, vector));
8425                                         MONO_INST_NEW (cfg, add, OP_PADD);
8426                                         add->inst_left = load;
8427                                         add->inst_right = data_offset;
8428                                         iargs [0] = add;
8429                                         if (cfg->compile_aot) {
8430                                                 NEW_AOTCONST_TOKEN (cfg, iargs [1], MONO_PATCH_INFO_RVA, method->klass->image, GPOINTER_TO_UINT(data_ptr), STACK_PTR, NULL);
8431                                         } else {
8432                                                 NEW_PCONST (cfg, iargs [1], (char*)data_ptr);
8433                                         }
8434                                         mono_emit_method_call_spilled (cfg, bblock, memcpy_method, memcpy_method->signature, iargs, ip, NULL);
8435                                         ip += 11;
8436                                 }
8437                                 NEW_TEMPLOAD (cfg, load, temp->inst_c0);
8438                                 load->cil_code = ins->cil_code;
8439                                 *sp++ = load;
8440                         }
8441                         inline_costs += 1;
8442                         break;
8443                 case CEE_LDLEN:
8444                         CHECK_STACK (1);
8445                         --sp;
8446                         if (sp [0]->type != STACK_OBJ)
8447                                 UNVERIFIED;
8448                         MONO_INST_NEW (cfg, ins, *ip);
8449                         ip++;
8450                         ins->inst_left = *sp;
8451                         ins->type = STACK_PTR;
8452                         *sp++ = ins;
8453                         break;
8454                 case CEE_LDELEMA:
8455                         CHECK_STACK (2);
8456                         sp -= 2;
8457                         CHECK_OPSIZE (5);
8458                         if (sp [0]->type != STACK_OBJ)
8459                                 UNVERIFIED;
8460
8461                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
8462                         CHECK_TYPELOAD (klass);
8463                         /* we need to make sure that this array is exactly the type it needs
8464                          * to be for correctness. the wrappers are lax with their usage
8465                          * so we need to ignore them here
8466                          */
8467                         if (!klass->valuetype && method->wrapper_type == MONO_WRAPPER_NONE && !readonly) {
8468                                 MonoInst* check;
8469
8470                                 /* Needed by the code generated in inssel.brg */
8471                                 mono_get_got_var (cfg);
8472
8473                                 MONO_INST_NEW (cfg, check, OP_CHECK_ARRAY_TYPE);
8474                                 check->klass = mono_array_class_get (klass, 1);
8475                                 check->inst_left = sp [0];
8476                                 check->type = STACK_OBJ;
8477                                 sp [0] = check;
8478                         }
8479                         
8480                         readonly = FALSE;
8481                         mono_class_init (klass);
8482                         NEW_LDELEMA (cfg, ins, sp, klass);
8483                         *sp++ = ins;
8484                         ip += 5;
8485                         break;
8486                 case CEE_LDELEM_ANY: {
8487                         MonoInst *load;
8488                         CHECK_STACK (2);
8489                         sp -= 2;
8490                         if (sp [0]->type != STACK_OBJ)
8491                                 UNVERIFIED;
8492                         CHECK_OPSIZE (5);
8493                         token = read32 (ip + 1);
8494                         klass = mini_get_class (method, token, generic_context);
8495                         CHECK_TYPELOAD (klass);
8496                         mono_class_init (klass);
8497                         NEW_LDELEMA (cfg, load, sp, klass);
8498                         MONO_INST_NEW (cfg, ins, mini_type_to_ldind (cfg, &klass->byval_arg));
8499                         ins->inst_left = load;
8500                         *sp++ = ins;
8501                         type_to_eval_stack_type (cfg, &klass->byval_arg, ins);
8502                         ip += 5;
8503                         break;
8504                 }
8505                 case CEE_LDELEM_I1:
8506                 case CEE_LDELEM_U1:
8507                 case CEE_LDELEM_I2:
8508                 case CEE_LDELEM_U2:
8509                 case CEE_LDELEM_I4:
8510                 case CEE_LDELEM_U4:
8511                 case CEE_LDELEM_I8:
8512                 case CEE_LDELEM_I:
8513                 case CEE_LDELEM_R4:
8514                 case CEE_LDELEM_R8:
8515                 case CEE_LDELEM_REF: {
8516                         MonoInst *load;
8517                         /*
8518                          * translate to:
8519                          * ldind.x (ldelema (array, index))
8520                          * ldelema does the bounds check
8521                          */
8522                         CHECK_STACK (2);
8523                         sp -= 2;
8524                         if (sp [0]->type != STACK_OBJ)
8525                                 UNVERIFIED;
8526                         klass = array_access_to_klass (*ip, sp [0]);
8527                         NEW_LDELEMA (cfg, load, sp, klass);
8528 #ifdef MONO_ARCH_SOFT_FLOAT
8529                         if (*ip == CEE_LDELEM_R4) {
8530                                 int temp;
8531                                 temp = handle_load_float (cfg, bblock, load, ip);
8532                                 NEW_TEMPLOAD (cfg, *sp, temp);
8533                                 sp++;
8534                                 ++ip;
8535                                 break;
8536                         }
8537 #endif
8538                         MONO_INST_NEW (cfg, ins, ldelem_to_ldind [*ip - CEE_LDELEM_I1]);
8539                         ins->inst_left = load;
8540                         *sp++ = ins;
8541                         ins->type = ldind_type [ins->opcode - CEE_LDIND_I1];
8542                         ins->klass = klass;
8543                         ++ip;
8544                         break;
8545                 }
8546                 case CEE_STELEM_I:
8547                 case CEE_STELEM_I1:
8548                 case CEE_STELEM_I2:
8549                 case CEE_STELEM_I4:
8550                 case CEE_STELEM_I8:
8551                 case CEE_STELEM_R4:
8552                 case CEE_STELEM_R8: {
8553                         MonoInst *load;
8554                         /*
8555                          * translate to:
8556                          * stind.x (ldelema (array, index), val)
8557                          * ldelema does the bounds check
8558                          */
8559                         CHECK_STACK (3);
8560                         sp -= 3;
8561                         if (sp [0]->type != STACK_OBJ)
8562                                 UNVERIFIED;
8563                         klass = array_access_to_klass (*ip, sp [0]);
8564                         NEW_LDELEMA (cfg, load, sp, klass);
8565 #ifdef MONO_ARCH_SOFT_FLOAT
8566                         if (*ip == CEE_STELEM_R4) {
8567                                 handle_store_float (cfg, bblock, load, sp [2], ip);
8568                                 ip++;
8569                                 break;
8570                         }
8571 #endif
8572                         MONO_INST_NEW (cfg, ins, stelem_to_stind [*ip - CEE_STELEM_I]);
8573                         ins->inst_left = load;
8574                         ins->inst_right = sp [2];
8575                         ++ip;
8576                         handle_loaded_temps (cfg, bblock, stack_start, sp);
8577                         MONO_ADD_INS (bblock, ins);
8578                         inline_costs += 1;
8579                         break;
8580                 }
8581                 case CEE_STELEM_ANY: {
8582                         MonoInst *load;
8583                         /*
8584                          * translate to:
8585                          * stind.x (ldelema (array, index), val)
8586                          * ldelema does the bounds check
8587                          */
8588                         CHECK_STACK (3);
8589                         sp -= 3;
8590                         if (sp [0]->type != STACK_OBJ)
8591                                 UNVERIFIED;
8592                         CHECK_OPSIZE (5);
8593                         token = read32 (ip + 1);
8594                         klass = mini_get_class (method, token, generic_context);
8595                         CHECK_TYPELOAD (klass);
8596                         mono_class_init (klass);
8597                         if (generic_class_is_reference_type (cfg, klass)) {
8598                                 /* storing a NULL doesn't need any of the complex checks in stelemref */
8599                                 if (sp [2]->opcode == OP_PCONST && sp [2]->inst_p0 == NULL) {
8600                                         MonoInst *load;
8601                                         NEW_LDELEMA (cfg, load, sp, mono_defaults.object_class);
8602                                         MONO_INST_NEW (cfg, ins, CEE_STIND_REF);
8603                                         ins->inst_left = load;
8604                                         ins->inst_right = sp [2];
8605                                         MONO_ADD_INS (bblock, ins);
8606                                 } else {
8607                                         MonoMethod* helper = mono_marshal_get_stelemref ();
8608                                         MonoInst *iargs [3];
8609                                         handle_loaded_temps (cfg, bblock, stack_start, sp);
8610
8611                                         iargs [2] = sp [2];
8612                                         iargs [1] = sp [1];
8613                                         iargs [0] = sp [0];
8614
8615                                         mono_emit_method_call_spilled (cfg, bblock, helper, mono_method_signature (helper), iargs, ip, NULL);
8616                                 }
8617                         } else {
8618                                 NEW_LDELEMA (cfg, load, sp, klass);
8619
8620                                 n = mini_type_to_stind (cfg, &klass->byval_arg);
8621                                 /* FIXME: CEE_STIND_R4 */
8622                                 if (n == CEE_STOBJ)
8623                                         handle_stobj (cfg, bblock, load, sp [2], ip, klass, FALSE, FALSE, TRUE);
8624                                 else {
8625                                         MONO_INST_NEW (cfg, ins, n);
8626                                         ins->inst_left = load;
8627                                         ins->inst_right = sp [2];
8628                                         handle_loaded_temps (cfg, bblock, stack_start, sp);
8629                                         MONO_ADD_INS (bblock, ins);
8630                                 }
8631                         }
8632                         ip += 5;
8633                         inline_costs += 1;
8634                         break;
8635                 }
8636                 case CEE_STELEM_REF: {
8637                         MonoInst *iargs [3];
8638                         MonoMethod* helper = mono_marshal_get_stelemref ();
8639
8640                         CHECK_STACK (3);
8641                         sp -= 3;
8642                         if (sp [0]->type != STACK_OBJ)
8643                                 UNVERIFIED;
8644                         if (sp [2]->type != STACK_OBJ)
8645                                 UNVERIFIED;
8646
8647                         handle_loaded_temps (cfg, bblock, stack_start, sp);
8648
8649                         /* storing a NULL doesn't need any of the complex checks in stelemref */
8650                         if (sp [2]->opcode == OP_PCONST && sp [2]->inst_p0 == NULL) {
8651                                 MonoInst *load;
8652                                 NEW_LDELEMA (cfg, load, sp, mono_defaults.object_class);
8653                                 MONO_INST_NEW (cfg, ins, stelem_to_stind [*ip - CEE_STELEM_I]);
8654                                 ins->inst_left = load;
8655                                 ins->inst_right = sp [2];
8656                                 MONO_ADD_INS (bblock, ins);
8657                         } else {
8658                                 iargs [2] = sp [2];
8659                                 iargs [1] = sp [1];
8660                                 iargs [0] = sp [0];
8661                         
8662                                 mono_emit_method_call_spilled (cfg, bblock, helper, mono_method_signature (helper), iargs, ip, NULL);
8663                                 inline_costs += 1;
8664                         }
8665
8666                         ++ip;
8667                         break;
8668                 }
8669                 case CEE_CKFINITE: {
8670                         MonoInst *store, *temp;
8671                         CHECK_STACK (1);
8672
8673                         /* this instr. can throw exceptions as side effect,
8674                          * so we cant eliminate dead code which contains CKFINITE opdodes.
8675                          * Spilling to memory makes sure that we always perform
8676                          * this check */
8677
8678                         
8679                         MONO_INST_NEW (cfg, ins, OP_CKFINITE);
8680                         ins->inst_left = sp [-1];
8681                         temp = mono_compile_create_var (cfg, &mono_defaults.double_class->byval_arg, OP_LOCAL);
8682
8683                         NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
8684                         MONO_ADD_INS (bblock, store);
8685
8686                         NEW_TEMPLOAD (cfg, sp [-1], temp->inst_c0);
8687                        
8688                         ++ip;
8689                         break;
8690                 }
8691                 case CEE_REFANYVAL:
8692                         CHECK_STACK (1);
8693                         --sp;
8694                         CHECK_OPSIZE (5);
8695                         token = read32 (ip + 1);
8696                         klass = mono_class_get_full (image, token, generic_context);
8697                         CHECK_TYPELOAD (klass);
8698                         mono_class_init (klass);
8699
8700                         /* Needed by the code generated in inssel.brg */
8701                         mono_get_got_var (cfg);
8702
8703                         if (cfg->generic_sharing_context) {
8704                                 context_used = mono_class_check_context_used (klass);
8705                                 if (context_used && cfg->compile_aot)
8706                                         GENERIC_SHARING_FAILURE (*ip);
8707                         }
8708
8709                         if (context_used) {
8710                                 MonoInst *rgctx;
8711
8712                                 MONO_INST_NEW (cfg, ins, OP_REFANYVAL_REG);
8713                                 ins->type = STACK_MP;
8714                                 ins->inst_left = *sp;
8715                                 ins->klass = klass;
8716
8717                                 GET_RGCTX (rgctx, context_used);
8718                                 ins->inst_right = get_runtime_generic_context_ptr (cfg, method, context_used,
8719                                                 bblock, klass, generic_context, rgctx, MONO_RGCTX_INFO_KLASS, ip);
8720                         } else {
8721                                 MONO_INST_NEW (cfg, ins, *ip);
8722                                 ins->type = STACK_MP;
8723                                 ins->inst_left = *sp;
8724                                 ins->klass = klass;
8725                                 ins->inst_newa_class = klass;
8726                         }
8727                         ip += 5;
8728                         *sp++ = ins;
8729                         break;
8730                 case CEE_MKREFANY: {
8731                         MonoInst *loc;
8732
8733                         CHECK_STACK (1);
8734                         --sp;
8735                         CHECK_OPSIZE (5);
8736                         token = read32 (ip + 1);
8737                         klass = mono_class_get_full (image, token, generic_context);
8738                         CHECK_TYPELOAD (klass);
8739                         mono_class_init (klass);
8740
8741                         if (cfg->generic_sharing_context) {
8742                                 context_used = mono_class_check_context_used (klass);
8743                                 if (context_used && cfg->compile_aot)
8744                                         GENERIC_SHARING_FAILURE (CEE_MKREFANY);
8745                         }
8746
8747                         loc = mono_compile_create_var (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL);
8748                         if (context_used) {
8749                                 MonoInst *rgctx, *klass_type, *klass_klass, *loc_load;
8750
8751                                 GET_RGCTX (rgctx, context_used);
8752                                 klass_klass = get_runtime_generic_context_ptr (cfg, method, context_used, bblock, klass,
8753                                                 generic_context, rgctx, MONO_RGCTX_INFO_KLASS, ip);
8754                                 GET_RGCTX (rgctx, context_used);
8755                                 klass_type = get_runtime_generic_context_ptr (cfg, method, context_used, bblock, klass,
8756                                                 generic_context, rgctx, MONO_RGCTX_INFO_TYPE, ip);
8757
8758                                 NEW_TEMPLOADA (cfg, loc_load, loc->inst_c0);
8759
8760                                 MONO_INST_NEW (cfg, ins, OP_MKREFANY_REGS);
8761                                 NEW_GROUP (cfg, ins->inst_left, klass_type, klass_klass);
8762                                 NEW_GROUP (cfg, ins->inst_right, *sp, loc_load);
8763                         } else {
8764                                 MonoInst *klassconst;
8765
8766                                 NEW_PCONST (cfg, klassconst, klass);
8767
8768                                 MONO_INST_NEW (cfg, ins, *ip);
8769                                 NEW_TEMPLOADA (cfg, ins->inst_right, loc->inst_c0);
8770                                 NEW_GROUP (cfg, ins->inst_left, *sp, klassconst);
8771                         }
8772
8773                         MONO_ADD_INS (bblock, ins);
8774
8775                         NEW_TEMPLOAD (cfg, *sp, loc->inst_c0);
8776                         ++sp;
8777                         ip += 5;
8778                         break;
8779                 }
8780                 case CEE_LDTOKEN: {
8781                         gpointer handle;
8782                         MonoClass *handle_class;
8783
8784                         CHECK_STACK_OVF (1);
8785
8786                         CHECK_OPSIZE (5);
8787                         n = read32 (ip + 1);
8788
8789                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
8790                                 handle = mono_method_get_wrapper_data (method, n);
8791                                 handle_class = mono_method_get_wrapper_data (method, n + 1);
8792                                 if (handle_class == mono_defaults.typehandle_class)
8793                                         handle = &((MonoClass*)handle)->byval_arg;
8794                         }
8795                         else {
8796                                 handle = mono_ldtoken (image, n, &handle_class, generic_context);
8797                         }
8798                         if (!handle)
8799                                 goto load_error;
8800                         mono_class_init (handle_class);
8801
8802                         if (cfg->generic_sharing_context) {
8803                                 if (handle_class == mono_defaults.typehandle_class) {
8804                                         /* If we get a MONO_TYPE_CLASS
8805                                            then we need to provide the
8806                                            open type, not an
8807                                            instantiation of it. */
8808                                         if (mono_type_get_type (handle) == MONO_TYPE_CLASS)
8809                                                 context_used = 0;
8810                                         else
8811                                                 context_used = mono_class_check_context_used (mono_class_from_mono_type (handle));
8812                                 } else if (handle_class == mono_defaults.fieldhandle_class)
8813                                         context_used = mono_class_check_context_used (((MonoClassField*)handle)->parent);
8814                                 else if (handle_class == mono_defaults.methodhandle_class)
8815                                         context_used = mono_method_check_context_used (handle);
8816                                 else
8817                                         g_assert_not_reached ();
8818                         }
8819
8820                         if (cfg->opt & MONO_OPT_SHARED) {
8821                                 int temp;
8822                                 MonoInst *res, *store, *addr, *vtvar, *iargs [3];
8823                                 int method_context_used;
8824
8825                                 if (cfg->generic_sharing_context)
8826                                         method_context_used = mono_method_check_context_used (method);
8827                                 else
8828                                         method_context_used = 0;
8829
8830                                 vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL); 
8831
8832                                 NEW_IMAGECONST (cfg, iargs [0], image);
8833                                 NEW_ICONST (cfg, iargs [1], n);
8834                                 if (method_context_used) {
8835                                         MonoInst *rgctx;
8836
8837                                         GET_RGCTX (rgctx, method_context_used);
8838                                         iargs [2] = get_runtime_generic_context_method (cfg, method, method_context_used,
8839                                                         bblock, method,
8840                                                         generic_context, rgctx, MONO_RGCTX_INFO_METHOD, ip);
8841                                         temp = mono_emit_jit_icall (cfg, bblock, mono_ldtoken_wrapper_generic_shared,
8842                                                         iargs, ip);
8843                                 } else {
8844                                         NEW_PCONST (cfg, iargs [2], generic_context);
8845                                         temp = mono_emit_jit_icall (cfg, bblock, mono_ldtoken_wrapper, iargs, ip);
8846                                 }
8847                                 NEW_TEMPLOAD (cfg, res, temp);
8848                                 NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
8849                                 NEW_INDSTORE (cfg, store, addr, res, &mono_defaults.int_class->byval_arg);
8850                                 MONO_ADD_INS (bblock, store);
8851                                 NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
8852                         } else {
8853                                 if ((ip + 10 < end) && ip_in_bb (cfg, bblock, ip + 5) &&
8854                                         handle_class == mono_defaults.typehandle_class &&
8855                                         ((ip [5] == CEE_CALL) || (ip [5] == CEE_CALLVIRT)) && 
8856                                         (cmethod = mini_get_method (cfg, method, read32 (ip + 6), NULL, generic_context)) &&
8857                                         (cmethod->klass == mono_defaults.monotype_class->parent) &&
8858                                         (strcmp (cmethod->name, "GetTypeFromHandle") == 0)) {
8859                                         MonoClass *tclass = mono_class_from_mono_type (handle);
8860                                         mono_class_init (tclass);
8861                                         if (context_used) {
8862                                                 MonoInst *rgctx;
8863
8864                                                 g_assert (!cfg->compile_aot);
8865
8866                                                 GET_RGCTX (rgctx, context_used);
8867                                                 ins = get_runtime_generic_context_ptr (cfg, method, context_used, bblock, tclass,
8868                                                         generic_context, rgctx, MONO_RGCTX_INFO_REFLECTION_TYPE, ip);
8869                                         } else if (cfg->compile_aot) {
8870                                                 /*
8871                                                  * FIXME: We would have to include the context into the
8872                                                  * aot constant too (tests/generic-array-type.2.exe).
8873                                                  */
8874                                                 if (generic_context)
8875                                                         cfg->disable_aot = TRUE;
8876                                                 NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, image, n);
8877                                         } else {
8878                                                 NEW_PCONST (cfg, ins, mono_type_get_object (cfg->domain, handle));
8879                                         }
8880                                         ins->type = STACK_OBJ;
8881                                         ins->klass = cmethod->klass;
8882                                         ip += 5;
8883                                 } else {
8884                                         MonoInst *store, *addr, *vtvar;
8885
8886                                         if (context_used) {
8887                                                         MonoInst *rgctx;
8888
8889                                                 g_assert (!cfg->compile_aot);
8890
8891                                                 GET_RGCTX (rgctx, context_used);
8892                                                 if (handle_class == mono_defaults.typehandle_class) {
8893                                                         ins = get_runtime_generic_context_ptr (cfg, method,
8894                                                                         context_used, bblock,
8895                                                                         mono_class_from_mono_type (handle), generic_context,
8896                                                                         rgctx, MONO_RGCTX_INFO_TYPE, ip);
8897                                                 } else if (handle_class == mono_defaults.methodhandle_class) {
8898                                                         ins = get_runtime_generic_context_method (cfg, method,
8899                                                                         context_used, bblock, handle, generic_context,
8900                                                                         rgctx, MONO_RGCTX_INFO_METHOD, ip);
8901                                                 } else if (handle_class == mono_defaults.fieldhandle_class) {
8902                                                         ins = get_runtime_generic_context_field (cfg, method,
8903                                                                         context_used, bblock, handle, generic_context,
8904                                                                         rgctx, MONO_RGCTX_INFO_CLASS_FIELD, ip);
8905                                                 } else {
8906                                                         g_assert_not_reached ();
8907                                                 }
8908                                         }
8909                                         else if (cfg->compile_aot) {
8910                                                 NEW_LDTOKENCONST (cfg, ins, image, n);
8911                                         } else {
8912                                                 NEW_PCONST (cfg, ins, handle);
8913                                         }
8914                                         vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL);
8915                                         NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
8916                                         NEW_INDSTORE (cfg, store, addr, ins, &mono_defaults.int_class->byval_arg);
8917                                         MONO_ADD_INS (bblock, store);
8918                                         NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
8919                                 }
8920                         }
8921
8922                         *sp++ = ins;
8923                         ip += 5;
8924                         break;
8925                 }
8926                 case CEE_CONV_U2:
8927                 case CEE_CONV_U1:
8928                 case CEE_CONV_I:
8929                         CHECK_STACK (1);
8930                         ADD_UNOP (*ip);
8931                         ip++;
8932                         break;
8933                 case CEE_ADD_OVF:
8934                 case CEE_ADD_OVF_UN:
8935                 case CEE_MUL_OVF:
8936                 case CEE_MUL_OVF_UN:
8937                 case CEE_SUB_OVF:
8938                 case CEE_SUB_OVF_UN:
8939                         CHECK_STACK (2);
8940                         ADD_BINOP (*ip);
8941                         if (mono_find_jit_opcode_emulation (ins->opcode)) {
8942                                 --sp;
8943                                 *sp++ = emit_tree (cfg, bblock, ins, ip + 1);
8944                         }
8945                         ip++;
8946                         break;
8947                 case CEE_ENDFINALLY:
8948                         MONO_INST_NEW (cfg, ins, OP_ENDFINALLY);
8949                         MONO_ADD_INS (bblock, ins);
8950                         ip++;
8951                         start_new_bblock = 1;
8952
8953                         /*
8954                          * Control will leave the method so empty the stack, otherwise
8955                          * the next basic block will start with a nonempty stack.
8956                          */
8957                         while (sp != stack_start) {
8958                                 MONO_INST_NEW (cfg, ins, CEE_POP);
8959                                 sp--;
8960                                 ins->inst_i0 = *sp;
8961                                 MONO_ADD_INS (bblock, ins);
8962                         }
8963                         break;
8964                 case CEE_LEAVE:
8965                 case CEE_LEAVE_S: {
8966                         GList *handlers;
8967
8968                         if (*ip == CEE_LEAVE) {
8969                                 CHECK_OPSIZE (5);
8970                                 target = ip + 5 + (gint32)read32(ip + 1);
8971                         } else {
8972                                 CHECK_OPSIZE (2);
8973                                 target = ip + 2 + (signed char)(ip [1]);
8974                         }
8975
8976                         /* empty the stack */
8977                         while (sp != stack_start) {
8978                                 MONO_INST_NEW (cfg, ins, CEE_POP);
8979                                 sp--;
8980                                 ins->inst_i0 = *sp;
8981                                 MONO_ADD_INS (bblock, ins);
8982                         }
8983
8984                         /* 
8985                          * If this leave statement is in a catch block, check for a
8986                          * pending exception, and rethrow it if necessary.
8987                          */
8988                         for (i = 0; i < header->num_clauses; ++i) {
8989                                 MonoExceptionClause *clause = &header->clauses [i];
8990
8991                                 /* 
8992                                  * Use <= in the final comparison to handle clauses with multiple
8993                                  * leave statements, like in bug #78024.
8994                                  * The ordering of the exception clauses guarantees that we find the
8995                                  * innermost clause.
8996                                  */
8997                                 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)) {
8998                                         int temp;
8999                                         MonoInst *load;
9000
9001                                         NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, clause->handler_offset)->inst_c0);
9002
9003                                         temp = mono_emit_jit_icall (cfg, bblock, mono_thread_get_undeniable_exception, NULL, ip);
9004                                         NEW_TEMPLOAD (cfg, *sp, temp);
9005                                 
9006                                         MONO_INST_NEW (cfg, ins, OP_THROW_OR_NULL);
9007                                         ins->inst_left = *sp;
9008                                         ins->inst_right = load;
9009                                         MONO_ADD_INS (bblock, ins);
9010                                 }
9011                         }
9012
9013                         if ((handlers = mono_find_final_block (cfg, ip, target, MONO_EXCEPTION_CLAUSE_FINALLY))) {
9014                                 GList *tmp;
9015                                 for (tmp = handlers; tmp; tmp = tmp->next) {
9016                                         tblock = tmp->data;
9017                                         link_bblock (cfg, bblock, tblock);
9018                                         MONO_INST_NEW (cfg, ins, OP_CALL_HANDLER);
9019                                         ins->inst_target_bb = tblock;
9020                                         MONO_ADD_INS (bblock, ins);
9021                                 }
9022                                 g_list_free (handlers);
9023                         } 
9024
9025                         MONO_INST_NEW (cfg, ins, OP_BR);
9026                         MONO_ADD_INS (bblock, ins);
9027                         GET_BBLOCK (cfg, tblock, target);
9028                         link_bblock (cfg, bblock, tblock);
9029                         CHECK_BBLOCK (target, ip, tblock);
9030                         ins->inst_target_bb = tblock;
9031                         start_new_bblock = 1;
9032
9033                         if (*ip == CEE_LEAVE)
9034                                 ip += 5;
9035                         else
9036                                 ip += 2;
9037
9038                         break;
9039                 }
9040                 case CEE_STIND_I:
9041                         CHECK_STACK (2);
9042                         MONO_INST_NEW (cfg, ins, *ip);
9043                         sp -= 2;
9044                         handle_loaded_temps (cfg, bblock, stack_start, sp);
9045                         MONO_ADD_INS (bblock, ins);
9046                         ip++;
9047                         ins->inst_i0 = sp [0];
9048                         ins->inst_i1 = sp [1];
9049                         inline_costs += 1;
9050                         break;
9051                 case CEE_CONV_U:
9052                         CHECK_STACK (1);
9053                         ADD_UNOP (*ip);
9054                         ip++;
9055                         break;
9056                 /* trampoline mono specific opcodes */
9057                 case MONO_CUSTOM_PREFIX: {
9058
9059                         g_assert (method->wrapper_type != MONO_WRAPPER_NONE);
9060
9061                         CHECK_OPSIZE (2);
9062                         switch (ip [1]) {
9063
9064                         case CEE_MONO_ICALL: {
9065                                 int temp;
9066                                 gpointer func;
9067                                 MonoJitICallInfo *info;
9068
9069                                 token = read32 (ip + 2);
9070                                 func = mono_method_get_wrapper_data (method, token);
9071                                 info = mono_find_jit_icall_by_addr (func);
9072                                 if (info == NULL){
9073                                         g_error ("An attempt has been made to perform an icall to address %p, "
9074                                                  "but the address has not been registered as an icall\n", info);
9075                                         g_assert_not_reached ();
9076                                 }
9077
9078                                 CHECK_STACK (info->sig->param_count);
9079                                 sp -= info->sig->param_count;
9080
9081                                 temp = mono_emit_jit_icall (cfg, bblock, info->func, sp, ip);
9082                                 if (!MONO_TYPE_IS_VOID (info->sig->ret)) {
9083                                         NEW_TEMPLOAD (cfg, *sp, temp);
9084                                         sp++;
9085                                 }
9086
9087                                 ip += 6;
9088                                 inline_costs += 10 * num_calls++;
9089
9090                                 break;
9091                         }
9092                         case CEE_MONO_LDPTR: {
9093                                 gpointer ptr;
9094
9095                                 CHECK_STACK_OVF (1);
9096                                 CHECK_OPSIZE (6);
9097                                 token = read32 (ip + 2);
9098
9099                                 ptr = mono_method_get_wrapper_data (method, token);
9100                                 if (cfg->compile_aot && (cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE || cfg->method->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE)) {
9101                                         MonoMethod *wrapped = mono_marshal_method_from_wrapper (cfg->method);
9102
9103                                         if (wrapped && ptr != NULL && mono_lookup_internal_call (wrapped) == ptr) {
9104                                                 NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_ICALL_ADDR, wrapped);
9105                                                 *sp++ = ins;
9106                                                 ip += 6;
9107                                                 break;
9108                                         }
9109
9110                                         if ((method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) && (strstr (method->name, "__icall_wrapper_") == method->name)) {
9111                                                 MonoJitICallInfo *callinfo;
9112                                                 const char *icall_name;
9113
9114                                                 icall_name = method->name + strlen ("__icall_wrapper_");
9115                                                 g_assert (icall_name);
9116                                                 callinfo = mono_find_jit_icall_by_name (icall_name);
9117                                                 g_assert (callinfo);
9118
9119                                                 if (ptr == callinfo->func) {
9120                                                         /* Will be transformed into an AOTCONST later */
9121                                                         NEW_PCONST (cfg, ins, ptr);
9122                                                         *sp++ = ins;
9123                                                         ip += 6;
9124                                                         break;
9125                                                 }
9126                                         }
9127                                 }
9128                                 /* FIXME: Generalize this */
9129                                 if (cfg->compile_aot && ptr == mono_thread_interruption_request_flag ()) {
9130                                         NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG, NULL);
9131                                         *sp++ = ins;
9132                                         ip += 6;
9133                                         break;
9134                                 }
9135                                 NEW_PCONST (cfg, ins, ptr);
9136                                 *sp++ = ins;
9137                                 ip += 6;
9138                                 inline_costs += 10 * num_calls++;
9139                                 /* Can't embed random pointers into AOT code */
9140                                 cfg->disable_aot = 1;
9141                                 break;
9142                         }
9143                         case CEE_MONO_ICALL_ADDR: {
9144                                 MonoMethod *cmethod;
9145
9146                                 CHECK_STACK_OVF (1);
9147                                 CHECK_OPSIZE (6);
9148                                 token = read32 (ip + 2);
9149
9150                                 cmethod = mono_method_get_wrapper_data (method, token);
9151
9152                                 g_assert (cfg->compile_aot);
9153
9154                                 NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_ICALL_ADDR, cmethod);
9155                                 *sp++ = ins;
9156                                 ip += 6;
9157                                 break;
9158                         }
9159                         case CEE_MONO_VTADDR:
9160                                 CHECK_STACK (1);
9161                                 --sp;
9162                                 MONO_INST_NEW (cfg, ins, OP_VTADDR);
9163                                 ins->type = STACK_MP;
9164                                 ins->inst_left = *sp;
9165                                 *sp++ = ins;
9166                                 ip += 2;
9167                                 break;
9168                         case CEE_MONO_NEWOBJ: {
9169                                 MonoInst *iargs [2];
9170                                 int temp;
9171                                 CHECK_STACK_OVF (1);
9172                                 CHECK_OPSIZE (6);
9173                                 token = read32 (ip + 2);
9174                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
9175                                 mono_class_init (klass);
9176                                 NEW_DOMAINCONST (cfg, iargs [0]);
9177                                 NEW_CLASSCONST (cfg, iargs [1], klass);
9178                                 temp = mono_emit_jit_icall (cfg, bblock, mono_object_new, iargs, ip);
9179                                 NEW_TEMPLOAD (cfg, *sp, temp);
9180                                 sp++;
9181                                 ip += 6;
9182                                 inline_costs += 10 * num_calls++;
9183                                 break;
9184                         }
9185                         case CEE_MONO_OBJADDR:
9186                                 CHECK_STACK (1);
9187                                 --sp;
9188                                 MONO_INST_NEW (cfg, ins, OP_OBJADDR);
9189                                 ins->type = STACK_MP;
9190                                 ins->inst_left = *sp;
9191                                 *sp++ = ins;
9192                                 ip += 2;
9193                                 break;
9194                         case CEE_MONO_LDNATIVEOBJ:
9195                                 CHECK_STACK (1);
9196                                 CHECK_OPSIZE (6);
9197                                 token = read32 (ip + 2);
9198                                 klass = mono_method_get_wrapper_data (method, token);
9199                                 g_assert (klass->valuetype);
9200                                 mono_class_init (klass);
9201                                 NEW_INDLOAD (cfg, ins, sp [-1], &klass->byval_arg);
9202                                 sp [-1] = ins;
9203                                 ip += 6;
9204                                 break;
9205                         case CEE_MONO_RETOBJ:
9206                                 g_assert (cfg->ret);
9207                                 g_assert (mono_method_signature (method)->pinvoke); 
9208                                 CHECK_STACK (1);
9209                                 --sp;
9210                                 
9211                                 CHECK_OPSIZE (6);
9212                                 token = read32 (ip + 2);    
9213                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
9214
9215                                 NEW_RETLOADA (cfg, ins);
9216                                 handle_stobj (cfg, bblock, ins, *sp, ip, klass, FALSE, TRUE, FALSE);
9217                                 
9218                                 if (sp != stack_start)
9219                                         UNVERIFIED;
9220                                 
9221                                 MONO_INST_NEW (cfg, ins, OP_BR);
9222                                 ins->inst_target_bb = end_bblock;
9223                                 MONO_ADD_INS (bblock, ins);
9224                                 link_bblock (cfg, bblock, end_bblock);
9225                                 start_new_bblock = 1;
9226                                 ip += 6;
9227                                 break;
9228                         case CEE_MONO_CISINST:
9229                         case CEE_MONO_CCASTCLASS: {
9230                                 int token;
9231                                 CHECK_STACK (1);
9232                                 --sp;
9233                                 CHECK_OPSIZE (6);
9234                                 token = read32 (ip + 2);
9235                                 /* Needed by the code generated in inssel.brg */
9236                                 mono_get_got_var (cfg);
9237
9238 #ifdef __i386__
9239                                 /* 
9240                                  * The code generated for CCASTCLASS has too much register pressure
9241                                  * (obj+vtable+ibitmap_byte_reg+iid_reg), leading to the usual
9242                                  * branches-inside-bblocks problem.
9243                                  */
9244                                 cfg->disable_aot = TRUE;
9245 #endif
9246                 
9247                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
9248                                 MONO_INST_NEW (cfg, ins, (ip [1] == CEE_MONO_CISINST) ? OP_CISINST : OP_CCASTCLASS);
9249                                 ins->type = STACK_I4;
9250                                 ins->inst_left = *sp;
9251                                 ins->inst_newa_class = klass;
9252                                 *sp++ = emit_tree (cfg, bblock, ins, ip + 6);
9253                                 ip += 6;
9254                                 break;
9255                         }
9256                         case CEE_MONO_SAVE_LMF:
9257                         case CEE_MONO_RESTORE_LMF:
9258 #ifdef MONO_ARCH_HAVE_LMF_OPS
9259                                 MONO_INST_NEW (cfg, ins, (ip [1] == CEE_MONO_SAVE_LMF) ? OP_SAVE_LMF : OP_RESTORE_LMF);
9260                                 MONO_ADD_INS (bblock, ins);
9261                                 cfg->need_lmf_area = TRUE;
9262 #endif
9263                                 ip += 2;
9264                                 break;
9265                         case CEE_MONO_CLASSCONST:
9266                                 CHECK_STACK_OVF (1);
9267                                 CHECK_OPSIZE (6);
9268                                 token = read32 (ip + 2);
9269                                 NEW_CLASSCONST (cfg, ins, mono_method_get_wrapper_data (method, token));
9270                                 *sp++ = ins;
9271                                 ip += 6;
9272                                 inline_costs += 10 * num_calls++;
9273                                 break;
9274                         case CEE_MONO_NOT_TAKEN:
9275                                 bblock->out_of_line = TRUE;
9276                                 ip += 2;
9277                                 break;
9278                         case CEE_MONO_TLS:
9279                                 CHECK_STACK_OVF (1);
9280                                 CHECK_OPSIZE (6);
9281                                 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
9282                                 ins->inst_offset = (gint32)read32 (ip + 2);
9283                                 ins->type = STACK_PTR;
9284                                 *sp++ = ins;
9285                                 ip += 6;
9286                                 break;
9287                         default:
9288                                 g_error ("opcode 0x%02x 0x%02x not handled", MONO_CUSTOM_PREFIX, ip [1]);
9289                                 break;
9290                         }
9291                         break;
9292                 }
9293                 case CEE_PREFIX1: {
9294                         CHECK_OPSIZE (2);
9295                         switch (ip [1]) {
9296                         case CEE_ARGLIST: {
9297                                 /* somewhat similar to LDTOKEN */
9298                                 MonoInst *addr, *vtvar;
9299                                 CHECK_STACK_OVF (1);
9300                                 vtvar = mono_compile_create_var (cfg, &mono_defaults.argumenthandle_class->byval_arg, OP_LOCAL); 
9301
9302                                 NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
9303                                 MONO_INST_NEW (cfg, ins, OP_ARGLIST);
9304                                 ins->inst_left = addr;
9305                                 MONO_ADD_INS (bblock, ins);
9306                                 NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
9307                                 *sp++ = ins;
9308                                 ip += 2;
9309                                 break;
9310                         }
9311                         case CEE_CEQ:
9312                         case CEE_CGT:
9313                         case CEE_CGT_UN:
9314                         case CEE_CLT:
9315                         case CEE_CLT_UN: {
9316                                 MonoInst *cmp;
9317                                 CHECK_STACK (2);
9318                                 /*
9319                                  * The following transforms:
9320                                  *    CEE_CEQ    into OP_CEQ
9321                                  *    CEE_CGT    into OP_CGT
9322                                  *    CEE_CGT_UN into OP_CGT_UN
9323                                  *    CEE_CLT    into OP_CLT
9324                                  *    CEE_CLT_UN into OP_CLT_UN
9325                                  */
9326                                 MONO_INST_NEW (cfg, cmp, (OP_CEQ - CEE_CEQ) + ip [1]);
9327                                 
9328                                 MONO_INST_NEW (cfg, ins, cmp->opcode);
9329                                 sp -= 2;
9330                                 cmp->inst_i0 = sp [0];
9331                                 cmp->inst_i1 = sp [1];
9332                                 type_from_op (cmp);
9333                                 CHECK_TYPE (cmp);
9334                                 ins->type = STACK_I4;
9335                                 ins->inst_i0 = cmp;
9336 #if MONO_ARCH_SOFT_FLOAT
9337                                 if (sp [0]->type == STACK_R8) {
9338                                         cmp->type = STACK_I4;
9339                                         *sp++ = emit_tree (cfg, bblock, cmp, ip + 2);
9340                                         ip += 2;
9341                                         break;
9342                                 }
9343 #endif
9344                                 if ((sp [0]->type == STACK_I8) || ((sizeof (gpointer) == 8) && ((sp [0]->type == STACK_PTR) || (sp [0]->type == STACK_OBJ) || (sp [0]->type == STACK_MP))))
9345                                         cmp->opcode = OP_LCOMPARE;
9346                                 else
9347                                         cmp->opcode = OP_COMPARE;
9348                                 *sp++ = ins;
9349                                 /* spill it to reduce the expression complexity
9350                                  * and workaround bug 54209 
9351                                  */
9352                                 if (cmp->inst_left->type == STACK_I8) {
9353                                         --sp;
9354                                         *sp++ = emit_tree (cfg, bblock, ins, ip + 2);
9355                                 }
9356                                 ip += 2;
9357                                 break;
9358                         }
9359                         case CEE_LDFTN: {
9360                                 MonoInst *argconst;
9361                                 MonoMethod *cil_method, *ctor_method;
9362                                 int temp;
9363                                 gboolean is_shared = FALSE;
9364
9365                                 CHECK_STACK_OVF (1);
9366                                 CHECK_OPSIZE (6);
9367                                 n = read32 (ip + 2);
9368                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
9369                                 if (!cmethod)
9370                                         goto load_error;
9371                                 mono_class_init (cmethod->klass);
9372
9373                                 if (cfg->generic_sharing_context)
9374                                         context_used = mono_method_check_context_used (cmethod);
9375
9376                                 if (mono_class_generic_sharing_enabled (cmethod->klass)) {
9377                                         if ((cmethod->flags & METHOD_ATTRIBUTE_STATIC) &&
9378                                                         (cmethod->klass->generic_class ||
9379                                                         cmethod->klass->generic_container)) {
9380                                                 is_shared = TRUE;
9381                                         }
9382                                         if (cmethod->is_inflated && mono_method_get_context (cmethod)->method_inst)
9383                                                 is_shared = TRUE;
9384                                 }
9385
9386                                 cil_method = cmethod;
9387                                 if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_method (method, cmethod))
9388                                         METHOD_ACCESS_FAILURE;
9389                                 if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS) {
9390                                         if (check_linkdemand (cfg, method, cmethod, bblock, ip))
9391                                                 INLINE_FAILURE;
9392                                         CHECK_CFG_EXCEPTION;
9393                                 } else if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR) {
9394                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod, bblock, ip);
9395                                 }
9396
9397                                 /* 
9398                                  * Optimize the common case of ldftn+delegate creation
9399                                  */
9400 #if defined(MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE) && !defined(HAVE_WRITE_BARRIERS)
9401                                 /* FIXME: SGEN support */
9402                                 /* FIXME: handle shared static generic methods */
9403                                 /* FIXME: handle this in shared code */
9404                                 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)) {
9405                                         MonoInst *target_ins;
9406
9407                                         ip += 6;
9408                                         if (cfg->verbose_level > 3)
9409                                                 g_print ("converting (in B%d: stack: %d) %s", bblock->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
9410                                         target_ins = sp [-1];
9411                                         sp --;
9412                                         *sp = handle_delegate_ctor (cfg, bblock, ctor_method->klass, target_ins, cmethod, ip);
9413                                         ip += 5;                                        
9414                                         sp ++;
9415                                         break;
9416                                 }
9417 #endif
9418
9419                                 handle_loaded_temps (cfg, bblock, stack_start, sp);
9420
9421                                 if (context_used) {
9422                                         MonoInst *rgctx;
9423
9424                                         if (is_shared)
9425                                                 cmethod = mono_marshal_get_static_rgctx_invoke (cmethod);
9426
9427                                         GET_RGCTX (rgctx, context_used);
9428                                         argconst = get_runtime_generic_context_method (cfg, method, context_used,
9429                                                         bblock, cmethod,
9430                                                         generic_context, rgctx, MONO_RGCTX_INFO_METHOD, ip);
9431                                 } else if (is_shared) {
9432                                         NEW_METHODCONST (cfg, argconst, mono_marshal_get_static_rgctx_invoke (cmethod));
9433                                 } else {
9434                                         NEW_METHODCONST (cfg, argconst, cmethod);
9435                                 }
9436                                 temp = mono_emit_jit_icall (cfg, bblock, mono_ldftn, &argconst, ip);
9437                                 NEW_TEMPLOAD (cfg, *sp, temp);
9438                                 sp ++;
9439                                 
9440                                 ip += 6;
9441                                 inline_costs += 10 * num_calls++;
9442                                 break;
9443                         }
9444                         case CEE_LDVIRTFTN: {
9445                                 MonoInst *args [2];
9446                                 int temp;
9447
9448                                 CHECK_STACK (1);
9449                                 CHECK_OPSIZE (6);
9450                                 n = read32 (ip + 2);
9451                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
9452                                 if (!cmethod)
9453                                         goto load_error;
9454                                 mono_class_init (cmethod->klass);
9455
9456                                 if (cfg->generic_sharing_context)
9457                                         context_used = mono_method_check_context_used (cmethod);
9458
9459                                 if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS) {
9460                                         if (check_linkdemand (cfg, method, cmethod, bblock, ip))
9461                                                 INLINE_FAILURE;
9462                                         CHECK_CFG_EXCEPTION;
9463                                 } else if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR) {
9464                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod, bblock, ip);
9465                                 }
9466
9467                                 handle_loaded_temps (cfg, bblock, stack_start, sp);
9468
9469                                 --sp;
9470                                 args [0] = *sp;
9471                                 if (context_used) {
9472                                         MonoInst *rgctx;
9473
9474                                         GET_RGCTX (rgctx, context_used);
9475                                         args [1] = get_runtime_generic_context_method (cfg, method, context_used,
9476                                                         bblock, cmethod,
9477                                                         generic_context, rgctx, MONO_RGCTX_INFO_METHOD, ip);
9478                                         temp = mono_emit_jit_icall (cfg, bblock, mono_ldvirtfn_gshared, args, ip);
9479                                 } else {
9480                                         NEW_METHODCONST (cfg, args [1], cmethod);
9481                                         temp = mono_emit_jit_icall (cfg, bblock, mono_ldvirtfn, args, ip);
9482                                 }
9483                                 NEW_TEMPLOAD (cfg, *sp, temp);
9484                                 sp ++;
9485
9486                                 ip += 6;
9487                                 inline_costs += 10 * num_calls++;
9488                                 break;
9489                         }
9490                         case CEE_LDARG:
9491                                 CHECK_STACK_OVF (1);
9492                                 CHECK_OPSIZE (4);
9493                                 n = read16 (ip + 2);
9494                                 CHECK_ARG (n);
9495                                 NEW_ARGLOAD (cfg, ins, n);
9496                                 LDARG_SOFT_FLOAT (cfg, ins, n, ip);
9497                                 *sp++ = ins;
9498                                 ip += 4;
9499                                 break;
9500                         case CEE_LDARGA:
9501                                 CHECK_STACK_OVF (1);
9502                                 CHECK_OPSIZE (4);
9503                                 n = read16 (ip + 2);
9504                                 CHECK_ARG (n);
9505                                 NEW_ARGLOADA (cfg, ins, n);
9506                                 *sp++ = ins;
9507                                 ip += 4;
9508                                 break;
9509                         case CEE_STARG:
9510                                 CHECK_STACK (1);
9511                                 --sp;
9512                                 handle_loaded_temps (cfg, bblock, stack_start, sp);
9513                                 CHECK_OPSIZE (4);
9514                                 n = read16 (ip + 2);
9515                                 CHECK_ARG (n);
9516                                 NEW_ARGSTORE (cfg, ins, n, *sp);
9517                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [n], *sp))
9518                                         UNVERIFIED;
9519                                 STARG_SOFT_FLOAT (cfg, ins, n, ip);
9520                                 if (ins->opcode == CEE_STOBJ) {
9521                                         NEW_ARGLOADA (cfg, ins, n);
9522                                         handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE, FALSE);
9523                                 } else
9524                                         MONO_ADD_INS (bblock, ins);
9525                                 ip += 4;
9526                                 break;
9527                         case CEE_LDLOC:
9528                                 CHECK_STACK_OVF (1);
9529                                 CHECK_OPSIZE (4);
9530                                 n = read16 (ip + 2);
9531                                 CHECK_LOCAL (n);
9532                                 NEW_LOCLOAD (cfg, ins, n);
9533                                 LDLOC_SOFT_FLOAT (cfg, ins, n, ip);
9534                                 *sp++ = ins;
9535                                 ip += 4;
9536                                 break;
9537                         case CEE_LDLOCA:
9538                                 CHECK_STACK_OVF (1);
9539                                 CHECK_OPSIZE (4);
9540                                 n = read16 (ip + 2);
9541                                 CHECK_LOCAL (n);
9542                                 NEW_LOCLOADA (cfg, ins, n);
9543                                 *sp++ = ins;
9544                                 ip += 4;
9545                                 break;
9546                         case CEE_STLOC:
9547                                 CHECK_STACK (1);
9548                                 --sp;
9549                                 CHECK_OPSIZE (4);
9550                                 n = read16 (ip + 2);
9551                                 CHECK_LOCAL (n);
9552                                 handle_loaded_temps (cfg, bblock, stack_start, sp);
9553                                 NEW_LOCSTORE (cfg, ins, n, *sp);
9554                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
9555                                         UNVERIFIED;
9556                                 STLOC_SOFT_FLOAT (cfg, ins, n, ip);
9557                                 if (ins->opcode == CEE_STOBJ) {
9558                                         NEW_LOCLOADA (cfg, ins, n);
9559                                         handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE, FALSE);
9560                                 } else
9561                                         MONO_ADD_INS (bblock, ins);
9562                                 ip += 4;
9563                                 inline_costs += 1;
9564                                 break;
9565                         case CEE_LOCALLOC:
9566                                 CHECK_STACK (1);
9567                                 --sp;
9568                                 if (sp != stack_start) 
9569                                         UNVERIFIED;
9570                                 if (cfg->method != method) 
9571                                         /* 
9572                                          * Inlining this into a loop in a parent could lead to 
9573                                          * stack overflows which is different behavior than the
9574                                          * non-inlined case, thus disable inlining in this case.
9575                                          */
9576                                         goto inline_failure;
9577                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
9578                                 ins->inst_left = *sp;
9579                                 ins->type = STACK_PTR;
9580
9581                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
9582                                 if (header->init_locals)
9583                                         ins->flags |= MONO_INST_INIT;
9584
9585                                 *sp++ = ins;
9586                                 ip += 2;
9587                                 /* FIXME: set init flag if locals init is set in this method */
9588                                 break;
9589                         case CEE_ENDFILTER: {
9590                                 MonoExceptionClause *clause, *nearest;
9591                                 int cc, nearest_num;
9592
9593                                 CHECK_STACK (1);
9594                                 --sp;
9595                                 if ((sp != stack_start) || (sp [0]->type != STACK_I4)) 
9596                                         UNVERIFIED;
9597                                 MONO_INST_NEW (cfg, ins, OP_ENDFILTER);
9598                                 ins->inst_left = *sp;
9599                                 MONO_ADD_INS (bblock, ins);
9600                                 start_new_bblock = 1;
9601                                 ip += 2;
9602
9603                                 nearest = NULL;
9604                                 nearest_num = 0;
9605                                 for (cc = 0; cc < header->num_clauses; ++cc) {
9606                                         clause = &header->clauses [cc];
9607                                         if ((clause->flags & MONO_EXCEPTION_CLAUSE_FILTER) &&
9608                                                 ((ip - header->code) > clause->data.filter_offset && (ip - header->code) <= clause->handler_offset) &&
9609                                             (!nearest || (clause->data.filter_offset < nearest->data.filter_offset))) {
9610                                                 nearest = clause;
9611                                                 nearest_num = cc;
9612                                         }
9613                                 }
9614                                 g_assert (nearest);
9615                                 if ((ip - header->code) != nearest->handler_offset)
9616                                         UNVERIFIED;
9617
9618                                 break;
9619                         }
9620                         case CEE_UNALIGNED_:
9621                                 ins_flag |= MONO_INST_UNALIGNED;
9622                                 /* FIXME: record alignment? we can assume 1 for now */
9623                                 CHECK_OPSIZE (3);
9624                                 ip += 3;
9625                                 break;
9626                         case CEE_VOLATILE_:
9627                                 ins_flag |= MONO_INST_VOLATILE;
9628                                 ip += 2;
9629                                 break;
9630                         case CEE_TAIL_:
9631                                 ins_flag   |= MONO_INST_TAILCALL;
9632                                 cfg->flags |= MONO_CFG_HAS_TAIL;
9633                                 /* Can't inline tail calls at this time */
9634                                 inline_costs += 100000;
9635                                 ip += 2;
9636                                 break;
9637                         case CEE_INITOBJ:
9638                                 CHECK_STACK (1);
9639                                 --sp;
9640                                 CHECK_OPSIZE (6);
9641                                 token = read32 (ip + 2);
9642                                 klass = mini_get_class (method, token, generic_context);
9643                                 CHECK_TYPELOAD (klass);
9644
9645                                 if (generic_class_is_reference_type (cfg, klass)) {
9646                                         MonoInst *store, *load;
9647                                         NEW_PCONST (cfg, load, NULL);
9648                                         load->type = STACK_OBJ;
9649                                         load->klass = klass;
9650                                         MONO_INST_NEW (cfg, store, CEE_STIND_REF);
9651                                         handle_loaded_temps (cfg, bblock, stack_start, sp);
9652                                         MONO_ADD_INS (bblock, store);
9653                                         store->inst_i0 = sp [0];
9654                                         store->inst_i1 = load;
9655                                 } else {
9656                                         handle_initobj (cfg, bblock, *sp, NULL, klass, stack_start, sp);
9657                                 }
9658                                 ip += 6;
9659                                 inline_costs += 1;
9660                                 break;
9661                         case CEE_CONSTRAINED_:
9662                                 /* FIXME: implement */
9663                                 CHECK_OPSIZE (6);
9664                                 token = read32 (ip + 2);
9665                                 constrained_call = mono_class_get_full (image, token, generic_context);
9666                                 CHECK_TYPELOAD (constrained_call);
9667                                 ip += 6;
9668                                 break;
9669                         case CEE_CPBLK:
9670                         case CEE_INITBLK: {
9671                                 MonoInst *iargs [3];
9672                                 CHECK_STACK (3);
9673                                 sp -= 3;
9674                                 if ((cfg->opt & MONO_OPT_INTRINS) && (ip [1] == CEE_CPBLK) && (sp [2]->opcode == OP_ICONST) && ((n = sp [2]->inst_c0) <= sizeof (gpointer) * 5)) {
9675                                         MonoInst *copy;
9676                                         NEW_MEMCPY (cfg, copy, sp [0], sp [1], n, 0);
9677                                         MONO_ADD_INS (bblock, copy);
9678                                         ip += 2;
9679                                         break;
9680                                 }
9681                                 iargs [0] = sp [0];
9682                                 iargs [1] = sp [1];
9683                                 iargs [2] = sp [2];
9684                                 handle_loaded_temps (cfg, bblock, stack_start, sp);
9685                                 if (ip [1] == CEE_CPBLK) {
9686                                         MonoMethod *memcpy_method = get_memcpy_method ();
9687                                         mono_emit_method_call_spilled (cfg, bblock, memcpy_method, memcpy_method->signature, iargs, ip, NULL);
9688                                 } else {
9689                                         MonoMethod *memset_method = get_memset_method ();
9690                                         mono_emit_method_call_spilled (cfg, bblock, memset_method, memset_method->signature, iargs, ip, NULL);
9691                                 }
9692                                 ip += 2;
9693                                 inline_costs += 1;
9694                                 break;
9695                         }
9696                         case CEE_NO_:
9697                                 CHECK_OPSIZE (3);
9698                                 if (ip [2] & 0x1)
9699                                         ins_flag |= MONO_INST_NOTYPECHECK;
9700                                 if (ip [2] & 0x2)
9701                                         ins_flag |= MONO_INST_NORANGECHECK;
9702                                 /* we ignore the no-nullcheck for now since we
9703                                  * really do it explicitly only when doing callvirt->call
9704                                  */
9705                                 ip += 3;
9706                                 break;
9707                         case CEE_RETHROW: {
9708                                 MonoInst *load;
9709                                 int handler_offset = -1;
9710
9711                                 for (i = 0; i < header->num_clauses; ++i) {
9712                                         MonoExceptionClause *clause = &header->clauses [i];
9713                                         if (MONO_OFFSET_IN_HANDLER (clause, ip - header->code) && !(clause->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
9714                                                 handler_offset = clause->handler_offset;
9715                                                 break;
9716                                         }
9717                                 }
9718
9719                                 bblock->flags |= BB_EXCEPTION_UNSAFE;
9720
9721                                 g_assert (handler_offset != -1);
9722
9723                                 NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, handler_offset)->inst_c0);
9724                                 MONO_INST_NEW (cfg, ins, OP_RETHROW);
9725                                 ins->inst_left = load;
9726                                 MONO_ADD_INS (bblock, ins);
9727                                 sp = stack_start;
9728                                 link_bblock (cfg, bblock, end_bblock);
9729                                 start_new_bblock = 1;
9730                                 ip += 2;
9731                                 break;
9732                         }
9733                         case CEE_SIZEOF:
9734                                 CHECK_STACK_OVF (1);
9735                                 CHECK_OPSIZE (6);
9736                                 token = read32 (ip + 2);
9737                                 /* FIXXME: handle generics. */
9738                                 if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC) {
9739                                         MonoType *type = mono_type_create_from_typespec (image, token);
9740                                         token = mono_type_size (type, &ialign);
9741                                 } else {
9742                                         MonoClass *klass = mono_class_get_full (image, token, generic_context);
9743                                         CHECK_TYPELOAD (klass);
9744                                         mono_class_init (klass);
9745                                         token = mono_class_value_size (klass, &align);
9746                                 }
9747                                 NEW_ICONST (cfg, ins, token);
9748                                 *sp++= ins;
9749                                 ip += 6;
9750                                 break;
9751                         case CEE_REFANYTYPE:
9752                                 CHECK_STACK (1);
9753                                 MONO_INST_NEW (cfg, ins, OP_REFANYTYPE);
9754                                 --sp;
9755                                 ins->type = STACK_MP;
9756                                 ins->inst_left = *sp;
9757                                 ins->type = STACK_VTYPE;
9758                                 ins->klass = mono_defaults.typehandle_class;
9759                                 ip += 2;
9760                                 *sp++ = ins;
9761                                 break;
9762                         case CEE_READONLY_:
9763                                 readonly = TRUE;
9764                                 ip += 2;
9765                                 break;
9766                         default:
9767                                 g_error ("opcode 0xfe 0x%02x not handled", ip [1]);
9768                         }
9769                         break;
9770                 }
9771                 default:
9772                         g_error ("opcode 0x%02x not handled", *ip);
9773                 }
9774         }
9775         if (start_new_bblock != 1)
9776                 UNVERIFIED;
9777
9778         bblock->cil_length = ip - bblock->cil_code;
9779         bblock->next_bb = end_bblock;
9780
9781         if (cfg->method == method && cfg->domainvar) {
9782                 MonoInst *store;
9783                 MonoInst *get_domain;
9784                 
9785                 if (! (get_domain = mono_arch_get_domain_intrinsic (cfg))) {
9786                         MonoCallInst *call;
9787                         
9788                         MONO_INST_NEW_CALL (cfg, call, OP_CALL);
9789                         call->signature = helper_sig_domain_get;
9790                         call->inst.type = STACK_PTR;
9791                         call->fptr = mono_domain_get;
9792                         get_domain = (MonoInst*)call;
9793                 }
9794                 
9795                 NEW_TEMPSTORE (cfg, store, cfg->domainvar->inst_c0, get_domain);
9796                 MONO_ADD_INS (init_localsbb, store);
9797         }
9798
9799         if (cfg->method == method && cfg->got_var)
9800                 mono_emit_load_got_addr (cfg);
9801
9802         if (header->init_locals) {
9803                 MonoInst *store;
9804                 cfg->ip = header->code;
9805                 for (i = 0; i < header->num_locals; ++i) {
9806                         MonoType *ptype = header->locals [i];
9807                         int t = ptype->type;
9808                         if (t == MONO_TYPE_VALUETYPE && ptype->data.klass->enumtype)
9809                                 t = ptype->data.klass->enum_basetype->type;
9810                         if (ptype->byref) {
9811                                 NEW_PCONST (cfg, ins, NULL);
9812                                 NEW_LOCSTORE (cfg, store, i, ins);
9813                                 MONO_ADD_INS (init_localsbb, store);
9814                         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
9815                                 NEW_ICONST (cfg, ins, 0);
9816                                 NEW_LOCSTORE (cfg, store, i, ins);
9817                                 MONO_ADD_INS (init_localsbb, store);
9818                         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
9819                                 MONO_INST_NEW (cfg, ins, OP_I8CONST);
9820                                 ins->type = STACK_I8;
9821                                 ins->inst_l = 0;
9822                                 NEW_LOCSTORE (cfg, store, i, ins);
9823                                 MONO_ADD_INS (init_localsbb, store);
9824                         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
9825 #ifdef MONO_ARCH_SOFT_FLOAT
9826                                 /* FIXME: handle init of R4 */
9827 #else
9828                                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
9829                                 ins->type = STACK_R8;
9830                                 ins->inst_p0 = (void*)&r8_0;
9831                                 NEW_LOCSTORE (cfg, store, i, ins);
9832                                 MONO_ADD_INS (init_localsbb, store);
9833 #endif
9834                         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
9835                                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (ptype))) {
9836                                 NEW_LOCLOADA (cfg, ins, i);
9837                                 handle_initobj (cfg, init_localsbb, ins, NULL, mono_class_from_mono_type (ptype), NULL, NULL);
9838                         } else {
9839                                 NEW_PCONST (cfg, ins, NULL);
9840                                 NEW_LOCSTORE (cfg, store, i, ins);
9841                                 MONO_ADD_INS (init_localsbb, store);
9842                         }
9843                 }
9844         }
9845
9846         cfg->ip = NULL;
9847
9848         /* resolve backward branches in the middle of an existing basic block */
9849         for (tmp = bb_recheck; tmp; tmp = tmp->next) {
9850                 bblock = tmp->data;
9851                 /*g_print ("need recheck in %s at IL_%04x\n", method->name, bblock->cil_code - header->code);*/
9852                 tblock = find_previous (cfg->cil_offset_to_bb, header->code_size, start_bblock, bblock->cil_code);
9853                 if (tblock != start_bblock) {
9854                         int l;
9855                         split_bblock (cfg, tblock, bblock);
9856                         l = bblock->cil_code - header->code;
9857                         bblock->cil_length = tblock->cil_length - l;
9858                         tblock->cil_length = l;
9859                 } else {
9860                         g_print ("recheck failed.\n");
9861                 }
9862         }
9863
9864         if (cfg->method == method) {
9865                 MonoBasicBlock *bb;
9866                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
9867                         bb->region = mono_find_block_region (cfg, bb->real_offset);
9868                         if (cfg->spvars)
9869                                 mono_create_spvar_for_region (cfg, bb->region);
9870                         if (cfg->verbose_level > 2)
9871                                 g_print ("REGION BB%d IL_%04x ID_%08X\n", bb->block_num, bb->real_offset, bb->region);
9872                 }
9873         }
9874
9875         g_slist_free (class_inits);
9876         dont_inline = g_list_remove (dont_inline, method);
9877
9878         if (inline_costs < 0) {
9879                 char *mname;
9880
9881                 /* Method is too large */
9882                 mname = mono_method_full_name (method, TRUE);
9883                 cfg->exception_type = MONO_EXCEPTION_INVALID_PROGRAM;
9884                 cfg->exception_message = g_strdup_printf ("Method %s is too complex.", mname);
9885                 g_free (mname);
9886                 return -1;
9887         }
9888
9889         return inline_costs;
9890
9891  exception_exit:
9892         g_assert (cfg->exception_type != MONO_EXCEPTION_NONE);
9893         g_slist_free (class_inits);
9894         dont_inline = g_list_remove (dont_inline, method);
9895         return -1;
9896
9897  inline_failure:
9898         g_slist_free (class_inits);
9899         dont_inline = g_list_remove (dont_inline, method);
9900         return -1;
9901
9902  load_error:
9903         g_slist_free (class_inits);
9904         dont_inline = g_list_remove (dont_inline, method);
9905         cfg->exception_type = MONO_EXCEPTION_TYPE_LOAD;
9906         return -1;
9907
9908  unverified:
9909         g_slist_free (class_inits);
9910         dont_inline = g_list_remove (dont_inline, method);
9911         set_exception_type_from_invalid_il (cfg, method, ip);
9912         return -1;
9913 }
9914
9915 void
9916 mono_print_tree (MonoInst *tree) {
9917         int arity;
9918
9919         if (!tree)
9920                 return;
9921
9922         arity = mono_burg_arity [tree->opcode];
9923
9924         printf (" %s%s", arity?"(":"",  mono_inst_name (tree->opcode));
9925
9926         switch (tree->opcode) {
9927         case OP_ICONST:
9928                 printf ("[%d]", (int)tree->inst_c0);
9929                 break;
9930         case OP_I8CONST:
9931                 printf ("[%lld]", (long long)tree->inst_l);
9932                 break;
9933         case OP_R8CONST:
9934                 printf ("[%f]", *(double*)tree->inst_p0);
9935                 break;
9936         case OP_R4CONST:
9937                 printf ("[%f]", *(float*)tree->inst_p0);
9938                 break;
9939         case OP_ARG:
9940         case OP_LOCAL:
9941                 printf ("[%d]", (int)tree->inst_c0);
9942                 break;
9943         case OP_REGOFFSET:
9944                 if (tree->inst_offset < 0)
9945                         printf ("[-0x%x(%s)]", (int)(-tree->inst_offset), mono_arch_regname (tree->inst_basereg));
9946                 else
9947                         printf ("[0x%x(%s)]", (int)(tree->inst_offset), mono_arch_regname (tree->inst_basereg));
9948                 break;
9949         case OP_REGVAR:
9950                 printf ("[%s]", mono_arch_regname (tree->dreg));
9951                 break;
9952         case CEE_NEWARR:
9953                 printf ("[%s]",  tree->inst_newa_class->name);
9954                 mono_print_tree (tree->inst_newa_len);
9955                 break;
9956         case OP_CALL:
9957         case OP_CALLVIRT:
9958         case OP_FCALL:
9959         case OP_FCALLVIRT:
9960         case OP_LCALL:
9961         case OP_LCALLVIRT:
9962         case OP_VCALL:
9963         case OP_VCALLVIRT:
9964         case OP_VOIDCALL:
9965         case OP_VOIDCALLVIRT:
9966         case OP_TRAMPCALL_VTABLE: {
9967                 MonoCallInst *call = (MonoCallInst*)tree;
9968                 if (call->method)
9969                         printf ("[%s]", call->method->name);
9970                 else if (call->fptr) {
9971                         MonoJitICallInfo *info = mono_find_jit_icall_by_addr (call->fptr);
9972                         if (info)
9973                                 printf ("[%s]", info->name);
9974                 }
9975                 break;
9976         }
9977         case OP_PHI: {
9978                 int i;
9979                 printf ("[%d (", (int)tree->inst_c0);
9980                 for (i = 0; i < tree->inst_phi_args [0]; i++) {
9981                         if (i)
9982                                 printf (", ");
9983                         printf ("%d", tree->inst_phi_args [i + 1]);
9984                 }
9985                 printf (")]");
9986                 break;
9987         }
9988         case OP_RENAME:
9989         case OP_RETARG:
9990         case OP_NOP:
9991         case OP_JMP:
9992         case OP_BREAK:
9993                 break;
9994         case OP_LOAD_MEMBASE:
9995         case OP_LOADI4_MEMBASE:
9996         case OP_LOADU4_MEMBASE:
9997         case OP_LOADU1_MEMBASE:
9998         case OP_LOADI1_MEMBASE:
9999         case OP_LOADU2_MEMBASE:
10000         case OP_LOADI2_MEMBASE:
10001                 printf ("[%s] <- [%s + 0x%x]", mono_arch_regname (tree->dreg), mono_arch_regname (tree->inst_basereg), (int)tree->inst_offset);
10002                 break;
10003         case OP_BR:
10004         case OP_CALL_HANDLER:
10005                 printf ("[B%d]", tree->inst_target_bb->block_num);
10006                 break;
10007         case OP_SWITCH:
10008         case CEE_ISINST:
10009         case CEE_CASTCLASS:
10010         case OP_OUTARG:
10011         case OP_CALL_REG:
10012         case OP_FCALL_REG:
10013         case OP_LCALL_REG:
10014         case OP_VCALL_REG:
10015         case OP_VOIDCALL_REG:
10016                 mono_print_tree (tree->inst_left);
10017                 break;
10018         case CEE_BNE_UN:
10019         case CEE_BEQ:
10020         case CEE_BLT:
10021         case CEE_BLT_UN:
10022         case CEE_BGT:
10023         case CEE_BGT_UN:
10024         case CEE_BGE:
10025         case CEE_BGE_UN:
10026         case CEE_BLE:
10027         case CEE_BLE_UN:
10028                 printf ("[B%dB%d]", tree->inst_true_bb->block_num, tree->inst_false_bb->block_num);
10029                 mono_print_tree (tree->inst_left);
10030                 break;
10031         default:
10032                 if (!mono_arch_print_tree(tree, arity)) {
10033                         if (arity) {
10034                                 mono_print_tree (tree->inst_left);
10035                                 if (arity > 1)
10036                                         mono_print_tree (tree->inst_right);
10037                         }
10038                 }
10039                 break;
10040         }
10041
10042         if (arity)
10043                 printf (")");
10044 }
10045
10046 void
10047 mono_print_tree_nl (MonoInst *tree)
10048 {
10049         mono_print_tree (tree);
10050         printf ("\n");
10051 }
10052
10053 static void
10054 create_helper_signature (void)
10055 {
10056         helper_sig_domain_get = mono_create_icall_signature ("ptr");
10057         helper_sig_class_init_trampoline = mono_create_icall_signature ("void");
10058         helper_sig_generic_class_init_trampoline = mono_create_icall_signature ("void");
10059         helper_sig_rgctx_lazy_fetch_trampoline = mono_create_icall_signature ("ptr ptr");
10060 }
10061
10062 gconstpointer
10063 mono_icall_get_wrapper (MonoJitICallInfo* callinfo)
10064 {
10065         char *name;
10066         MonoMethod *wrapper;
10067         gconstpointer trampoline;
10068         MonoDomain *domain = mono_get_root_domain ();
10069         
10070         if (callinfo->wrapper) {
10071                 return callinfo->wrapper;
10072         }
10073
10074         if (callinfo->trampoline)
10075                 return callinfo->trampoline;
10076
10077         /* 
10078          * We use the lock on the root domain instead of the JIT lock to protect 
10079          * callinfo->trampoline, since we do a lot of stuff inside the critical section.
10080          */
10081         mono_domain_lock (domain);
10082
10083         if (callinfo->trampoline) {
10084                 mono_domain_unlock (domain);
10085                 return callinfo->trampoline;
10086         }
10087
10088         name = g_strdup_printf ("__icall_wrapper_%s", callinfo->name);
10089         wrapper = mono_marshal_get_icall_wrapper (callinfo->sig, name, callinfo->func, check_for_pending_exc);
10090         g_free (name);
10091
10092         trampoline = mono_create_ftnptr (domain, mono_create_jit_trampoline_in_domain (domain, wrapper));
10093         mono_register_jit_icall_wrapper (callinfo, trampoline);
10094
10095         callinfo->trampoline = trampoline;
10096
10097         mono_domain_unlock (domain);
10098         
10099         return callinfo->trampoline;
10100 }
10101
10102 static void
10103 mono_dynamic_code_hash_insert (MonoDomain *domain, MonoMethod *method, MonoJitDynamicMethodInfo *ji)
10104 {
10105         if (!domain->dynamic_code_hash)
10106                 domain->dynamic_code_hash = g_hash_table_new (NULL, NULL);
10107         g_hash_table_insert (domain->dynamic_code_hash, method, ji);
10108 }
10109
10110 static MonoJitDynamicMethodInfo*
10111 mono_dynamic_code_hash_lookup (MonoDomain *domain, MonoMethod *method)
10112 {
10113         MonoJitDynamicMethodInfo *res;
10114
10115         if (domain->dynamic_code_hash)
10116                 res = g_hash_table_lookup (domain->dynamic_code_hash, method);
10117         else
10118                 res = NULL;
10119         return res;
10120 }
10121
10122 typedef struct {
10123         MonoClass *vtype;
10124         GList *active, *inactive;
10125         GSList *slots;
10126 } StackSlotInfo;
10127
10128 static gint 
10129 compare_by_interval_start_pos_func (gconstpointer a, gconstpointer b)
10130 {
10131         MonoMethodVar *v1 = (MonoMethodVar*)a;
10132         MonoMethodVar *v2 = (MonoMethodVar*)b;
10133
10134         if (v1 == v2)
10135                 return 0;
10136         else if (v1->interval->range && v2->interval->range)
10137                 return v1->interval->range->from - v2->interval->range->from;
10138         else if (v1->interval->range)
10139                 return -1;
10140         else
10141                 return 1;
10142 }
10143
10144 #ifndef DISABLE_JIT
10145
10146 #if 0
10147 #define LSCAN_DEBUG(a) do { a; } while (0)
10148 #else
10149 #define LSCAN_DEBUG(a)
10150 #endif
10151
10152 static gint32*
10153 mono_allocate_stack_slots_full2 (MonoCompile *cfg, gboolean backward, guint32 *stack_size, guint32 *stack_align)
10154 {
10155         int i, slot, offset, size;
10156         guint32 align;
10157         MonoMethodVar *vmv;
10158         MonoInst *inst;
10159         gint32 *offsets;
10160         GList *vars = NULL, *l, *unhandled;
10161         StackSlotInfo *scalar_stack_slots, *vtype_stack_slots, *slot_info;
10162         MonoType *t;
10163         int nvtypes;
10164
10165         LSCAN_DEBUG (printf ("Allocate Stack Slots 2 for %s:\n", mono_method_full_name (cfg->method, TRUE)));
10166
10167         scalar_stack_slots = mono_mempool_alloc0 (cfg->mempool, sizeof (StackSlotInfo) * MONO_TYPE_PINNED);
10168         vtype_stack_slots = NULL;
10169         nvtypes = 0;
10170
10171         offsets = mono_mempool_alloc (cfg->mempool, sizeof (gint32) * cfg->num_varinfo);
10172         for (i = 0; i < cfg->num_varinfo; ++i)
10173                 offsets [i] = -1;
10174
10175         for (i = cfg->locals_start; i < cfg->num_varinfo; i++) {
10176                 inst = cfg->varinfo [i];
10177                 vmv = MONO_VARINFO (cfg, i);
10178
10179                 if ((inst->flags & MONO_INST_IS_DEAD) || inst->opcode == OP_REGVAR || inst->opcode == OP_REGOFFSET)
10180                         continue;
10181
10182                 vars = g_list_prepend (vars, vmv);
10183         }
10184
10185         vars = g_list_sort (g_list_copy (vars), compare_by_interval_start_pos_func);
10186
10187         /* Sanity check */
10188         /*
10189         i = 0;
10190         for (unhandled = vars; unhandled; unhandled = unhandled->next) {
10191                 MonoMethodVar *current = unhandled->data;
10192
10193                 if (current->interval->range) {
10194                         g_assert (current->interval->range->from >= i);
10195                         i = current->interval->range->from;
10196                 }
10197         }
10198         */
10199
10200         offset = 0;
10201         *stack_align = 0;
10202         for (unhandled = vars; unhandled; unhandled = unhandled->next) {
10203                 MonoMethodVar *current = unhandled->data;
10204
10205                 vmv = current;
10206                 inst = cfg->varinfo [vmv->idx];
10207
10208                 /* inst->backend.is_pinvoke indicates native sized value types, this is used by the
10209                 * pinvoke wrappers when they call functions returning structures */
10210                 if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->inst_vtype->type != MONO_TYPE_TYPEDBYREF)
10211                         size = mono_class_native_size (inst->inst_vtype->data.klass, &align);
10212                 else {
10213                         int ialign;
10214
10215                         size = mono_type_size (inst->inst_vtype, &ialign);
10216                         align = ialign;
10217                 }
10218
10219                 t = mono_type_get_underlying_type (inst->inst_vtype);
10220                 switch (t->type) {
10221                 case MONO_TYPE_GENERICINST:
10222                         if (!mono_type_generic_inst_is_valuetype (t)) {
10223                                 slot_info = &scalar_stack_slots [t->type];
10224                                 break;
10225                         }
10226                         /* Fall through */
10227                 case MONO_TYPE_VALUETYPE:
10228                         if (!vtype_stack_slots)
10229                                 vtype_stack_slots = mono_mempool_alloc0 (cfg->mempool, sizeof (StackSlotInfo) * 256);
10230                         for (i = 0; i < nvtypes; ++i)
10231                                 if (t->data.klass == vtype_stack_slots [i].vtype)
10232                                         break;
10233                         if (i < nvtypes)
10234                                 slot_info = &vtype_stack_slots [i];
10235                         else {
10236                                 g_assert (nvtypes < 256);
10237                                 vtype_stack_slots [nvtypes].vtype = t->data.klass;
10238                                 slot_info = &vtype_stack_slots [nvtypes];
10239                                 nvtypes ++;
10240                         }
10241                         break;
10242                 case MONO_TYPE_CLASS:
10243                 case MONO_TYPE_OBJECT:
10244                 case MONO_TYPE_ARRAY:
10245                 case MONO_TYPE_SZARRAY:
10246                 case MONO_TYPE_STRING:
10247                 case MONO_TYPE_PTR:
10248                 case MONO_TYPE_I:
10249                 case MONO_TYPE_U:
10250 #if SIZEOF_VOID_P == 4
10251                 case MONO_TYPE_I4:
10252 #else
10253                 case MONO_TYPE_I8:
10254                         /* Share non-float stack slots of the same size */
10255                         slot_info = &scalar_stack_slots [MONO_TYPE_CLASS];
10256                         break;
10257 #endif
10258                 default:
10259                         slot_info = &scalar_stack_slots [t->type];
10260                 }
10261
10262                 slot = 0xffffff;
10263                 if (cfg->comp_done & MONO_COMP_LIVENESS) {
10264                         int pos;
10265                         gboolean changed;
10266
10267                         //printf ("START  %2d %08x %08x\n",  vmv->idx, vmv->range.first_use.abs_pos, vmv->range.last_use.abs_pos);
10268
10269                         if (!current->interval->range) {
10270                                 if (inst->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT))
10271                                         pos = ~0;
10272                                 else {
10273                                         /* Dead */
10274                                         inst->flags |= MONO_INST_IS_DEAD;
10275                                         continue;
10276                                 }
10277                         }
10278                         else
10279                                 pos = current->interval->range->from;
10280
10281                         LSCAN_DEBUG (printf ("process R%d ", inst->dreg));
10282                         if (current->interval->range)
10283                                 LSCAN_DEBUG (mono_linterval_print (current->interval));
10284                         LSCAN_DEBUG (printf ("\n"));
10285
10286                         /* Check for intervals in active which expired or inactive */
10287                         changed = TRUE;
10288                         /* FIXME: Optimize this */
10289                         while (changed) {
10290                                 changed = FALSE;
10291                                 for (l = slot_info->active; l != NULL; l = l->next) {
10292                                         MonoMethodVar *v = (MonoMethodVar*)l->data;
10293
10294                                         if (v->interval->last_range->to < pos) {
10295                                                 slot_info->active = g_list_delete_link (slot_info->active, l);
10296                                                 slot_info->slots = g_slist_prepend_mempool (cfg->mempool, slot_info->slots, GINT_TO_POINTER (offsets [v->idx]));
10297                                                 LSCAN_DEBUG (printf ("Interval R%d has expired, adding 0x%x to slots\n", cfg->varinfo [v->idx]->dreg, offsets [v->idx]));
10298                                                 changed = TRUE;
10299                                                 break;
10300                                         }
10301                                         else if (!mono_linterval_covers (v->interval, pos)) {
10302                                                 slot_info->inactive = g_list_append (slot_info->inactive, v);
10303                                                 slot_info->active = g_list_delete_link (slot_info->active, l);
10304                                                 LSCAN_DEBUG (printf ("Interval R%d became inactive\n", cfg->varinfo [v->idx]->dreg));
10305                                                 changed = TRUE;
10306                                                 break;
10307                                         }
10308                                 }
10309                         }
10310
10311                         /* Check for intervals in inactive which expired or active */
10312                         changed = TRUE;
10313                         /* FIXME: Optimize this */
10314                         while (changed) {
10315                                 changed = FALSE;
10316                                 for (l = slot_info->inactive; l != NULL; l = l->next) {
10317                                         MonoMethodVar *v = (MonoMethodVar*)l->data;
10318
10319                                         if (v->interval->last_range->to < pos) {
10320                                                 slot_info->inactive = g_list_delete_link (slot_info->inactive, l);
10321                                                 // FIXME: Enabling this seems to cause impossible to debug crashes
10322                                                 //slot_info->slots = g_slist_prepend_mempool (cfg->mempool, slot_info->slots, GINT_TO_POINTER (offsets [v->idx]));
10323                                                 LSCAN_DEBUG (printf ("Interval R%d has expired, adding 0x%x to slots\n", cfg->varinfo [v->idx]->dreg, offsets [v->idx]));
10324                                                 changed = TRUE;
10325                                                 break;
10326                                         }
10327                                         else if (mono_linterval_covers (v->interval, pos)) {
10328                                                 slot_info->active = g_list_append (slot_info->active, v);
10329                                                 slot_info->inactive = g_list_delete_link (slot_info->inactive, l);
10330                                                 LSCAN_DEBUG (printf ("\tInterval R%d became active\n", cfg->varinfo [v->idx]->dreg));
10331                                                 changed = TRUE;
10332                                                 break;
10333                                         }
10334                                 }
10335                         }
10336
10337                         /* 
10338                          * This also handles the case when the variable is used in an
10339                          * exception region, as liveness info is not computed there.
10340                          */
10341                         /* 
10342                          * FIXME: All valuetypes are marked as INDIRECT because of LDADDR
10343                          * opcodes.
10344                          */
10345                         if (! (inst->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT))) {
10346                                 if (slot_info->slots) {
10347                                         slot = GPOINTER_TO_INT (slot_info->slots->data);
10348
10349                                         slot_info->slots = slot_info->slots->next;
10350                                 }
10351
10352                                 /* FIXME: We might want to consider the inactive intervals as well if slot_info->slots is empty */
10353
10354                                 slot_info->active = mono_varlist_insert_sorted (cfg, slot_info->active, vmv, TRUE);
10355                         }
10356                 }
10357
10358 #if 0
10359                 {
10360                         static int count = 0;
10361                         count ++;
10362
10363                         if (count == atoi (getenv ("COUNT3")))
10364                                 printf ("LAST: %s\n", mono_method_full_name (cfg->method, TRUE));
10365                         if (count > atoi (getenv ("COUNT3")))
10366                                 slot = 0xffffff;
10367                         else {
10368                                 mono_print_tree_nl (inst);
10369                                 }
10370                 }
10371 #endif
10372
10373                 LSCAN_DEBUG (printf ("R%d %s -> 0x%x\n", inst->dreg, mono_type_full_name (t), slot));
10374
10375                 if (slot == 0xffffff) {
10376                         /*
10377                          * Allways allocate valuetypes to sizeof (gpointer) to allow more
10378                          * efficient copying (and to work around the fact that OP_MEMCPY
10379                          * and OP_MEMSET ignores alignment).
10380                          */
10381                         if (MONO_TYPE_ISSTRUCT (t))
10382                                 align = sizeof (gpointer);
10383
10384                         if (backward) {
10385                                 offset += size;
10386                                 offset += align - 1;
10387                                 offset &= ~(align - 1);
10388                                 slot = offset;
10389                         }
10390                         else {
10391                                 offset += align - 1;
10392                                 offset &= ~(align - 1);
10393                                 slot = offset;
10394                                 offset += size;
10395                         }
10396
10397                         if (*stack_align == 0)
10398                                 *stack_align = align;
10399                 }
10400
10401                 offsets [vmv->idx] = slot;
10402         }
10403         g_list_free (vars);
10404         for (i = 0; i < MONO_TYPE_PINNED; ++i) {
10405                 if (scalar_stack_slots [i].active)
10406                         g_list_free (scalar_stack_slots [i].active);
10407         }
10408         for (i = 0; i < nvtypes; ++i) {
10409                 if (vtype_stack_slots [i].active)
10410                         g_list_free (vtype_stack_slots [i].active);
10411         }
10412
10413         mono_jit_stats.locals_stack_size += offset;
10414
10415         *stack_size = offset;
10416         return offsets;
10417 }
10418
10419 /*
10420  *  mono_allocate_stack_slots_full:
10421  *
10422  *  Allocate stack slots for all non register allocated variables using a
10423  * linear scan algorithm.
10424  * Returns: an array of stack offsets.
10425  * STACK_SIZE is set to the amount of stack space needed.
10426  * STACK_ALIGN is set to the alignment needed by the locals area.
10427  */
10428 gint32*
10429 mono_allocate_stack_slots_full (MonoCompile *cfg, gboolean backward, guint32 *stack_size, guint32 *stack_align)
10430 {
10431         int i, slot, offset, size;
10432         guint32 align;
10433         MonoMethodVar *vmv;
10434         MonoInst *inst;
10435         gint32 *offsets;
10436         GList *vars = NULL, *l;
10437         StackSlotInfo *scalar_stack_slots, *vtype_stack_slots, *slot_info;
10438         MonoType *t;
10439         int nvtypes;
10440
10441         if ((cfg->num_varinfo > 0) && MONO_VARINFO (cfg, 0)->interval)
10442                 return mono_allocate_stack_slots_full2 (cfg, backward, stack_size, stack_align);
10443
10444         scalar_stack_slots = mono_mempool_alloc0 (cfg->mempool, sizeof (StackSlotInfo) * MONO_TYPE_PINNED);
10445         vtype_stack_slots = NULL;
10446         nvtypes = 0;
10447
10448         offsets = mono_mempool_alloc (cfg->mempool, sizeof (gint32) * cfg->num_varinfo);
10449         for (i = 0; i < cfg->num_varinfo; ++i)
10450                 offsets [i] = -1;
10451
10452         for (i = cfg->locals_start; i < cfg->num_varinfo; i++) {
10453                 inst = cfg->varinfo [i];
10454                 vmv = MONO_VARINFO (cfg, i);
10455
10456                 if ((inst->flags & MONO_INST_IS_DEAD) || inst->opcode == OP_REGVAR || inst->opcode == OP_REGOFFSET)
10457                         continue;
10458
10459                 vars = g_list_prepend (vars, vmv);
10460         }
10461
10462         vars = mono_varlist_sort (cfg, vars, 0);
10463         offset = 0;
10464         *stack_align = 0;
10465         for (l = vars; l; l = l->next) {
10466                 vmv = l->data;
10467                 inst = cfg->varinfo [vmv->idx];
10468
10469                 /* inst->backend.is_pinvoke indicates native sized value types, this is used by the
10470                 * pinvoke wrappers when they call functions returning structures */
10471                 if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->inst_vtype->type != MONO_TYPE_TYPEDBYREF)
10472                         size = mono_class_native_size (inst->inst_vtype->data.klass, &align);
10473                 else {
10474                         int ialign;
10475
10476                         size = mono_type_size (inst->inst_vtype, &ialign);
10477                         align = ialign;
10478                 }
10479
10480                 t = mono_type_get_underlying_type (inst->inst_vtype);
10481                 if (t->byref) {
10482                         slot_info = &scalar_stack_slots [MONO_TYPE_I];
10483                 } else {
10484                         switch (t->type) {
10485                         case MONO_TYPE_GENERICINST:
10486                                 if (!mono_type_generic_inst_is_valuetype (t)) {
10487                                         slot_info = &scalar_stack_slots [t->type];
10488                                         break;
10489                                 }
10490                                 /* Fall through */
10491                         case MONO_TYPE_VALUETYPE:
10492                                 if (!vtype_stack_slots)
10493                                         vtype_stack_slots = mono_mempool_alloc0 (cfg->mempool, sizeof (StackSlotInfo) * 256);
10494                                 for (i = 0; i < nvtypes; ++i)
10495                                         if (t->data.klass == vtype_stack_slots [i].vtype)
10496                                                 break;
10497                                 if (i < nvtypes)
10498                                         slot_info = &vtype_stack_slots [i];
10499                                 else {
10500                                         g_assert (nvtypes < 256);
10501                                         vtype_stack_slots [nvtypes].vtype = t->data.klass;
10502                                         slot_info = &vtype_stack_slots [nvtypes];
10503                                         nvtypes ++;
10504                                 }
10505                                 break;
10506                         case MONO_TYPE_CLASS:
10507                         case MONO_TYPE_OBJECT:
10508                         case MONO_TYPE_ARRAY:
10509                         case MONO_TYPE_SZARRAY:
10510                         case MONO_TYPE_STRING:
10511                         case MONO_TYPE_PTR:
10512                         case MONO_TYPE_I:
10513                         case MONO_TYPE_U:
10514 #if SIZEOF_VOID_P == 4
10515                         case MONO_TYPE_I4:
10516 #else
10517                         case MONO_TYPE_I8:
10518 #endif
10519                                 /* Share non-float stack slots of the same size */
10520                                 slot_info = &scalar_stack_slots [MONO_TYPE_CLASS];
10521                                 break;
10522                         default:
10523                                 slot_info = &scalar_stack_slots [t->type];
10524                         }
10525                 }
10526
10527                 slot = 0xffffff;
10528                 if (cfg->comp_done & MONO_COMP_LIVENESS) {
10529                         //printf ("START  %2d %08x %08x\n",  vmv->idx, vmv->range.first_use.abs_pos, vmv->range.last_use.abs_pos);
10530                         
10531                         /* expire old intervals in active */
10532                         while (slot_info->active) {
10533                                 MonoMethodVar *amv = (MonoMethodVar *)slot_info->active->data;
10534
10535                                 if (amv->range.last_use.abs_pos > vmv->range.first_use.abs_pos)
10536                                         break;
10537
10538                                 //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);
10539
10540                                 slot_info->active = g_list_delete_link (slot_info->active, slot_info->active);
10541                                 slot_info->slots = g_slist_prepend_mempool (cfg->mempool, slot_info->slots, GINT_TO_POINTER (offsets [amv->idx]));
10542                         }
10543
10544                         /* 
10545                          * This also handles the case when the variable is used in an
10546                          * exception region, as liveness info is not computed there.
10547                          */
10548                         /* 
10549                          * FIXME: All valuetypes are marked as INDIRECT because of LDADDR
10550                          * opcodes.
10551                          */
10552                         if (! (inst->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT))) {
10553                                 if (slot_info->slots) {
10554                                         slot = GPOINTER_TO_INT (slot_info->slots->data);
10555
10556                                         slot_info->slots = slot_info->slots->next;
10557                                 }
10558
10559                                 slot_info->active = mono_varlist_insert_sorted (cfg, slot_info->active, vmv, TRUE);
10560                         }
10561                 }
10562
10563                 {
10564                         static int count = 0;
10565                         count ++;
10566
10567                         /*
10568                         if (count == atoi (getenv ("COUNT")))
10569                                 printf ("LAST: %s\n", mono_method_full_name (cfg->method, TRUE));
10570                         if (count > atoi (getenv ("COUNT")))
10571                                 slot = 0xffffff;
10572                         else {
10573                                 mono_print_tree_nl (inst);
10574                                 }
10575                         */
10576                 }
10577
10578                 if (cfg->disable_reuse_stack_slots)
10579                         slot = 0xffffff;
10580
10581                 if (slot == 0xffffff) {
10582                         /*
10583                          * Allways allocate valuetypes to sizeof (gpointer) to allow more
10584                          * efficient copying (and to work around the fact that OP_MEMCPY
10585                          * and OP_MEMSET ignores alignment).
10586                          */
10587                         if (MONO_TYPE_ISSTRUCT (t))
10588                                 align = sizeof (gpointer);
10589
10590                         if (backward) {
10591                                 offset += size;
10592                                 offset += align - 1;
10593                                 offset &= ~(align - 1);
10594                                 slot = offset;
10595                         }
10596                         else {
10597                                 offset += align - 1;
10598                                 offset &= ~(align - 1);
10599                                 slot = offset;
10600                                 offset += size;
10601                         }
10602
10603                         if (*stack_align == 0)
10604                                 *stack_align = align;
10605                 }
10606
10607                 offsets [vmv->idx] = slot;
10608         }
10609         g_list_free (vars);
10610         for (i = 0; i < MONO_TYPE_PINNED; ++i) {
10611                 if (scalar_stack_slots [i].active)
10612                         g_list_free (scalar_stack_slots [i].active);
10613         }
10614         for (i = 0; i < nvtypes; ++i) {
10615                 if (vtype_stack_slots [i].active)
10616                         g_list_free (vtype_stack_slots [i].active);
10617         }
10618
10619         mono_jit_stats.locals_stack_size += offset;
10620
10621         *stack_size = offset;
10622         return offsets;
10623 }
10624
10625 gint32*
10626 mono_allocate_stack_slots (MonoCompile *m, guint32 *stack_size, guint32 *stack_align)
10627 {
10628         return mono_allocate_stack_slots_full (m, TRUE, stack_size, stack_align);
10629 }
10630
10631 #else
10632
10633 gint32*
10634 mono_allocate_stack_slots_full (MonoCompile *cfg, gboolean backward, guint32 *stack_size, guint32 *stack_align)
10635 {
10636         g_assert_not_reached ();
10637         return NULL;
10638 }
10639
10640 #endif /* DISABLE_JIT */
10641
10642 void
10643 mono_register_opcode_emulation (int opcode, const char *name, const char *sigstr, gpointer func, gboolean no_throw)
10644 {
10645         MonoJitICallInfo *info;
10646         MonoMethodSignature *sig = mono_create_icall_signature (sigstr);
10647
10648         if (!emul_opcode_map)
10649                 emul_opcode_map = g_new0 (MonoJitICallInfo*, OP_LAST + 1);
10650
10651         g_assert (!sig->hasthis);
10652         g_assert (sig->param_count < 3);
10653
10654         info = mono_register_jit_icall (func, name, sig, no_throw);
10655
10656         emul_opcode_map [opcode] = info;
10657 }
10658
10659 static void
10660 register_icall (gpointer func, const char *name, const char *sigstr, gboolean save)
10661 {
10662         MonoMethodSignature *sig;
10663
10664         if (sigstr)
10665                 sig = mono_create_icall_signature (sigstr);
10666         else
10667                 sig = NULL;
10668
10669         mono_register_jit_icall (func, name, sig, save);
10670 }
10671
10672 static void
10673 decompose_foreach (MonoInst *tree, gpointer data) 
10674 {
10675         static MonoJitICallInfo *newarr_info = NULL;
10676         static MonoJitICallInfo *newarr_specific_info = NULL;
10677         MonoJitICallInfo *info;
10678         int i;
10679
10680         switch (tree->opcode) {
10681         case CEE_NEWARR: {
10682                 MonoCompile *cfg = data;
10683                 MonoInst *iargs [3];
10684
10685                 if (!newarr_info) {
10686                         newarr_info = mono_find_jit_icall_by_addr (mono_array_new);
10687                         g_assert (newarr_info);
10688                         newarr_specific_info = mono_find_jit_icall_by_addr (mono_array_new_specific);
10689                         g_assert (newarr_specific_info);
10690                 }
10691
10692                 if (cfg->opt & MONO_OPT_SHARED) {
10693                         NEW_DOMAINCONST (cfg, iargs [0]);
10694                         NEW_CLASSCONST (cfg, iargs [1], tree->inst_newa_class);
10695                         iargs [2] = tree->inst_newa_len;
10696
10697                         info = newarr_info;
10698                 }
10699                 else {
10700                         MonoVTable *vtable = mono_class_vtable (cfg->domain, mono_array_class_get (tree->inst_newa_class, 1));
10701
10702                         g_assert (vtable);
10703                         NEW_VTABLECONST (cfg, iargs [0], vtable);
10704                         iargs [1] = tree->inst_newa_len;
10705
10706                         info = newarr_specific_info;
10707                 }
10708
10709                 mono_emulate_opcode (cfg, tree, iargs, info);
10710
10711                 /* Need to decompose arguments after the the opcode is decomposed */
10712                 for (i = 0; i < info->sig->param_count; ++i)
10713                         dec_foreach (iargs [i], cfg);
10714                 break;
10715         }
10716 #ifdef MONO_ARCH_SOFT_FLOAT
10717         case OP_FBEQ:
10718         case OP_FBGE:
10719         case OP_FBGT:
10720         case OP_FBLE:
10721         case OP_FBLT:
10722         case OP_FBNE_UN:
10723         case OP_FBGE_UN:
10724         case OP_FBGT_UN:
10725         case OP_FBLE_UN:
10726         case OP_FBLT_UN: {
10727                 if ((info = mono_find_jit_opcode_emulation (tree->opcode))) {
10728                         MonoCompile *cfg = data;
10729                         MonoInst *iargs [2];
10730                 
10731                         iargs [0] = tree->inst_i0;
10732                         iargs [1] = tree->inst_i1;
10733                 
10734                         mono_emulate_opcode (cfg, tree, iargs, info);
10735
10736                         dec_foreach (iargs [0], cfg);
10737                         dec_foreach (iargs [1], cfg);
10738                         break;
10739                 } else {
10740                         g_assert_not_reached ();
10741                 }
10742                 break;
10743         }
10744         case OP_FCEQ:
10745         case OP_FCGT:
10746         case OP_FCGT_UN:
10747         case OP_FCLT:
10748         case OP_FCLT_UN: {
10749                 if ((info = mono_find_jit_opcode_emulation (tree->opcode))) {
10750                         MonoCompile *cfg = data;
10751                         MonoInst *iargs [2];
10752
10753                         /* the args are in the compare opcode ... */
10754                         iargs [0] = tree->inst_i0;
10755                         iargs [1] = tree->inst_i1;
10756                 
10757                         mono_emulate_opcode (cfg, tree, iargs, info);
10758
10759                         dec_foreach (iargs [0], cfg);
10760                         dec_foreach (iargs [1], cfg);
10761                         break;
10762                 } else {
10763                         g_assert_not_reached ();
10764                 }
10765                 break;
10766         }
10767 #endif
10768
10769         default:
10770                 break;
10771         }
10772 }
10773
10774 void
10775 mono_inst_foreach (MonoInst *tree, MonoInstFunc func, gpointer data) {
10776
10777         switch (mono_burg_arity [tree->opcode]) {
10778         case 0: break;
10779         case 1: 
10780                 mono_inst_foreach (tree->inst_left, func, data);
10781                 break;
10782         case 2: 
10783                 mono_inst_foreach (tree->inst_left, func, data);
10784                 mono_inst_foreach (tree->inst_right, func, data);
10785                 break;
10786         default:
10787                 g_assert_not_reached ();
10788         }
10789         func (tree, data);
10790 }
10791
10792 G_GNUC_UNUSED
10793 static void
10794 mono_print_bb_code (MonoBasicBlock *bb)
10795 {
10796         MonoInst *c;
10797
10798         MONO_BB_FOR_EACH_INS (bb, c) {
10799                 mono_print_tree (c);
10800                 g_print ("\n");
10801         }
10802 }
10803
10804 static void
10805 print_dfn (MonoCompile *cfg) {
10806         int i, j;
10807         char *code;
10808         MonoBasicBlock *bb;
10809         MonoInst *c;
10810
10811         g_print ("IR code for method %s\n", mono_method_full_name (cfg->method, TRUE));
10812
10813         for (i = 0; i < cfg->num_bblocks; ++i) {
10814                 bb = cfg->bblocks [i];
10815                 /*if (bb->cil_code) {
10816                         char* code1, *code2;
10817                         code1 = mono_disasm_code_one (NULL, cfg->method, bb->cil_code, NULL);
10818                         if (bb->last_ins->cil_code)
10819                                 code2 = mono_disasm_code_one (NULL, cfg->method, bb->last_ins->cil_code, NULL);
10820                         else
10821                                 code2 = g_strdup ("");
10822
10823                         code1 [strlen (code1) - 1] = 0;
10824                         code = g_strdup_printf ("%s -> %s", code1, code2);
10825                         g_free (code1);
10826                         g_free (code2);
10827                 } else*/
10828                         code = g_strdup ("\n");
10829                 g_print ("\nBB%d (%d) (len: %d): %s", bb->block_num, i, bb->cil_length, code);
10830                 MONO_BB_FOR_EACH_INS (bb, c) {
10831                         if (cfg->new_ir) {
10832                                 mono_print_ins_index (-1, c);
10833                         } else {
10834                                 mono_print_tree (c);
10835                                 g_print ("\n");
10836                         }
10837                 }
10838
10839                 g_print ("\tprev:");
10840                 for (j = 0; j < bb->in_count; ++j) {
10841                         g_print (" BB%d", bb->in_bb [j]->block_num);
10842                 }
10843                 g_print ("\t\tsucc:");
10844                 for (j = 0; j < bb->out_count; ++j) {
10845                         g_print (" BB%d", bb->out_bb [j]->block_num);
10846                 }
10847                 g_print ("\n\tidom: BB%d\n", bb->idom? bb->idom->block_num: -1);
10848
10849                 if (bb->idom)
10850                         g_assert (mono_bitset_test_fast (bb->dominators, bb->idom->dfn));
10851
10852                 if (bb->dominators)
10853                         mono_blockset_print (cfg, bb->dominators, "\tdominators", bb->idom? bb->idom->dfn: -1);
10854                 if (bb->dfrontier)
10855                         mono_blockset_print (cfg, bb->dfrontier, "\tdfrontier", -1);
10856                 g_free (code);
10857         }
10858
10859         g_print ("\n");
10860 }
10861
10862 void
10863 mono_bblock_add_inst (MonoBasicBlock *bb, MonoInst *inst)
10864 {
10865         MONO_ADD_INS (bb, inst);
10866 }
10867
10868 void
10869 mono_bblock_insert_after_ins (MonoBasicBlock *bb, MonoInst *ins, MonoInst *ins_to_insert)
10870 {
10871         if (ins == NULL) {
10872                 ins = bb->code;
10873                 bb->code = ins_to_insert;
10874
10875                 /* Link with next */
10876                 ins_to_insert->next = ins;
10877                 if (ins)
10878                         ins->prev = ins_to_insert;
10879
10880                 if (bb->last_ins == NULL)
10881                         bb->last_ins = ins_to_insert;
10882         } else {
10883                 /* Link with next */
10884                 ins_to_insert->next = ins->next;
10885                 if (ins->next)
10886                         ins->next->prev = ins_to_insert;
10887
10888                 /* Link with previous */
10889                 ins->next = ins_to_insert;
10890                 ins_to_insert->prev = ins;
10891
10892                 if (bb->last_ins == ins)
10893                         bb->last_ins = ins_to_insert;
10894         }
10895 }
10896
10897 void
10898 mono_bblock_insert_before_ins (MonoBasicBlock *bb, MonoInst *ins, MonoInst *ins_to_insert)
10899 {
10900         if (ins == NULL) {
10901                 NOT_IMPLEMENTED;
10902                 ins = bb->code;
10903                 bb->code = ins_to_insert;
10904                 ins_to_insert->next = ins;
10905                 if (bb->last_ins == NULL)
10906                         bb->last_ins = ins_to_insert;
10907         } else {
10908                 /* Link with previous */
10909                 if (ins->prev)
10910                         ins->prev->next = ins_to_insert;
10911                 ins_to_insert->prev = ins->prev;
10912
10913                 /* Link with next */
10914                 ins->prev = ins_to_insert;
10915                 ins_to_insert->next = ins;
10916
10917                 if (bb->code == ins)
10918                         bb->code = ins_to_insert;
10919         }
10920 }
10921
10922 /*
10923  * mono_verify_bblock:
10924  *
10925  *   Verify that the next and prev pointers are consistent inside the instructions in BB.
10926  */
10927 void
10928 mono_verify_bblock (MonoBasicBlock *bb)
10929 {
10930         MonoInst *ins, *prev;
10931
10932         prev = NULL;
10933         for (ins = bb->code; ins; ins = ins->next) {
10934                 g_assert (ins->prev == prev);
10935                 prev = ins;
10936         }
10937         if (bb->last_ins)
10938                 g_assert (!bb->last_ins->next);
10939 }
10940
10941 /*
10942  * mono_verify_cfg:
10943  *
10944  *   Perform consistency checks on the JIT data structures and the IR
10945  */
10946 void
10947 mono_verify_cfg (MonoCompile *cfg)
10948 {
10949         MonoBasicBlock *bb;
10950
10951         for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
10952                 mono_verify_bblock (bb);
10953 }
10954
10955 void
10956 mono_destroy_compile (MonoCompile *cfg)
10957 {
10958         //mono_mempool_stats (cfg->mempool);
10959         mono_free_loop_info (cfg);
10960         if (cfg->rs)
10961                 mono_regstate_free (cfg->rs);
10962         if (cfg->spvars)
10963                 g_hash_table_destroy (cfg->spvars);
10964         if (cfg->exvars)
10965                 g_hash_table_destroy (cfg->exvars);
10966         mono_mempool_destroy (cfg->mempool);
10967         g_list_free (cfg->ldstr_list);
10968         g_hash_table_destroy (cfg->token_info_hash);
10969         if (cfg->abs_patches)
10970                 g_hash_table_destroy (cfg->abs_patches);
10971
10972         g_free (cfg->varinfo);
10973         g_free (cfg->vars);
10974         g_free (cfg->exception_message);
10975         g_free (cfg);
10976 }
10977
10978 #ifdef HAVE_KW_THREAD
10979 static __thread gpointer mono_lmf_addr MONO_TLS_FAST;
10980 #ifdef MONO_ARCH_ENABLE_MONO_LMF_VAR
10981 /* 
10982  * When this is defined, the current lmf is stored in this tls variable instead of in 
10983  * jit_tls->lmf.
10984  */
10985 static __thread gpointer mono_lmf MONO_TLS_FAST;
10986 #endif
10987 #endif
10988
10989 guint32
10990 mono_get_jit_tls_key (void)
10991 {
10992         return mono_jit_tls_id;
10993 }
10994
10995 gint32
10996 mono_get_jit_tls_offset (void)
10997 {
10998 #ifdef HAVE_KW_THREAD
10999         int offset;
11000         MONO_THREAD_VAR_OFFSET (mono_jit_tls, offset);
11001         return offset;
11002 #else
11003         return -1;
11004 #endif
11005 }
11006
11007 gint32
11008 mono_get_lmf_tls_offset (void)
11009 {
11010 #if defined(HAVE_KW_THREAD) && defined(MONO_ARCH_ENABLE_MONO_LMF_VAR)
11011         int offset;
11012         MONO_THREAD_VAR_OFFSET(mono_lmf,offset);
11013         return offset;
11014 #else
11015         return -1;
11016 #endif
11017 }
11018
11019 gint32
11020 mono_get_lmf_addr_tls_offset (void)
11021 {
11022         int offset;
11023         MONO_THREAD_VAR_OFFSET(mono_lmf_addr,offset);
11024         return offset;
11025 }
11026
11027 MonoLMF *
11028 mono_get_lmf (void)
11029 {
11030 #if defined(HAVE_KW_THREAD) && defined(MONO_ARCH_ENABLE_MONO_LMF_VAR)
11031         return mono_lmf;
11032 #else
11033         MonoJitTlsData *jit_tls;
11034
11035         if ((jit_tls = TlsGetValue (mono_jit_tls_id)))
11036                 return jit_tls->lmf;
11037
11038         g_assert_not_reached ();
11039         return NULL;
11040 #endif
11041 }
11042
11043 MonoLMF **
11044 mono_get_lmf_addr (void)
11045 {
11046 #ifdef HAVE_KW_THREAD
11047         return mono_lmf_addr;
11048 #else
11049         MonoJitTlsData *jit_tls;
11050
11051         if ((jit_tls = TlsGetValue (mono_jit_tls_id)))
11052                 return &jit_tls->lmf;
11053
11054         g_assert_not_reached ();
11055         return NULL;
11056 #endif
11057 }
11058
11059 /* Called by native->managed wrappers */
11060 void
11061 mono_jit_thread_attach (MonoDomain *domain)
11062 {
11063 #ifdef HAVE_KW_THREAD
11064         if (!mono_lmf_addr) {
11065                 mono_thread_attach (domain);
11066         }
11067 #else
11068         if (!TlsGetValue (mono_jit_tls_id))
11069                 mono_thread_attach (domain);
11070 #endif
11071         if (mono_domain_get () != domain)
11072                 mono_domain_set (domain, TRUE);
11073 }       
11074
11075 /**
11076  * mono_thread_abort:
11077  * @obj: exception object
11078  *
11079  * abort the thread, print exception information and stack trace
11080  */
11081 static void
11082 mono_thread_abort (MonoObject *obj)
11083 {
11084         /* MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id); */
11085         
11086         /* handle_remove should be eventually called for this thread, too
11087         g_free (jit_tls);*/
11088
11089         if ((mono_runtime_unhandled_exception_policy_get () == MONO_UNHANLED_POLICY_LEGACY) ||
11090                         (obj->vtable->klass == mono_defaults.threadabortexception_class)) {
11091                 mono_thread_exit ();
11092         } else {
11093                 exit (mono_environment_exitcode_get ());
11094         }
11095 }
11096
11097 static void*
11098 setup_jit_tls_data (gpointer stack_start, gpointer abort_func)
11099 {
11100         MonoJitTlsData *jit_tls;
11101         MonoLMF *lmf;
11102
11103         jit_tls = TlsGetValue (mono_jit_tls_id);
11104         if (jit_tls)
11105                 return jit_tls;
11106
11107         jit_tls = g_new0 (MonoJitTlsData, 1);
11108
11109         TlsSetValue (mono_jit_tls_id, jit_tls);
11110
11111 #ifdef HAVE_KW_THREAD
11112         mono_jit_tls = jit_tls;
11113 #endif
11114
11115         jit_tls->abort_func = abort_func;
11116         jit_tls->end_of_stack = stack_start;
11117
11118         lmf = g_new0 (MonoLMF, 1);
11119 #ifdef MONO_ARCH_INIT_TOP_LMF_ENTRY
11120         MONO_ARCH_INIT_TOP_LMF_ENTRY (lmf);
11121 #else
11122         lmf->ebp = -1;
11123 #endif
11124
11125         jit_tls->first_lmf = lmf;
11126
11127 #if defined(HAVE_KW_THREAD) && defined(MONO_ARCH_ENABLE_MONO_LMF_VAR)
11128         /* jit_tls->lmf is unused */
11129         mono_lmf = lmf;
11130         mono_lmf_addr = &mono_lmf;
11131 #else
11132 #if defined(HAVE_KW_THREAD)
11133         mono_lmf_addr = &jit_tls->lmf;  
11134 #endif
11135
11136         jit_tls->lmf = lmf;
11137 #endif
11138
11139         mono_arch_setup_jit_tls_data (jit_tls);
11140         mono_setup_altstack (jit_tls);
11141
11142         return jit_tls;
11143 }
11144
11145 static void
11146 mono_thread_start_cb (gsize tid, gpointer stack_start, gpointer func)
11147 {
11148         MonoThread *thread;
11149         void *jit_tls = setup_jit_tls_data (stack_start, mono_thread_abort);
11150         thread = mono_thread_current ();
11151         mono_debugger_thread_created (tid, thread, jit_tls);
11152         if (thread)
11153                 thread->jit_data = jit_tls;
11154 }
11155
11156 void (*mono_thread_attach_aborted_cb ) (MonoObject *obj) = NULL;
11157
11158 static void
11159 mono_thread_abort_dummy (MonoObject *obj)
11160 {
11161   if (mono_thread_attach_aborted_cb)
11162     mono_thread_attach_aborted_cb (obj);
11163   else
11164     mono_thread_abort (obj);
11165 }
11166
11167 static void
11168 mono_thread_attach_cb (gsize tid, gpointer stack_start)
11169 {
11170         MonoThread *thread;
11171         void *jit_tls = setup_jit_tls_data (stack_start, mono_thread_abort_dummy);
11172         thread = mono_thread_current ();
11173         mono_debugger_thread_created (tid, thread, (MonoJitTlsData *) jit_tls);
11174         if (thread)
11175                 thread->jit_data = jit_tls;
11176         if (mono_profiler_get_events () & MONO_PROFILE_STATISTICAL)
11177                 setup_stat_profiler ();
11178 }
11179
11180 static void
11181 mini_thread_cleanup (MonoThread *thread)
11182 {
11183         MonoJitTlsData *jit_tls = thread->jit_data;
11184
11185         if (jit_tls) {
11186                 mono_debugger_thread_cleanup (jit_tls);
11187                 mono_arch_free_jit_tls_data (jit_tls);
11188
11189                 mono_free_altstack (jit_tls);
11190                 g_free (jit_tls->first_lmf);
11191                 g_free (jit_tls);
11192                 thread->jit_data = NULL;
11193                 TlsSetValue (mono_jit_tls_id, NULL);
11194         }
11195 }
11196
11197 static MonoInst*
11198 mono_create_tls_get (MonoCompile *cfg, int offset)
11199 {
11200 #ifdef MONO_ARCH_HAVE_TLS_GET
11201         MonoInst* ins;
11202         
11203         if (offset == -1)
11204                 return NULL;
11205         
11206         MONO_INST_NEW (cfg, ins, OP_TLS_GET);
11207         ins->dreg = cfg->new_ir ? mono_alloc_preg (cfg) : mono_regstate_next_int (cfg->rs);
11208         ins->inst_offset = offset;
11209         return ins;
11210 #else
11211         return NULL;
11212 #endif
11213 }
11214
11215 MonoInst*
11216 mono_get_jit_tls_intrinsic (MonoCompile *cfg)
11217 {
11218         return mono_create_tls_get (cfg, mono_get_jit_tls_offset ());
11219 }
11220
11221 void
11222 mono_add_patch_info (MonoCompile *cfg, int ip, MonoJumpInfoType type, gconstpointer target)
11223 {
11224         MonoJumpInfo *ji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo));
11225
11226         ji->ip.i = ip;
11227         ji->type = type;
11228         ji->data.target = target;
11229         ji->next = cfg->patch_info;
11230
11231         cfg->patch_info = ji;
11232 }
11233
11234 MonoJumpInfo *
11235 mono_patch_info_list_prepend (MonoJumpInfo *list, int ip, MonoJumpInfoType type, gconstpointer target)
11236 {
11237         MonoJumpInfo *ji = g_new0 (MonoJumpInfo, 1);
11238
11239         ji->ip.i = ip;
11240         ji->type = type;
11241         ji->data.target = target;
11242         ji->next = list;
11243
11244         return ji;
11245 }
11246
11247 void
11248 mono_remove_patch_info (MonoCompile *cfg, int ip)
11249 {
11250         MonoJumpInfo **ji = &cfg->patch_info;
11251
11252         while (*ji) {
11253                 if ((*ji)->ip.i == ip)
11254                         *ji = (*ji)->next;
11255                 else
11256                         ji = &((*ji)->next);
11257         }
11258 }
11259
11260 /**
11261  * mono_patch_info_dup_mp:
11262  *
11263  * Make a copy of PATCH_INFO, allocating memory from the mempool MP.
11264  */
11265 MonoJumpInfo*
11266 mono_patch_info_dup_mp (MonoMemPool *mp, MonoJumpInfo *patch_info)
11267 {
11268         MonoJumpInfo *res = mono_mempool_alloc (mp, sizeof (MonoJumpInfo));
11269         memcpy (res, patch_info, sizeof (MonoJumpInfo));
11270
11271         switch (patch_info->type) {
11272         case MONO_PATCH_INFO_RVA:
11273         case MONO_PATCH_INFO_LDSTR:
11274         case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
11275         case MONO_PATCH_INFO_LDTOKEN:
11276         case MONO_PATCH_INFO_DECLSEC:
11277                 res->data.token = mono_mempool_alloc (mp, sizeof (MonoJumpInfoToken));
11278                 memcpy (res->data.token, patch_info->data.token, sizeof (MonoJumpInfoToken));
11279                 break;
11280         case MONO_PATCH_INFO_SWITCH:
11281                 res->data.table = mono_mempool_alloc (mp, sizeof (MonoJumpInfoBBTable));
11282                 memcpy (res->data.table, patch_info->data.table, sizeof (MonoJumpInfoBBTable));
11283                 break;
11284         case MONO_PATCH_INFO_RGCTX_FETCH:
11285                 res->data.rgctx_entry = mono_mempool_alloc (mp, sizeof (MonoJumpInfoRgctxEntry));
11286                 memcpy (res->data.rgctx_entry, patch_info->data.rgctx_entry, sizeof (MonoJumpInfoRgctxEntry));
11287                 res->data.rgctx_entry->data = mono_patch_info_dup_mp (mp, res->data.rgctx_entry->data);
11288                 break;
11289         default:
11290                 break;
11291         }
11292
11293         return res;
11294 }
11295
11296 guint
11297 mono_patch_info_hash (gconstpointer data)
11298 {
11299         const MonoJumpInfo *ji = (MonoJumpInfo*)data;
11300
11301         switch (ji->type) {
11302         case MONO_PATCH_INFO_RVA:
11303         case MONO_PATCH_INFO_LDSTR:
11304         case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
11305         case MONO_PATCH_INFO_LDTOKEN:
11306         case MONO_PATCH_INFO_DECLSEC:
11307                 return (ji->type << 8) | ji->data.token->token;
11308         case MONO_PATCH_INFO_VTABLE:
11309         case MONO_PATCH_INFO_CLASS:
11310         case MONO_PATCH_INFO_IID:
11311         case MONO_PATCH_INFO_ADJUSTED_IID:
11312         case MONO_PATCH_INFO_CLASS_INIT:
11313         case MONO_PATCH_INFO_METHODCONST:
11314         case MONO_PATCH_INFO_METHOD:
11315         case MONO_PATCH_INFO_METHOD_JUMP:
11316         case MONO_PATCH_INFO_IMAGE:
11317         case MONO_PATCH_INFO_INTERNAL_METHOD:
11318         case MONO_PATCH_INFO_JIT_ICALL_ADDR:
11319         case MONO_PATCH_INFO_FIELD:
11320         case MONO_PATCH_INFO_SFLDA:
11321                 return (ji->type << 8) | (gssize)ji->data.target;
11322         default:
11323                 return (ji->type << 8);
11324         }
11325 }
11326
11327 /* 
11328  * mono_patch_info_equal:
11329  * 
11330  * This might fail to recognize equivalent patches, i.e. floats, so its only
11331  * usable in those cases where this is not a problem, i.e. sharing GOT slots
11332  * in AOT.
11333  */
11334 gint
11335 mono_patch_info_equal (gconstpointer ka, gconstpointer kb)
11336 {
11337         const MonoJumpInfo *ji1 = (MonoJumpInfo*)ka;
11338         const MonoJumpInfo *ji2 = (MonoJumpInfo*)kb;
11339
11340         if (ji1->type != ji2->type)
11341                 return 0;
11342
11343         switch (ji1->type) {
11344         case MONO_PATCH_INFO_RVA:
11345         case MONO_PATCH_INFO_LDSTR:
11346         case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
11347         case MONO_PATCH_INFO_LDTOKEN:
11348         case MONO_PATCH_INFO_DECLSEC:
11349                 if ((ji1->data.token->image != ji2->data.token->image) ||
11350                         (ji1->data.token->token != ji2->data.token->token))
11351                         return 0;
11352                 break;
11353         default:
11354                 if (ji1->data.target != ji2->data.target)
11355                         return 0;
11356                 break;
11357         }
11358
11359         return 1;
11360 }
11361
11362 gpointer
11363 mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *patch_info, gboolean run_cctors)
11364 {
11365         unsigned char *ip = patch_info->ip.i + code;
11366         gconstpointer target = NULL;
11367
11368         switch (patch_info->type) {
11369         case MONO_PATCH_INFO_BB:
11370                 g_assert (patch_info->data.bb->native_offset);
11371                 target = patch_info->data.bb->native_offset + code;
11372                 break;
11373         case MONO_PATCH_INFO_ABS:
11374                 target = patch_info->data.target;
11375                 break;
11376         case MONO_PATCH_INFO_LABEL:
11377                 target = patch_info->data.inst->inst_c0 + code;
11378                 break;
11379         case MONO_PATCH_INFO_IP:
11380                 target = ip;
11381                 break;
11382         case MONO_PATCH_INFO_METHOD_REL:
11383                 target = code + patch_info->data.offset;
11384                 break;
11385         case MONO_PATCH_INFO_INTERNAL_METHOD: {
11386                 MonoJitICallInfo *mi = mono_find_jit_icall_by_name (patch_info->data.name);
11387                 if (!mi) {
11388                         g_warning ("unknown MONO_PATCH_INFO_INTERNAL_METHOD %s", patch_info->data.name);
11389                         g_assert_not_reached ();
11390                 }
11391                 target = mono_icall_get_wrapper (mi);
11392                 break;
11393         }
11394         case MONO_PATCH_INFO_METHOD_JUMP:
11395                 target = mono_create_jump_trampoline (domain, patch_info->data.method, FALSE);
11396                 break;
11397         case MONO_PATCH_INFO_METHOD:
11398                 if (patch_info->data.method == method) {
11399                         target = code;
11400                 } else {
11401                         /* get the trampoline to the method from the domain */
11402                         if (method && method->wrapper_type == MONO_WRAPPER_STATIC_RGCTX_INVOKE) {
11403                                 target = mono_create_jit_trampoline_in_domain (mono_domain_get (),
11404                                         patch_info->data.method);
11405                         } else {
11406                                 target = mono_create_jit_trampoline (patch_info->data.method);
11407                         }
11408                 }
11409                 break;
11410         case MONO_PATCH_INFO_SWITCH: {
11411                 gpointer *jump_table;
11412                 int i;
11413
11414                 if (method && method->dynamic) {
11415                         jump_table = mono_code_manager_reserve (mono_dynamic_code_hash_lookup (domain, method)->code_mp, sizeof (gpointer) * patch_info->data.table->table_size);
11416                 } else {
11417                         mono_domain_lock (domain);
11418                         if (mono_aot_only)
11419                                 jump_table = mono_mempool_alloc (domain->mp, sizeof (gpointer) * patch_info->data.table->table_size);
11420                         else
11421                                 jump_table = mono_code_manager_reserve (domain->code_mp, sizeof (gpointer) * patch_info->data.table->table_size);
11422                         mono_domain_unlock (domain);
11423                 }
11424
11425                 for (i = 0; i < patch_info->data.table->table_size; i++)
11426                         jump_table [i] = code + GPOINTER_TO_INT (patch_info->data.table->table [i]);
11427                 target = jump_table;
11428                 break;
11429         }
11430         case MONO_PATCH_INFO_METHODCONST:
11431         case MONO_PATCH_INFO_CLASS:
11432         case MONO_PATCH_INFO_IMAGE:
11433         case MONO_PATCH_INFO_FIELD:
11434                 target = patch_info->data.target;
11435                 break;
11436         case MONO_PATCH_INFO_IID:
11437                 mono_class_init (patch_info->data.klass);
11438                 target = GINT_TO_POINTER ((int)patch_info->data.klass->interface_id);
11439                 break;
11440         case MONO_PATCH_INFO_ADJUSTED_IID:
11441                 mono_class_init (patch_info->data.klass);
11442                 target = GINT_TO_POINTER ((int)(-((patch_info->data.klass->interface_id + 1) * SIZEOF_VOID_P)));
11443                 break;
11444         case MONO_PATCH_INFO_VTABLE:
11445                 target = mono_class_vtable (domain, patch_info->data.klass);
11446                 g_assert (target);
11447                 break;
11448         case MONO_PATCH_INFO_CLASS_INIT: {
11449                 MonoVTable *vtable = mono_class_vtable (domain, patch_info->data.klass);
11450
11451                 g_assert (vtable);
11452                 target = mono_create_class_init_trampoline (vtable);
11453                 break;
11454         }
11455         case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE:
11456                 target = mono_create_delegate_trampoline (patch_info->data.klass);
11457                 break;
11458         case MONO_PATCH_INFO_SFLDA: {
11459                 MonoVTable *vtable = mono_class_vtable (domain, patch_info->data.field->parent);
11460
11461                 g_assert (vtable);
11462                 if (!vtable->initialized && !(vtable->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) && (method && mono_class_needs_cctor_run (vtable->klass, method)))
11463                         /* Done by the generated code */
11464                         ;
11465                 else {
11466                         if (run_cctors)
11467                                 mono_runtime_class_init (vtable);
11468                 }
11469                 target = (char*)vtable->data + patch_info->data.field->offset;
11470                 break;
11471         }
11472         case MONO_PATCH_INFO_RVA:
11473                 target = mono_image_rva_map (patch_info->data.token->image, patch_info->data.token->token);
11474                 break;
11475         case MONO_PATCH_INFO_R4:
11476         case MONO_PATCH_INFO_R8:
11477                 target = patch_info->data.target;
11478                 break;
11479         case MONO_PATCH_INFO_EXC_NAME:
11480                 target = patch_info->data.name;
11481                 break;
11482         case MONO_PATCH_INFO_LDSTR:
11483                 target =
11484                         mono_ldstr (domain, patch_info->data.token->image, 
11485                                                 mono_metadata_token_index (patch_info->data.token->token));
11486                 break;
11487         case MONO_PATCH_INFO_TYPE_FROM_HANDLE: {
11488                 gpointer handle;
11489                 MonoClass *handle_class;
11490
11491                 handle = mono_ldtoken (patch_info->data.token->image, 
11492                                        patch_info->data.token->token, &handle_class, NULL);
11493                 mono_class_init (handle_class);
11494                 mono_class_init (mono_class_from_mono_type (handle));
11495
11496                 target =
11497                         mono_type_get_object (domain, handle);
11498                 break;
11499         }
11500         case MONO_PATCH_INFO_LDTOKEN: {
11501                 gpointer handle;
11502                 MonoClass *handle_class;
11503                 
11504                 handle = mono_ldtoken (patch_info->data.token->image,
11505                                        patch_info->data.token->token, &handle_class, NULL);
11506                 mono_class_init (handle_class);
11507                 
11508                 target = handle;
11509                 break;
11510         }
11511         case MONO_PATCH_INFO_DECLSEC:
11512                 target = (mono_metadata_blob_heap (patch_info->data.token->image, patch_info->data.token->token) + 2);
11513                 break;
11514         case MONO_PATCH_INFO_ICALL_ADDR:
11515                 target = mono_lookup_internal_call (patch_info->data.method);
11516                 /* run_cctors == 0 -> AOT */
11517                 if (!target && run_cctors)
11518                         g_error ("Unregistered icall '%s'\n", mono_method_full_name (patch_info->data.method, TRUE));
11519                 break;
11520         case MONO_PATCH_INFO_JIT_ICALL_ADDR: {
11521                 MonoJitICallInfo *mi = mono_find_jit_icall_by_name (patch_info->data.name);
11522                 if (!mi) {
11523                         g_warning ("unknown MONO_PATCH_INFO_JIT_ICALL_ADDR %s", patch_info->data.name);
11524                         g_assert_not_reached ();
11525                 }
11526                 target = mi->func;
11527                 break;
11528         }
11529         case MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG:
11530                 target = mono_thread_interruption_request_flag ();
11531                 break;
11532         case MONO_PATCH_INFO_METHOD_RGCTX:
11533                 target = mono_method_lookup_rgctx (mono_class_vtable (domain, patch_info->data.method->klass), mini_method_get_context (patch_info->data.method)->method_inst);
11534                 break;
11535         case MONO_PATCH_INFO_BB_OVF:
11536         case MONO_PATCH_INFO_EXC_OVF:
11537         case MONO_PATCH_INFO_GOT_OFFSET:
11538         case MONO_PATCH_INFO_NONE:
11539                 break;
11540         case MONO_PATCH_INFO_RGCTX_FETCH: {
11541                 MonoJumpInfoRgctxEntry *entry = patch_info->data.rgctx_entry;
11542                 guint32 slot = -1;
11543
11544                 switch (entry->data->type) {
11545                 case MONO_PATCH_INFO_CLASS:
11546                         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));
11547                         break;
11548                 case MONO_PATCH_INFO_METHOD:
11549                 case MONO_PATCH_INFO_METHODCONST:
11550                         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));
11551                         break;
11552                 case MONO_PATCH_INFO_FIELD:
11553                         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));
11554                         break;
11555                 default:
11556                         g_assert_not_reached ();
11557                         break;
11558                 }
11559
11560                 target = mono_create_rgctx_lazy_fetch_trampoline (slot);
11561                 break;
11562         }
11563         case MONO_PATCH_INFO_GENERIC_CLASS_INIT:
11564                 target = mono_create_generic_class_init_trampoline ();
11565                 break;
11566         default:
11567                 g_assert_not_reached ();
11568         }
11569
11570         return (gpointer)target;
11571 }
11572
11573 static void
11574 dec_foreach (MonoInst *tree, MonoCompile *cfg) {
11575         MonoJitICallInfo *info;
11576
11577         decompose_foreach (tree, cfg);
11578
11579         switch (mono_burg_arity [tree->opcode]) {
11580         case 0: break;
11581         case 1: 
11582                 dec_foreach (tree->inst_left, cfg);
11583
11584                 if ((info = mono_find_jit_opcode_emulation (tree->opcode))) {
11585                         MonoInst *iargs [2];
11586                 
11587                         iargs [0] = tree->inst_left;
11588
11589                         mono_emulate_opcode (cfg, tree, iargs, info);
11590                         return;
11591                 }
11592
11593                 break;
11594         case 2:
11595 #ifdef MONO_ARCH_BIGMUL_INTRINS
11596                 if (tree->opcode == OP_LMUL
11597                                 && (cfg->opt & MONO_OPT_INTRINS)
11598                                 && (tree->inst_left->opcode == CEE_CONV_I8 
11599                                         || tree->inst_left->opcode == CEE_CONV_U8)
11600                                 && tree->inst_left->inst_left->type == STACK_I4
11601                                 && (tree->inst_right->opcode == CEE_CONV_I8 
11602                                         || tree->inst_right->opcode == CEE_CONV_U8)
11603                                 && tree->inst_right->inst_left->type == STACK_I4
11604                                 && tree->inst_left->opcode == tree->inst_right->opcode) {
11605                         tree->opcode = (tree->inst_left->opcode == CEE_CONV_I8 ? OP_BIGMUL: OP_BIGMUL_UN);
11606                         tree->inst_left = tree->inst_left->inst_left;
11607                         tree->inst_right = tree->inst_right->inst_left;
11608                         dec_foreach (tree, cfg);
11609                 } else 
11610 #endif
11611                         if ((info = mono_find_jit_opcode_emulation (tree->opcode))) {
11612                         MonoInst *iargs [2];
11613                 
11614                         iargs [0] = tree->inst_i0;
11615                         iargs [1] = tree->inst_i1;
11616                 
11617                         mono_emulate_opcode (cfg, tree, iargs, info);
11618
11619                         dec_foreach (iargs [0], cfg);
11620                         dec_foreach (iargs [1], cfg);
11621                         return;
11622                 } else {
11623                         dec_foreach (tree->inst_left, cfg);
11624                         dec_foreach (tree->inst_right, cfg);
11625                 }
11626                 break;
11627         default:
11628                 g_assert_not_reached ();
11629         }
11630 }
11631
11632 static void
11633 decompose_pass (MonoCompile *cfg) {
11634         MonoBasicBlock *bb;
11635
11636         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
11637                 MonoInst *tree;
11638                 cfg->cbb = bb;
11639                 cfg->prev_ins = NULL;
11640                 MONO_BB_FOR_EACH_INS (cfg->cbb, tree) {
11641                         dec_foreach (tree, cfg);
11642                         cfg->prev_ins = tree;
11643                 }
11644         }
11645 }
11646
11647 static void
11648 mono_compile_create_vars (MonoCompile *cfg)
11649 {
11650         MonoMethodSignature *sig;
11651         MonoMethodHeader *header;
11652         int i;
11653
11654         header = mono_method_get_header (cfg->method);
11655
11656         sig = mono_method_signature (cfg->method);
11657         
11658         if (!MONO_TYPE_IS_VOID (sig->ret)) {
11659                 if (cfg->new_ir) {
11660                         cfg->ret = mono_compile_create_var (cfg, sig->ret, OP_ARG);
11661                         /* Inhibit optimizations */
11662                         cfg->ret->flags |= MONO_INST_VOLATILE;
11663                 } else {
11664                         cfg->ret = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst));
11665                         cfg->ret->opcode = OP_RETARG;
11666                         cfg->ret->inst_vtype = sig->ret;
11667                         cfg->ret->klass = mono_class_from_mono_type (sig->ret);
11668                 }
11669         }
11670         if (cfg->verbose_level > 2)
11671                 g_print ("creating vars\n");
11672
11673         cfg->args = mono_mempool_alloc0 (cfg->mempool, (sig->param_count + sig->hasthis) * sizeof (MonoInst*));
11674
11675         if (sig->hasthis)
11676                 cfg->args [0] = mono_compile_create_var (cfg, &cfg->method->klass->this_arg, OP_ARG);
11677
11678         for (i = 0; i < sig->param_count; ++i) {
11679                 cfg->args [i + sig->hasthis] = mono_compile_create_var (cfg, sig->params [i], OP_ARG);
11680                 if (sig->params [i]->byref) {
11681                         if (!cfg->new_ir) cfg->disable_ssa = TRUE;
11682                 }
11683         }
11684
11685         if (cfg->new_ir && cfg->verbose_level > 2) {
11686                 if (cfg->ret) {
11687                         printf ("\treturn : ");
11688                         mono_print_ins (cfg->ret);
11689                 }
11690
11691                 if (sig->hasthis) {
11692                         printf ("\tthis: ");
11693                         mono_print_ins (cfg->args [0]);
11694                 }
11695
11696                 for (i = 0; i < sig->param_count; ++i) {
11697                         printf ("\targ [%d]: ", i);
11698                         mono_print_ins (cfg->args [i + sig->hasthis]);
11699                 }
11700         }
11701
11702         cfg->locals_start = cfg->num_varinfo;
11703         cfg->locals = mono_mempool_alloc0 (cfg->mempool, header->num_locals * sizeof (MonoInst*));
11704
11705         if (cfg->verbose_level > 2)
11706                 g_print ("creating locals\n");
11707
11708         for (i = 0; i < header->num_locals; ++i)
11709                 cfg->locals [i] = mono_compile_create_var (cfg, header->locals [i], OP_LOCAL);
11710
11711         if (cfg->verbose_level > 2)
11712                 g_print ("locals done\n");
11713
11714         mono_arch_create_vars (cfg);
11715 }
11716
11717 void
11718 mono_print_code (MonoCompile *cfg, const char* msg)
11719 {
11720         MonoBasicBlock *bb;
11721         
11722         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
11723                 MonoInst *tree = bb->code;      
11724
11725                 if (cfg->new_ir) {
11726                         mono_print_bb (bb, msg);
11727                 } else {
11728                         if (!tree)
11729                                 continue;
11730                         
11731                         g_print ("%s CODE BLOCK %d (nesting %d):\n", msg, bb->block_num, bb->nesting);
11732
11733                         MONO_BB_FOR_EACH_INS (bb, tree) {
11734                                 mono_print_tree (tree);
11735                                 g_print ("\n");
11736                         }
11737                 }
11738         }
11739 }
11740
11741 #ifndef DISABLE_JIT
11742
11743 extern const char * const mono_burg_rule_string [];
11744
11745 static void
11746 emit_state (MonoCompile *cfg, MBState *state, int goal)
11747 {
11748         MBState *kids [10];
11749         int ern = mono_burg_rule (state, goal);
11750         const guint16 *nts = mono_burg_nts_data + mono_burg_nts [ern];
11751
11752         //g_print ("rule: %s\n", mono_burg_rule_string [ern]);
11753         switch (goal) {
11754         case MB_NTERM_reg:
11755                 //if (state->reg2)
11756                 //      state->reg1 = state->reg2; /* chain rule */
11757                 //else
11758 #ifdef MONO_ARCH_ENABLE_EMIT_STATE_OPT
11759                 if (!state->reg1)
11760 #endif
11761                         state->reg1 = mono_regstate_next_int (cfg->rs);
11762                 //g_print ("alloc symbolic R%d (reg2: R%d) in block %d\n", state->reg1, state->reg2, cfg->cbb->block_num);
11763                 break;
11764         case MB_NTERM_lreg:
11765                 state->reg1 = mono_regstate_next_int (cfg->rs);
11766                 state->reg2 = mono_regstate_next_int (cfg->rs);
11767                 break;
11768         case MB_NTERM_freg:
11769 #ifdef MONO_ARCH_SOFT_FLOAT
11770                 state->reg1 = mono_regstate_next_int (cfg->rs);
11771                 state->reg2 = mono_regstate_next_int (cfg->rs);
11772 #else
11773                 state->reg1 = mono_regstate_next_float (cfg->rs);
11774 #endif
11775                 break;
11776         default:
11777 #ifdef MONO_ARCH_ENABLE_EMIT_STATE_OPT
11778                 /*
11779                  * Enabling this might cause bugs to surface in the local register
11780                  * allocators on some architectures like x86.
11781                  */
11782                 if ((state->tree->ssa_op == MONO_SSA_STORE) && (state->left->tree->opcode == OP_REGVAR)) {
11783                         /* Do not optimize away reg-reg moves */
11784                         if (! ((state->right->tree->ssa_op == MONO_SSA_LOAD) && (state->right->left->tree->opcode == OP_REGVAR))) {
11785                                 state->right->reg1 = state->left->tree->dreg;
11786                         }
11787                 }
11788 #endif
11789
11790                 /* do nothing */
11791                 break;
11792         }
11793         if (nts [0]) {
11794                 mono_burg_kids (state, ern, kids);
11795
11796                 emit_state (cfg, kids [0], nts [0]);
11797                 if (nts [1]) {
11798                         emit_state (cfg, kids [1], nts [1]);
11799                         if (nts [2]) {
11800                                 emit_state (cfg, kids [2], nts [2]);
11801                                 if (nts [3]) {
11802                                         g_assert (!nts [4]);
11803                                         emit_state (cfg, kids [3], nts [3]);
11804                                 }
11805                         }
11806                 }
11807         }
11808
11809 //      g_print ("emit: %s (%p)\n", mono_burg_rule_string [ern], state);
11810         mono_burg_emit (ern, state, state->tree, cfg);
11811 }
11812
11813 #define DEBUG_SELECTION
11814
11815 static void 
11816 mini_select_instructions (MonoCompile *cfg)
11817 {
11818         MonoBasicBlock *bb;
11819         
11820         cfg->state_pool = mono_mempool_new ();
11821         cfg->rs = mono_regstate_new ();
11822
11823         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
11824                 if (bb->last_ins && MONO_IS_COND_BRANCH_OP (bb->last_ins) &&
11825                     bb->last_ins->inst_false_bb && bb->next_bb != bb->last_ins->inst_false_bb) {
11826
11827                         /* we are careful when inverting, since bugs like #59580
11828                          * could show up when dealing with NaNs.
11829                          */
11830                         if (MONO_IS_COND_BRANCH_NOFP(bb->last_ins) && bb->next_bb == bb->last_ins->inst_true_bb) {
11831                                 MonoBasicBlock *tmp =  bb->last_ins->inst_true_bb;
11832                                 bb->last_ins->inst_true_bb = bb->last_ins->inst_false_bb;
11833                                 bb->last_ins->inst_false_bb = tmp;
11834
11835                                 bb->last_ins->opcode = mono_reverse_branch_op (bb->last_ins->opcode);
11836                         } else {                        
11837                                 MonoInst *ins;
11838
11839                                 MONO_INST_NEW (cfg, ins, OP_BR);
11840                                 ins->inst_target_bb = bb->last_ins->inst_false_bb;
11841                                 MONO_ADD_INS (bb, ins);
11842                         }
11843                 }
11844         }
11845
11846 #ifdef DEBUG_SELECTION
11847         if (cfg->verbose_level >= 4) {
11848                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
11849                         MonoInst *tree;
11850                         g_print ("DUMP BLOCK %d:\n", bb->block_num);
11851                         MONO_BB_FOR_EACH_INS (bb, tree) {
11852                                 mono_print_tree (tree);
11853                                 g_print ("\n");
11854                         }
11855                 }
11856         }
11857 #endif
11858
11859         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
11860                 MonoInst *tree = bb->code, *next;       
11861                 MBState *mbstate;
11862
11863                 if (!tree)
11864                         continue;
11865                 bb->code = NULL;
11866                 bb->last_ins = NULL;
11867                 
11868                 cfg->cbb = bb;
11869                 mono_regstate_reset (cfg->rs);
11870
11871 #ifdef DEBUG_SELECTION
11872                 if (cfg->verbose_level >= 3)
11873                         g_print ("LABEL BLOCK %d:\n", bb->block_num);
11874 #endif
11875                 for (; tree; tree = next) {
11876                         next = tree->next;
11877 #ifdef DEBUG_SELECTION
11878                         if (cfg->verbose_level >= 3) {
11879                                 mono_print_tree (tree);
11880                                 g_print ("\n");
11881                         }
11882 #endif
11883
11884                         cfg->ip = tree->cil_code;
11885                         if (!(mbstate = mono_burg_label (tree, cfg))) {
11886                                 g_warning ("unable to label tree %p", tree);
11887                                 mono_print_tree (tree);
11888                                 g_print ("\n");                         
11889                                 g_assert_not_reached ();
11890                         }
11891                         emit_state (cfg, mbstate, MB_NTERM_stmt);
11892                 }
11893                 bb->max_vreg = cfg->rs->next_vreg;
11894
11895                 if (bb->last_ins)
11896                         bb->last_ins->next = NULL;
11897
11898                 mono_mempool_empty (cfg->state_pool); 
11899         }
11900         mono_mempool_destroy (cfg->state_pool); 
11901
11902         cfg->ip = NULL;
11903 }
11904
11905 /*
11906  * mono_normalize_opcodes:
11907  *
11908  *   Replace CEE_ and OP_ opcodes with the corresponding OP_I or OP_L opcodes.
11909  */
11910
11911 static gint16 *remap_table;
11912
11913 #if SIZEOF_VOID_P == 8
11914 #define REMAP_OPCODE(opcode) OP_L ## opcode
11915 #else
11916 #define REMAP_OPCODE(opcode) OP_I ## opcode
11917 #endif
11918
11919 static G_GNUC_UNUSED void
11920 mono_normalize_opcodes (MonoCompile *cfg, MonoBasicBlock *bb)
11921 {
11922         MonoInst *ins;
11923
11924         if (!remap_table) {
11925                 remap_table = g_new0 (gint16, OP_LAST);
11926
11927 #if SIZEOF_VOID_P == 8
11928                 remap_table [CEE_CONV_U8] = OP_ZEXT_I4;
11929                 remap_table [CEE_CONV_U] = OP_ZEXT_I4;
11930                 remap_table [CEE_CONV_I8] = OP_SEXT_I4;
11931                 remap_table [CEE_CONV_I] = OP_SEXT_I4;
11932                 remap_table [CEE_CONV_OVF_U4] = OP_LCONV_TO_OVF_U4;
11933                 remap_table [CEE_CONV_OVF_I4_UN] = OP_LCONV_TO_OVF_I4_UN;
11934 #else
11935 #endif
11936                 remap_table [CEE_CONV_R4] = OP_ICONV_TO_R4;
11937                 remap_table [CEE_CONV_R8] = OP_ICONV_TO_R8;
11938                 remap_table [CEE_CONV_I4] = OP_MOVE;
11939                 remap_table [CEE_CONV_U4] = OP_MOVE;
11940                 remap_table [CEE_CONV_I1] = REMAP_OPCODE (CONV_TO_I1);
11941                 remap_table [CEE_CONV_I2] = REMAP_OPCODE (CONV_TO_I2);
11942                 remap_table [CEE_CONV_U1] = REMAP_OPCODE (CONV_TO_U1);
11943                 remap_table [CEE_CONV_U2] = REMAP_OPCODE (CONV_TO_U2);
11944                 remap_table [CEE_CONV_R_UN] = REMAP_OPCODE (CONV_TO_R_UN);
11945                 remap_table [CEE_ADD] = REMAP_OPCODE (ADD);
11946                 remap_table [CEE_SUB] = REMAP_OPCODE (SUB);
11947                 remap_table [CEE_MUL] = REMAP_OPCODE (MUL);
11948                 remap_table [CEE_DIV] = REMAP_OPCODE (DIV);
11949                 remap_table [CEE_REM] = REMAP_OPCODE (REM);
11950                 remap_table [CEE_DIV_UN] = REMAP_OPCODE (DIV_UN);
11951                 remap_table [CEE_REM_UN] = REMAP_OPCODE (REM_UN);
11952                 remap_table [CEE_AND] = REMAP_OPCODE (AND);
11953                 remap_table [CEE_OR] = REMAP_OPCODE (OR);
11954                 remap_table [CEE_XOR] = REMAP_OPCODE (XOR);
11955                 remap_table [CEE_SHL] = REMAP_OPCODE (SHL);
11956                 remap_table [CEE_SHR] = REMAP_OPCODE (SHR);
11957                 remap_table [CEE_SHR_UN] = REMAP_OPCODE (SHR_UN);
11958                 remap_table [CEE_NOT] = REMAP_OPCODE (NOT);
11959                 remap_table [CEE_NEG] = REMAP_OPCODE (NEG);
11960                 remap_table [CEE_CALL] = OP_CALL;
11961                 remap_table [CEE_BEQ] = REMAP_OPCODE (BEQ);
11962                 remap_table [CEE_BNE_UN] = REMAP_OPCODE (BNE_UN);
11963                 remap_table [CEE_BLT] = REMAP_OPCODE (BLT);
11964                 remap_table [CEE_BLT_UN] = REMAP_OPCODE (BLT_UN);
11965                 remap_table [CEE_BGT] = REMAP_OPCODE (BGT);
11966                 remap_table [CEE_BGT_UN] = REMAP_OPCODE (BGT_UN);
11967                 remap_table [CEE_BGE] = REMAP_OPCODE (BGE);
11968                 remap_table [CEE_BGE_UN] = REMAP_OPCODE (BGE_UN);
11969                 remap_table [CEE_BLE] = REMAP_OPCODE (BLE);
11970                 remap_table [CEE_BLE_UN] = REMAP_OPCODE (BLE_UN);
11971                 remap_table [CEE_ADD_OVF] = REMAP_OPCODE (ADD_OVF);
11972                 remap_table [CEE_ADD_OVF_UN] = REMAP_OPCODE (ADD_OVF_UN);
11973                 remap_table [CEE_SUB_OVF] = REMAP_OPCODE (SUB_OVF);
11974                 remap_table [CEE_SUB_OVF_UN] = REMAP_OPCODE (SUB_OVF_UN);
11975                 remap_table [CEE_MUL_OVF] = REMAP_OPCODE (MUL_OVF);
11976                 remap_table [CEE_MUL_OVF_UN] = REMAP_OPCODE (MUL_OVF_UN);
11977         }
11978
11979         MONO_BB_FOR_EACH_INS (bb, ins) {
11980                 int remapped = remap_table [ins->opcode];
11981                 if (remapped)
11982                         ins->opcode = remapped;
11983         }
11984 }
11985
11986 void
11987 mono_codegen (MonoCompile *cfg)
11988 {
11989         MonoJumpInfo *patch_info;
11990         MonoBasicBlock *bb;
11991         int i, max_epilog_size;
11992         guint8 *code;
11993
11994         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
11995                 cfg->spill_count = 0;
11996                 /* we reuse dfn here */
11997                 /* bb->dfn = bb_count++; */
11998 #ifdef MONO_ARCH_ENABLE_NORMALIZE_OPCODES
11999                 if (!cfg->new_ir)
12000                         mono_normalize_opcodes (cfg, bb);
12001 #endif
12002
12003                 mono_arch_lowering_pass (cfg, bb);
12004
12005                 if (cfg->opt & MONO_OPT_PEEPHOLE)
12006                         mono_arch_peephole_pass_1 (cfg, bb);
12007
12008                 if (!cfg->globalra)
12009                         mono_local_regalloc (cfg, bb);
12010
12011                 if (cfg->opt & MONO_OPT_PEEPHOLE)
12012                         mono_arch_peephole_pass_2 (cfg, bb);
12013         }
12014
12015         if (cfg->prof_options & MONO_PROFILE_COVERAGE)
12016                 cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, cfg->num_bblocks);
12017
12018         code = mono_arch_emit_prolog (cfg);
12019
12020         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
12021                 code = mono_arch_instrument_prolog (cfg, mono_profiler_method_enter, code, FALSE);
12022
12023         cfg->code_len = code - cfg->native_code;
12024         cfg->prolog_end = cfg->code_len;
12025
12026         mono_debug_open_method (cfg);
12027
12028         /* emit code all basic blocks */
12029         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
12030                 bb->native_offset = cfg->code_len;
12031                 //if ((bb == cfg->bb_entry) || !(bb->region == -1 && !bb->dfn))
12032                         mono_arch_output_basic_block (cfg, bb);
12033
12034                 if (bb == cfg->bb_exit) {
12035                         cfg->epilog_begin = cfg->code_len;
12036
12037                         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE) {
12038                                 code = cfg->native_code + cfg->code_len;
12039                                 code = mono_arch_instrument_epilog (cfg, mono_profiler_method_leave, code, FALSE);
12040                                 cfg->code_len = code - cfg->native_code;
12041                                 g_assert (cfg->code_len < cfg->code_size);
12042                         }
12043
12044                         mono_arch_emit_epilog (cfg);
12045                 }
12046         }
12047
12048         mono_arch_emit_exceptions (cfg);
12049
12050         max_epilog_size = 0;
12051
12052         code = cfg->native_code + cfg->code_len;
12053
12054         /* we always allocate code in cfg->domain->code_mp to increase locality */
12055         cfg->code_size = cfg->code_len + max_epilog_size;
12056         /* fixme: align to MONO_ARCH_CODE_ALIGNMENT */
12057
12058         if (cfg->method->dynamic) {
12059                 guint unwindlen = 0;
12060 #ifdef MONO_ARCH_HAVE_UNWIND_TABLE
12061                 unwindlen = mono_arch_unwindinfo_get_size (cfg->arch.unwindinfo);
12062 #endif
12063                 /* Allocate the code into a separate memory pool so it can be freed */
12064                 cfg->dynamic_info = g_new0 (MonoJitDynamicMethodInfo, 1);
12065                 cfg->dynamic_info->code_mp = mono_code_manager_new_dynamic ();
12066                 mono_domain_lock (cfg->domain);
12067                 mono_dynamic_code_hash_insert (cfg->domain, cfg->method, cfg->dynamic_info);
12068                 mono_domain_unlock (cfg->domain);
12069
12070                 code = mono_code_manager_reserve (cfg->dynamic_info->code_mp, cfg->code_size + unwindlen);
12071         } else {
12072                 guint unwindlen = 0;
12073 #ifdef MONO_ARCH_HAVE_UNWIND_TABLE
12074                 unwindlen = mono_arch_unwindinfo_get_size (cfg->arch.unwindinfo);
12075 #endif
12076                 mono_domain_lock (cfg->domain);
12077                 code = mono_code_manager_reserve (cfg->domain->code_mp, cfg->code_size + unwindlen);
12078                 mono_domain_unlock (cfg->domain);
12079         }
12080
12081         memcpy (code, cfg->native_code, cfg->code_len);
12082         g_free (cfg->native_code);
12083         cfg->native_code = code;
12084         code = cfg->native_code + cfg->code_len;
12085   
12086         /* g_assert (((int)cfg->native_code & (MONO_ARCH_CODE_ALIGNMENT - 1)) == 0); */
12087         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
12088                 switch (patch_info->type) {
12089                 case MONO_PATCH_INFO_ABS: {
12090                         MonoJitICallInfo *info = mono_find_jit_icall_by_addr (patch_info->data.target);
12091
12092                         /*
12093                          * Change patches of type MONO_PATCH_INFO_ABS into patches describing the 
12094                          * absolute address.
12095                          */
12096                         if (info) {
12097                                 //printf ("TEST %s %p\n", info->name, patch_info->data.target);
12098                                 // FIXME: CLEAN UP THIS MESS.
12099                                 if ((cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) && 
12100                                         strstr (cfg->method->name, info->name)) {
12101                                         /*
12102                                          * This is an icall wrapper, and this is a call to the
12103                                          * wrapped function.
12104                                          */
12105                                         if (cfg->compile_aot) {
12106                                                 patch_info->type = MONO_PATCH_INFO_JIT_ICALL_ADDR;
12107                                                 patch_info->data.name = info->name;
12108                                         }
12109                                 } else {
12110                                         /* for these array methods we currently register the same function pointer
12111                                          * since it's a vararg function. But this means that mono_find_jit_icall_by_addr ()
12112                                          * will return the incorrect one depending on the order they are registered.
12113                                          * See tests/test-arr.cs
12114                                          */
12115                                         if (strstr (info->name, "ves_array_new_va_") == NULL && strstr (info->name, "ves_array_element_address_") == NULL) {
12116                                                 patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
12117                                                 patch_info->data.name = info->name;
12118                                         }
12119                                 }
12120                         }
12121                         
12122                         if (patch_info->type == MONO_PATCH_INFO_ABS && !cfg->new_ir) {
12123                                 MonoVTable *vtable = mono_find_class_init_trampoline_by_addr (patch_info->data.target);
12124                                 if (vtable) {
12125                                         patch_info->type = MONO_PATCH_INFO_CLASS_INIT;
12126                                         patch_info->data.klass = vtable->klass;
12127                                 }
12128                         }
12129
12130                         if (patch_info->type == MONO_PATCH_INFO_ABS) {
12131                                 MonoClass *klass = mono_find_delegate_trampoline_by_addr (patch_info->data.target);
12132                                 if (klass) {
12133                                         patch_info->type = MONO_PATCH_INFO_DELEGATE_TRAMPOLINE;
12134                                         patch_info->data.klass = klass;
12135                                 }
12136                         }
12137
12138                         if (patch_info->type == MONO_PATCH_INFO_ABS) {
12139                                 if (cfg->abs_patches) {
12140                                         MonoJumpInfo *abs_ji = g_hash_table_lookup (cfg->abs_patches, patch_info->data.target);
12141                                         if (abs_ji) {
12142                                                 patch_info->type = abs_ji->type;
12143                                                 patch_info->data.target = abs_ji->data.target;
12144                                         }
12145                                 }
12146                         }
12147
12148                         break;
12149                 }
12150                 case MONO_PATCH_INFO_SWITCH: {
12151                         gpointer *table;
12152                         if (cfg->method->dynamic) {
12153                                 table = mono_code_manager_reserve (cfg->dynamic_info->code_mp, sizeof (gpointer) * patch_info->data.table->table_size);
12154                         } else {
12155                                 mono_domain_lock (cfg->domain);
12156                                 table = mono_code_manager_reserve (cfg->domain->code_mp, sizeof (gpointer) * patch_info->data.table->table_size);
12157                                 mono_domain_unlock (cfg->domain);
12158                         }
12159
12160                         if (!cfg->compile_aot && !cfg->new_ir)
12161                                 /* In the aot case, the patch already points to the correct location */
12162                                 patch_info->ip.i = patch_info->ip.label->inst_c0;
12163                         for (i = 0; i < patch_info->data.table->table_size; i++) {
12164                                 /* Might be NULL if the switch is eliminated */
12165                                 if (patch_info->data.table->table [i]) {
12166                                         g_assert (patch_info->data.table->table [i]->native_offset);
12167                                         table [i] = GINT_TO_POINTER (patch_info->data.table->table [i]->native_offset);
12168                                 } else {
12169                                         table [i] = NULL;
12170                                 }
12171                         }
12172                         patch_info->data.table->table = (MonoBasicBlock**)table;
12173                         break;
12174                 }
12175                 case MONO_PATCH_INFO_METHOD_JUMP: {
12176                         GSList *list;
12177                         MonoDomain *domain = cfg->domain;
12178                         unsigned char *ip = cfg->native_code + patch_info->ip.i;
12179
12180                         mono_domain_lock (domain);
12181                         if (!domain->jump_target_hash)
12182                                 domain->jump_target_hash = g_hash_table_new (NULL, NULL);
12183                         list = g_hash_table_lookup (domain->jump_target_hash, patch_info->data.method);
12184                         list = g_slist_prepend (list, ip);
12185                         g_hash_table_insert (domain->jump_target_hash, patch_info->data.method, list);
12186                         mono_domain_unlock (domain);
12187                         break;
12188                 }
12189                 default:
12190                         /* do nothing */
12191                         break;
12192                 }
12193         }
12194
12195 #ifdef VALGRIND_JIT_REGISTER_MAP
12196 if (valgrind_register){
12197                 char* nm = mono_method_full_name (cfg->method, TRUE);
12198                 VALGRIND_JIT_REGISTER_MAP (nm, cfg->native_code, cfg->native_code + cfg->code_len);
12199                 g_free (nm);
12200         }
12201 #endif
12202  
12203         if (cfg->verbose_level > 0) {
12204                 char* nm = mono_method_full_name (cfg->method, TRUE);
12205                 g_print ("Method %s emitted at %p to %p (code length %d) [%s]\n", 
12206                                  nm, 
12207                                  cfg->native_code, cfg->native_code + cfg->code_len, cfg->code_len, cfg->domain->friendly_name);
12208                 g_free (nm);
12209         }
12210
12211         {
12212                 gboolean is_generic = FALSE;
12213
12214                 if (cfg->method->is_inflated || mono_method_get_generic_container (cfg->method) ||
12215                                 cfg->method->klass->generic_container || cfg->method->klass->generic_class) {
12216                         is_generic = TRUE;
12217                 }
12218
12219                 if (cfg->generic_sharing_context)
12220                         g_assert (is_generic);
12221         }
12222
12223 #ifdef MONO_ARCH_HAVE_SAVE_UNWIND_INFO
12224         mono_arch_save_unwind_info (cfg);
12225 #endif
12226         
12227         mono_arch_patch_code (cfg->method, cfg->domain, cfg->native_code, cfg->patch_info, cfg->run_cctors);
12228
12229         if (cfg->method->dynamic) {
12230                 mono_code_manager_commit (cfg->dynamic_info->code_mp, cfg->native_code, cfg->code_size, cfg->code_len);
12231         } else {
12232                 mono_domain_lock (cfg->domain);
12233                 mono_code_manager_commit (cfg->domain->code_mp, cfg->native_code, cfg->code_size, cfg->code_len);
12234                 mono_domain_unlock (cfg->domain);
12235         }
12236         
12237         mono_arch_flush_icache (cfg->native_code, cfg->code_len);
12238
12239         mono_debug_close_method (cfg);
12240 #ifdef MONO_ARCH_HAVE_UNWIND_TABLE
12241         mono_arch_unwindinfo_install_unwind_info (&cfg->arch.unwindinfo, cfg->native_code, cfg->code_len);
12242 #endif
12243 }
12244
12245 static MonoGenericInst*
12246 get_object_generic_inst (int type_argc)
12247 {
12248         MonoType **type_argv;
12249         int i;
12250
12251         type_argv = alloca (sizeof (MonoType*) * type_argc);
12252
12253         for (i = 0; i < type_argc; ++i)
12254                 type_argv [i] = &mono_defaults.object_class->byval_arg;
12255
12256         return mono_metadata_get_generic_inst (type_argc, type_argv);
12257 }
12258
12259 /*
12260  * mini_method_compile:
12261  * @method: the method to compile
12262  * @opts: the optimization flags to use
12263  * @domain: the domain where the method will be compiled in
12264  * @run_cctors: whether we should run type ctors if possible
12265  * @compile_aot: whether this is an AOT compilation
12266  * @parts: debug flag
12267  *
12268  * Returns: a MonoCompile* pointer. Caller must check the exception_type
12269  * field in the returned struct to see if compilation succeded.
12270  */
12271 MonoCompile*
12272 mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gboolean run_cctors, gboolean compile_aot, int parts)
12273 {
12274         MonoMethodHeader *header;
12275         guint8 *ip;
12276         MonoCompile *cfg;
12277         MonoJitInfo *jinfo;
12278         int dfn, i, code_size_ratio;
12279         gboolean deadce_has_run = FALSE;
12280         gboolean try_generic_shared;
12281         MonoMethod *method_to_compile, *method_to_register;
12282         int generic_info_size;
12283
12284         mono_jit_stats.methods_compiled++;
12285         if (mono_profiler_get_events () & MONO_PROFILE_JIT_COMPILATION)
12286                 mono_profiler_method_jit (method);
12287         if (MONO_PROBE_METHOD_COMPILE_BEGIN_ENABLED ())
12288                 MONO_PROBE_METHOD_COMPILE_BEGIN (method);
12289  
12290         if (compile_aot)
12291                 /* We are passed the original generic method definition */
12292                 try_generic_shared = mono_class_generic_sharing_enabled (method->klass) &&
12293                         (opts & MONO_OPT_GSHARED) && (method->is_generic || method->klass->generic_container);
12294         else
12295                 try_generic_shared = mono_class_generic_sharing_enabled (method->klass) &&
12296                         (opts & MONO_OPT_GSHARED) && mono_method_is_generic_sharable_impl (method, FALSE);
12297
12298         if (opts & MONO_OPT_GSHARED) {
12299                 if (try_generic_shared)
12300                         mono_stats.generics_sharable_methods++;
12301                 else if (mono_method_is_generic_impl (method))
12302                         mono_stats.generics_unsharable_methods++;
12303         }
12304
12305  restart_compile:
12306         if (try_generic_shared) {
12307                 MonoMethod *declaring_method;
12308                 MonoGenericContext *shared_context;
12309
12310                 if (compile_aot) {
12311                         declaring_method = method;
12312                 } else {
12313                         declaring_method = mono_method_get_declaring_generic_method (method);
12314                         if (method->klass->generic_class)
12315                                 g_assert (method->klass->generic_class->container_class == declaring_method->klass);
12316                         else
12317                                 g_assert (method->klass == declaring_method->klass);
12318                 }
12319
12320                 if (declaring_method->is_generic)
12321                         shared_context = &(mono_method_get_generic_container (declaring_method)->context);
12322                 else
12323                         shared_context = &declaring_method->klass->generic_container->context;
12324
12325                 method_to_compile = mono_class_inflate_generic_method (declaring_method, shared_context);
12326                 g_assert (method_to_compile);
12327         } else {
12328                 method_to_compile = method;
12329         }
12330
12331         cfg = g_new0 (MonoCompile, 1);
12332         cfg->method = method_to_compile;
12333         cfg->mempool = mono_mempool_new ();
12334         cfg->opt = opts;
12335         cfg->prof_options = mono_profiler_get_events ();
12336         cfg->run_cctors = run_cctors;
12337         cfg->domain = domain;
12338         cfg->verbose_level = mini_verbose;
12339         cfg->compile_aot = compile_aot;
12340         cfg->skip_visibility = method->skip_visibility;
12341         cfg->orig_method = method;
12342         if (try_generic_shared)
12343                 cfg->generic_sharing_context = (MonoGenericSharingContext*)&cfg->generic_sharing_context;
12344         cfg->token_info_hash = g_hash_table_new (NULL, NULL);
12345
12346         if (cfg->compile_aot && !try_generic_shared && (method->is_generic || method->klass->generic_container)) {
12347                 cfg->exception_type = MONO_EXCEPTION_GENERIC_SHARING_FAILED;
12348                 return cfg;
12349         }
12350
12351         /* The debugger has no liveness information, so avoid sharing registers/stack slots */
12352         if (mono_debug_using_mono_debugger () || debug_options.mdb_optimizations) {
12353                 cfg->disable_reuse_registers = TRUE;
12354                 cfg->disable_reuse_stack_slots = TRUE;
12355                 /* 
12356                  * This decreases the change the debugger will read registers/stack slots which are
12357                  * not yet initialized.
12358                  */
12359                 cfg->disable_initlocals_opt = TRUE;
12360
12361                 /* Temporarily disable this when running in the debugger until we have support
12362                  * for this in the debugger. */
12363                 cfg->disable_omit_fp = TRUE;
12364
12365                 // cfg->opt |= MONO_OPT_SHARED;
12366                 cfg->opt &= ~MONO_OPT_INLINE;
12367                 cfg->opt &= ~MONO_OPT_COPYPROP;
12368                 cfg->opt &= ~MONO_OPT_CONSPROP;
12369                 cfg->opt &= ~MONO_OPT_GSHARED;
12370         }
12371
12372         header = mono_method_get_header (method_to_compile);
12373         if (!header) {
12374                 cfg->exception_type = MONO_EXCEPTION_INVALID_PROGRAM;
12375                 cfg->exception_message = g_strdup_printf ("Missing or incorrect header for method %s", cfg->method->name);
12376                 if (MONO_PROBE_METHOD_COMPILE_END_ENABLED ())
12377                         MONO_PROBE_METHOD_COMPILE_END (method, FALSE);
12378                 if (cfg->prof_options & MONO_PROFILE_JIT_COMPILATION)
12379                         mono_profiler_method_end_jit (method, NULL, MONO_PROFILE_FAILED);
12380                 return cfg;
12381         }
12382
12383         if (getenv ("MONO_VERBOSE_METHOD")) {
12384                 if (strcmp (cfg->method->name, getenv ("MONO_VERBOSE_METHOD")) == 0)
12385                         cfg->verbose_level = 4;
12386         }
12387
12388         ip = (guint8 *)header->code;
12389
12390         cfg->intvars = mono_mempool_alloc0 (cfg->mempool, sizeof (guint16) * STACK_MAX * header->max_stack);
12391
12392         if (cfg->verbose_level > 2) {
12393                 if (cfg->generic_sharing_context)
12394                         g_print ("converting shared method %s\n", mono_method_full_name (method, TRUE));
12395                 else
12396                         g_print ("converting method %s\n", mono_method_full_name (method, TRUE));
12397         }
12398
12399         if (cfg->opt & (MONO_OPT_ABCREM | MONO_OPT_SSAPRE))
12400                 cfg->opt |= MONO_OPT_SSA;
12401
12402         {
12403                 static int count = 0;
12404
12405                 count ++;
12406
12407                 if (getenv ("MONO_COUNT")) {
12408                         if (count == atoi (getenv ("MONO_COUNT"))) {
12409                                 printf ("LAST: %s\n", mono_method_full_name (method, TRUE));
12410                                 //cfg->verbose_level = 5;
12411                         }
12412                         if (count <= atoi (getenv ("MONO_COUNT")))
12413                                 cfg->new_ir = TRUE;
12414
12415                         /*
12416                          * Passing/returning vtypes in registers in managed methods is an ABI change 
12417                          * from the old JIT.
12418                          */
12419                         disable_vtypes_in_regs = TRUE;
12420                 }
12421                 else
12422                         cfg->new_ir = TRUE;
12423         }
12424
12425         /* 
12426         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")))
12427                 cfg->globalra = TRUE;
12428         */
12429
12430         //cfg->globalra = TRUE;
12431
12432         //if (!strcmp (cfg->method->klass->name, "Tests") && !cfg->method->wrapper_type)
12433         //      cfg->globalra = TRUE;
12434
12435         {
12436                 static int count = 0;
12437                 count ++;
12438
12439                 if (getenv ("COUNT2")) {
12440                         if (count == atoi (getenv ("COUNT2")))
12441                                 printf ("LAST: %s\n", mono_method_full_name (cfg->method, TRUE));
12442                         if (count > atoi (getenv ("COUNT2")))
12443                                 cfg->globalra = FALSE;
12444                 }
12445         }
12446
12447         if (header->clauses)
12448                 cfg->globalra = FALSE;
12449
12450         if (cfg->method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED)
12451                 /* The code in the prolog clobbers caller saved registers */
12452                 cfg->globalra = FALSE;
12453
12454         // FIXME: Disable globalra in case of tracing/profiling
12455
12456         if (cfg->method->save_lmf)
12457                 /* The LMF saving code might clobber caller saved registers */
12458                 cfg->globalra = FALSE;
12459
12460         // FIXME:
12461         if (!strcmp (cfg->method->name, "CompareInternal"))
12462                 cfg->globalra = FALSE;
12463
12464         /*
12465         if (strstr (cfg->method->name, "LoadData"))
12466                 cfg->new_ir = FALSE;
12467         */
12468
12469         if (cfg->new_ir) {
12470                 cfg->rs = mono_regstate_new ();
12471                 cfg->next_vreg = cfg->rs->next_vreg;
12472         }
12473
12474         /* FIXME: Fix SSA to handle branches inside bblocks */
12475         if (cfg->opt & MONO_OPT_SSA)
12476                 cfg->enable_extended_bblocks = FALSE;
12477
12478         /*
12479          * FIXME: This confuses liveness analysis because variables which are assigned after
12480          * a branch inside a bblock become part of the kill set, even though the assignment
12481          * might not get executed. This causes the optimize_initlocals pass to delete some
12482          * assignments which are needed.
12483          * Also, the mono_if_conversion pass needs to be modified to recognize the code
12484          * created by this.
12485          */
12486         //cfg->enable_extended_bblocks = TRUE;
12487
12488         /*
12489          * create MonoInst* which represents arguments and local variables
12490          */
12491         mono_compile_create_vars (cfg);
12492
12493         if (cfg->new_ir) {
12494                 /* SSAPRE is not supported on linear IR */
12495                 cfg->opt &= ~MONO_OPT_SSAPRE;
12496
12497                 i = mono_method_to_ir2 (cfg, method_to_compile, NULL, NULL, NULL, NULL, NULL, 0, FALSE);
12498         }
12499         else {
12500                 i = mono_method_to_ir (cfg, method_to_compile, NULL, NULL, cfg->locals_start, NULL, NULL, NULL, 0, FALSE);
12501         }
12502
12503         if (i < 0) {
12504                 if (try_generic_shared && cfg->exception_type == MONO_EXCEPTION_GENERIC_SHARING_FAILED) {
12505                         if (compile_aot) {
12506                                 if (MONO_PROBE_METHOD_COMPILE_END_ENABLED ())
12507                                         MONO_PROBE_METHOD_COMPILE_END (method, FALSE);
12508                                 return cfg;
12509                         }
12510                         mono_destroy_compile (cfg);
12511                         try_generic_shared = FALSE;
12512                         goto restart_compile;
12513                 }
12514                 g_assert (cfg->exception_type != MONO_EXCEPTION_GENERIC_SHARING_FAILED);
12515
12516                 if (MONO_PROBE_METHOD_COMPILE_END_ENABLED ())
12517                         MONO_PROBE_METHOD_COMPILE_END (method, FALSE);
12518                 if (cfg->prof_options & MONO_PROFILE_JIT_COMPILATION)
12519                         mono_profiler_method_end_jit (method, NULL, MONO_PROFILE_FAILED);
12520                 /* cfg contains the details of the failure, so let the caller cleanup */
12521                 return cfg;
12522         }
12523
12524         mono_jit_stats.basic_blocks += cfg->num_bblocks;
12525         mono_jit_stats.max_basic_blocks = MAX (cfg->num_bblocks, mono_jit_stats.max_basic_blocks);
12526
12527         /*g_print ("numblocks = %d\n", cfg->num_bblocks);*/
12528
12529         if (cfg->new_ir) {
12530                 mono_decompose_long_opts (cfg);
12531
12532                 /* Should be done before branch opts */
12533                 if (cfg->opt & (MONO_OPT_CONSPROP | MONO_OPT_COPYPROP))
12534                         mono_local_cprop2 (cfg);
12535         }
12536
12537         if (cfg->opt & MONO_OPT_BRANCH)
12538                 mono_optimize_branches (cfg);
12539
12540         if (cfg->new_ir) {
12541                 /* This must be done _before_ global reg alloc and _after_ decompose */
12542                 mono_handle_global_vregs (cfg);
12543                 mono_local_deadce (cfg);
12544                 mono_if_conversion (cfg);
12545         }
12546
12547         if ((cfg->opt & MONO_OPT_SSAPRE) || cfg->globalra)
12548                 mono_remove_critical_edges (cfg);
12549
12550         /* Depth-first ordering on basic blocks */
12551         cfg->bblocks = mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * (cfg->num_bblocks + 1));
12552
12553         dfn = 0;
12554         df_visit (cfg->bb_entry, &dfn, cfg->bblocks);
12555         if (cfg->num_bblocks != dfn + 1) {
12556                 MonoBasicBlock *bb;
12557
12558                 cfg->num_bblocks = dfn + 1;
12559
12560                 /* remove unreachable code, because the code in them may be 
12561                  * inconsistent  (access to dead variables for example) */
12562                 for (bb = cfg->bb_entry; bb;) {
12563                         MonoBasicBlock *bbn = bb->next_bb;
12564
12565                         /* 
12566                          * FIXME: Can't use the second case in methods with clauses, since the 
12567                          * bblocks inside the clauses are not processed during dfn computation.
12568                          */
12569                         if (((header->clauses && (bbn && bbn->region == -1 && bbn->in_count == 0)) ||
12570                                  (!header->clauses && (bbn && bbn->region == -1 && !bbn->dfn))) &&
12571                                 bbn != cfg->bb_exit) {
12572                                 if (cfg->verbose_level > 1)
12573                                         g_print ("found unreachable code in BB%d\n", bbn->block_num);
12574                                 /* There may exist unreachable branches to this bb */
12575                                 bb->next_bb = bbn->next_bb;
12576                                 mono_nullify_basic_block (bbn);                 
12577                         } else {
12578                                 bb = bb->next_bb;
12579                         }
12580                 }
12581         }
12582
12583         if (((cfg->num_varinfo > 2000) || (cfg->num_bblocks > 1000)) && !cfg->compile_aot) {
12584                 /* 
12585                  * we disable some optimizations if there are too many variables
12586                  * because JIT time may become too expensive. The actual number needs 
12587                  * to be tweaked and eventually the non-linear algorithms should be fixed.
12588                  */
12589                 cfg->opt &= ~ (MONO_OPT_LINEARS | MONO_OPT_COPYPROP | MONO_OPT_CONSPROP);
12590                 cfg->disable_ssa = TRUE;
12591         }
12592
12593         if (cfg->opt & MONO_OPT_LOOP) {
12594                 mono_compile_dominator_info (cfg, MONO_COMP_DOM | MONO_COMP_IDOM);
12595                 mono_compute_natural_loops (cfg);
12596         }
12597
12598         /* after method_to_ir */
12599         if (parts == 1) {
12600                 if (MONO_PROBE_METHOD_COMPILE_END_ENABLED ())
12601                         MONO_PROBE_METHOD_COMPILE_END (method, TRUE);
12602                 return cfg;
12603         }
12604
12605 //#define DEBUGSSA "logic_run"
12606 #define DEBUGSSA_CLASS "Tests"
12607 #ifdef DEBUGSSA
12608
12609         if (!header->num_clauses && !cfg->disable_ssa) {
12610                 mono_local_cprop (cfg);
12611
12612 #ifndef DISABLE_SSA
12613                 if (cfg->new_ir)
12614                         mono_ssa_compute2 (cfg);
12615                 else
12616                         mono_ssa_compute (cfg);
12617 #endif
12618         }
12619 #else 
12620         if (cfg->opt & MONO_OPT_SSA) {
12621                 if (!(cfg->comp_done & MONO_COMP_SSA) && !header->num_clauses && !cfg->disable_ssa) {
12622 #ifndef DISABLE_SSA
12623                         if (!cfg->new_ir)
12624                                 mono_local_cprop (cfg);
12625                         if (cfg->new_ir)
12626                                 mono_ssa_compute2 (cfg);
12627                         else
12628                                 mono_ssa_compute (cfg);
12629 #endif
12630
12631                         if (cfg->verbose_level >= 2) {
12632                                 print_dfn (cfg);
12633                         }
12634                 }
12635         }
12636 #endif
12637
12638         /* after SSA translation */
12639         if (parts == 2) {
12640                 if (MONO_PROBE_METHOD_COMPILE_END_ENABLED ())
12641                         MONO_PROBE_METHOD_COMPILE_END (method, TRUE);
12642                 return cfg;
12643         }
12644
12645         if ((cfg->opt & MONO_OPT_CONSPROP) || (cfg->opt & MONO_OPT_COPYPROP)) {
12646                 if (cfg->comp_done & MONO_COMP_SSA) {
12647 #ifndef DISABLE_SSA
12648                         if (cfg->new_ir)
12649                                 mono_ssa_cprop2 (cfg);
12650                         else
12651                                 mono_ssa_cprop (cfg);
12652 #endif
12653                 } else {
12654                         if (!cfg->new_ir)
12655                                 mono_local_cprop (cfg);
12656                 }
12657         }
12658
12659 #ifndef DISABLE_SSA
12660         if (cfg->comp_done & MONO_COMP_SSA) {                   
12661                 //mono_ssa_strength_reduction (cfg);
12662
12663                 if (cfg->opt & MONO_OPT_SSAPRE) {
12664                         mono_perform_ssapre (cfg);
12665                         //mono_local_cprop (cfg);
12666                 }
12667
12668                 if (cfg->opt & MONO_OPT_DEADCE) {
12669                         if (cfg->new_ir)
12670                                 mono_ssa_deadce2 (cfg);
12671                         else
12672                                 mono_ssa_deadce (cfg);
12673                         deadce_has_run = TRUE;
12674                 }
12675
12676                 if (cfg->new_ir) {
12677                         if ((cfg->flags & (MONO_CFG_HAS_LDELEMA|MONO_CFG_HAS_CHECK_THIS)) && (cfg->opt & MONO_OPT_ABCREM))
12678                                 mono_perform_abc_removal2 (cfg);
12679                 } else {
12680                         if ((cfg->flags & MONO_CFG_HAS_LDELEMA) && (cfg->opt & MONO_OPT_ABCREM))
12681                                 mono_perform_abc_removal (cfg);
12682                 }
12683
12684                 if (cfg->new_ir) {
12685                         mono_ssa_remove2 (cfg);
12686                         mono_local_cprop2 (cfg);
12687                         mono_handle_global_vregs (cfg);
12688                         mono_local_deadce (cfg);
12689                 }
12690                 else
12691                         mono_ssa_remove (cfg);
12692
12693                 if (cfg->opt & MONO_OPT_BRANCH) {
12694                         MonoBasicBlock *bb;
12695
12696                         mono_optimize_branches (cfg);
12697
12698                         /* Have to recompute cfg->bblocks and bb->dfn */
12699                         if (cfg->globalra) {
12700                                 mono_remove_critical_edges (cfg);
12701
12702                                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
12703                                         bb->dfn = 0;
12704
12705                                 /* Depth-first ordering on basic blocks */
12706                                 cfg->bblocks = mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * (cfg->num_bblocks + 1));
12707
12708                                 dfn = 0;
12709                                 df_visit (cfg->bb_entry, &dfn, cfg->bblocks);
12710                                 cfg->num_bblocks = dfn + 1;
12711                         }
12712                 }
12713         }
12714 #endif
12715
12716         /* after SSA removal */
12717         if (parts == 3) {
12718                 if (MONO_PROBE_METHOD_COMPILE_END_ENABLED ())
12719                         MONO_PROBE_METHOD_COMPILE_END (method, TRUE);
12720                 return cfg;
12721         }
12722
12723         if (cfg->new_ir) {
12724 #ifdef MONO_ARCH_SOFT_FLOAT
12725                 mono_handle_soft_float (cfg);
12726 #endif
12727                 mono_decompose_vtype_opts (cfg);
12728                 if (cfg->flags & MONO_CFG_HAS_ARRAY_ACCESS)
12729                         mono_decompose_array_access_opts (cfg);
12730         }
12731
12732         if (!cfg->new_ir) {
12733                 if (cfg->verbose_level > 4)
12734                         mono_print_code (cfg, "BEFORE DECOMPOSE");
12735
12736                 decompose_pass (cfg);
12737         }
12738
12739         if (cfg->got_var) {
12740                 GList *regs;
12741
12742                 g_assert (cfg->got_var_allocated);
12743
12744                 /* 
12745                  * Allways allocate the GOT var to a register, because keeping it
12746                  * in memory will increase the number of live temporaries in some
12747                  * code created by inssel.brg, leading to the well known spills+
12748                  * branches problem. Testcase: mcs crash in 
12749                  * System.MonoCustomAttrs:GetCustomAttributes.
12750                  */
12751                 regs = mono_arch_get_global_int_regs (cfg);
12752                 g_assert (regs);
12753                 cfg->got_var->opcode = OP_REGVAR;
12754                 cfg->got_var->dreg = GPOINTER_TO_INT (regs->data);
12755                 cfg->used_int_regs |= 1LL << cfg->got_var->dreg;
12756                 
12757                 g_list_free (regs);
12758         }
12759
12760         /* todo: remove code when we have verified that the liveness for try/catch blocks
12761          * works perfectly 
12762          */
12763         /* 
12764          * Currently, this can't be commented out since exception blocks are not
12765          * processed during liveness analysis.
12766          */
12767         mono_liveness_handle_exception_clauses (cfg);
12768
12769         if (cfg->globalra) {
12770                 MonoBasicBlock *bb;
12771
12772                 /* Have to do this before regalloc since it can create vregs */
12773                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
12774                         mono_arch_lowering_pass (cfg, bb);
12775
12776                 mono_global_regalloc (cfg);
12777         }
12778
12779         if ((cfg->opt & MONO_OPT_LINEARS) && !cfg->globalra) {
12780                 GList *vars, *regs;
12781                 
12782                 /* For now, compute aliasing info only if needed for deadce... */
12783                 if (!cfg->new_ir && (cfg->opt & MONO_OPT_DEADCE) && (! deadce_has_run) && (header->num_clauses == 0)) {
12784                         cfg->aliasing_info = mono_build_aliasing_information (cfg);
12785                 }
12786
12787                 /* fixme: maybe we can avoid to compute livenesss here if already computed ? */
12788                 cfg->comp_done &= ~MONO_COMP_LIVENESS;
12789                 if (!(cfg->comp_done & MONO_COMP_LIVENESS))
12790                         mono_analyze_liveness (cfg);
12791
12792                 if (cfg->aliasing_info != NULL) {
12793                         mono_aliasing_deadce (cfg->aliasing_info);
12794                         deadce_has_run = TRUE;
12795                 }
12796                 
12797                 if ((vars = mono_arch_get_allocatable_int_vars (cfg))) {
12798                         regs = mono_arch_get_global_int_regs (cfg);
12799                         if (cfg->got_var)
12800                                 regs = g_list_delete_link (regs, regs);
12801                         mono_linear_scan (cfg, vars, regs, &cfg->used_int_regs);
12802                 }
12803                 
12804                 if (cfg->aliasing_info != NULL) {
12805                         mono_destroy_aliasing_information (cfg->aliasing_info);
12806                         cfg->aliasing_info = NULL;
12807                 }
12808         }
12809
12810         //mono_print_code (cfg);
12811
12812     //print_dfn (cfg);
12813         
12814         /* variables are allocated after decompose, since decompose could create temps */
12815         if (!cfg->globalra)
12816                 mono_arch_allocate_vars (cfg);
12817
12818         if (!cfg->new_ir && cfg->opt & MONO_OPT_CFOLD)
12819                 mono_constant_fold (cfg);
12820
12821         if (cfg->new_ir) {
12822                 MonoBasicBlock *bb;
12823                 gboolean need_local_opts;
12824
12825                 if (!cfg->globalra) {
12826                         mono_spill_global_vars (cfg, &need_local_opts);
12827
12828                         if (need_local_opts || cfg->compile_aot) {
12829                                 /* To optimize code created by spill_global_vars */
12830                                 mono_local_cprop2 (cfg);
12831                                 mono_local_deadce (cfg);
12832                         }
12833                 }
12834
12835                 /* Add branches between non-consecutive bblocks */
12836                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
12837                         if (bb->last_ins && MONO_IS_COND_BRANCH_OP (bb->last_ins) &&
12838                                 bb->last_ins->inst_false_bb && bb->next_bb != bb->last_ins->inst_false_bb) {
12839                                 /* we are careful when inverting, since bugs like #59580
12840                                  * could show up when dealing with NaNs.
12841                                  */
12842                                 if (MONO_IS_COND_BRANCH_NOFP(bb->last_ins) && bb->next_bb == bb->last_ins->inst_true_bb) {
12843                                         MonoBasicBlock *tmp =  bb->last_ins->inst_true_bb;
12844                                         bb->last_ins->inst_true_bb = bb->last_ins->inst_false_bb;
12845                                         bb->last_ins->inst_false_bb = tmp;
12846
12847                                         bb->last_ins->opcode = mono_reverse_branch_op (bb->last_ins->opcode);
12848                                 } else {                        
12849                                         MonoInst *inst = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst));
12850                                         inst->opcode = OP_BR;
12851                                         inst->inst_target_bb = bb->last_ins->inst_false_bb;
12852                                         mono_bblock_add_inst (bb, inst);
12853                                 }
12854                         }
12855                 }
12856
12857                 if (cfg->verbose_level >= 4 && !cfg->globalra) {
12858                         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
12859                                 MonoInst *tree = bb->code;      
12860                                 g_print ("DUMP BLOCK %d:\n", bb->block_num);
12861                                 if (!tree)
12862                                         continue;
12863                                 for (; tree; tree = tree->next) {
12864                                         mono_print_ins_index (-1, tree);
12865                                 }
12866                         }
12867                 }
12868
12869                 /* FIXME: */
12870                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
12871                         bb->max_vreg = cfg->next_vreg;
12872                 }
12873         }
12874         else
12875                 mini_select_instructions (cfg);
12876
12877         mono_codegen (cfg);
12878         if (cfg->verbose_level >= 2) {
12879                 char *id =  mono_method_full_name (cfg->method, FALSE);
12880                 mono_disassemble_code (cfg, cfg->native_code, cfg->code_len, id + 3);
12881                 g_free (id);
12882         }
12883
12884         if (cfg->generic_sharing_context)
12885                 generic_info_size = sizeof (MonoGenericJitInfo);
12886         else
12887                 generic_info_size = 0;
12888
12889         if (cfg->method->dynamic) {
12890                 jinfo = g_malloc0 (sizeof (MonoJitInfo) + (header->num_clauses * sizeof (MonoJitExceptionInfo)) +
12891                                 generic_info_size);
12892         } else {
12893                 /* we access cfg->domain->mp */
12894                 mono_domain_lock (cfg->domain);
12895                 jinfo = mono_mempool_alloc0 (cfg->domain->mp, sizeof (MonoJitInfo) +
12896                                 (header->num_clauses * sizeof (MonoJitExceptionInfo)) +
12897                                 generic_info_size);
12898                 mono_domain_unlock (cfg->domain);
12899         }
12900
12901         if (cfg->generic_sharing_context) {
12902                 MonoGenericContext object_context;
12903
12904                 g_assert (!method_to_compile->klass->generic_class);
12905                 if (method_to_compile->klass->generic_container) {
12906                         int type_argc = method_to_compile->klass->generic_container->type_argc;
12907
12908                         object_context.class_inst = get_object_generic_inst (type_argc);
12909                 } else {
12910                         object_context.class_inst = NULL;
12911                 }
12912
12913                 if (mini_method_get_context (method_to_compile)->method_inst) {
12914                         int type_argc = mini_method_get_context (method_to_compile)->method_inst->type_argc;
12915
12916                         object_context.method_inst = get_object_generic_inst (type_argc);
12917                 } else {
12918                         object_context.method_inst = NULL;
12919                 }
12920
12921                 g_assert (object_context.class_inst || object_context.method_inst);
12922
12923                 method_to_register = mono_class_inflate_generic_method (method_to_compile, &object_context);
12924         } else {
12925                 g_assert (method == method_to_compile);
12926                 method_to_register = method;
12927         }
12928
12929         jinfo->method = method_to_register;
12930         jinfo->code_start = cfg->native_code;
12931         jinfo->code_size = cfg->code_len;
12932         jinfo->used_regs = cfg->used_int_regs;
12933         jinfo->domain_neutral = (cfg->opt & MONO_OPT_SHARED) != 0;
12934         jinfo->cas_inited = FALSE; /* initialization delayed at the first stalk walk using this method */
12935         jinfo->num_clauses = header->num_clauses;
12936
12937         if (cfg->generic_sharing_context) {
12938                 MonoInst *inst;
12939                 MonoGenericJitInfo *gi;
12940
12941                 jinfo->has_generic_jit_info = 1;
12942
12943                 gi = mono_jit_info_get_generic_jit_info (jinfo);
12944                 g_assert (gi);
12945
12946                 gi->generic_sharing_context = cfg->generic_sharing_context;
12947
12948                 /*
12949                  * Non-generic static methods only get a "this" info
12950                  * if they use the rgctx variable (which they are
12951                  * forced to if they have any open catch clauses).
12952                  */
12953                 if (cfg->rgctx_var ||
12954                                 (!(method_to_compile->flags & METHOD_ATTRIBUTE_STATIC) &&
12955                                 !mini_method_get_context (method_to_compile)->method_inst)) {
12956                         gi->has_this = 1;
12957
12958                         if ((method_to_compile->flags & METHOD_ATTRIBUTE_STATIC) ||
12959                                         mini_method_get_context (method_to_compile)->method_inst) {
12960                                 inst = cfg->rgctx_var;
12961                                 g_assert (inst->opcode == OP_REGOFFSET);
12962                         } else {
12963                                 inst = cfg->args [0];
12964                         }
12965
12966                         if (inst->opcode == OP_REGVAR) {
12967                                 gi->this_in_reg = 1;
12968                                 gi->this_reg = inst->dreg;
12969
12970                                 //g_print ("this in reg %d\n", inst->dreg);
12971                         } else {
12972                                 g_assert (inst->opcode == OP_REGOFFSET);
12973 #ifdef __i386__
12974                                 g_assert (inst->inst_basereg == X86_EBP);
12975 #elif defined(__x86_64__)
12976                                 g_assert (inst->inst_basereg == X86_EBP || inst->inst_basereg == X86_ESP);
12977 #endif
12978                                 g_assert (inst->inst_offset >= G_MININT32 && inst->inst_offset <= G_MAXINT32);
12979
12980                                 gi->this_in_reg = 0;
12981                                 gi->this_reg = inst->inst_basereg;
12982                                 gi->this_offset = inst->inst_offset;
12983
12984                                 //g_print ("this at offset %d from reg %d\n", gi->this_offset, gi->this_reg);
12985                         }
12986                 } else {
12987                         gi->has_this = 0;
12988                 }
12989         }
12990
12991         if (header->num_clauses) {
12992                 int i;
12993
12994                 for (i = 0; i < header->num_clauses; i++) {
12995                         MonoExceptionClause *ec = &header->clauses [i];
12996                         MonoJitExceptionInfo *ei = &jinfo->clauses [i];
12997                         MonoBasicBlock *tblock;
12998                         MonoInst *exvar;
12999
13000                         ei->flags = ec->flags;
13001
13002                         exvar = mono_find_exvar_for_offset (cfg, ec->handler_offset);
13003                         ei->exvar_offset = exvar ? exvar->inst_offset : 0;
13004
13005                         if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
13006                                 tblock = cfg->cil_offset_to_bb [ec->data.filter_offset];
13007                                 g_assert (tblock);
13008                                 ei->data.filter = cfg->native_code + tblock->native_offset;
13009                         } else {
13010                                 ei->data.catch_class = ec->data.catch_class;
13011                         }
13012
13013                         tblock = cfg->cil_offset_to_bb [ec->try_offset];
13014                         g_assert (tblock);
13015                         ei->try_start = cfg->native_code + tblock->native_offset;
13016                         g_assert (tblock->native_offset);
13017                         tblock = cfg->cil_offset_to_bb [ec->try_offset + ec->try_len];
13018                         g_assert (tblock);
13019                         ei->try_end = cfg->native_code + tblock->native_offset;
13020                         g_assert (tblock->native_offset);
13021                         tblock = cfg->cil_offset_to_bb [ec->handler_offset];
13022                         g_assert (tblock);
13023                         ei->handler_start = cfg->native_code + tblock->native_offset;
13024                 }
13025         }
13026
13027         cfg->jit_info = jinfo;
13028 #if defined(__arm__)
13029         mono_arch_fixup_jinfo (cfg);
13030 #endif
13031
13032         if (!cfg->compile_aot) {
13033                 mono_domain_lock (cfg->domain);
13034                 mono_jit_info_table_add (cfg->domain, jinfo);
13035
13036                 if (cfg->method->dynamic)
13037                         mono_dynamic_code_hash_lookup (cfg->domain, cfg->method)->ji = jinfo;
13038                 mono_domain_unlock (cfg->domain);
13039         }
13040
13041         /* collect statistics */
13042         mono_perfcounters->jit_methods++;
13043         mono_perfcounters->jit_bytes += header->code_size;
13044         mono_jit_stats.allocated_code_size += cfg->code_len;
13045         code_size_ratio = cfg->code_len;
13046         if (code_size_ratio > mono_jit_stats.biggest_method_size && mono_jit_stats.enabled) {
13047                 mono_jit_stats.biggest_method_size = code_size_ratio;
13048                 g_free (mono_jit_stats.biggest_method);
13049                 mono_jit_stats.biggest_method = g_strdup_printf ("%s::%s)", method->klass->name, method->name);
13050         }
13051         code_size_ratio = (code_size_ratio * 100) / mono_method_get_header (method)->code_size;
13052         if (code_size_ratio > mono_jit_stats.max_code_size_ratio && mono_jit_stats.enabled) {
13053                 mono_jit_stats.max_code_size_ratio = code_size_ratio;
13054                 g_free (mono_jit_stats.max_ratio_method);
13055                 mono_jit_stats.max_ratio_method = g_strdup_printf ("%s::%s)", method->klass->name, method->name);
13056         }
13057         mono_jit_stats.native_code_size += cfg->code_len;
13058
13059         if (MONO_PROBE_METHOD_COMPILE_END_ENABLED ())
13060                 MONO_PROBE_METHOD_COMPILE_END (method, TRUE);
13061         if (cfg->prof_options & MONO_PROFILE_JIT_COMPILATION)
13062                 mono_profiler_method_end_jit (method, jinfo, MONO_PROFILE_OK);
13063
13064         return cfg;
13065 }
13066
13067 #else
13068
13069 MonoCompile*
13070 mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gboolean run_cctors, gboolean compile_aot, int parts)
13071 {
13072         g_assert_not_reached ();
13073         return NULL;
13074 }
13075
13076 #endif /* DISABLE_JIT */
13077
13078 static MonoJitInfo*
13079 lookup_generic_method (MonoDomain *domain, MonoMethod *method)
13080 {
13081         MonoMethod *open_method;
13082
13083         if (!mono_method_is_generic_sharable_impl (method, FALSE))
13084                 return NULL;
13085
13086         open_method = mono_method_get_declaring_generic_method (method);
13087
13088         return mono_domain_lookup_shared_generic (domain, open_method);
13089 }
13090
13091 /*
13092  * LOCKING: Assumes domain->jit_code_hash_lock is held.
13093  */
13094 static MonoJitInfo*
13095 lookup_method_inner (MonoDomain *domain, MonoMethod *method)
13096 {
13097         MonoJitInfo *ji = mono_internal_hash_table_lookup (&domain->jit_code_hash, method);
13098
13099         if (ji)
13100                 return ji;
13101
13102         return lookup_generic_method (domain, method);
13103 }
13104
13105 static MonoJitInfo*
13106 lookup_method (MonoDomain *domain, MonoMethod *method)
13107 {
13108         MonoJitInfo *info;
13109
13110         mono_domain_jit_code_hash_lock (domain);
13111         info = lookup_method_inner (domain, method);
13112         mono_domain_jit_code_hash_unlock (domain);
13113
13114         return info;
13115 }
13116
13117 static gpointer
13118 mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, int opt)
13119 {
13120         MonoCompile *cfg;
13121         gpointer code = NULL;
13122         MonoJitInfo *info;
13123         MonoVTable *vtable;
13124
13125 #ifdef MONO_USE_AOT_COMPILER
13126         if ((opt & MONO_OPT_AOT) && !(mono_profiler_get_events () & MONO_PROFILE_JIT_COMPILATION)) {
13127                 MonoDomain *domain = mono_domain_get ();
13128
13129                 mono_class_init (method->klass);
13130
13131                 mono_domain_lock (domain);
13132                 if ((code = mono_aot_get_method (domain, method))) {
13133                         mono_domain_unlock (domain);
13134                         vtable = mono_class_vtable (domain, method->klass);
13135                         g_assert (vtable);
13136                         mono_runtime_class_init (vtable);
13137                         return code;
13138                 }
13139
13140                 mono_domain_unlock (domain);
13141         }
13142 #endif
13143
13144         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
13145             (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
13146                 MonoMethod *nm;
13147                 MonoMethodPInvoke* piinfo = (MonoMethodPInvoke *) method;
13148
13149                 if (!piinfo->addr) {
13150                         if (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL)
13151                                 piinfo->addr = mono_lookup_internal_call (method);
13152                         else if (method->iflags & METHOD_IMPL_ATTRIBUTE_NATIVE)
13153 #ifdef PLATFORM_WIN32
13154                                 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);
13155 #else
13156                                 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);
13157 #endif
13158                         else
13159                                 mono_lookup_pinvoke_call (method, NULL, NULL);
13160                 }
13161                 nm = mono_marshal_get_native_wrapper (method, check_for_pending_exc, FALSE);
13162                 return mono_get_addr_from_ftnptr (mono_compile_method (nm));
13163
13164                 //if (mono_debug_format != MONO_DEBUG_FORMAT_NONE) 
13165                 //mono_debug_add_wrapper (method, nm);
13166         } else if ((method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME)) {
13167                 const char *name = method->name;
13168                 MonoMethod *nm;
13169
13170                 if (method->klass->parent == mono_defaults.multicastdelegate_class) {
13171                         if (*name == '.' && (strcmp (name, ".ctor") == 0)) {
13172                                 MonoJitICallInfo *mi = mono_find_jit_icall_by_name ("mono_delegate_ctor");
13173                                 g_assert (mi);
13174                                 return mono_get_addr_from_ftnptr ((gpointer)mono_icall_get_wrapper (mi));
13175                         } else if (*name == 'I' && (strcmp (name, "Invoke") == 0)) {
13176 #ifdef MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE
13177                                 return mono_create_delegate_trampoline (method->klass);
13178 #else
13179                                 nm = mono_marshal_get_delegate_invoke (method, NULL);
13180                                 return mono_get_addr_from_ftnptr (mono_compile_method (nm));
13181 #endif
13182                         } else if (*name == 'B' && (strcmp (name, "BeginInvoke") == 0)) {
13183                                 nm = mono_marshal_get_delegate_begin_invoke (method);
13184                                 return mono_get_addr_from_ftnptr (mono_compile_method (nm));
13185                         } else if (*name == 'E' && (strcmp (name, "EndInvoke") == 0)) {
13186                                 nm = mono_marshal_get_delegate_end_invoke (method);
13187                                 return mono_get_addr_from_ftnptr (mono_compile_method (nm));
13188                         }
13189                 }
13190                 return NULL;
13191         }
13192
13193         if (mono_aot_only)
13194                 g_error ("Attempting to JIT compile method '%s' while running with --aot-only.\n", mono_method_full_name (method, TRUE));
13195
13196         cfg = mini_method_compile (method, opt, target_domain, TRUE, FALSE, 0);
13197
13198         switch (cfg->exception_type) {
13199         case MONO_EXCEPTION_NONE:
13200                 break;
13201         case MONO_EXCEPTION_TYPE_LOAD:
13202         case MONO_EXCEPTION_MISSING_FIELD:
13203         case MONO_EXCEPTION_MISSING_METHOD:
13204         case MONO_EXCEPTION_FILE_NOT_FOUND:
13205         case MONO_EXCEPTION_BAD_IMAGE: {
13206                 /* Throw a type load exception if needed */
13207                 MonoLoaderError *error = mono_loader_get_last_error ();
13208                 MonoException *ex;
13209
13210                 if (error) {
13211                         ex = mono_loader_error_prepare_exception (error);
13212                 } else {
13213                         if (cfg->exception_ptr) {
13214                                 ex = mono_class_get_exception_for_failure (cfg->exception_ptr);
13215                         } else {
13216                                 if (cfg->exception_type == MONO_EXCEPTION_MISSING_FIELD)
13217                                         ex = mono_exception_from_name_msg (mono_defaults.corlib, "System", "MissingFieldException", cfg->exception_message);
13218                                 else if (cfg->exception_type == MONO_EXCEPTION_MISSING_METHOD)
13219                                         ex = mono_exception_from_name_msg (mono_defaults.corlib, "System", "MissingMethodException", cfg->exception_message);
13220                                 else if (cfg->exception_type == MONO_EXCEPTION_TYPE_LOAD)
13221                                         ex = mono_exception_from_name_msg (mono_defaults.corlib, "System", "TypeLoadException", cfg->exception_message);
13222                                 else if (cfg->exception_type == MONO_EXCEPTION_FILE_NOT_FOUND)
13223                                         ex = mono_exception_from_name_msg (mono_defaults.corlib, "System", "FileNotFoundException", cfg->exception_message);
13224                                 else if (cfg->exception_type == MONO_EXCEPTION_BAD_IMAGE)
13225                                         ex = mono_get_exception_bad_image_format (cfg->exception_message);
13226                                 else
13227                                         g_assert_not_reached ();
13228                         }
13229                 }
13230                 mono_destroy_compile (cfg);
13231                 mono_raise_exception (ex);
13232                 break;
13233         }
13234         case MONO_EXCEPTION_INVALID_PROGRAM: {
13235                 MonoException *ex = mono_exception_from_name_msg (mono_defaults.corlib, "System", "InvalidProgramException", cfg->exception_message);
13236                 mono_destroy_compile (cfg);
13237                 mono_raise_exception (ex);
13238                 break;
13239         }
13240         case MONO_EXCEPTION_UNVERIFIABLE_IL: {
13241                 MonoException *ex = mono_exception_from_name_msg (mono_defaults.corlib, "System.Security", "VerificationException", cfg->exception_message);
13242                 mono_destroy_compile (cfg);
13243                 mono_raise_exception (ex);
13244                 break;
13245         }
13246         case MONO_EXCEPTION_METHOD_ACCESS: {
13247                 MonoException *ex = mono_exception_from_name_msg (mono_defaults.corlib, "System", "MethodAccessException", cfg->exception_message);
13248                 mono_destroy_compile (cfg);
13249                 mono_raise_exception (ex);
13250                 break;
13251         }
13252         case MONO_EXCEPTION_FIELD_ACCESS: {
13253                 MonoException *ex = mono_exception_from_name_msg (mono_defaults.corlib, "System", "FieldAccessException", cfg->exception_message);
13254                 mono_destroy_compile (cfg);
13255                 mono_raise_exception (ex);
13256                 break;
13257         }
13258         /* this can only be set if the security manager is active */
13259         case MONO_EXCEPTION_SECURITY_LINKDEMAND: {
13260                 MonoSecurityManager* secman = mono_security_manager_get_methods ();
13261                 MonoObject *exc = NULL;
13262                 gpointer args [2];
13263
13264                 args [0] = &cfg->exception_data;
13265                 args [1] = &method;
13266                 mono_runtime_invoke (secman->linkdemandsecurityexception, NULL, args, &exc);
13267
13268                 mono_destroy_compile (cfg);
13269                 cfg = NULL;
13270
13271                 mono_raise_exception ((MonoException*)exc);
13272         }
13273         case MONO_EXCEPTION_OBJECT_SUPPLIED: {
13274                 MonoException *exp = cfg->exception_ptr;
13275                 MONO_GC_UNREGISTER_ROOT (cfg->exception_ptr);
13276                 mono_destroy_compile (cfg);
13277                 mono_raise_exception (exp);
13278                 break;
13279         }
13280         default:
13281                 g_assert_not_reached ();
13282         }
13283
13284         mono_domain_lock (target_domain);
13285
13286         /* Check if some other thread already did the job. In this case, we can
13287        discard the code this thread generated. */
13288
13289         mono_domain_jit_code_hash_lock (target_domain);
13290
13291         info = lookup_method_inner (target_domain, method);
13292         if (info) {
13293                 /* We can't use a domain specific method in another domain */
13294                 if ((target_domain == mono_domain_get ()) || info->domain_neutral) {
13295                         code = info->code_start;
13296 //                      printf("Discarding code for method %s\n", method->name);
13297                 }
13298         }
13299         
13300         if (code == NULL) {
13301                 mono_internal_hash_table_insert (&target_domain->jit_code_hash, cfg->jit_info->method, cfg->jit_info);
13302                 mono_domain_jit_code_hash_unlock (target_domain);
13303                 code = cfg->native_code;
13304
13305                 if (cfg->generic_sharing_context && mono_method_is_generic_sharable_impl (method, FALSE)) {
13306                         /* g_print ("inserting method %s.%s.%s\n", method->klass->name_space, method->klass->name, method->name); */
13307                         mono_domain_register_shared_generic (target_domain, 
13308                                 mono_method_get_declaring_generic_method (method), cfg->jit_info);
13309                         mono_stats.generics_shared_methods++;
13310                 }
13311         } else {
13312                 mono_domain_jit_code_hash_unlock (target_domain);
13313         }
13314
13315         mono_destroy_compile (cfg);
13316
13317         if (target_domain->jump_target_hash) {
13318                 MonoJumpInfo patch_info;
13319                 GSList *list, *tmp;
13320                 list = g_hash_table_lookup (target_domain->jump_target_hash, method);
13321                 if (list) {
13322                         patch_info.next = NULL;
13323                         patch_info.ip.i = 0;
13324                         patch_info.type = MONO_PATCH_INFO_METHOD_JUMP;
13325                         patch_info.data.method = method;
13326                         g_hash_table_remove (target_domain->jump_target_hash, method);
13327                 }
13328                 for (tmp = list; tmp; tmp = tmp->next)
13329                         mono_arch_patch_code (NULL, target_domain, tmp->data, &patch_info, TRUE);
13330                 g_slist_free (list);
13331         }
13332
13333         mono_domain_unlock (target_domain);
13334
13335         vtable = mono_class_vtable (target_domain, method->klass);
13336         if (!vtable) {
13337                 MonoException *exc;
13338                 exc = mono_class_get_exception_for_failure (method->klass);
13339                 g_assert (exc);
13340                 mono_raise_exception (exc);
13341         }
13342         mono_runtime_class_init (vtable);
13343         return code;
13344 }
13345
13346 static gpointer
13347 mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt)
13348 {
13349         MonoDomain *target_domain, *domain = mono_domain_get ();
13350         MonoJitInfo *info;
13351         gpointer p;
13352         MonoJitICallInfo *callinfo = NULL;
13353
13354         /*
13355          * ICALL wrappers are handled specially, since there is only one copy of them
13356          * shared by all appdomains.
13357          */
13358         if ((method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) && (strstr (method->name, "__icall_wrapper_") == method->name)) {
13359                 const char *icall_name;
13360
13361                 icall_name = method->name + strlen ("__icall_wrapper_");
13362                 g_assert (icall_name);
13363                 callinfo = mono_find_jit_icall_by_name (icall_name);
13364                 g_assert (callinfo);
13365
13366                 /* Must be domain neutral since there is only one copy */
13367                 opt |= MONO_OPT_SHARED;
13368         }
13369
13370         if (opt & MONO_OPT_SHARED)
13371                 target_domain = mono_get_root_domain ();
13372         else 
13373                 target_domain = domain;
13374
13375         info = lookup_method (target_domain, method);
13376         if (info) {
13377                 /* We can't use a domain specific method in another domain */
13378                 if (! ((domain != target_domain) && !info->domain_neutral)) {
13379                         MonoVTable *vtable;
13380
13381                         mono_jit_stats.methods_lookups++;
13382                         vtable = mono_class_vtable (domain, method->klass);
13383                         mono_runtime_class_init (vtable);
13384                         return mono_create_ftnptr (target_domain, info->code_start);
13385                 }
13386         }
13387
13388         p = mono_create_ftnptr (target_domain, mono_jit_compile_method_inner (method, target_domain, opt));
13389
13390         if (callinfo) {
13391                 mono_jit_lock ();
13392                 if (!callinfo->wrapper) {
13393                         callinfo->wrapper = p;
13394                         mono_register_jit_icall_wrapper (callinfo, p);
13395                         mono_debug_add_icall_wrapper (method, callinfo);
13396                 }
13397                 mono_jit_unlock ();
13398         }
13399
13400         return p;
13401 }
13402
13403 static gpointer
13404 mono_jit_compile_method (MonoMethod *method)
13405 {
13406         return mono_jit_compile_method_with_opt (method, default_opt);
13407 }
13408
13409 #ifdef MONO_ARCH_HAVE_INVALIDATE_METHOD
13410 static void
13411 invalidated_delegate_trampoline (char *desc)
13412 {
13413         g_error ("Unmanaged code called delegate of type %s which was already garbage collected.\n"
13414                  "See http://www.go-mono.com/delegate.html for an explanation and ways to fix this.",
13415                  desc);
13416 }
13417 #endif
13418
13419 /*
13420  * mono_jit_free_method:
13421  *
13422  *  Free all memory allocated by the JIT for METHOD.
13423  */
13424 static void
13425 mono_jit_free_method (MonoDomain *domain, MonoMethod *method)
13426 {
13427         MonoJitDynamicMethodInfo *ji;
13428         gboolean destroy = TRUE;
13429
13430         g_assert (method->dynamic);
13431
13432         mono_domain_lock (domain);
13433         ji = mono_dynamic_code_hash_lookup (domain, method);
13434         mono_domain_unlock (domain);
13435
13436         if (!ji)
13437                 return;
13438         mono_domain_lock (domain);
13439         g_hash_table_remove (domain->dynamic_code_hash, method);
13440         mono_internal_hash_table_remove (&domain->jit_code_hash, method);
13441         g_hash_table_remove (domain->jump_trampoline_hash, method);
13442         mono_domain_unlock (domain);
13443
13444 #ifdef MONO_ARCH_HAVE_INVALIDATE_METHOD
13445         if (debug_options.keep_delegates && method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
13446                 /*
13447                  * Instead of freeing the code, change it to call an error routine
13448                  * so people can fix their code.
13449                  */
13450                 char *type = mono_type_full_name (&method->klass->byval_arg);
13451                 char *type_and_method = g_strdup_printf ("%s.%s", type, method->name);
13452
13453                 g_free (type);
13454                 mono_arch_invalidate_method (ji->ji, invalidated_delegate_trampoline, type_and_method);
13455                 destroy = FALSE;
13456         }
13457 #endif
13458
13459         /* 
13460          * This needs to be done before freeing code_mp, since the code address is the
13461          * key in the table, so if we free the code_mp first, another thread can grab the
13462          * same code address and replace our entry in the table.
13463          */
13464         mono_jit_info_table_remove (domain, ji->ji);
13465
13466         if (destroy)
13467                 mono_code_manager_destroy (ji->code_mp);
13468         g_free (ji);
13469 }
13470
13471 gpointer
13472 mono_jit_find_compiled_method (MonoDomain *domain, MonoMethod *method)
13473 {
13474         MonoDomain *target_domain;
13475         MonoJitInfo *info;
13476
13477         if (default_opt & MONO_OPT_SHARED)
13478                 target_domain = mono_get_root_domain ();
13479         else 
13480                 target_domain = domain;
13481
13482         info = lookup_method (target_domain, method);
13483         if (info) {
13484                 /* We can't use a domain specific method in another domain */
13485                 if (! ((domain != target_domain) && !info->domain_neutral)) {
13486                         mono_jit_stats.methods_lookups++;
13487                         return info->code_start;
13488                 }
13489         }
13490
13491         return NULL;
13492 }
13493
13494 /**
13495  * mono_jit_runtime_invoke:
13496  * @method: the method to invoke
13497  * @obj: this pointer
13498  * @params: array of parameter values.
13499  * @exc: used to catch exceptions objects
13500  */
13501 static MonoObject*
13502 mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
13503 {
13504         MonoMethod *to_compile;
13505         MonoMethod *invoke;
13506         MonoObject *(*runtime_invoke) (MonoObject *this, void **params, MonoObject **exc, void* compiled_method);
13507         void* compiled_method;
13508         MonoVTable *vtable;
13509
13510         if (obj == NULL && !(method->flags & METHOD_ATTRIBUTE_STATIC) && !method->string_ctor && (method->wrapper_type == 0)) {
13511                 g_warning ("Ignoring invocation of an instance method on a NULL instance.\n");
13512                 return NULL;
13513         }
13514
13515         if (((method->flags & METHOD_ATTRIBUTE_STATIC) ||
13516                                 (method->is_inflated && mono_method_get_context (method)->method_inst)) &&
13517                         mono_class_generic_sharing_enabled (method->klass) &&
13518                         mono_method_is_generic_sharable_impl (method, FALSE)) {
13519                 to_compile = mono_marshal_get_static_rgctx_invoke (method);
13520         } else {
13521                 to_compile = method;
13522         }
13523
13524         invoke = mono_marshal_get_runtime_invoke (method);
13525         runtime_invoke = mono_jit_compile_method (invoke);
13526         
13527         /* We need this here becuase mono_marshal_get_runtime_invoke can be place 
13528          * the helper method in System.Object and not the target class
13529          */
13530         vtable = mono_class_vtable (mono_domain_get (), method->klass);
13531         g_assert (vtable);
13532         mono_runtime_class_init (vtable);
13533
13534         if (method->klass->rank && (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) &&
13535                 (method->iflags & METHOD_IMPL_ATTRIBUTE_NATIVE)) {
13536                 /* 
13537                  * Array Get/Set/Address methods. The JIT implements them using inline code 
13538                  * inside the runtime invoke wrappers, so no need to compile them.
13539                  */
13540                 compiled_method = NULL;
13541         } else {
13542                 compiled_method = mono_jit_compile_method (to_compile);
13543         }
13544         return runtime_invoke (obj, params, exc, compiled_method);
13545 }
13546
13547 #ifdef MONO_GET_CONTEXT
13548 #define GET_CONTEXT MONO_GET_CONTEXT
13549 #endif
13550
13551 #ifndef GET_CONTEXT
13552 #ifdef PLATFORM_WIN32
13553 #define GET_CONTEXT \
13554         struct sigcontext *ctx = (struct sigcontext*)_dummy;
13555 #else
13556 #ifdef MONO_ARCH_USE_SIGACTION
13557 #define GET_CONTEXT \
13558     void *ctx = context;
13559 #elif defined(__sparc__)
13560 #define GET_CONTEXT \
13561     void *ctx = sigctx;
13562 #else
13563 #define GET_CONTEXT \
13564         void **_p = (void **)&_dummy; \
13565         struct sigcontext *ctx = (struct sigcontext *)++_p;
13566 #endif
13567 #endif
13568 #endif
13569
13570 #ifdef MONO_ARCH_USE_SIGACTION
13571 #define SIG_HANDLER_SIGNATURE(ftn) ftn (int _dummy, siginfo_t *info, void *context)
13572 #elif defined(__sparc__)
13573 #define SIG_HANDLER_SIGNATURE(ftn) ftn (int _dummy, void *sigctx)
13574 #else
13575 #define SIG_HANDLER_SIGNATURE(ftn) ftn (int _dummy)
13576 #endif
13577
13578 static void
13579 SIG_HANDLER_SIGNATURE (sigfpe_signal_handler)
13580 {
13581         MonoException *exc = NULL;
13582 #ifndef MONO_ARCH_USE_SIGACTION
13583         void *info = NULL;
13584 #endif
13585         GET_CONTEXT;
13586
13587 #if defined(MONO_ARCH_HAVE_IS_INT_OVERFLOW)
13588         if (mono_arch_is_int_overflow (ctx, info))
13589                 exc = mono_get_exception_arithmetic ();
13590         else
13591                 exc = mono_get_exception_divide_by_zero ();
13592 #else
13593         exc = mono_get_exception_divide_by_zero ();
13594 #endif
13595         
13596         mono_arch_handle_exception (ctx, exc, FALSE);
13597 }
13598
13599 static void
13600 SIG_HANDLER_SIGNATURE (sigill_signal_handler)
13601 {
13602         MonoException *exc;
13603         GET_CONTEXT;
13604
13605         exc = mono_get_exception_execution_engine ("SIGILL");
13606         
13607         mono_arch_handle_exception (ctx, exc, FALSE);
13608 }
13609
13610 static void
13611 SIG_HANDLER_SIGNATURE (sigsegv_signal_handler)
13612 {
13613 #ifndef MONO_ARCH_SIGSEGV_ON_ALTSTACK
13614         MonoException *exc = NULL;
13615 #endif
13616         MonoJitInfo *ji;
13617         MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
13618
13619         GET_CONTEXT;
13620
13621 #ifdef MONO_ARCH_USE_SIGACTION
13622         if (debug_options.collect_pagefault_stats) {
13623                 if (mono_raw_buffer_is_pagefault (info->si_addr)) {
13624                         mono_raw_buffer_handle_pagefault (info->si_addr);
13625                         return;
13626                 }
13627                 if (mono_aot_is_pagefault (info->si_addr)) {
13628                         mono_aot_handle_pagefault (info->si_addr);
13629                         return;
13630                 }
13631         }
13632 #endif
13633
13634         /* The thread might no be registered with the runtime */
13635         if (!mono_domain_get () || !jit_tls)
13636                 mono_handle_native_sigsegv (SIGSEGV, ctx);
13637
13638         ji = mono_jit_info_table_find (mono_domain_get (), mono_arch_ip_from_context (ctx));
13639
13640 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
13641         /* we got a stack overflow in the soft-guard pages
13642          * There are two cases:
13643          * 1) managed code caused the overflow: we unprotect the soft-guard page
13644          * and let the arch-specific code trigger the exception handling mechanism
13645          * in the thread stack. The soft-guard pages will be protected again as the stack is unwound.
13646          * 2) unmanaged code caused the overflow: we unprotect the soft-guard page
13647          * and hope we can continue with those enabled, at least until the hard-guard page
13648          * is hit. The alternative to continuing here is to just print a message and abort.
13649          * We may add in the future the code to protect the pages again in the codepath
13650          * when we return from unmanaged to managed code.
13651          */
13652         if (jit_tls->stack_ovf_guard_size && (guint8*)info->si_addr >= (guint8*)jit_tls->stack_ovf_guard_base &&
13653                         (guint8*)info->si_addr < (guint8*)jit_tls->stack_ovf_guard_base + jit_tls->stack_ovf_guard_size) {
13654                 mono_mprotect (jit_tls->stack_ovf_guard_base, jit_tls->stack_ovf_guard_size, MONO_MMAP_READ|MONO_MMAP_WRITE|MONO_MMAP_EXEC);
13655                 if (ji) {
13656                         mono_arch_handle_altstack_exception (ctx, info->si_addr, TRUE);
13657                 } else {
13658                         /* We print a message: after this even managed stack overflows
13659                          * may crash the runtime
13660                          */
13661                         fprintf (stderr, "Stack overflow in unmanaged: IP: %p, fault addr: %p\n", mono_arch_ip_from_context (ctx), (gpointer)info->si_addr);
13662                 }
13663                 return;
13664         }
13665         /* The hard-guard page has been hit: there is not much we can do anymore
13666          * Print a hopefully clear message and abort.
13667          */
13668         if (jit_tls->stack_size && 
13669                         ABS ((guint8*)info->si_addr - ((guint8*)jit_tls->end_of_stack - jit_tls->stack_size)) < 32768) {
13670                 const char *method;
13671                 /* we don't do much now, but we can warn the user with a useful message */
13672                 fprintf (stderr, "Stack overflow: IP: %p, fault addr: %p\n", mono_arch_ip_from_context (ctx), (gpointer)info->si_addr);
13673                 if (ji && ji->method)
13674                         method = mono_method_full_name (ji->method, TRUE);
13675                 else
13676                         method = "Unmanaged";
13677                 fprintf (stderr, "At %s\n", method);
13678                 abort ();
13679         } else {
13680                 mono_arch_handle_altstack_exception (ctx, info->si_addr, FALSE);
13681         }
13682 #else
13683
13684         if (!ji) {
13685                 mono_handle_native_sigsegv (SIGSEGV, ctx);
13686         }
13687                         
13688         mono_arch_handle_exception (ctx, exc, FALSE);
13689 #endif
13690 }
13691
13692 #ifndef PLATFORM_WIN32
13693
13694 static void
13695 SIG_HANDLER_SIGNATURE (sigabrt_signal_handler)
13696 {
13697         MonoJitInfo *ji;
13698         GET_CONTEXT;
13699
13700         ji = mono_jit_info_table_find (mono_domain_get (), mono_arch_ip_from_context(ctx));
13701         if (!ji) {
13702                 mono_handle_native_sigsegv (SIGABRT, ctx);
13703         }
13704 }
13705
13706 static void
13707 SIG_HANDLER_SIGNATURE (sigusr1_signal_handler)
13708 {
13709         gboolean running_managed;
13710         MonoException *exc;
13711         MonoThread *thread = mono_thread_current ();
13712         void *ji;
13713         
13714         GET_CONTEXT;
13715
13716         if (thread->thread_dump_requested) {
13717                 thread->thread_dump_requested = FALSE;
13718
13719                 mono_print_thread_dump (ctx);
13720         }
13721
13722         /*
13723          * FIXME:
13724          * This is an async signal, so the code below must not call anything which
13725          * is not async safe. That includes the pthread locking functions. If we
13726          * know that we interrupted managed code, then locking is safe.
13727          */
13728         ji = mono_jit_info_table_find (mono_domain_get (), mono_arch_ip_from_context(ctx));
13729         running_managed = ji != NULL;
13730         
13731         exc = mono_thread_request_interruption (running_managed); 
13732         if (!exc) return;
13733
13734         mono_arch_handle_exception (ctx, exc, FALSE);
13735 }
13736
13737 #if defined(__i386__) || defined(__x86_64__)
13738 #define FULL_STAT_PROFILER_BACKTRACE 1
13739 #define CURRENT_FRAME_GET_BASE_POINTER(f) (* (gpointer*)(f))
13740 #define CURRENT_FRAME_GET_RETURN_ADDRESS(f) (* (((gpointer*)(f)) + 1))
13741 #if MONO_ARCH_STACK_GROWS_UP
13742 #define IS_BEFORE_ON_STACK <
13743 #define IS_AFTER_ON_STACK >
13744 #else
13745 #define IS_BEFORE_ON_STACK >
13746 #define IS_AFTER_ON_STACK <
13747 #endif
13748 #else
13749 #define FULL_STAT_PROFILER_BACKTRACE 0
13750 #endif
13751
13752 #if defined(__ia64__) || defined(__sparc__) || defined(sparc) || defined(__s390__) || defined(s390)
13753
13754 static void
13755 SIG_HANDLER_SIGNATURE (sigprof_signal_handler)
13756 {
13757         NOT_IMPLEMENTED;
13758 }
13759
13760 #else
13761
13762 static void
13763 SIG_HANDLER_SIGNATURE (sigprof_signal_handler)
13764 {
13765         int call_chain_depth = mono_profiler_stat_get_call_chain_depth ();
13766         GET_CONTEXT;
13767         
13768         if (call_chain_depth == 0) {
13769                 mono_profiler_stat_hit (mono_arch_ip_from_context (ctx), ctx);
13770         } else {
13771                 MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
13772                 int current_frame_index = 1;
13773                 MonoContext mono_context;
13774 #if FULL_STAT_PROFILER_BACKTRACE
13775                 guchar *current_frame;
13776                 guchar *stack_bottom;
13777                 guchar *stack_top;
13778 #else
13779                 MonoDomain *domain;
13780 #endif
13781                 guchar *ips [call_chain_depth + 1];
13782
13783                 mono_arch_sigctx_to_monoctx (ctx, &mono_context);
13784                 ips [0] = MONO_CONTEXT_GET_IP (&mono_context);
13785                 
13786                 if (jit_tls != NULL) {
13787 #if FULL_STAT_PROFILER_BACKTRACE
13788                         stack_bottom = jit_tls->end_of_stack;
13789                         stack_top = MONO_CONTEXT_GET_SP (&mono_context);
13790                         current_frame = MONO_CONTEXT_GET_BP (&mono_context);
13791                         
13792                         while ((current_frame_index <= call_chain_depth) &&
13793                                         (stack_bottom IS_BEFORE_ON_STACK (guchar*) current_frame) &&
13794                                         ((guchar*) current_frame IS_BEFORE_ON_STACK stack_top)) {
13795                                 ips [current_frame_index] = CURRENT_FRAME_GET_RETURN_ADDRESS (current_frame);
13796                                 current_frame_index ++;
13797                                 stack_top = current_frame;
13798                                 current_frame = CURRENT_FRAME_GET_BASE_POINTER (current_frame);
13799                         }
13800 #else
13801                         domain = mono_domain_get ();
13802                         if (domain != NULL) {
13803                                 MonoLMF *lmf = NULL;
13804                                 MonoJitInfo *ji;
13805                                 MonoJitInfo res;
13806                                 MonoContext new_mono_context;
13807                                 int native_offset;
13808                                 ji = mono_find_jit_info (domain, jit_tls, &res, NULL, &mono_context,
13809                                                 &new_mono_context, NULL, &lmf, &native_offset, NULL);
13810                                 while ((ji != NULL) && (current_frame_index <= call_chain_depth)) {
13811                                         ips [current_frame_index] = MONO_CONTEXT_GET_IP (&new_mono_context);
13812                                         current_frame_index ++;
13813                                         mono_context = new_mono_context;
13814                                         ji = mono_find_jit_info (domain, jit_tls, &res, NULL, &mono_context,
13815                                                         &new_mono_context, NULL, &lmf, &native_offset, NULL);
13816                                 }
13817                         }
13818 #endif
13819                 }
13820                 
13821                 
13822                 mono_profiler_stat_call_chain (current_frame_index, & ips [0], ctx);
13823         }
13824 }
13825
13826 #endif
13827
13828 static void
13829 SIG_HANDLER_SIGNATURE (sigquit_signal_handler)
13830 {
13831         GET_CONTEXT;
13832
13833         printf ("Full thread dump:\n");
13834
13835         mono_threads_request_thread_dump ();
13836
13837         /*
13838          * print_thread_dump () skips the current thread, since sending a signal
13839          * to it would invoke the signal handler below the sigquit signal handler,
13840          * and signal handlers don't create an lmf, so the stack walk could not
13841          * be performed.
13842          */
13843         mono_print_thread_dump (ctx);
13844 }
13845
13846 static void
13847 SIG_HANDLER_SIGNATURE (sigusr2_signal_handler)
13848 {
13849         gboolean enabled = mono_trace_is_enabled ();
13850
13851         mono_trace_enable (!enabled);
13852 }
13853
13854 #endif
13855
13856 static void
13857 SIG_HANDLER_SIGNATURE (sigint_signal_handler)
13858 {
13859         MonoException *exc;
13860         GET_CONTEXT;
13861
13862         exc = mono_get_exception_execution_engine ("Interrupted (SIGINT).");
13863         
13864         mono_arch_handle_exception (ctx, exc, FALSE);
13865 }
13866
13867 #ifdef PLATFORM_MACOSX
13868
13869 /*
13870  * This code disables the CrashReporter of MacOS X by installing
13871  * a dummy Mach exception handler.
13872  */
13873
13874 /*
13875  * http://darwinsource.opendarwin.org/10.4.3/xnu-792.6.22/osfmk/man/exc_server.html
13876  */
13877 extern
13878 boolean_t
13879 exc_server (mach_msg_header_t *request_msg,
13880             mach_msg_header_t *reply_msg);
13881
13882 /*
13883  * The exception message
13884  */
13885 typedef struct {
13886         mach_msg_base_t msg;  /* common mach message header */
13887         char payload [1024];  /* opaque */
13888 } mach_exception_msg_t;
13889
13890 /* The exception port */
13891 static mach_port_t mach_exception_port = VM_MAP_NULL;
13892
13893 /*
13894  * Implicitly called by exc_server. Must be public.
13895  *
13896  * http://darwinsource.opendarwin.org/10.4.3/xnu-792.6.22/osfmk/man/catch_exception_raise.html
13897  */
13898 kern_return_t
13899 catch_exception_raise (
13900         mach_port_t exception_port,
13901         mach_port_t thread,
13902         mach_port_t task,
13903         exception_type_t exception,
13904         exception_data_t code,
13905         mach_msg_type_number_t code_count)
13906 {
13907         /* consume the exception */
13908         return KERN_FAILURE;
13909 }
13910
13911 /*
13912  * Exception thread handler.
13913  */
13914 static
13915 void *
13916 mach_exception_thread (void *arg)
13917 {
13918         for (;;) {
13919                 mach_exception_msg_t request;
13920                 mach_exception_msg_t reply;
13921                 mach_msg_return_t result;
13922
13923                 /* receive from "mach_exception_port" */
13924                 result = mach_msg (&request.msg.header,
13925                                    MACH_RCV_MSG | MACH_RCV_LARGE,
13926                                    0,
13927                                    sizeof (request),
13928                                    mach_exception_port,
13929                                    MACH_MSG_TIMEOUT_NONE,
13930                                    MACH_PORT_NULL);
13931
13932                 g_assert (result == MACH_MSG_SUCCESS);
13933
13934                 /* dispatch to catch_exception_raise () */
13935                 exc_server (&request.msg.header, &reply.msg.header);
13936
13937                 /* send back to sender */
13938                 result = mach_msg (&reply.msg.header,
13939                                    MACH_SEND_MSG,
13940                                    reply.msg.header.msgh_size,
13941                                    0,
13942                                    MACH_PORT_NULL,
13943                                    MACH_MSG_TIMEOUT_NONE,
13944                                    MACH_PORT_NULL);
13945
13946                 g_assert (result == MACH_MSG_SUCCESS);
13947         }
13948         return NULL;
13949 }
13950
13951 static void
13952 macosx_register_exception_handler ()
13953 {
13954         mach_port_t task;
13955         pthread_attr_t attr;
13956         pthread_t thread;
13957
13958         if (mach_exception_port != VM_MAP_NULL)
13959                 return;
13960
13961         task = mach_task_self ();
13962
13963         /* create the "mach_exception_port" with send & receive rights */
13964         g_assert (mach_port_allocate (task, MACH_PORT_RIGHT_RECEIVE,
13965                                       &mach_exception_port) == KERN_SUCCESS);
13966         g_assert (mach_port_insert_right (task, mach_exception_port, mach_exception_port,
13967                                           MACH_MSG_TYPE_MAKE_SEND) == KERN_SUCCESS);
13968
13969         /* create the exception handler thread */
13970         g_assert (!pthread_attr_init (&attr));
13971         g_assert (!pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED));
13972         g_assert (!pthread_create (&thread, &attr, mach_exception_thread, NULL));
13973         pthread_attr_destroy (&attr);
13974
13975         /*
13976          * register "mach_exception_port" as a receiver for the
13977          * EXC_BAD_ACCESS exception
13978          *
13979          * http://darwinsource.opendarwin.org/10.4.3/xnu-792.6.22/osfmk/man/task_set_exception_ports.html
13980          */
13981         g_assert (task_set_exception_ports (task, EXC_MASK_BAD_ACCESS,
13982                                             mach_exception_port,
13983                                             EXCEPTION_DEFAULT,
13984                                             MACHINE_THREAD_STATE) == KERN_SUCCESS);
13985 }
13986 #endif
13987
13988 #ifndef PLATFORM_WIN32
13989 static void
13990 add_signal_handler (int signo, gpointer handler)
13991 {
13992         struct sigaction sa;
13993
13994 #ifdef MONO_ARCH_USE_SIGACTION
13995         sa.sa_sigaction = handler;
13996         sigemptyset (&sa.sa_mask);
13997         sa.sa_flags = SA_SIGINFO;
13998 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
13999         if (signo == SIGSEGV)
14000                 sa.sa_flags |= SA_ONSTACK;
14001 #endif
14002 #else
14003         sa.sa_handler = handler;
14004         sigemptyset (&sa.sa_mask);
14005         sa.sa_flags = 0;
14006 #endif
14007         g_assert (sigaction (signo, &sa, NULL) != -1);
14008 }
14009
14010 static void
14011 remove_signal_handler (int signo)
14012 {
14013         struct sigaction sa;
14014
14015         sa.sa_handler = SIG_DFL;
14016         sigemptyset (&sa.sa_mask);
14017         sa.sa_flags = 0;
14018
14019         g_assert (sigaction (signo, &sa, NULL) != -1);
14020 }
14021 #endif
14022
14023 static void
14024 mono_runtime_install_handlers (void)
14025 {
14026 #ifdef PLATFORM_WIN32
14027         win32_seh_init();
14028         win32_seh_set_handler(SIGFPE, sigfpe_signal_handler);
14029         win32_seh_set_handler(SIGILL, sigill_signal_handler);
14030         win32_seh_set_handler(SIGSEGV, sigsegv_signal_handler);
14031         if (debug_options.handle_sigint)
14032                 win32_seh_set_handler(SIGINT, sigint_signal_handler);
14033
14034 #else /* !PLATFORM_WIN32 */
14035
14036
14037 #if defined(PLATFORM_MACOSX) && !defined(__arm__)
14038         macosx_register_exception_handler ();
14039 #endif
14040
14041         if (debug_options.handle_sigint)
14042                 add_signal_handler (SIGINT, sigint_signal_handler);
14043
14044         add_signal_handler (SIGFPE, sigfpe_signal_handler);
14045         add_signal_handler (SIGQUIT, sigquit_signal_handler);
14046         add_signal_handler (SIGILL, sigill_signal_handler);
14047         add_signal_handler (SIGBUS, sigsegv_signal_handler);
14048         if (mono_jit_trace_calls != NULL)
14049                 add_signal_handler (SIGUSR2, sigusr2_signal_handler);
14050
14051         add_signal_handler (mono_thread_get_abort_signal (), sigusr1_signal_handler);
14052         signal (SIGPIPE, SIG_IGN);
14053
14054         add_signal_handler (SIGABRT, sigabrt_signal_handler);
14055
14056         /* catch SIGSEGV */
14057         add_signal_handler (SIGSEGV, sigsegv_signal_handler);
14058 #endif /* PLATFORM_WIN32 */
14059 }
14060
14061 static void
14062 mono_runtime_cleanup_handlers (void)
14063 {
14064 #ifdef PLATFORM_WIN32
14065         win32_seh_cleanup();
14066 #else
14067         if (debug_options.handle_sigint)
14068                 remove_signal_handler (SIGINT);
14069
14070         remove_signal_handler (SIGFPE);
14071         remove_signal_handler (SIGQUIT);
14072         remove_signal_handler (SIGILL);
14073         remove_signal_handler (SIGBUS);
14074         if (mono_jit_trace_calls != NULL)
14075                 remove_signal_handler (SIGUSR2);
14076
14077         remove_signal_handler (mono_thread_get_abort_signal ());
14078
14079         remove_signal_handler (SIGABRT);
14080
14081         remove_signal_handler (SIGSEGV);
14082 #endif /* PLATFORM_WIN32 */
14083 }
14084
14085
14086 #ifdef HAVE_LINUX_RTC_H
14087 #include <linux/rtc.h>
14088 #include <sys/ioctl.h>
14089 #include <fcntl.h>
14090 static int rtc_fd = -1;
14091
14092 static int
14093 enable_rtc_timer (gboolean enable)
14094 {
14095         int flags;
14096         flags = fcntl (rtc_fd, F_GETFL);
14097         if (flags < 0) {
14098                 perror ("getflags");
14099                 return 0;
14100         }
14101         if (enable)
14102                 flags |= FASYNC;
14103         else
14104                 flags &= ~FASYNC;
14105         if (fcntl (rtc_fd, F_SETFL, flags) == -1) {
14106                 perror ("setflags");
14107                 return 0;
14108         }
14109         return 1;
14110 }
14111 #endif
14112
14113 #ifdef PLATFORM_WIN32
14114 static HANDLE win32_main_thread;
14115 static MMRESULT win32_timer;
14116
14117 static void CALLBACK
14118 win32_time_proc (UINT uID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2)
14119 {
14120         CONTEXT context;
14121
14122         context.ContextFlags = CONTEXT_CONTROL;
14123         if (GetThreadContext (win32_main_thread, &context)) {
14124 #ifdef _WIN64
14125                 mono_profiler_stat_hit ((guchar *) context.Rip, &context);
14126 #else
14127                 mono_profiler_stat_hit ((guchar *) context.Eip, &context);
14128 #endif
14129         }
14130 }
14131 #endif
14132
14133 static void
14134 setup_stat_profiler (void)
14135 {
14136 #ifdef ITIMER_PROF
14137         struct itimerval itval;
14138         static int inited = 0;
14139 #ifdef HAVE_LINUX_RTC_H
14140         const char *rtc_freq;
14141         if (!inited && (rtc_freq = g_getenv ("MONO_RTC"))) {
14142                 int freq = 0;
14143                 inited = 1;
14144                 if (*rtc_freq)
14145                         freq = atoi (rtc_freq);
14146                 if (!freq)
14147                         freq = 1024;
14148                 rtc_fd = open ("/dev/rtc", O_RDONLY);
14149                 if (rtc_fd == -1) {
14150                         perror ("open /dev/rtc");
14151                         return;
14152                 }
14153                 add_signal_handler (SIGPROF, sigprof_signal_handler);
14154                 if (ioctl (rtc_fd, RTC_IRQP_SET, freq) == -1) {
14155                         perror ("set rtc freq");
14156                         return;
14157                 }
14158                 if (ioctl (rtc_fd, RTC_PIE_ON, 0) == -1) {
14159                         perror ("start rtc");
14160                         return;
14161                 }
14162                 if (fcntl (rtc_fd, F_SETSIG, SIGPROF) == -1) {
14163                         perror ("setsig");
14164                         return;
14165                 }
14166                 if (fcntl (rtc_fd, F_SETOWN, getpid ()) == -1) {
14167                         perror ("setown");
14168                         return;
14169                 }
14170                 enable_rtc_timer (TRUE);
14171                 return;
14172         }
14173         if (rtc_fd >= 0)
14174                 return;
14175 #endif
14176
14177         itval.it_interval.tv_usec = 999;
14178         itval.it_interval.tv_sec = 0;
14179         itval.it_value = itval.it_interval;
14180         setitimer (ITIMER_PROF, &itval, NULL);
14181         if (inited)
14182                 return;
14183         inited = 1;
14184         add_signal_handler (SIGPROF, sigprof_signal_handler);
14185 #elif defined (PLATFORM_WIN32)
14186         static int inited = 0;
14187         TIMECAPS timecaps;
14188
14189         if (inited)
14190                 return;
14191
14192         inited = 1;
14193         if (timeGetDevCaps (&timecaps, sizeof (timecaps)) != TIMERR_NOERROR)
14194                 return;
14195
14196         if ((win32_main_thread = OpenThread (READ_CONTROL | THREAD_GET_CONTEXT, FALSE, GetCurrentThreadId ())) == NULL)
14197                 return;
14198
14199         if (timeBeginPeriod (1) != TIMERR_NOERROR)
14200                 return;
14201
14202         if ((win32_timer = timeSetEvent (1, 0, win32_time_proc, 0, TIME_PERIODIC)) == 0) {
14203                 timeEndPeriod (1);
14204                 return;
14205         }
14206 #endif
14207 }
14208
14209 /* mono_jit_create_remoting_trampoline:
14210  * @method: pointer to the method info
14211  *
14212  * Creates a trampoline which calls the remoting functions. This
14213  * is used in the vtable of transparent proxies.
14214  * 
14215  * Returns: a pointer to the newly created code 
14216  */
14217 static gpointer
14218 mono_jit_create_remoting_trampoline (MonoMethod *method, MonoRemotingTarget target)
14219 {
14220         MonoMethod *nm;
14221         guint8 *addr = NULL;
14222
14223         if ((method->flags & METHOD_ATTRIBUTE_ABSTRACT) || 
14224             (mono_method_signature (method)->hasthis && (method->klass->marshalbyref || method->klass == mono_defaults.object_class))) {
14225                 nm = mono_marshal_get_remoting_invoke_for_target (method, target);
14226                 addr = mono_compile_method (nm);
14227         } else {
14228                 addr = mono_compile_method (method);
14229         }
14230         return mono_get_addr_from_ftnptr (addr);
14231 }
14232
14233 #ifdef MONO_ARCH_HAVE_IMT
14234 static gpointer
14235 mini_get_imt_trampoline (void)
14236 {
14237         static gpointer tramp = NULL;
14238         if (!tramp)
14239                 tramp = mono_create_specific_trampoline (MONO_FAKE_IMT_METHOD, MONO_TRAMPOLINE_JIT, mono_get_root_domain (), NULL);
14240         return tramp;
14241 }
14242 #endif
14243
14244 #ifdef MONO_ARCH_COMMON_VTABLE_TRAMPOLINE
14245 gpointer
14246 mini_get_vtable_trampoline (void)
14247 {
14248         static gpointer tramp = NULL;
14249         if (!tramp)
14250                 tramp = mono_create_specific_trampoline (MONO_FAKE_VTABLE_METHOD, MONO_TRAMPOLINE_JIT, mono_get_root_domain (), NULL);
14251         return tramp;
14252 }
14253 #endif
14254
14255 static void
14256 mini_parse_debug_options (void)
14257 {
14258         char *options = getenv ("MONO_DEBUG");
14259         gchar **args, **ptr;
14260         
14261         if (!options)
14262                 return;
14263
14264         args = g_strsplit (options, ",", -1);
14265
14266         for (ptr = args; ptr && *ptr; ptr++) {
14267                 const char *arg = *ptr;
14268
14269                 if (!strcmp (arg, "handle-sigint"))
14270                         debug_options.handle_sigint = TRUE;
14271                 else if (!strcmp (arg, "keep-delegates"))
14272                         debug_options.keep_delegates = TRUE;
14273                 else if (!strcmp (arg, "collect-pagefault-stats"))
14274                         debug_options.collect_pagefault_stats = TRUE;
14275                 else if (!strcmp (arg, "break-on-unverified"))
14276                         debug_options.break_on_unverified = TRUE;
14277                 else if (!strcmp (arg, "no-gdb-backtrace"))
14278                         debug_options.no_gdb_backtrace = TRUE;
14279                 else if (!strcmp (arg, "dont-free-domains"))
14280                         mono_dont_free_domains = TRUE;
14281                 else {
14282                         fprintf (stderr, "Invalid option for the MONO_DEBUG env variable: %s\n", arg);
14283                         fprintf (stderr, "Available options: 'handle-sigint', 'keep-delegates', 'collect-pagefault-stats', 'break-on-unverified', 'no-gdb-backtrace', 'dont-free-domains'\n");
14284                         exit (1);
14285                 }
14286         }
14287
14288         g_strfreev (args);
14289 }
14290
14291 MonoDebugOptions *
14292 mini_get_debug_options (void)
14293 {
14294         return &debug_options;
14295 }
14296  
14297 static void
14298 mini_create_jit_domain_info (MonoDomain *domain)
14299 {
14300         MonoJitDomainInfo *info = g_new0 (MonoJitDomainInfo, 1);
14301
14302         domain->runtime_info = info;
14303 }
14304
14305 static void
14306 delete_jump_list (gpointer key, gpointer value, gpointer user_data)
14307 {
14308         g_slist_free (value);
14309 }
14310
14311 static void
14312 mini_free_jit_domain_info (MonoDomain *domain)
14313 {
14314         MonoJitDomainInfo *info = jit_domain_info (domain);
14315
14316         if (info->jump_target_got_slot_hash) {
14317                 g_hash_table_foreach (info->jump_target_got_slot_hash, delete_jump_list, NULL);
14318                 g_hash_table_destroy (info->jump_target_got_slot_hash);
14319         }
14320         g_free (domain->runtime_info);
14321 }
14322
14323 MonoDomain *
14324 mini_init (const char *filename, const char *runtime_version)
14325 {
14326         MonoDomain *domain;
14327
14328         MONO_PROBE_VES_INIT_BEGIN ();
14329
14330 #ifdef __linux__
14331         if (access ("/proc/self/maps", F_OK) != 0) {
14332                 g_print ("Mono requires /proc to be mounted.\n");
14333                 exit (1);
14334         }
14335 #endif
14336
14337         /* Happens when using the embedding interface */
14338         if (!default_opt_set)
14339                 default_opt = mono_parse_default_optimizations (NULL);
14340
14341         InitializeCriticalSection (&jit_mutex);
14342
14343         if (!global_codeman)
14344                 global_codeman = mono_code_manager_new ();
14345         jit_icall_name_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
14346
14347         mono_arch_cpu_init ();
14348
14349         mono_arch_init ();
14350
14351         mono_trampolines_init ();
14352
14353         if (!g_thread_supported ())
14354                 g_thread_init (NULL);
14355
14356         if (getenv ("MONO_DEBUG") != NULL)
14357                 mini_parse_debug_options ();
14358
14359         mono_gc_base_init ();
14360
14361         mono_jit_tls_id = TlsAlloc ();
14362         setup_jit_tls_data ((gpointer)-1, mono_thread_abort);
14363
14364 #ifndef DISABLE_JIT
14365         mono_burg_init ();
14366 #endif
14367
14368         if (default_opt & MONO_OPT_AOT)
14369                 mono_aot_init ();
14370
14371         mono_runtime_install_handlers ();
14372         mono_threads_install_cleanup (mini_thread_cleanup);
14373
14374 #ifdef MONO_ARCH_HAVE_NOTIFY_PENDING_EXC
14375         // This is experimental code so provide an env var to switch it off
14376         if (getenv ("MONO_DISABLE_PENDING_EXCEPTIONS")) {
14377                 printf ("MONO_DISABLE_PENDING_EXCEPTIONS env var set.\n");
14378         } else {
14379                 check_for_pending_exc = FALSE;
14380                 mono_threads_install_notify_pending_exc (mono_arch_notify_pending_exc);
14381         }
14382 #endif
14383
14384 #define JIT_TRAMPOLINES_WORK
14385 #ifdef JIT_TRAMPOLINES_WORK
14386         mono_install_compile_method (mono_jit_compile_method);
14387         mono_install_free_method (mono_jit_free_method);
14388         mono_install_trampoline (mono_create_jit_trampoline);
14389         mono_install_jump_trampoline (mono_create_jump_trampoline);
14390         mono_install_remoting_trampoline (mono_jit_create_remoting_trampoline);
14391         mono_install_delegate_trampoline (mono_create_delegate_trampoline);
14392         mono_install_create_domain_hook (mini_create_jit_domain_info);
14393         mono_install_free_domain_hook (mini_free_jit_domain_info);
14394 #endif
14395 #define JIT_INVOKE_WORKS
14396 #ifdef JIT_INVOKE_WORKS
14397         mono_install_runtime_invoke (mono_jit_runtime_invoke);
14398 #endif
14399         mono_install_stack_walk (mono_jit_walk_stack);
14400         mono_install_get_cached_class_info (mono_aot_get_cached_class_info);
14401         mono_install_get_class_from_name (mono_aot_get_class_from_name);
14402         mono_install_jit_info_find_in_aot (mono_aot_find_jit_info);
14403
14404         if (debug_options.collect_pagefault_stats) {
14405                 mono_raw_buffer_set_make_unreadable (TRUE);
14406                 mono_aot_set_make_unreadable (TRUE);
14407         }
14408
14409         if (runtime_version)
14410                 domain = mono_init_version (filename, runtime_version);
14411         else
14412                 domain = mono_init_from_assembly (filename, filename);
14413
14414         if (mono_aot_only) {
14415                 /* The IMT tables are very dynamic thus they are hard to AOT */
14416                 mono_use_imt = FALSE;
14417                 /* This helps catch code allocation requests */
14418                 mono_code_manager_set_read_only (domain->code_mp);
14419         }
14420
14421 #ifdef MONO_ARCH_HAVE_IMT
14422         if (mono_use_imt) {
14423                 mono_install_imt_thunk_builder (mono_arch_build_imt_thunk);
14424                 mono_install_imt_trampoline (mini_get_imt_trampoline ());
14425 #if MONO_ARCH_COMMON_VTABLE_TRAMPOLINE
14426                 mono_install_vtable_trampoline (mini_get_vtable_trampoline ());
14427 #endif
14428         }
14429 #endif
14430
14431         /* This must come after mono_init () in the aot-only case */
14432         mono_exceptions_init ();
14433         mono_install_handler (mono_get_throw_exception ());
14434
14435         mono_icall_init ();
14436
14437         mono_add_internal_call ("System.Diagnostics.StackFrame::get_frame_info", 
14438                                 ves_icall_get_frame_info);
14439         mono_add_internal_call ("System.Diagnostics.StackTrace::get_trace", 
14440                                 ves_icall_get_trace);
14441         mono_add_internal_call ("System.Exception::get_trace", 
14442                                 ves_icall_System_Exception_get_trace);
14443         mono_add_internal_call ("System.Security.SecurityFrame::_GetSecurityFrame",
14444                                 ves_icall_System_Security_SecurityFrame_GetSecurityFrame);
14445         mono_add_internal_call ("System.Security.SecurityFrame::_GetSecurityStack",
14446                                 ves_icall_System_Security_SecurityFrame_GetSecurityStack);
14447         mono_add_internal_call ("Mono.Runtime::mono_runtime_install_handlers", 
14448                                 mono_runtime_install_handlers);
14449
14450
14451         create_helper_signature ();
14452
14453 #define JIT_CALLS_WORK
14454 #ifdef JIT_CALLS_WORK
14455         /* Needs to be called here since register_jit_icall depends on it */
14456         mono_marshal_init ();
14457
14458         mono_arch_register_lowlevel_calls ();
14459         register_icall (mono_profiler_method_enter, "mono_profiler_method_enter", NULL, TRUE);
14460         register_icall (mono_profiler_method_leave, "mono_profiler_method_leave", NULL, TRUE);
14461         register_icall (mono_trace_enter_method, "mono_trace_enter_method", NULL, TRUE);
14462         register_icall (mono_trace_leave_method, "mono_trace_leave_method", NULL, TRUE);
14463         register_icall (mono_get_lmf_addr, "mono_get_lmf_addr", "ptr", TRUE);
14464         register_icall (mono_jit_thread_attach, "mono_jit_thread_attach", "void", TRUE);
14465         register_icall (mono_domain_get, "mono_domain_get", "ptr", TRUE);
14466
14467         register_icall (mono_get_throw_exception (), "mono_arch_throw_exception", "void object", TRUE);
14468         register_icall (mono_get_rethrow_exception (), "mono_arch_rethrow_exception", "void object", TRUE);
14469         register_icall (mono_get_throw_exception_by_name (), "mono_arch_throw_exception_by_name", "void ptr", TRUE); 
14470 #if MONO_ARCH_HAVE_THROW_CORLIB_EXCEPTION
14471         register_icall (mono_get_throw_corlib_exception (), "mono_arch_throw_corlib_exception", 
14472                                  "void ptr", TRUE);
14473 #endif
14474         register_icall (mono_thread_get_undeniable_exception, "mono_thread_get_undeniable_exception", "object", FALSE);
14475         register_icall (mono_thread_interruption_checkpoint, "mono_thread_interruption_checkpoint", "void", FALSE);
14476         register_icall (mono_thread_force_interruption_checkpoint, "mono_thread_force_interruption_checkpoint", "void", FALSE);
14477         register_icall (mono_load_remote_field_new, "mono_load_remote_field_new", "object object ptr ptr", FALSE);
14478         register_icall (mono_store_remote_field_new, "mono_store_remote_field_new", "void object ptr ptr object", FALSE);
14479
14480         /* 
14481          * NOTE, NOTE, NOTE, NOTE:
14482          * when adding emulation for some opcodes, remember to also add a dummy
14483          * rule to the burg files, because we need the arity information to be correct.
14484          */
14485 #ifndef MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS
14486         mono_register_opcode_emulation (OP_LMUL, "__emul_lmul", "long long long", mono_llmult, TRUE);
14487         mono_register_opcode_emulation (OP_LDIV, "__emul_ldiv", "long long long", mono_lldiv, FALSE);
14488         mono_register_opcode_emulation (OP_LDIV_UN, "__emul_ldiv_un", "long long long", mono_lldiv_un, FALSE);
14489         mono_register_opcode_emulation (OP_LREM, "__emul_lrem", "long long long", mono_llrem, FALSE);
14490         mono_register_opcode_emulation (OP_LREM_UN, "__emul_lrem_un", "long long long", mono_llrem_un, FALSE);
14491         mono_register_opcode_emulation (OP_LMUL_OVF_UN, "__emul_lmul_ovf_un", "long long long", mono_llmult_ovf_un, FALSE);
14492         mono_register_opcode_emulation (OP_LMUL_OVF, "__emul_lmul_ovf", "long long long", mono_llmult_ovf, FALSE);
14493 #endif
14494
14495 #ifndef MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
14496         mono_register_opcode_emulation (OP_LSHL, "__emul_lshl", "long long int32", mono_lshl, TRUE);
14497         mono_register_opcode_emulation (OP_LSHR, "__emul_lshr", "long long int32", mono_lshr, TRUE);
14498         mono_register_opcode_emulation (OP_LSHR_UN, "__emul_lshr_un", "long long int32", mono_lshr_un, TRUE);
14499 #endif
14500
14501 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
14502         mono_register_opcode_emulation (CEE_DIV, "__emul_idiv", "int32 int32 int32", mono_idiv, FALSE);
14503         mono_register_opcode_emulation (CEE_DIV_UN, "__emul_idiv_un", "int32 int32 int32", mono_idiv_un, FALSE);
14504         mono_register_opcode_emulation (CEE_REM, "__emul_irem", "int32 int32 int32", mono_irem, FALSE);
14505         mono_register_opcode_emulation (CEE_REM_UN, "__emul_irem_un", "int32 int32 int32", mono_irem_un, FALSE);
14506         mono_register_opcode_emulation (OP_IDIV, "__emul_op_idiv", "int32 int32 int32", mono_idiv, FALSE);
14507         mono_register_opcode_emulation (OP_IDIV_UN, "__emul_op_idiv_un", "int32 int32 int32", mono_idiv_un, FALSE);
14508         mono_register_opcode_emulation (OP_IREM, "__emul_op_irem", "int32 int32 int32", mono_irem, FALSE);
14509         mono_register_opcode_emulation (OP_IREM_UN, "__emul_op_irem_un", "int32 int32 int32", mono_irem_un, FALSE);
14510 #endif
14511
14512 #ifdef MONO_ARCH_EMULATE_MUL_DIV
14513         mono_register_opcode_emulation (CEE_MUL_OVF, "__emul_imul_ovf", "int32 int32 int32", mono_imul_ovf, FALSE);
14514         mono_register_opcode_emulation (CEE_MUL_OVF_UN, "__emul_imul_ovf_un", "int32 int32 int32", mono_imul_ovf_un, FALSE);
14515         mono_register_opcode_emulation (CEE_MUL, "__emul_imul", "int32 int32 int32", mono_imul, TRUE);
14516         mono_register_opcode_emulation (OP_IMUL, "__emul_op_imul", "int32 int32 int32", mono_imul, TRUE);
14517         mono_register_opcode_emulation (OP_IMUL_OVF, "__emul_op_imul_ovf", "int32 int32 int32", mono_imul_ovf, FALSE);
14518         mono_register_opcode_emulation (OP_IMUL_OVF_UN, "__emul_op_imul_ovf_un", "int32 int32 int32", mono_imul_ovf_un, FALSE);
14519 #endif
14520 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_SOFT_FLOAT)
14521         mono_register_opcode_emulation (OP_FDIV, "__emul_fdiv", "double double double", mono_fdiv, FALSE);
14522 #endif
14523
14524         mono_register_opcode_emulation (OP_FCONV_TO_U8, "__emul_fconv_to_u8", "ulong double", mono_fconv_u8, FALSE);
14525         mono_register_opcode_emulation (OP_FCONV_TO_U4, "__emul_fconv_to_u4", "uint32 double", mono_fconv_u4, FALSE);
14526         mono_register_opcode_emulation (OP_FCONV_TO_OVF_I8, "__emul_fconv_to_ovf_i8", "long double", mono_fconv_ovf_i8, FALSE);
14527         mono_register_opcode_emulation (OP_FCONV_TO_OVF_U8, "__emul_fconv_to_ovf_u8", "ulong double", mono_fconv_ovf_u8, FALSE);
14528
14529 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
14530         mono_register_opcode_emulation (OP_FCONV_TO_I8, "__emul_fconv_to_i8", "long double", mono_fconv_i8, FALSE);
14531 #endif
14532 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
14533         mono_register_opcode_emulation (CEE_CONV_R_UN, "__emul_conv_r_un", "double int32", mono_conv_to_r8_un, FALSE);
14534         mono_register_opcode_emulation (OP_ICONV_TO_R_UN, "__emul_iconv_to_r_un", "double int32", mono_conv_to_r8_un, FALSE);
14535 #endif
14536 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
14537         mono_register_opcode_emulation (OP_LCONV_TO_R8, "__emul_lconv_to_r8", "double long", mono_lconv_to_r8, FALSE);
14538 #endif
14539 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
14540         mono_register_opcode_emulation (OP_LCONV_TO_R4, "__emul_lconv_to_r4", "float long", mono_lconv_to_r4, FALSE);
14541 #endif
14542 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
14543         mono_register_opcode_emulation (OP_LCONV_TO_R_UN, "__emul_lconv_to_r8_un", "double long", mono_lconv_to_r8_un, FALSE);
14544 #endif
14545 #ifdef MONO_ARCH_EMULATE_FREM
14546         mono_register_opcode_emulation (OP_FREM, "__emul_frem", "double double double", fmod, FALSE);
14547 #endif
14548
14549 #ifdef MONO_ARCH_SOFT_FLOAT
14550         mono_register_opcode_emulation (OP_FSUB, "__emul_fsub", "double double double", mono_fsub, FALSE);
14551         mono_register_opcode_emulation (OP_FADD, "__emul_fadd", "double double double", mono_fadd, FALSE);
14552         mono_register_opcode_emulation (OP_FMUL, "__emul_fmul", "double double double", mono_fmul, FALSE);
14553         mono_register_opcode_emulation (OP_FNEG, "__emul_fneg", "double double", mono_fneg, FALSE);
14554         mono_register_opcode_emulation (CEE_CONV_R8, "__emul_conv_r8", "double int32", mono_conv_to_r8, FALSE);
14555         mono_register_opcode_emulation (OP_ICONV_TO_R8, "__emul_iconv_to_r8", "double int32", mono_conv_to_r8, FALSE);
14556         mono_register_opcode_emulation (CEE_CONV_R4, "__emul_conv_r4", "double int32", mono_conv_to_r4, FALSE);
14557         mono_register_opcode_emulation (OP_ICONV_TO_R4, "__emul_iconv_to_r4", "double int32", mono_conv_to_r4, FALSE);
14558         mono_register_opcode_emulation (OP_FCONV_TO_R4, "__emul_fconv_to_r4", "double double", mono_fconv_r4, FALSE);
14559         mono_register_opcode_emulation (OP_FCONV_TO_I1, "__emul_fconv_to_i1", "int8 double", mono_fconv_i1, FALSE);
14560         mono_register_opcode_emulation (OP_FCONV_TO_I2, "__emul_fconv_to_i2", "int16 double", mono_fconv_i2, FALSE);
14561         mono_register_opcode_emulation (OP_FCONV_TO_I4, "__emul_fconv_to_i4", "int32 double", mono_fconv_i4, FALSE);
14562         mono_register_opcode_emulation (OP_FCONV_TO_U1, "__emul_fconv_to_u1", "uint8 double", mono_fconv_u1, FALSE);
14563         mono_register_opcode_emulation (OP_FCONV_TO_U2, "__emul_fconv_to_u2", "uint16 double", mono_fconv_u2, FALSE);
14564
14565         mono_register_opcode_emulation (OP_FBEQ, "__emul_fcmp_eq", "uint32 double double", mono_fcmp_eq, FALSE);
14566         mono_register_opcode_emulation (OP_FBLT, "__emul_fcmp_lt", "uint32 double double", mono_fcmp_lt, FALSE);
14567         mono_register_opcode_emulation (OP_FBGT, "__emul_fcmp_gt", "uint32 double double", mono_fcmp_gt, FALSE);
14568         mono_register_opcode_emulation (OP_FBLE, "__emul_fcmp_le", "uint32 double double", mono_fcmp_le, FALSE);
14569         mono_register_opcode_emulation (OP_FBGE, "__emul_fcmp_ge", "uint32 double double", mono_fcmp_ge, FALSE);
14570         mono_register_opcode_emulation (OP_FBNE_UN, "__emul_fcmp_ne_un", "uint32 double double", mono_fcmp_ne_un, FALSE);
14571         mono_register_opcode_emulation (OP_FBLT_UN, "__emul_fcmp_lt_un", "uint32 double double", mono_fcmp_lt_un, FALSE);
14572         mono_register_opcode_emulation (OP_FBGT_UN, "__emul_fcmp_gt_un", "uint32 double double", mono_fcmp_gt_un, FALSE);
14573         mono_register_opcode_emulation (OP_FBLE_UN, "__emul_fcmp_le_un", "uint32 double double", mono_fcmp_le_un, FALSE);
14574         mono_register_opcode_emulation (OP_FBGE_UN, "__emul_fcmp_ge_un", "uint32 double double", mono_fcmp_ge_un, FALSE);
14575
14576         mono_register_opcode_emulation (OP_FCEQ, "__emul_fcmp_ceq", "uint32 double double", mono_fceq, FALSE);
14577         mono_register_opcode_emulation (OP_FCGT, "__emul_fcmp_cgt", "uint32 double double", mono_fcgt, FALSE);
14578         mono_register_opcode_emulation (OP_FCGT_UN, "__emul_fcmp_cgt_un", "uint32 double double", mono_fcgt_un, FALSE);
14579         mono_register_opcode_emulation (OP_FCLT, "__emul_fcmp_clt", "uint32 double double", mono_fclt, FALSE);
14580         mono_register_opcode_emulation (OP_FCLT_UN, "__emul_fcmp_clt_un", "uint32 double double", mono_fclt_un, FALSE);
14581
14582         register_icall (mono_fload_r4, "mono_fload_r4", "double ptr", FALSE);
14583         register_icall (mono_fstore_r4, "mono_fstore_r4", "void double ptr", FALSE);
14584         register_icall (mono_fload_r4_arg, "mono_fload_r4_arg", "uint32 double", FALSE);
14585 #endif
14586
14587 #if SIZEOF_VOID_P == 4
14588         mono_register_opcode_emulation (OP_FCONV_TO_U, "__emul_fconv_to_u", "uint32 double", mono_fconv_u4, TRUE);
14589 #endif
14590
14591         /* other jit icalls */
14592         register_icall (mono_delegate_ctor, "mono_delegate_ctor", "void object object ptr", FALSE);
14593         register_icall (mono_class_static_field_address , "mono_class_static_field_address", 
14594                                  "ptr ptr ptr", FALSE);
14595         register_icall (mono_ldtoken_wrapper, "mono_ldtoken_wrapper", "ptr ptr ptr ptr", FALSE);
14596         register_icall (mono_ldtoken_wrapper_generic_shared, "mono_ldtoken_wrapper_generic_shared",
14597                 "ptr ptr ptr ptr", FALSE);
14598         register_icall (mono_get_special_static_data, "mono_get_special_static_data", "ptr int", FALSE);
14599         register_icall (mono_ldstr, "mono_ldstr", "object ptr ptr int32", FALSE);
14600         register_icall (mono_helper_stelem_ref_check, "helper_stelem_ref_check", "void object object", FALSE);
14601         register_icall (mono_object_new, "mono_object_new", "object ptr ptr", FALSE);
14602         register_icall (mono_object_new_specific, "mono_object_new_specific", "object ptr", FALSE);
14603         register_icall (mono_array_new, "mono_array_new", "object ptr ptr int32", FALSE);
14604         register_icall (mono_array_new_specific, "mono_array_new_specific", "object ptr int32", FALSE);
14605         register_icall (mono_runtime_class_init, "mono_runtime_class_init", "void ptr", FALSE);
14606         register_icall (mono_ldftn, "mono_ldftn", "ptr ptr", FALSE);
14607         register_icall (mono_ldvirtfn, "mono_ldvirtfn", "ptr object ptr", FALSE);
14608         register_icall (mono_ldvirtfn_gshared, "mono_ldvirtfn_gshared", "ptr object ptr", FALSE);
14609         register_icall (mono_helper_compile_generic_method, "compile_generic_method", "ptr object ptr ptr", FALSE);
14610         register_icall (mono_helper_ldstr, "helper_ldstr", "object ptr int", FALSE);
14611         register_icall (mono_helper_ldstr_mscorlib, "helper_ldstr_mscorlib", "object int", FALSE);
14612         register_icall (mono_helper_newobj_mscorlib, "helper_newobj_mscorlib", "object int", FALSE);
14613         register_icall (mono_value_copy, "mono_value_copy", "void ptr ptr ptr", FALSE);
14614         register_icall (mono_object_castclass, "mono_object_castclass", "object object ptr", FALSE);
14615         register_icall (mono_break, "mono_break", NULL, TRUE);
14616         register_icall (mono_create_corlib_exception_0, "mono_create_corlib_exception_0", "object int", TRUE);
14617         register_icall (mono_create_corlib_exception_1, "mono_create_corlib_exception_1", "object int object", TRUE);
14618         register_icall (mono_create_corlib_exception_2, "mono_create_corlib_exception_2", "object int object object", TRUE);
14619         register_icall (mono_array_new_1, "mono_array_new_1", "object ptr int", FALSE);
14620         register_icall (mono_array_new_2, "mono_array_new_2", "object ptr int int", FALSE);
14621 #endif
14622
14623         mono_generic_sharing_init ();
14624
14625         if (mono_compile_aot)
14626                 /* 
14627                  * Avoid running managed code when AOT compiling, since the platform
14628                  * might only support aot-only execution.
14629                  */
14630                 mono_runtime_set_no_exec (TRUE);
14631
14632 #define JIT_RUNTIME_WORKS
14633 #ifdef JIT_RUNTIME_WORKS
14634         mono_install_runtime_cleanup ((MonoDomainFunc)mini_cleanup);
14635         mono_runtime_init (domain, mono_thread_start_cb, mono_thread_attach_cb);
14636         mono_thread_attach (domain);
14637 #endif
14638
14639         mono_profiler_runtime_initialized ();
14640         
14641         MONO_PROBE_VES_INIT_END ();
14642         
14643         return domain;
14644 }
14645
14646 MonoJitStats mono_jit_stats = {0};
14647
14648 static void 
14649 print_jit_stats (void)
14650 {
14651         if (mono_jit_stats.enabled) {
14652                 g_print ("Mono Jit statistics\n");
14653                 g_print ("Compiled methods:       %ld\n", mono_jit_stats.methods_compiled);
14654                 g_print ("Methods from AOT:       %ld\n", mono_jit_stats.methods_aot);
14655                 g_print ("Methods cache lookup:   %ld\n", mono_jit_stats.methods_lookups);
14656                 g_print ("Method trampolines:     %ld\n", mono_jit_stats.method_trampolines);
14657                 g_print ("Basic blocks:           %ld\n", mono_jit_stats.basic_blocks);
14658                 g_print ("Max basic blocks:       %ld\n", mono_jit_stats.max_basic_blocks);
14659                 g_print ("Allocated vars:         %ld\n", mono_jit_stats.allocate_var);
14660                 g_print ("Analyze stack repeat:   %ld\n", mono_jit_stats.analyze_stack_repeat);
14661                 g_print ("Compiled CIL code size: %ld\n", mono_jit_stats.cil_code_size);
14662                 g_print ("Native code size:       %ld\n", mono_jit_stats.native_code_size);
14663                 g_print ("Max code size ratio:    %.2f (%s)\n", mono_jit_stats.max_code_size_ratio/100.0,
14664                                  mono_jit_stats.max_ratio_method);
14665                 g_print ("Biggest method:         %ld (%s)\n", mono_jit_stats.biggest_method_size,
14666                                  mono_jit_stats.biggest_method);
14667                 g_print ("Code reallocs:          %ld\n", mono_jit_stats.code_reallocs);
14668                 g_print ("Allocated code size:    %ld\n", mono_jit_stats.allocated_code_size);
14669                 g_print ("Inlineable methods:     %ld\n", mono_jit_stats.inlineable_methods);
14670                 g_print ("Inlined methods:        %ld\n", mono_jit_stats.inlined_methods);
14671                 g_print ("Regvars:                %ld\n", mono_jit_stats.regvars);
14672                 g_print ("Locals stack size:      %ld\n", mono_jit_stats.locals_stack_size);
14673
14674                 g_print ("\nCreated object count:   %ld\n", mono_stats.new_object_count);
14675                 g_print ("Delegates created:      %ld\n", mono_stats.delegate_creations);
14676                 g_print ("Initialized classes:    %ld\n", mono_stats.initialized_class_count);
14677                 g_print ("Used classes:           %ld\n", mono_stats.used_class_count);
14678                 g_print ("Generic vtables:        %ld\n", mono_stats.generic_vtable_count);
14679                 g_print ("Methods:                %ld\n", mono_stats.method_count);
14680                 g_print ("Static data size:       %ld\n", mono_stats.class_static_data_size);
14681                 g_print ("VTable data size:       %ld\n", mono_stats.class_vtable_size);
14682                 g_print ("Mscorlib mempool size:  %d\n", mono_mempool_get_allocated (mono_defaults.corlib->mempool));
14683
14684                 g_print ("\nGeneric instances:      %ld\n", mono_stats.generic_instance_count);
14685                 g_print ("Initialized classes:    %ld\n", mono_stats.generic_class_count);
14686                 g_print ("Inflated methods:       %ld / %ld\n", mono_stats.inflated_method_count_2,
14687                          mono_stats.inflated_method_count);
14688                 g_print ("Inflated types:         %ld\n", mono_stats.inflated_type_count);
14689                 g_print ("Generics metadata size: %ld\n", mono_stats.generics_metadata_size);
14690                 g_print ("Generics virtual invokes: %ld\n", mono_jit_stats.generic_virtual_invocations);
14691
14692                 g_print ("Sharable generic methods: %ld\n", mono_stats.generics_sharable_methods);
14693                 g_print ("Unsharable generic methods: %ld\n", mono_stats.generics_unsharable_methods);
14694                 g_print ("Shared generic methods: %ld\n", mono_stats.generics_shared_methods);
14695
14696                 g_print ("Dynamic code allocs:    %ld\n", mono_stats.dynamic_code_alloc_count);
14697                 g_print ("Dynamic code bytes:     %ld\n", mono_stats.dynamic_code_bytes_count);
14698                 g_print ("Dynamic code frees:     %ld\n", mono_stats.dynamic_code_frees_count);
14699
14700                 g_print ("IMT tables size:        %ld\n", mono_stats.imt_tables_size);
14701                 g_print ("IMT number of tables:   %ld\n", mono_stats.imt_number_of_tables);
14702                 g_print ("IMT number of methods:  %ld\n", mono_stats.imt_number_of_methods);
14703                 g_print ("IMT used slots:         %ld\n", mono_stats.imt_used_slots);
14704                 g_print ("IMT colliding slots:    %ld\n", mono_stats.imt_slots_with_collisions);
14705                 g_print ("IMT max collisions:     %ld\n", mono_stats.imt_max_collisions_in_slot);
14706                 g_print ("IMT methods at max col: %ld\n", mono_stats.imt_method_count_when_max_collisions);
14707                 g_print ("IMT thunks size:        %ld\n", mono_stats.imt_thunks_size);
14708
14709                 g_print ("JIT info table inserts: %ld\n", mono_stats.jit_info_table_insert_count);
14710                 g_print ("JIT info table removes: %ld\n", mono_stats.jit_info_table_remove_count);
14711                 g_print ("JIT info table lookups: %ld\n", mono_stats.jit_info_table_lookup_count);
14712
14713                 g_print ("Hazardous pointers:     %ld\n", mono_stats.hazardous_pointer_count);
14714 #ifdef HAVE_SGEN_GC
14715                 g_print ("Minor GC collections:   %ld\n", mono_stats.minor_gc_count);
14716                 g_print ("Major GC collections:   %ld\n", mono_stats.major_gc_count);
14717                 g_print ("Minor GC time in msecs: %lf\n", (double)mono_stats.minor_gc_time_usecs / 1000.0);
14718                 g_print ("Major GC time in msecs: %lf\n", (double)mono_stats.major_gc_time_usecs / 1000.0);
14719 #endif
14720                 if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS) {
14721                         g_print ("\nDecl security check   : %ld\n", mono_jit_stats.cas_declsec_check);
14722                         g_print ("LinkDemand (user)     : %ld\n", mono_jit_stats.cas_linkdemand);
14723                         g_print ("LinkDemand (icall)    : %ld\n", mono_jit_stats.cas_linkdemand_icall);
14724                         g_print ("LinkDemand (pinvoke)  : %ld\n", mono_jit_stats.cas_linkdemand_pinvoke);
14725                         g_print ("LinkDemand (aptc)     : %ld\n", mono_jit_stats.cas_linkdemand_aptc);
14726                         g_print ("Demand (code gen)     : %ld\n", mono_jit_stats.cas_demand_generation);
14727                 }
14728                 if (debug_options.collect_pagefault_stats) {
14729                         g_print ("Metadata pagefaults   : %d\n", mono_raw_buffer_get_n_pagefaults ());
14730                         g_print ("AOT pagefaults        : %d\n", mono_aot_get_n_pagefaults ());
14731                 }
14732
14733                 g_free (mono_jit_stats.max_ratio_method);
14734                 mono_jit_stats.max_ratio_method = NULL;
14735                 g_free (mono_jit_stats.biggest_method);
14736                 mono_jit_stats.biggest_method = NULL;
14737         }
14738 }
14739
14740 void
14741 mini_cleanup (MonoDomain *domain)
14742 {
14743 #ifdef HAVE_LINUX_RTC_H
14744         if (rtc_fd >= 0)
14745                 enable_rtc_timer (FALSE);
14746 #endif
14747
14748         /* 
14749          * mono_runtime_cleanup() and mono_domain_finalize () need to
14750          * be called early since they need the execution engine still
14751          * fully working (mono_domain_finalize may invoke managed finalizers
14752          * and mono_runtime_cleanup will wait for other threads to finish).
14753          */
14754         mono_domain_finalize (domain, 2000);
14755
14756         /* This accesses metadata so needs to be called before runtime shutdown */
14757         print_jit_stats ();
14758
14759         mono_runtime_cleanup (domain);
14760
14761         mono_profiler_shutdown ();
14762
14763         mono_icall_cleanup ();
14764
14765         mono_runtime_cleanup_handlers ();
14766
14767         mono_domain_free (domain, TRUE);
14768
14769         mono_debugger_cleanup ();
14770
14771         mono_trampolines_cleanup ();
14772
14773         mono_code_manager_destroy (global_codeman);
14774         g_hash_table_destroy (jit_icall_name_hash);
14775         g_free (emul_opcode_map);
14776
14777         mono_arch_cleanup ();
14778
14779         mono_cleanup ();
14780
14781         mono_trace_cleanup ();
14782
14783         mono_counters_dump (-1, stdout);
14784
14785         if (mono_inject_async_exc_method)
14786                 mono_method_desc_free (mono_inject_async_exc_method);
14787
14788         TlsFree(mono_jit_tls_id);
14789
14790         DeleteCriticalSection (&jit_mutex);
14791
14792         DeleteCriticalSection (&mono_delegate_section);
14793 }
14794
14795 void
14796 mono_set_defaults (int verbose_level, guint32 opts)
14797 {
14798         mini_verbose = verbose_level;
14799         default_opt = opts;
14800         default_opt_set = TRUE;
14801 }
14802
14803 static void
14804 mono_precompile_assembly (MonoAssembly *ass, void *user_data)
14805 {
14806         GHashTable *assemblies = (GHashTable*)user_data;
14807         MonoImage *image = mono_assembly_get_image (ass);
14808         MonoMethod *method, *invoke;
14809         int i, count = 0;
14810
14811         if (g_hash_table_lookup (assemblies, ass))
14812                 return;
14813
14814         g_hash_table_insert (assemblies, ass, ass);
14815
14816         if (mini_verbose > 0)
14817                 printf ("PRECOMPILE: %s.\n", mono_image_get_filename (image));
14818
14819         for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_METHOD); ++i) {
14820                 method = mono_get_method (image, MONO_TOKEN_METHOD_DEF | (i + 1), NULL);
14821                 if (method->flags & METHOD_ATTRIBUTE_ABSTRACT)
14822                         continue;
14823
14824                 count++;
14825                 if (mini_verbose > 1) {
14826                         char * desc = mono_method_full_name (method, TRUE);
14827                         g_print ("Compiling %d %s\n", count, desc);
14828                         g_free (desc);
14829                 }
14830                 mono_compile_method (method);
14831                 if (strcmp (method->name, "Finalize") == 0) {
14832                         invoke = mono_marshal_get_runtime_invoke (method);
14833                         mono_compile_method (invoke);
14834                 }
14835                 if (method->klass->marshalbyref && mono_method_signature (method)->hasthis) {
14836                         invoke = mono_marshal_get_remoting_invoke_with_check (method);
14837                         mono_compile_method (invoke);
14838                 }
14839         }
14840
14841         /* Load and precompile referenced assemblies as well */
14842         for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_ASSEMBLYREF); ++i) {
14843                 mono_assembly_load_reference (image, i);
14844                 if (image->references [i])
14845                         mono_precompile_assembly (image->references [i], assemblies);
14846         }
14847 }
14848
14849 void mono_precompile_assemblies ()
14850 {
14851         GHashTable *assemblies = g_hash_table_new (NULL, NULL);
14852
14853         mono_assembly_foreach ((GFunc)mono_precompile_assembly, assemblies);
14854
14855         g_hash_table_destroy (assemblies);
14856 }