2008-08-14 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mono / mini / mini.c
1 /*
2  * mini.c: The new Mono code generator.
3  *
4  * Author:
5  *   Paolo Molaro (lupus@ximian.com)
6  *   Dietmar Maurer (dietmar@ximian.com)
7  *
8  * (C) 2002 Ximian, Inc.
9  */
10
11 #include <config.h>
12 #include <signal.h>
13 #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/utils/mono-math.h>
63 #include <mono/utils/mono-compiler.h>
64 #include <mono/utils/mono-counters.h>
65 #include <mono/utils/mono-logger.h>
66 #include <mono/utils/mono-mmap.h>
67 #include <mono/utils/dtrace.h>
68
69 #include "mini.h"
70 #include <string.h>
71 #include <ctype.h>
72 #include "inssel.h"
73 #include "trace.h"
74
75 #include "jit-icalls.h"
76
77 #include "aliasing.h"
78
79 #include "debug-mini.h"
80
81 #define BRANCH_COST 100
82 #define INLINE_LENGTH_LIMIT 20
83 #define INLINE_FAILURE do {\
84                 if ((cfg->method != method) && (method->wrapper_type == MONO_WRAPPER_NONE))\
85                         goto inline_failure;\
86         } while (0)
87 #define CHECK_CFG_EXCEPTION do {\
88                 if (cfg->exception_type != MONO_EXCEPTION_NONE)\
89                         goto exception_exit;\
90         } while (0)
91 #define METHOD_ACCESS_FAILURE do {      \
92                 char *method_fname = mono_method_full_name (method, TRUE);      \
93                 char *cil_method_fname = mono_method_full_name (cil_method, TRUE);      \
94                 cfg->exception_type = MONO_EXCEPTION_METHOD_ACCESS;     \
95                 cfg->exception_message = g_strdup_printf ("Method `%s' is inaccessible from method `%s'\n", cil_method_fname, method_fname);    \
96                 g_free (method_fname);  \
97                 g_free (cil_method_fname);      \
98                 goto exception_exit;    \
99         } while (0)
100 #define FIELD_ACCESS_FAILURE do {       \
101                 char *method_fname = mono_method_full_name (method, TRUE);      \
102                 char *field_fname = mono_field_full_name (field);       \
103                 cfg->exception_type = MONO_EXCEPTION_FIELD_ACCESS;      \
104                 cfg->exception_message = g_strdup_printf ("Field `%s' is inaccessible from method `%s'\n", field_fname, method_fname);  \
105                 g_free (method_fname);  \
106                 g_free (field_fname);   \
107                 goto exception_exit;    \
108         } while (0)
109 #define GENERIC_SHARING_FAILURE(opcode) do {            \
110                 if (cfg->generic_sharing_context) {     \
111             if (cfg->verbose_level > 1) \
112                             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__); \
113                         cfg->exception_type = MONO_EXCEPTION_GENERIC_SHARING_FAILED;    \
114                         goto exception_exit;    \
115                 }                       \
116         } while (0)
117 #define GENERIC_SHARING_FAILURE_IF_VALUETYPE_METHOD(opcode) do {                        \
118                 if (method->klass->valuetype)   \
119                         GENERIC_SHARING_FAILURE ((opcode)); \
120         } while (0)
121 #define GET_RGCTX(rgctx, context_used) do {                                             \
122                 MonoInst *this = NULL;                                  \
123                 g_assert (context_used);                                \
124                 GENERIC_SHARING_FAILURE_IF_VALUETYPE_METHOD(*ip);       \
125                 if (!(method->flags & METHOD_ATTRIBUTE_STATIC) &&       \
126                                 !((context_used) & MONO_GENERIC_CONTEXT_USED_METHOD)) \
127                         NEW_ARGLOAD (cfg, this, 0);                     \
128                 (rgctx) = get_runtime_generic_context (cfg, method, (context_used), this, ip); \
129         } while (0)
130
131
132 #define MONO_CHECK_THIS(ins) (mono_method_signature (cfg->method)->hasthis && (ins)->ssa_op == MONO_SSA_LOAD && (ins)->inst_left->inst_c0 == 0)
133
134 static void setup_stat_profiler (void);
135 gboolean  mono_arch_print_tree(MonoInst *tree, int arity);
136 static gpointer mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt);
137 static gpointer mono_jit_compile_method (MonoMethod *method);
138 inline static int mono_emit_jit_icall (MonoCompile *cfg, MonoBasicBlock *bblock, gconstpointer func, MonoInst **args, const guint8 *ip);
139
140 static void handle_stobj (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *dest, MonoInst *src, 
141                           const unsigned char *ip, MonoClass *klass, gboolean to_end, gboolean native, gboolean write_barrier);
142
143 static void dec_foreach (MonoInst *tree, MonoCompile *cfg);
144
145 int mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock, 
146                    MonoInst *return_var, GList *dont_inline, MonoInst **inline_args, 
147                    guint inline_offset, gboolean is_virtual_call);
148
149 static int mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock, 
150                    int locals_offset, MonoInst *return_var, GList *dont_inline, MonoInst **inline_args, 
151                    guint inline_offset, gboolean is_virtual_call);
152
153 #ifdef MONO_ARCH_SOFT_FLOAT
154 static void
155 handle_store_float (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *ptr, MonoInst *val, const unsigned char *ip);
156 #endif
157
158 /* helper methods signature */
159 /* FIXME: Make these static again */
160 MonoMethodSignature *helper_sig_class_init_trampoline = NULL;
161 MonoMethodSignature *helper_sig_domain_get = NULL;
162 MonoMethodSignature *helper_sig_generic_class_init_trampoline = NULL;
163 MonoMethodSignature *helper_sig_rgctx_lazy_fetch_trampoline = NULL;
164
165 static guint32 default_opt = 0;
166 static gboolean default_opt_set = FALSE;
167
168 guint32 mono_jit_tls_id = -1;
169
170 #ifdef HAVE_KW_THREAD
171 static __thread gpointer mono_jit_tls MONO_TLS_FAST;
172 #endif
173
174 MonoTraceSpec *mono_jit_trace_calls = NULL;
175 gboolean mono_break_on_exc = FALSE;
176 #ifndef DISABLE_AOT
177 gboolean mono_compile_aot = FALSE;
178 #endif
179 /* If this is set, no code is generated dynamically, everything is taken from AOT files */
180 gboolean mono_aot_only = FALSE;
181 /* Whenever to use IMT */
182 #ifdef MONO_ARCH_HAVE_IMT
183 gboolean mono_use_imt = TRUE;
184 #else
185 gboolean mono_use_imt = FALSE;
186 #endif
187 MonoMethodDesc *mono_inject_async_exc_method = NULL;
188 int mono_inject_async_exc_pos;
189 MonoMethodDesc *mono_break_at_bb_method = NULL;
190 int mono_break_at_bb_bb_num;
191
192 static int mini_verbose = 0;
193
194 #define mono_jit_lock() EnterCriticalSection (&jit_mutex)
195 #define mono_jit_unlock() LeaveCriticalSection (&jit_mutex)
196 static CRITICAL_SECTION jit_mutex;
197
198 static GHashTable *rgctx_lazy_fetch_trampoline_hash = NULL;
199
200 static MonoCodeManager *global_codeman = NULL;
201
202 /* FIXME: Make this static again */
203 GHashTable *jit_icall_name_hash = NULL;
204
205 static MonoDebugOptions debug_options;
206
207 #ifdef VALGRIND_JIT_REGISTER_MAP
208 static int valgrind_register = 0;
209 #endif
210
211 /*
212  * Table written to by the debugger with a 1-based index into the
213  * mono_breakpoint_info table, which contains changes made to
214  * the JIT instructions by the debugger.
215  */
216 gssize
217 mono_breakpoint_info_index [MONO_BREAKPOINT_ARRAY_SIZE];
218
219 /* Whenever to check for pending exceptions in managed-to-native wrappers */
220 gboolean check_for_pending_exc = TRUE;
221
222 /* Whenever to disable passing/returning small valuetypes in registers for managed methods */
223 gboolean disable_vtypes_in_regs = FALSE;
224
225 gboolean
226 mono_running_on_valgrind (void)
227 {
228 #ifdef HAVE_VALGRIND_MEMCHECK_H
229                 if (RUNNING_ON_VALGRIND){
230 #ifdef VALGRIND_JIT_REGISTER_MAP
231                         valgrind_register = TRUE;
232 #endif
233                         return TRUE;
234                 } else
235                         return FALSE;
236 #else
237                 return FALSE;
238 #endif
239 }
240
241 typedef struct {
242         void *ip;
243         MonoMethod *method;
244 } FindTrampUserData;
245
246 static void
247 find_tramp (gpointer key, gpointer value, gpointer user_data)
248 {
249         FindTrampUserData *ud = (FindTrampUserData*)user_data;
250
251         if (value == ud->ip)
252                 ud->method = (MonoMethod*)key;
253 }
254
255 /* debug function */
256 G_GNUC_UNUSED static char*
257 get_method_from_ip (void *ip)
258 {
259         MonoJitInfo *ji;
260         char *method;
261         char *res;
262         MonoDomain *domain = mono_domain_get ();
263         MonoDebugSourceLocation *location;
264         FindTrampUserData user_data;
265         
266         ji = mono_jit_info_table_find (domain, ip);
267         if (!ji) {
268                 user_data.ip = ip;
269                 user_data.method = NULL;
270                 mono_domain_lock (domain);
271                 g_hash_table_foreach (domain->jit_trampoline_hash, find_tramp, &user_data);
272                 mono_domain_unlock (domain);
273                 if (user_data.method) {
274                         char *mname = mono_method_full_name (user_data.method, TRUE);
275                         res = g_strdup_printf ("<%p - JIT trampoline for %s>", ip, mname);
276                         g_free (mname);
277                         return res;
278                 }
279                 else
280                         return NULL;
281         }
282         method = mono_method_full_name (ji->method, TRUE);
283         /* FIXME: unused ? */
284         location = mono_debug_lookup_source_location (ji->method, (guint32)((guint8*)ip - (guint8*)ji->code_start), domain);
285
286         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);
287
288         mono_debug_free_source_location (location);
289         g_free (method);
290
291         return res;
292 }
293
294 /** 
295  * mono_pmip:
296  * @ip: an instruction pointer address
297  *
298  * This method is used from a debugger to get the name of the
299  * method at address @ip.   This routine is typically invoked from
300  * a debugger like this:
301  *
302  * (gdb) print mono_pmip ($pc)
303  *
304  * Returns: the name of the method at address @ip.
305  */
306 G_GNUC_UNUSED char *
307 mono_pmip (void *ip)
308 {
309         return get_method_from_ip (ip);
310 }
311
312 /** 
313  * mono_print_method_from_ip
314  * @ip: an instruction pointer address
315  *
316  * This method is used from a debugger to get the name of the
317  * method at address @ip.
318  *
319  * This prints the name of the method at address @ip in the standard
320  * output.  Unlike mono_pmip which returns a string, this routine
321  * prints the value on the standard output. 
322  */
323 void
324 mono_print_method_from_ip (void *ip)
325 {
326         MonoJitInfo *ji;
327         char *method;
328         MonoDebugSourceLocation *source;
329         MonoDomain *domain = mono_domain_get ();
330         FindTrampUserData user_data;
331         
332         ji = mono_jit_info_table_find (domain, ip);
333         if (!ji) {
334                 user_data.ip = ip;
335                 user_data.method = NULL;
336                 mono_domain_lock (domain);
337                 g_hash_table_foreach (domain->jit_trampoline_hash, find_tramp, &user_data);
338                 mono_domain_unlock (domain);
339                 if (user_data.method) {
340                         char *mname = mono_method_full_name (user_data.method, TRUE);
341                         printf ("IP %p is a JIT trampoline for %s\n", ip, mname);
342                         g_free (mname);
343                 }
344                 else
345                         g_print ("No method at %p\n", ip);
346                 return;
347         }
348         method = mono_method_full_name (ji->method, TRUE);
349         source = mono_debug_lookup_source_location (ji->method, (guint32)((guint8*)ip - (guint8*)ji->code_start), domain);
350
351         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);
352
353         if (source)
354                 g_print ("%s:%d\n", source->source_file, source->row);
355
356         mono_debug_free_source_location (source);
357         g_free (method);
358 }
359         
360 /* 
361  * mono_method_same_domain:
362  *
363  * Determine whenever two compiled methods are in the same domain, thus
364  * the address of the callee can be embedded in the caller.
365  */
366 gboolean mono_method_same_domain (MonoJitInfo *caller, MonoJitInfo *callee)
367 {
368         if (!caller || !callee)
369                 return FALSE;
370
371         /*
372          * If the call was made from domain-neutral to domain-specific 
373          * code, we can't patch the call site.
374          */
375         if (caller->domain_neutral && !callee->domain_neutral)
376                 return FALSE;
377
378         if ((caller->method->klass == mono_defaults.appdomain_class) &&
379                 (strstr (caller->method->name, "InvokeInDomain"))) {
380                  /* The InvokeInDomain methods change the current appdomain */
381                 return FALSE;
382         }
383
384         return TRUE;
385 }
386
387 /*
388  * mono_global_codeman_reserve:
389  *
390  *  Allocate code memory from the global code manager.
391  */
392 void *mono_global_codeman_reserve (int size)
393 {
394         void *ptr;
395
396         if (mono_aot_only)
397                 g_error ("Attempting to allocate from the global code manager while running with --aot-only.\n");
398
399         if (!global_codeman) {
400                 /* This can happen during startup */
401                 global_codeman = mono_code_manager_new ();
402                 return mono_code_manager_reserve (global_codeman, size);
403         }
404         else {
405                 mono_jit_lock ();
406                 ptr = mono_code_manager_reserve (global_codeman, size);
407                 mono_jit_unlock ();
408                 return ptr;
409         }
410 }
411
412 MonoJumpInfoToken *
413 mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
414 {
415         MonoJumpInfoToken *res = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoToken));
416         res->image = image;
417         res->token = token;
418
419         return res;
420 }
421
422 #define MONO_INIT_VARINFO(vi,id) do { \
423         (vi)->range.first_use.pos.bid = 0xffff; \
424         (vi)->reg = -1; \
425         (vi)->idx = (id); \
426 } while (0)
427
428 //#define UNVERIFIED do { G_BREAKPOINT (); goto unverified; } while (0)
429 #define UNVERIFIED do { if (debug_options.break_on_unverified) G_BREAKPOINT (); else goto unverified; } while (0)
430
431 /*
432  * Basic blocks have two numeric identifiers:
433  * dfn: Depth First Number
434  * block_num: unique ID assigned at bblock creation
435  */
436 #define NEW_BBLOCK(cfg) (mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock)))
437 #define ADD_BBLOCK(cfg,b) do {  \
438                 cfg->cil_offset_to_bb [(b)->cil_code - cfg->cil_start] = (b);   \
439                 (b)->block_num = cfg->num_bblocks++;    \
440                 (b)->real_offset = real_offset; \
441         } while (0)
442
443 #define GET_BBLOCK(cfg,tblock,ip) do {  \
444                 (tblock) = cfg->cil_offset_to_bb [(ip) - cfg->cil_start]; \
445                 if (!(tblock)) {        \
446                         if ((ip) >= end || (ip) < header->code) UNVERIFIED; \
447                         (tblock) = NEW_BBLOCK (cfg);    \
448                         (tblock)->cil_code = (ip);      \
449                         ADD_BBLOCK (cfg, (tblock));     \
450                 } \
451         } while (0)
452
453 #define CHECK_BBLOCK(target,ip,tblock) do {     \
454                 if ((target) < (ip) && !(tblock)->code) {       \
455                         bb_recheck = g_list_prepend (bb_recheck, (tblock));     \
456                         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));     \
457                 }       \
458         } while (0)
459
460 #define NEW_ICONST(cfg,dest,val) do {   \
461                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
462                 (dest)->opcode = OP_ICONST;     \
463                 (dest)->inst_c0 = (val);        \
464                 (dest)->type = STACK_I4;        \
465         } while (0)
466
467 #define NEW_PCONST(cfg,dest,val) do {   \
468                 MONO_INST_NEW ((cfg), (dest), OP_PCONST);       \
469                 (dest)->inst_p0 = (val);        \
470                 (dest)->type = STACK_PTR;       \
471         } while (0)
472
473
474 #ifdef MONO_ARCH_NEED_GOT_VAR
475
476 #define NEW_PATCH_INFO(cfg,dest,el1,el2) do {   \
477                 MONO_INST_NEW ((cfg), (dest), OP_PATCH_INFO);   \
478                 (dest)->inst_left = (gpointer)(el1);    \
479                 (dest)->inst_right = (gpointer)(el2);   \
480         } while (0)
481
482 #define NEW_AOTCONST(cfg,dest,patch_type,cons) do {                     \
483                 MONO_INST_NEW ((cfg), (dest), OP_NOP); \
484                 (dest)->opcode = cfg->compile_aot ? OP_GOT_ENTRY : OP_PCONST; \
485                 if (cfg->compile_aot) {                                 \
486                         MonoInst *group, *got_var, *got_loc;            \
487                         got_loc = mono_get_got_var (cfg);               \
488                         NEW_TEMPLOAD ((cfg), got_var, got_loc->inst_c0); \
489                         NEW_PATCH_INFO ((cfg), group, cons, patch_type); \
490                         (dest)->inst_p0 = got_var;                      \
491                         (dest)->inst_p1 = group;                        \
492                 } else {                                                \
493                         (dest)->inst_p0 = (cons);                       \
494                         (dest)->inst_i1 = (gpointer)(patch_type);       \
495                 }                                                       \
496                 (dest)->type = STACK_PTR;                               \
497         } while (0)
498
499 #define NEW_AOTCONST_TOKEN(cfg,dest,patch_type,image,token,stack_type,stack_class) do { \
500                 MonoInst *group, *got_var, *got_loc;                    \
501                 MONO_INST_NEW ((cfg), (dest), OP_GOT_ENTRY); \
502                 got_loc = mono_get_got_var (cfg);                       \
503                 NEW_TEMPLOAD ((cfg), got_var, got_loc->inst_c0);        \
504                 NEW_PATCH_INFO ((cfg), group, NULL, patch_type);        \
505                 group->inst_p0 = mono_jump_info_token_new ((cfg)->mempool, (image), (token)); \
506                 (dest)->inst_p0 = got_var;                              \
507                 (dest)->inst_p1 = group;                                \
508                 (dest)->type = (stack_type);                    \
509         (dest)->klass = (stack_class);          \
510         } while (0)
511
512 #else
513
514 #define NEW_AOTCONST(cfg,dest,patch_type,cons) do {    \
515                 MONO_INST_NEW ((cfg), (dest), OP_NOP);  \
516                 (dest)->opcode = cfg->compile_aot ? OP_AOTCONST : OP_PCONST;    \
517                 (dest)->inst_p0 = (cons);       \
518                 (dest)->inst_i1 = (gpointer)(patch_type); \
519                 (dest)->type = STACK_PTR;       \
520     } while (0)
521
522 #define NEW_AOTCONST_TOKEN(cfg,dest,patch_type,image,token,stack_type,stack_class) do { \
523                 MONO_INST_NEW ((cfg), (dest), OP_AOTCONST);     \
524                 (dest)->inst_p0 = mono_jump_info_token_new ((cfg)->mempool, (image), (token));  \
525                 (dest)->inst_p1 = (gpointer)(patch_type); \
526                 (dest)->type = (stack_type);    \
527         (dest)->klass = (stack_class);          \
528     } while (0)
529
530 #endif
531
532 #define NEW_CLASSCONST(cfg,dest,val) NEW_AOTCONST ((cfg), (dest), MONO_PATCH_INFO_CLASS, (val))
533
534 #define NEW_IMAGECONST(cfg,dest,val) NEW_AOTCONST ((cfg), (dest), MONO_PATCH_INFO_IMAGE, (val))
535
536 #define NEW_FIELDCONST(cfg,dest,val) NEW_AOTCONST ((cfg), (dest), MONO_PATCH_INFO_FIELD, (val))
537
538 #define NEW_METHODCONST(cfg,dest,val) NEW_AOTCONST ((cfg), (dest), MONO_PATCH_INFO_METHODCONST, (val))
539
540 #define NEW_VTABLECONST(cfg,dest,vtable) NEW_AOTCONST ((cfg), (dest), MONO_PATCH_INFO_VTABLE, cfg->compile_aot ? (gpointer)((vtable)->klass) : (vtable))
541
542 #define NEW_SFLDACONST(cfg,dest,val) NEW_AOTCONST ((cfg), (dest), MONO_PATCH_INFO_SFLDA, (val))
543
544 #define NEW_LDSTRCONST(cfg,dest,image,token) NEW_AOTCONST_TOKEN ((cfg), (dest), MONO_PATCH_INFO_LDSTR, (image), (token), STACK_OBJ, mono_defaults.string_class)
545
546 #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)
547
548 #define NEW_LDTOKENCONST(cfg,dest,image,token) NEW_AOTCONST_TOKEN ((cfg), (dest), MONO_PATCH_INFO_LDTOKEN, (image), (token), STACK_PTR, NULL)
549
550 #define NEW_DECLSECCONST(cfg,dest,image,entry) do { \
551                 if (cfg->compile_aot) { \
552                         NEW_AOTCONST_TOKEN (cfg, dest, MONO_PATCH_INFO_DECLSEC, image, (entry).index, STACK_OBJ, NULL); \
553                 } else { \
554                         NEW_PCONST (cfg, args [0], (entry).blob); \
555                 } \
556         } while (0)
557
558 #define NEW_DOMAINCONST(cfg,dest) do { \
559                 if (cfg->opt & MONO_OPT_SHARED) { \
560                         /* avoid depending on undefined C behavior in sequence points */ \
561                         MonoInst* __domain_var = mono_get_domainvar (cfg); \
562                         NEW_TEMPLOAD (cfg, dest, __domain_var->inst_c0); \
563                 } else { \
564                         NEW_PCONST (cfg, dest, (cfg)->domain); \
565                 } \
566         } while (0)
567
568 #define GET_VARINFO_INST(cfg,num) ((cfg)->varinfo [(num)]->inst)
569
570 #define NEW_ARGLOAD(cfg,dest,num) do {  \
571                 if (arg_array [(num)]->opcode == OP_ICONST) (dest) = arg_array [(num)]; else { \
572                 MONO_INST_NEW ((cfg), (dest), OP_NOP);  \
573                 (dest)->ssa_op = MONO_SSA_LOAD; \
574                 (dest)->inst_i0 = arg_array [(num)];    \
575                 (dest)->opcode = mini_type_to_ldind ((cfg), (dest)->inst_i0->inst_vtype); \
576                 type_to_eval_stack_type ((cfg), param_types [(num)], (dest));   \
577                 (dest)->klass = (dest)->inst_i0->klass; \
578         }} while (0)
579
580 #define NEW_LOCLOAD(cfg,dest,num) do {  \
581                 MONO_INST_NEW ((cfg), (dest), OP_NOP);  \
582                 (dest)->ssa_op = MONO_SSA_LOAD; \
583                 (dest)->inst_i0 = (cfg)->varinfo [locals_offset + (num)];       \
584                 (dest)->opcode = mini_type_to_ldind ((cfg), (dest)->inst_i0->inst_vtype); \
585                 type_to_eval_stack_type ((cfg), header->locals [(num)], (dest));        \
586                 (dest)->klass = (dest)->inst_i0->klass; \
587         } while (0)
588
589 #define NEW_LOCLOADA(cfg,dest,num) do { \
590                 MONO_INST_NEW ((cfg), (dest), OP_LDADDR);       \
591                 (dest)->ssa_op = MONO_SSA_ADDRESS_TAKEN;        \
592                 (dest)->inst_i0 = (cfg)->varinfo [locals_offset + (num)];       \
593                 (dest)->inst_i0->flags |= MONO_INST_INDIRECT;   \
594                 (dest)->type = STACK_MP;        \
595                 (dest)->klass = (dest)->inst_i0->klass; \
596         if (!MONO_TYPE_ISSTRUCT (header->locals [(num)])) \
597            (cfg)->disable_ssa = TRUE; \
598         } while (0)
599
600 #define NEW_RETLOADA(cfg,dest) do {     \
601         if (cfg->vret_addr) { \
602                     MONO_INST_NEW ((cfg), (dest), OP_NOP);      \
603                     (dest)->ssa_op = MONO_SSA_LOAD;     \
604                     (dest)->inst_i0 = cfg->vret_addr; \
605                     (dest)->opcode = mini_type_to_ldind ((cfg), (dest)->inst_i0->inst_vtype); \
606             (dest)->type = STACK_MP; \
607                     (dest)->klass = (dest)->inst_i0->klass;     \
608         } else { \
609                         MONO_INST_NEW ((cfg), (dest), OP_NOP);  \
610                     (dest)->ssa_op = MONO_SSA_ADDRESS_TAKEN;    \
611                     (dest)->inst_i0 = (cfg)->ret;       \
612                     (dest)->inst_i0->flags |= MONO_INST_INDIRECT;       \
613                     (dest)->opcode = cfg->ret_var_is_local ? OP_LDADDR : CEE_LDIND_I;   \
614                     (dest)->type = STACK_MP;    \
615                     (dest)->klass = (dest)->inst_i0->klass;     \
616             (cfg)->disable_ssa = TRUE; \
617         } \
618         } while (0)
619
620 #define NEW_ARGLOADA(cfg,dest,num) do { \
621                 if (arg_array [(num)]->opcode == OP_ICONST) goto inline_failure; \
622                 MONO_INST_NEW ((cfg), (dest), OP_LDADDR);       \
623                 (dest)->ssa_op = MONO_SSA_ADDRESS_TAKEN;        \
624                 (dest)->inst_i0 = arg_array [(num)];    \
625                 (dest)->inst_i0->flags |= MONO_INST_INDIRECT;   \
626                 (dest)->type = STACK_MP;        \
627                 (dest)->klass = (dest)->inst_i0->klass; \
628                 (cfg)->disable_ssa = TRUE; \
629         } while (0)
630
631 #define NEW_TEMPLOAD(cfg,dest,num) do { \
632                 MONO_INST_NEW ((cfg), (dest), OP_NOP);  \
633                 (dest)->ssa_op = MONO_SSA_LOAD; \
634                 (dest)->inst_i0 = (cfg)->varinfo [(num)];       \
635                 (dest)->opcode = mini_type_to_ldind ((cfg), (dest)->inst_i0->inst_vtype); \
636                 type_to_eval_stack_type ((cfg), (dest)->inst_i0->inst_vtype, (dest));   \
637                 (dest)->klass = (dest)->inst_i0->klass; \
638         } while (0)
639
640 #define NEW_TEMPLOADA(cfg,dest,num) do {        \
641                 MONO_INST_NEW ((cfg), (dest), OP_LDADDR);       \
642                 (dest)->ssa_op = MONO_SSA_ADDRESS_TAKEN;        \
643                 (dest)->inst_i0 = (cfg)->varinfo [(num)];       \
644                 (dest)->inst_i0->flags |= MONO_INST_INDIRECT;   \
645                 (dest)->type = STACK_MP;        \
646                 (dest)->klass = (dest)->inst_i0->klass; \
647         if (!MONO_TYPE_ISSTRUCT (cfg->varinfo [(num)]->inst_vtype)) \
648            (cfg)->disable_ssa = TRUE; \
649         } while (0)
650
651 #define NEW_INDLOAD(cfg,dest,addr,vtype) do {   \
652                 MONO_INST_NEW ((cfg), (dest), OP_NOP);  \
653                 (dest)->inst_left = addr;       \
654                 (dest)->opcode = mini_type_to_ldind ((cfg), vtype);     \
655                 type_to_eval_stack_type ((cfg), vtype, (dest)); \
656                 /* FIXME: (dest)->klass = (dest)->inst_i0->klass;*/     \
657         } while (0)
658
659 #define NEW_INDSTORE(cfg,dest,addr,value,vtype) do {    \
660                 MONO_INST_NEW ((cfg), (dest), OP_NOP);  \
661                 (dest)->inst_i0 = addr; \
662                 (dest)->opcode = mini_type_to_stind ((cfg), vtype);     \
663                 (dest)->inst_i1 = (value);      \
664                 /* FIXME: (dest)->klass = (dest)->inst_i0->klass;*/     \
665         } while (0)
666
667 #define NEW_TEMPSTORE(cfg,dest,num,inst) do {   \
668                 MONO_INST_NEW ((cfg), (dest), OP_NOP);  \
669                 (dest)->ssa_op = MONO_SSA_STORE;        \
670                 (dest)->inst_i0 = (cfg)->varinfo [(num)];       \
671                 (dest)->opcode = mini_type_to_stind ((cfg), (dest)->inst_i0->inst_vtype); \
672                 (dest)->inst_i1 = (inst);       \
673                 (dest)->klass = (dest)->inst_i0->klass; \
674         } while (0)
675
676 #define NEW_LOCSTORE(cfg,dest,num,inst) do {    \
677                 MONO_INST_NEW ((cfg), (dest), OP_NOP);  \
678                 (dest)->opcode = mini_type_to_stind ((cfg), header->locals [(num)]); \
679                 (dest)->ssa_op = MONO_SSA_STORE;        \
680                 (dest)->inst_i0 = (cfg)->varinfo [locals_offset + (num)];       \
681                 (dest)->inst_i1 = (inst);       \
682                 (dest)->klass = (dest)->inst_i0->klass; \
683         } while (0)
684
685 #define NEW_ARGSTORE(cfg,dest,num,inst) do {    \
686                 if (arg_array [(num)]->opcode == OP_ICONST) goto inline_failure; \
687                 MONO_INST_NEW ((cfg), (dest), OP_NOP);  \
688                 (dest)->opcode = mini_type_to_stind ((cfg), param_types [(num)]); \
689                 (dest)->ssa_op = MONO_SSA_STORE;        \
690                 (dest)->inst_i0 = arg_array [(num)];    \
691                 (dest)->inst_i1 = (inst);       \
692                 (dest)->klass = (dest)->inst_i0->klass; \
693         } while (0)
694
695 #define NEW_MEMCPY(cfg,dest,dst,src,memcpy_size,memcpy_align) do { \
696                 MONO_INST_NEW (cfg, dest, OP_MEMCPY); \
697         (dest)->inst_left = (dst); \
698                 (dest)->inst_right = (src); \
699         (dest)->backend.memcpy_args = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoMemcpyArgs)); \
700                 (dest)->backend.memcpy_args->size = (memcpy_size); \
701                 (dest)->backend.memcpy_args->align = (memcpy_align); \
702     } while (0)
703
704 #define NEW_MEMSET(cfg,dest,dst,imm,memcpy_size,memcpy_align) do { \
705                 MONO_INST_NEW (cfg, dest, OP_MEMSET); \
706         (dest)->inst_left = (dst); \
707                 (dest)->inst_imm = (imm); \
708         (dest)->backend.memcpy_args = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoMemcpyArgs)); \
709                 (dest)->backend.memcpy_args->size = (memcpy_size); \
710                 (dest)->backend.memcpy_args->align = (memcpy_align); \
711     } while (0)
712
713 #define NEW_DUMMY_USE(cfg,dest,load) do { \
714                 MONO_INST_NEW ((cfg), (dest), OP_DUMMY_USE);    \
715                 (dest)->inst_left = (load); \
716     } while (0)
717
718 #define NEW_DUMMY_STORE(cfg,dest,num) do { \
719                 MONO_INST_NEW ((cfg), (dest), OP_DUMMY_STORE);  \
720                 (dest)->inst_i0 = (cfg)->varinfo [(num)];       \
721                 (dest)->klass = (dest)->inst_i0->klass; \
722         } while (0)
723
724 #define ADD_BINOP(op) do {      \
725                 MONO_INST_NEW (cfg, ins, (op)); \
726                 sp -= 2;        \
727                 ins->inst_i0 = sp [0];  \
728                 ins->inst_i1 = sp [1];  \
729                 *sp++ = ins;    \
730                 type_from_op (ins);     \
731                 CHECK_TYPE (ins);       \
732                 /* Have to insert a widening op */               \
733                 /* FIXME: Need to add many more cases */ \
734                 if (ins->inst_i0->type == STACK_PTR && ins->inst_i1->type == STACK_I4) { \
735                         MonoInst *widen;  \
736                         MONO_INST_NEW (cfg, widen, CEE_CONV_I); \
737             widen->inst_i0 = ins->inst_i1; \
738                         ins->inst_i1 = widen; \
739                 } \
740         } while (0)
741
742 #define ADD_UNOP(op) do {       \
743                 MONO_INST_NEW (cfg, ins, (op)); \
744                 sp--;   \
745                 ins->inst_i0 = sp [0];  \
746                 *sp++ = ins;    \
747                 type_from_op (ins);     \
748                 CHECK_TYPE (ins);       \
749         } while (0)
750
751 #define ADD_BINCOND(next_block) do {    \
752                 MonoInst *cmp;  \
753                 sp -= 2;                \
754                 MONO_INST_NEW(cfg, cmp, OP_COMPARE);    \
755                 cmp->inst_i0 = sp [0];  \
756                 cmp->inst_i1 = sp [1];  \
757                 cmp->cil_code = ins->cil_code;  \
758                 type_from_op (cmp);     \
759                 CHECK_TYPE (cmp);       \
760                 ins->inst_i0 = cmp;     \
761                 MONO_ADD_INS (bblock, ins);     \
762                 ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);      \
763                 GET_BBLOCK (cfg, tblock, target);               \
764                 link_bblock (cfg, bblock, tblock);      \
765                 ins->inst_true_bb = tblock;     \
766                 CHECK_BBLOCK (target, ip, tblock);      \
767                 if ((next_block)) {     \
768                         link_bblock (cfg, bblock, (next_block));        \
769                         ins->inst_false_bb = (next_block);      \
770                         start_new_bblock = 1;   \
771                 } else {        \
772                         GET_BBLOCK (cfg, tblock, ip);           \
773                         link_bblock (cfg, bblock, tblock);      \
774                         ins->inst_false_bb = tblock;    \
775                         start_new_bblock = 2;   \
776                 }       \
777         } while (0)
778
779 /* FIXME: handle float, long ... */
780 #define ADD_UNCOND(istrue) do { \
781                 MonoInst *cmp;  \
782                 sp--;           \
783                 MONO_INST_NEW(cfg, cmp, OP_COMPARE);    \
784                 cmp->inst_i0 = sp [0];  \
785                 switch (cmp->inst_i0->type) { \
786                 case STACK_I8: \
787                         cmp->inst_i1 = zero_int64; break; \
788                 case STACK_R8: \
789                         cmp->inst_i1 = zero_r8; break; \
790                 case STACK_PTR: \
791                 case STACK_MP: \
792                         cmp->inst_i1 = zero_ptr; break; \
793                 case STACK_OBJ: \
794                         cmp->inst_i1 = zero_obj; break; \
795                 default: \
796                         cmp->inst_i1 = zero_int32;  \
797                 }  \
798                 cmp->cil_code = ins->cil_code;  \
799                 type_from_op (cmp);     \
800                 CHECK_TYPE (cmp);       \
801                 ins->inst_i0 = cmp;     \
802                 ins->opcode = (istrue)? CEE_BNE_UN: CEE_BEQ;    \
803                 MONO_ADD_INS (bblock, ins);     \
804                 ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);      \
805                 GET_BBLOCK (cfg, tblock, target);               \
806                 link_bblock (cfg, bblock, tblock);      \
807                 ins->inst_true_bb = tblock;     \
808                 CHECK_BBLOCK (target, ip, tblock);      \
809                 GET_BBLOCK (cfg, tblock, ip);           \
810                 link_bblock (cfg, bblock, tblock);      \
811                 ins->inst_false_bb = tblock;    \
812                 start_new_bblock = 2;   \
813         } while (0)
814
815 #define NEW_LDELEMA(cfg,dest,sp,k) do { \
816                 MONO_INST_NEW ((cfg), (dest), CEE_LDELEMA);     \
817                 (dest)->inst_left = (sp) [0];   \
818                 (dest)->inst_right = (sp) [1];  \
819                 (dest)->type = STACK_MP;        \
820                 (dest)->klass = (k);    \
821                 (cfg)->flags |= MONO_CFG_HAS_LDELEMA; \
822         } while (0)
823
824 #define NEW_GROUP(cfg,dest,el1,el2) do {        \
825                 MONO_INST_NEW ((cfg), (dest), OP_GROUP);        \
826                 (dest)->inst_left = (el1);      \
827                 (dest)->inst_right = (el2);     \
828         } while (0)
829
830 #if 0
831 static gint
832 compare_bblock (gconstpointer a, gconstpointer b)
833 {
834         const MonoBasicBlock *b1 = a;
835         const MonoBasicBlock *b2 = b;
836
837         return b2->cil_code - b1->cil_code;
838 }
839 #endif
840
841 /* *
842  * link_bblock: Links two basic blocks
843  *
844  * links two basic blocks in the control flow graph, the 'from'
845  * argument is the starting block and the 'to' argument is the block
846  * the control flow ends to after 'from'.
847  */
848 static void
849 link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
850 {
851         MonoBasicBlock **newa;
852         int i, found;
853
854 #if 0
855         if (from->cil_code) {
856                 if (to->cil_code)
857                         g_print ("edge from IL%04x to IL_%04x\n", from->cil_code - cfg->cil_code, to->cil_code - cfg->cil_code);
858                 else
859                         g_print ("edge from IL%04x to exit\n", from->cil_code - cfg->cil_code);
860         } else {
861                 if (to->cil_code)
862                         g_print ("edge from entry to IL_%04x\n", to->cil_code - cfg->cil_code);
863                 else
864                         g_print ("edge from entry to exit\n");
865         }
866 #endif
867         found = FALSE;
868         for (i = 0; i < from->out_count; ++i) {
869                 if (to == from->out_bb [i]) {
870                         found = TRUE;
871                         break;
872                 }
873         }
874         if (!found) {
875                 newa = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (from->out_count + 1));
876                 for (i = 0; i < from->out_count; ++i) {
877                         newa [i] = from->out_bb [i];
878                 }
879                 newa [i] = to;
880                 from->out_count++;
881                 from->out_bb = newa;
882         }
883
884         found = FALSE;
885         for (i = 0; i < to->in_count; ++i) {
886                 if (from == to->in_bb [i]) {
887                         found = TRUE;
888                         break;
889                 }
890         }
891         if (!found) {
892                 newa = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (to->in_count + 1));
893                 for (i = 0; i < to->in_count; ++i) {
894                         newa [i] = to->in_bb [i];
895                 }
896                 newa [i] = from;
897                 to->in_count++;
898                 to->in_bb = newa;
899         }
900 }
901
902 /**
903  * mono_unlink_bblock:
904  *
905  *   Unlink two basic blocks.
906  */
907 void
908 mono_unlink_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
909 {
910         int i, pos;
911         gboolean found;
912
913         found = FALSE;
914         for (i = 0; i < from->out_count; ++i) {
915                 if (to == from->out_bb [i]) {
916                         found = TRUE;
917                         break;
918                 }
919         }
920         if (found) {
921                 pos = 0;
922                 for (i = 0; i < from->out_count; ++i) {
923                         if (from->out_bb [i] != to)
924                                 from->out_bb [pos ++] = from->out_bb [i];
925                 }
926                 g_assert (pos == from->out_count - 1);
927                 from->out_count--;
928         }
929
930         found = FALSE;
931         for (i = 0; i < to->in_count; ++i) {
932                 if (from == to->in_bb [i]) {
933                         found = TRUE;
934                         break;
935                 }
936         }
937         if (found) {
938                 pos = 0;
939                 for (i = 0; i < to->in_count; ++i) {
940                         if (to->in_bb [i] != from)
941                                 to->in_bb [pos ++] = to->in_bb [i];
942                 }
943                 g_assert (pos == to->in_count - 1);
944                 to->in_count--;
945         }
946 }
947
948 /*
949  * mono_bblocks_linked:
950  *
951  *   Return whenever BB1 and BB2 are linked in the CFG.
952  */
953 static gboolean
954 mono_bblocks_linked (MonoBasicBlock *bb1, MonoBasicBlock *bb2)
955 {
956         int i;
957
958         for (i = 0; i < bb1->out_count; ++i) {
959                 if (bb1->out_bb [i] == bb2)
960                         return TRUE;
961         }
962
963         return FALSE;
964 }
965
966 /**
967  * mono_find_block_region:
968  *
969  *   We mark each basic block with a region ID. We use that to avoid BB
970  *   optimizations when blocks are in different regions.
971  *
972  * Returns:
973  *   A region token that encodes where this region is, and information
974  *   about the clause owner for this block.
975  *
976  *   The region encodes the try/catch/filter clause that owns this block
977  *   as well as the type.  -1 is a special value that represents a block
978  *   that is in none of try/catch/filter.
979  */
980 static int
981 mono_find_block_region (MonoCompile *cfg, int offset)
982 {
983         MonoMethod *method = cfg->method;
984         MonoMethodHeader *header = mono_method_get_header (method);
985         MonoExceptionClause *clause;
986         int i;
987
988         /* first search for handlers and filters */
989         for (i = 0; i < header->num_clauses; ++i) {
990                 clause = &header->clauses [i];
991                 if ((clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) && (offset >= clause->data.filter_offset) &&
992                     (offset < (clause->handler_offset)))
993                         return ((i + 1) << 8) | MONO_REGION_FILTER | clause->flags;
994                            
995                 if (MONO_OFFSET_IN_HANDLER (clause, offset)) {
996                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY)
997                                 return ((i + 1) << 8) | MONO_REGION_FINALLY | clause->flags;
998                         else if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
999                                 return ((i + 1) << 8) | MONO_REGION_FAULT | clause->flags;
1000                         else if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE)
1001                                 return ((i + 1) << 8) | MONO_REGION_CATCH | clause->flags;
1002                 }
1003         }
1004
1005         /* search the try blocks */
1006         for (i = 0; i < header->num_clauses; ++i) {
1007                 clause = &header->clauses [i];
1008                 if (MONO_OFFSET_IN_CLAUSE (clause, offset))
1009                         return ((i + 1) << 8) | clause->flags;
1010         }
1011
1012         return -1;
1013 }
1014
1015 static GList*
1016 mono_find_final_block (MonoCompile *cfg, unsigned char *ip, unsigned char *target, int type)
1017 {
1018         MonoMethod *method = cfg->method;
1019         MonoMethodHeader *header = mono_method_get_header (method);
1020         MonoExceptionClause *clause;
1021         MonoBasicBlock *handler;
1022         int i;
1023         GList *res = NULL;
1024
1025         for (i = 0; i < header->num_clauses; ++i) {
1026                 clause = &header->clauses [i];
1027                 if (MONO_OFFSET_IN_CLAUSE (clause, (ip - header->code)) && 
1028                     (!MONO_OFFSET_IN_CLAUSE (clause, (target - header->code)))) {
1029                         if (clause->flags == type) {
1030                                 handler = cfg->cil_offset_to_bb [clause->handler_offset];
1031                                 g_assert (handler);
1032                                 res = g_list_append (res, handler);
1033                         }
1034                 }
1035         }
1036         return res;
1037 }
1038
1039 MonoInst *
1040 mono_find_spvar_for_region (MonoCompile *cfg, int region)
1041 {
1042         return g_hash_table_lookup (cfg->spvars, GINT_TO_POINTER (region));
1043 }
1044
1045 static void
1046 mono_create_spvar_for_region (MonoCompile *cfg, int region)
1047 {
1048         MonoInst *var;
1049
1050         var = g_hash_table_lookup (cfg->spvars, GINT_TO_POINTER (region));
1051         if (var)
1052                 return;
1053
1054         var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1055         /* prevent it from being register allocated */
1056         var->flags |= MONO_INST_INDIRECT;
1057
1058         g_hash_table_insert (cfg->spvars, GINT_TO_POINTER (region), var);
1059 }
1060
1061 static MonoInst *
1062 mono_find_exvar_for_offset (MonoCompile *cfg, int offset)
1063 {
1064         return g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
1065 }
1066
1067 static MonoInst*
1068 mono_create_exvar_for_offset (MonoCompile *cfg, int offset)
1069 {
1070         MonoInst *var;
1071
1072         var = g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
1073         if (var)
1074                 return var;
1075
1076         var = mono_compile_create_var (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL);
1077         /* prevent it from being register allocated */
1078         var->flags |= MONO_INST_INDIRECT;
1079
1080         g_hash_table_insert (cfg->exvars, GINT_TO_POINTER (offset), var);
1081
1082         return var;
1083 }
1084
1085 static void
1086 df_visit (MonoBasicBlock *start, int *dfn, MonoBasicBlock **array)
1087 {
1088         int i;
1089
1090         array [*dfn] = start;
1091         /* g_print ("visit %d at %p (BB%ld)\n", *dfn, start->cil_code, start->block_num); */
1092         for (i = 0; i < start->out_count; ++i) {
1093                 if (start->out_bb [i]->dfn)
1094                         continue;
1095                 (*dfn)++;
1096                 start->out_bb [i]->dfn = *dfn;
1097                 start->out_bb [i]->df_parent = start;
1098                 array [*dfn] = start->out_bb [i];
1099                 df_visit (start->out_bb [i], dfn, array);
1100         }
1101 }
1102
1103 static MonoBasicBlock*
1104 find_previous (MonoBasicBlock **bblocks, guint32 n_bblocks, MonoBasicBlock *start, const guchar *code)
1105 {
1106         MonoBasicBlock *best = start;
1107         int i;
1108
1109         for (i = 0; i < n_bblocks; ++i) {
1110                 if (bblocks [i]) {
1111                         MonoBasicBlock *bb = bblocks [i];
1112
1113                         if (bb->cil_code && bb->cil_code < code && bb->cil_code > best->cil_code)
1114                                 best = bb;
1115                 }
1116         }
1117
1118         return best;
1119 }
1120
1121 static void
1122 split_bblock (MonoCompile *cfg, MonoBasicBlock *first, MonoBasicBlock *second) {
1123         int i, j;
1124         MonoInst *inst;
1125         MonoBasicBlock *bb;
1126
1127         if (second->code)
1128                 return;
1129         
1130         /* 
1131          * FIXME: take into account all the details:
1132          * second may have been the target of more than one bblock
1133          */
1134         second->out_count = first->out_count;
1135         second->out_bb = first->out_bb;
1136
1137         for (i = 0; i < first->out_count; ++i) {
1138                 bb = first->out_bb [i];
1139                 for (j = 0; j < bb->in_count; ++j) {
1140                         if (bb->in_bb [j] == first)
1141                                 bb->in_bb [j] = second;
1142                 }
1143         }
1144
1145         first->out_count = 0;
1146         first->out_bb = NULL;
1147         link_bblock (cfg, first, second);
1148
1149         second->last_ins = first->last_ins;
1150
1151         /*g_print ("start search at %p for %p\n", first->cil_code, second->cil_code);*/
1152         MONO_BB_FOR_EACH_INS (first, inst) {
1153                 /*char *code = mono_disasm_code_one (NULL, cfg->method, inst->next->cil_code, NULL);
1154                 g_print ("found %p: %s", inst->next->cil_code, code);
1155                 g_free (code);*/
1156                 if (inst->cil_code < second->cil_code && inst->next->cil_code >= second->cil_code) {
1157                         second->code = inst->next;
1158                         inst->next = NULL;
1159                         first->last_ins = inst;
1160                         second->next_bb = first->next_bb;
1161                         first->next_bb = second;
1162                         return;
1163                 }
1164         }
1165         if (!second->code) {
1166                 g_warning ("bblock split failed in %s::%s\n", cfg->method->klass->name, cfg->method->name);
1167                 //G_BREAKPOINT ();
1168         }
1169 }
1170
1171 static guint32
1172 reverse_branch_op (guint32 opcode)
1173 {
1174         static const int reverse_map [] = {
1175                 CEE_BNE_UN, CEE_BLT, CEE_BLE, CEE_BGT, CEE_BGE,
1176                 CEE_BEQ, CEE_BLT_UN, CEE_BLE_UN, CEE_BGT_UN, CEE_BGE_UN
1177         };
1178         static const int reverse_fmap [] = {
1179                 OP_FBNE_UN, OP_FBLT, OP_FBLE, OP_FBGT, OP_FBGE,
1180                 OP_FBEQ, OP_FBLT_UN, OP_FBLE_UN, OP_FBGT_UN, OP_FBGE_UN
1181         };
1182         static const int reverse_lmap [] = {
1183                 OP_LBNE_UN, OP_LBLT, OP_LBLE, OP_LBGT, OP_LBGE,
1184                 OP_LBEQ, OP_LBLT_UN, OP_LBLE_UN, OP_LBGT_UN, OP_LBGE_UN
1185         };
1186         static const int reverse_imap [] = {
1187                 OP_IBNE_UN, OP_IBLT, OP_IBLE, OP_IBGT, OP_IBGE,
1188                 OP_IBEQ, OP_IBLT_UN, OP_IBLE_UN, OP_IBGT_UN, OP_IBGE_UN
1189         };
1190                                 
1191         if (opcode >= CEE_BEQ && opcode <= CEE_BLT_UN) {
1192                 opcode = reverse_map [opcode - CEE_BEQ];
1193         } else if (opcode >= OP_FBEQ && opcode <= OP_FBLT_UN) {
1194                 opcode = reverse_fmap [opcode - OP_FBEQ];
1195         } else if (opcode >= OP_LBEQ && opcode <= OP_LBLT_UN) {
1196                 opcode = reverse_lmap [opcode - OP_LBEQ];
1197         } else if (opcode >= OP_IBEQ && opcode <= OP_IBLT_UN) {
1198                 opcode = reverse_imap [opcode - OP_IBEQ];
1199         } else
1200                 g_assert_not_reached ();
1201
1202         return opcode;
1203 }
1204
1205 guint
1206 mono_type_to_store_membase (MonoCompile *cfg, MonoType *type)
1207 {
1208         if (type->byref)
1209                 return OP_STORE_MEMBASE_REG;
1210
1211 handle_enum:
1212         switch (type->type) {
1213         case MONO_TYPE_I1:
1214         case MONO_TYPE_U1:
1215         case MONO_TYPE_BOOLEAN:
1216                 return OP_STOREI1_MEMBASE_REG;
1217         case MONO_TYPE_I2:
1218         case MONO_TYPE_U2:
1219         case MONO_TYPE_CHAR:
1220                 return OP_STOREI2_MEMBASE_REG;
1221         case MONO_TYPE_I4:
1222         case MONO_TYPE_U4:
1223                 return OP_STOREI4_MEMBASE_REG;
1224         case MONO_TYPE_I:
1225         case MONO_TYPE_U:
1226         case MONO_TYPE_PTR:
1227         case MONO_TYPE_FNPTR:
1228                 return OP_STORE_MEMBASE_REG;
1229         case MONO_TYPE_CLASS:
1230         case MONO_TYPE_STRING:
1231         case MONO_TYPE_OBJECT:
1232         case MONO_TYPE_SZARRAY:
1233         case MONO_TYPE_ARRAY:    
1234                 return OP_STORE_MEMBASE_REG;
1235         case MONO_TYPE_I8:
1236         case MONO_TYPE_U8:
1237                 return OP_STOREI8_MEMBASE_REG;
1238         case MONO_TYPE_R4:
1239                 return OP_STORER4_MEMBASE_REG;
1240         case MONO_TYPE_R8:
1241                 return OP_STORER8_MEMBASE_REG;
1242         case MONO_TYPE_VALUETYPE:
1243                 if (type->data.klass->enumtype) {
1244                         type = type->data.klass->enum_basetype;
1245                         goto handle_enum;
1246                 }
1247                 return OP_STOREV_MEMBASE;
1248         case MONO_TYPE_TYPEDBYREF:
1249                 return OP_STOREV_MEMBASE;
1250         case MONO_TYPE_GENERICINST:
1251                 type = &type->data.generic_class->container_class->byval_arg;
1252                 goto handle_enum;
1253         case MONO_TYPE_VAR:
1254         case MONO_TYPE_MVAR:
1255                 /* FIXME: all the arguments must be references for now,
1256                  * later look inside cfg and see if the arg num is
1257                  * really a reference
1258                  */
1259                 g_assert (cfg->generic_sharing_context);
1260                 return OP_STORE_MEMBASE_REG;
1261         default:
1262                 g_error ("unknown type 0x%02x in type_to_store_membase", type->type);
1263         }
1264         return -1;
1265 }
1266
1267 guint
1268 mono_type_to_load_membase (MonoCompile *cfg, MonoType *type)
1269 {
1270         if (type->byref)
1271                 return OP_LOAD_MEMBASE;
1272
1273         switch (mono_type_get_underlying_type (type)->type) {
1274         case MONO_TYPE_I1:
1275                 return OP_LOADI1_MEMBASE;
1276         case MONO_TYPE_U1:
1277         case MONO_TYPE_BOOLEAN:
1278                 return OP_LOADU1_MEMBASE;
1279         case MONO_TYPE_I2:
1280                 return OP_LOADI2_MEMBASE;
1281         case MONO_TYPE_U2:
1282         case MONO_TYPE_CHAR:
1283                 return OP_LOADU2_MEMBASE;
1284         case MONO_TYPE_I4:
1285                 return OP_LOADI4_MEMBASE;
1286         case MONO_TYPE_U4:
1287                 return OP_LOADU4_MEMBASE;
1288         case MONO_TYPE_I:
1289         case MONO_TYPE_U:
1290         case MONO_TYPE_PTR:
1291         case MONO_TYPE_FNPTR:
1292                 return OP_LOAD_MEMBASE;
1293         case MONO_TYPE_CLASS:
1294         case MONO_TYPE_STRING:
1295         case MONO_TYPE_OBJECT:
1296         case MONO_TYPE_SZARRAY:
1297         case MONO_TYPE_ARRAY:    
1298                 return OP_LOAD_MEMBASE;
1299         case MONO_TYPE_I8:
1300         case MONO_TYPE_U8:
1301                 return OP_LOADI8_MEMBASE;
1302         case MONO_TYPE_R4:
1303                 return OP_LOADR4_MEMBASE;
1304         case MONO_TYPE_R8:
1305                 return OP_LOADR8_MEMBASE;
1306         case MONO_TYPE_VALUETYPE:
1307         case MONO_TYPE_TYPEDBYREF:
1308                 return OP_LOADV_MEMBASE;
1309         case MONO_TYPE_GENERICINST:
1310                 if (mono_type_generic_inst_is_valuetype (type))
1311                         return OP_LOADV_MEMBASE;
1312                 else
1313                         return OP_LOAD_MEMBASE;
1314                 break;
1315         case MONO_TYPE_VAR:
1316         case MONO_TYPE_MVAR:
1317                 /* FIXME: all the arguments must be references for now,
1318                  * later look inside cfg and see if the arg num is
1319                  * really a reference
1320                  */
1321                 g_assert (cfg->generic_sharing_context);
1322                 return OP_LOAD_MEMBASE;
1323         default:
1324                 g_error ("unknown type 0x%02x in type_to_load_membase", type->type);
1325         }
1326         return -1;
1327 }
1328
1329 #ifdef MONO_ARCH_SOFT_FLOAT
1330 static int
1331 condbr_to_fp_br (int opcode)
1332 {
1333         switch (opcode) {
1334         case CEE_BEQ: return OP_FBEQ;
1335         case CEE_BGE: return OP_FBGE;
1336         case CEE_BGT: return OP_FBGT;
1337         case CEE_BLE: return OP_FBLE;
1338         case CEE_BLT: return OP_FBLT;
1339         case CEE_BNE_UN: return OP_FBNE_UN;
1340         case CEE_BGE_UN: return OP_FBGE_UN;
1341         case CEE_BGT_UN: return OP_FBGT_UN;
1342         case CEE_BLE_UN: return OP_FBLE_UN;
1343         case CEE_BLT_UN: return OP_FBLT_UN;
1344         }
1345         g_assert_not_reached ();
1346         return 0;
1347 }
1348 #endif
1349
1350 /*
1351  * Returns the type used in the eval stack when @type is loaded.
1352  * FIXME: return a MonoType/MonoClass for the byref and VALUETYPE cases.
1353  */
1354 static void
1355 type_to_eval_stack_type (MonoCompile *cfg, MonoType *type, MonoInst *inst)
1356 {
1357         MonoClass *klass;
1358
1359         inst->klass = klass = mono_class_from_mono_type (type);
1360         if (type->byref) {
1361                 inst->type = STACK_MP;
1362                 return;
1363         }
1364
1365 handle_enum:
1366         switch (type->type) {
1367         case MONO_TYPE_VOID:
1368                 inst->type = STACK_INV;
1369                 return;
1370         case MONO_TYPE_I1:
1371         case MONO_TYPE_U1:
1372         case MONO_TYPE_BOOLEAN:
1373         case MONO_TYPE_I2:
1374         case MONO_TYPE_U2:
1375         case MONO_TYPE_CHAR:
1376         case MONO_TYPE_I4:
1377         case MONO_TYPE_U4:
1378                 inst->type = STACK_I4;
1379                 return;
1380         case MONO_TYPE_I:
1381         case MONO_TYPE_U:
1382         case MONO_TYPE_PTR:
1383         case MONO_TYPE_FNPTR:
1384                 inst->type = STACK_PTR;
1385                 return;
1386         case MONO_TYPE_CLASS:
1387         case MONO_TYPE_STRING:
1388         case MONO_TYPE_OBJECT:
1389         case MONO_TYPE_SZARRAY:
1390         case MONO_TYPE_ARRAY:    
1391                 inst->type = STACK_OBJ;
1392                 return;
1393         case MONO_TYPE_I8:
1394         case MONO_TYPE_U8:
1395                 inst->type = STACK_I8;
1396                 return;
1397         case MONO_TYPE_R4:
1398         case MONO_TYPE_R8:
1399                 inst->type = STACK_R8;
1400                 return;
1401         case MONO_TYPE_VALUETYPE:
1402                 if (type->data.klass->enumtype) {
1403                         type = type->data.klass->enum_basetype;
1404                         goto handle_enum;
1405                 } else {
1406                         inst->klass = klass;
1407                         inst->type = STACK_VTYPE;
1408                         return;
1409                 }
1410         case MONO_TYPE_TYPEDBYREF:
1411                 inst->klass = mono_defaults.typed_reference_class;
1412                 inst->type = STACK_VTYPE;
1413                 return;
1414         case MONO_TYPE_GENERICINST:
1415                 type = &type->data.generic_class->container_class->byval_arg;
1416                 goto handle_enum;
1417         case MONO_TYPE_VAR :
1418         case MONO_TYPE_MVAR :
1419                 /* FIXME: all the arguments must be references for now,
1420                  * later look inside cfg and see if the arg num is
1421                  * really a reference
1422                  */
1423                 g_assert (cfg->generic_sharing_context);
1424                 inst->type = STACK_OBJ;
1425                 return;
1426         default:
1427                 g_error ("unknown type 0x%02x in eval stack type", type->type);
1428         }
1429 }
1430
1431 /*
1432  * The following tables are used to quickly validate the IL code in type_from_op ().
1433  */
1434 static const char
1435 bin_num_table [STACK_MAX] [STACK_MAX] = {
1436         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1437         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
1438         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1439         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
1440         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_R8,  STACK_INV, STACK_INV, STACK_INV},
1441         {STACK_INV, STACK_MP,  STACK_INV, STACK_MP,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV},
1442         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1443         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
1444 };
1445
1446 static const char 
1447 neg_table [] = {
1448         STACK_INV, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_INV, STACK_INV, STACK_INV
1449 };
1450
1451 /* reduce the size of this table */
1452 static const char
1453 bin_int_table [STACK_MAX] [STACK_MAX] = {
1454         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1455         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1456         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1457         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1458         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1459         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1460         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, 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 };
1463
1464 static const char
1465 bin_comp_table [STACK_MAX] [STACK_MAX] = {
1466 /*      Inv i  L  p  F  &  O  vt */
1467         {0},
1468         {0, 1, 0, 1, 0, 0, 0, 0}, /* i, int32 */
1469         {0, 0, 1, 0, 0, 0, 0, 0}, /* L, int64 */
1470         {0, 1, 0, 1, 0, 2, 4, 0}, /* p, ptr */
1471         {0, 0, 0, 0, 1, 0, 0, 0}, /* F, R8 */
1472         {0, 0, 0, 2, 0, 1, 0, 0}, /* &, managed pointer */
1473         {0, 0, 0, 4, 0, 0, 3, 0}, /* O, reference */
1474         {0, 0, 0, 0, 0, 0, 0, 0}, /* vt value type */
1475 };
1476
1477 /* reduce the size of this table */
1478 static const char
1479 shift_table [STACK_MAX] [STACK_MAX] = {
1480         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1481         {STACK_INV, STACK_I4,  STACK_INV, STACK_I4,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1482         {STACK_INV, STACK_I8,  STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1483         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1484         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1485         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1486         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, 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 };
1489
1490 /*
1491  * Tables to map from the non-specific opcode to the matching
1492  * type-specific opcode.
1493  */
1494 /* handles from CEE_ADD to CEE_SHR_UN (CEE_REM_UN for floats) */
1495 static const guint16
1496 binops_op_map [STACK_MAX] = {
1497         0, 0, OP_LADD-CEE_ADD, OP_PADD-CEE_ADD, OP_FADD-CEE_ADD, OP_PADD-CEE_ADD
1498 };
1499
1500 /* handles from CEE_NEG to CEE_CONV_U8 */
1501 static const guint16
1502 unops_op_map [STACK_MAX] = {
1503         0, 0, OP_LNEG-CEE_NEG, OP_PNEG-CEE_NEG, OP_FNEG-CEE_NEG, OP_PNEG-CEE_NEG
1504 };
1505
1506 /* handles from CEE_CONV_U2 to CEE_SUB_OVF_UN */
1507 static const guint16
1508 ovfops_op_map [STACK_MAX] = {
1509         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
1510 };
1511
1512 /* handles from CEE_CONV_OVF_I1_UN to CEE_CONV_OVF_U_UN */
1513 static const guint16
1514 ovf2ops_op_map [STACK_MAX] = {
1515         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
1516 };
1517
1518 /* handles from CEE_CONV_OVF_I1 to CEE_CONV_OVF_U8 */
1519 static const guint16
1520 ovf3ops_op_map [STACK_MAX] = {
1521         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
1522 };
1523
1524 /* handles from CEE_CEQ to CEE_CLT_UN */
1525 static const guint16
1526 ceqops_op_map [STACK_MAX] = {
1527         0, 0, OP_LCEQ-OP_CEQ, OP_PCEQ-OP_CEQ, OP_FCEQ-OP_CEQ, OP_LCEQ-OP_CEQ
1528 };
1529
1530 /*
1531  * Sets ins->type (the type on the eval stack) according to the
1532  * type of the opcode and the arguments to it.
1533  * Invalid IL code is marked by setting ins->type to the invalid value STACK_INV.
1534  *
1535  * FIXME: this function sets ins->type unconditionally in some cases, but
1536  * it should set it to invalid for some types (a conv.x on an object)
1537  */
1538 static void
1539 type_from_op (MonoInst *ins) {
1540         switch (ins->opcode) {
1541         /* binops */
1542         case CEE_ADD:
1543         case CEE_SUB:
1544         case CEE_MUL:
1545         case CEE_DIV:
1546         case CEE_REM:
1547                 /* FIXME: check unverifiable args for STACK_MP */
1548                 ins->type = bin_num_table [ins->inst_i0->type] [ins->inst_i1->type];
1549                 ins->opcode += binops_op_map [ins->type];
1550                 return;
1551         case CEE_DIV_UN:
1552         case CEE_REM_UN:
1553         case CEE_AND:
1554         case CEE_OR:
1555         case CEE_XOR:
1556                 ins->type = bin_int_table [ins->inst_i0->type] [ins->inst_i1->type];
1557                 ins->opcode += binops_op_map [ins->type];
1558                 return;
1559         case CEE_SHL:
1560         case CEE_SHR:
1561         case CEE_SHR_UN:
1562                 ins->type = shift_table [ins->inst_i0->type] [ins->inst_i1->type];
1563                 ins->opcode += binops_op_map [ins->type];
1564                 return;
1565         case OP_COMPARE:
1566         case OP_LCOMPARE:
1567                 /* FIXME: handle some specifics with ins->next->type */
1568                 ins->type = bin_comp_table [ins->inst_i0->type] [ins->inst_i1->type] ? STACK_I4: STACK_INV;
1569                 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))))
1570                         ins->opcode = OP_LCOMPARE;
1571                 return;
1572         case OP_CEQ:
1573                 ins->type = bin_comp_table [ins->inst_i0->type] [ins->inst_i1->type] ? STACK_I4: STACK_INV;
1574                 ins->opcode += ceqops_op_map [ins->inst_i0->type];
1575                 return;
1576                 
1577         case OP_CGT:
1578         case OP_CGT_UN:
1579         case OP_CLT:
1580         case OP_CLT_UN:
1581                 ins->type = (bin_comp_table [ins->inst_i0->type] [ins->inst_i1->type] & 1) ? STACK_I4: STACK_INV;
1582                 ins->opcode += ceqops_op_map [ins->inst_i0->type];
1583                 return;
1584         /* unops */
1585         case CEE_NEG:
1586                 ins->type = neg_table [ins->inst_i0->type];
1587                 ins->opcode += unops_op_map [ins->type];
1588                 return;
1589         case CEE_NOT:
1590                 if (ins->inst_i0->type >= STACK_I4 && ins->inst_i0->type <= STACK_PTR)
1591                         ins->type = ins->inst_i0->type;
1592                 else
1593                         ins->type = STACK_INV;
1594                 ins->opcode += unops_op_map [ins->type];
1595                 return;
1596         case CEE_CONV_I1:
1597         case CEE_CONV_I2:
1598         case CEE_CONV_I4:
1599         case CEE_CONV_U4:
1600                 ins->type = STACK_I4;
1601                 ins->opcode += unops_op_map [ins->inst_i0->type];
1602                 return;
1603         case CEE_CONV_R_UN:
1604                 ins->type = STACK_R8;
1605                 switch (ins->inst_i0->type) {
1606                 case STACK_I4:
1607                 case STACK_PTR:
1608                         break;
1609                 case STACK_I8:
1610                         ins->opcode = OP_LCONV_TO_R_UN; 
1611                         break;
1612                 }
1613                 return;
1614         case CEE_CONV_OVF_I1:
1615         case CEE_CONV_OVF_U1:
1616         case CEE_CONV_OVF_I2:
1617         case CEE_CONV_OVF_U2:
1618         case CEE_CONV_OVF_I4:
1619         case CEE_CONV_OVF_U4:
1620                 ins->type = STACK_I4;
1621                 ins->opcode += ovf3ops_op_map [ins->inst_i0->type];
1622                 return;
1623         case CEE_CONV_OVF_I_UN:
1624         case CEE_CONV_OVF_U_UN:
1625                 ins->type = STACK_PTR;
1626                 ins->opcode += ovf2ops_op_map [ins->inst_i0->type];
1627                 return;
1628         case CEE_CONV_OVF_I1_UN:
1629         case CEE_CONV_OVF_I2_UN:
1630         case CEE_CONV_OVF_I4_UN:
1631         case CEE_CONV_OVF_U1_UN:
1632         case CEE_CONV_OVF_U2_UN:
1633         case CEE_CONV_OVF_U4_UN:
1634                 ins->type = STACK_I4;
1635                 ins->opcode += ovf2ops_op_map [ins->inst_i0->type];
1636                 return;
1637         case CEE_CONV_U:
1638                 ins->type = STACK_PTR;
1639                 switch (ins->inst_i0->type) {
1640                 case STACK_I4:
1641                         break;
1642                 case STACK_PTR:
1643                 case STACK_MP:
1644 #if SIZEOF_VOID_P == 8
1645                         ins->opcode = OP_LCONV_TO_U;
1646 #endif
1647                         break;
1648                 case STACK_I8:
1649                         ins->opcode = OP_LCONV_TO_U;
1650                         break;
1651                 case STACK_R8:
1652                         ins->opcode = OP_FCONV_TO_U;
1653                         break;
1654                 }
1655                 return;
1656         case CEE_CONV_I8:
1657         case CEE_CONV_U8:
1658                 ins->type = STACK_I8;
1659                 ins->opcode += unops_op_map [ins->inst_i0->type];
1660                 return;
1661         case CEE_CONV_OVF_I8:
1662         case CEE_CONV_OVF_U8:
1663                 ins->type = STACK_I8;
1664                 ins->opcode += ovf3ops_op_map [ins->inst_i0->type];
1665                 return;
1666         case CEE_CONV_OVF_U8_UN:
1667         case CEE_CONV_OVF_I8_UN:
1668                 ins->type = STACK_I8;
1669                 ins->opcode += ovf2ops_op_map [ins->inst_i0->type];
1670                 return;
1671         case CEE_CONV_R4:
1672         case CEE_CONV_R8:
1673                 ins->type = STACK_R8;
1674                 ins->opcode += unops_op_map [ins->inst_i0->type];
1675                 return;
1676         case OP_CKFINITE:
1677                 ins->type = STACK_R8;           
1678                 return;
1679         case CEE_CONV_U2:
1680         case CEE_CONV_U1:
1681                 ins->type = STACK_I4;
1682                 ins->opcode += ovfops_op_map [ins->inst_i0->type];
1683                 break;
1684         case CEE_CONV_I:
1685         case CEE_CONV_OVF_I:
1686         case CEE_CONV_OVF_U:
1687                 ins->type = STACK_PTR;
1688                 ins->opcode += ovfops_op_map [ins->inst_i0->type];
1689                 return;
1690         case CEE_ADD_OVF:
1691         case CEE_ADD_OVF_UN:
1692         case CEE_MUL_OVF:
1693         case CEE_MUL_OVF_UN:
1694         case CEE_SUB_OVF:
1695         case CEE_SUB_OVF_UN:
1696                 ins->type = bin_num_table [ins->inst_i0->type] [ins->inst_i1->type];
1697                 ins->opcode += ovfops_op_map [ins->inst_i0->type];
1698                 if (ins->type == STACK_R8)
1699                         ins->type = STACK_INV;
1700                 return;
1701         default:
1702                 g_error ("opcode 0x%04x not handled in type from op", ins->opcode);
1703                 break;
1704         }
1705 }
1706
1707 static const char 
1708 ldind_type [] = {
1709         STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_R8, STACK_OBJ
1710 };
1711
1712 /* map ldelem.x to the matching ldind.x opcode */
1713 static const guchar
1714 ldelem_to_ldind [] = {
1715         CEE_LDIND_I1,
1716         CEE_LDIND_U1,
1717         CEE_LDIND_I2,
1718         CEE_LDIND_U2,
1719         CEE_LDIND_I4,
1720         CEE_LDIND_U4,
1721         CEE_LDIND_I8,
1722         CEE_LDIND_I,
1723         CEE_LDIND_R4,
1724         CEE_LDIND_R8,
1725         CEE_LDIND_REF
1726 };
1727
1728 /* map stelem.x to the matching stind.x opcode */
1729 static const guchar
1730 stelem_to_stind [] = {
1731         CEE_STIND_I,
1732         CEE_STIND_I1,
1733         CEE_STIND_I2,
1734         CEE_STIND_I4,
1735         CEE_STIND_I8,
1736         CEE_STIND_R4,
1737         CEE_STIND_R8,
1738         CEE_STIND_REF
1739 };
1740
1741
1742 #ifdef MONO_ARCH_SOFT_FLOAT
1743 static void
1744 handle_store_float (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *ptr, MonoInst *val, const unsigned char *ip)
1745 {
1746         MonoInst *iargs [2];
1747         iargs [0] = val;
1748         iargs [1] = ptr;
1749
1750         mono_emit_jit_icall (cfg, bblock, mono_fstore_r4, iargs, ip);
1751 }
1752
1753 static int
1754 handle_load_float (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *ptr, const unsigned char *ip)
1755 {
1756         MonoInst *iargs [1];
1757         iargs [0] = ptr;
1758
1759         return mono_emit_jit_icall (cfg, bblock, mono_fload_r4, iargs, ip);
1760 }
1761
1762 #define LDLOC_SOFT_FLOAT(cfg,ins,idx,ip) do {\
1763                 if (header->locals [(idx)]->type == MONO_TYPE_R4 && !header->locals [(idx)]->byref) {   \
1764                         int temp;       \
1765                         NEW_LOCLOADA (cfg, (ins), (idx));       \
1766                         temp = handle_load_float (cfg, bblock, (ins), (ip));    \
1767                         NEW_TEMPLOAD (cfg, (ins), temp);        \
1768                 }       \
1769         } while (0)
1770 #define STLOC_SOFT_FLOAT(cfg,ins,idx,ip) do {\
1771                 if (header->locals [(idx)]->type == MONO_TYPE_R4 && !header->locals [(idx)]->byref) {   \
1772                         NEW_LOCLOADA (cfg, (ins), (idx));       \
1773                         handle_store_float (cfg, bblock, (ins), *sp, (ip));     \
1774                         MONO_INST_NEW (cfg, (ins), OP_NOP);     \
1775                 }       \
1776         } while (0)
1777 #define LDARG_SOFT_FLOAT(cfg,ins,idx,ip) do {\
1778                 if (param_types [(idx)]->type == MONO_TYPE_R4 && !param_types [(idx)]->byref) { \
1779                         int temp;       \
1780                         NEW_ARGLOADA (cfg, (ins), (idx));       \
1781                         temp = handle_load_float (cfg, bblock, (ins), (ip));    \
1782                         NEW_TEMPLOAD (cfg, (ins), temp);        \
1783                 }       \
1784         } while (0)
1785 #define STARG_SOFT_FLOAT(cfg,ins,idx,ip) do {\
1786                 if (param_types [(idx)]->type == MONO_TYPE_R4 && !param_types [(idx)]->byref) { \
1787                         NEW_ARGLOADA (cfg, (ins), (idx));       \
1788                         handle_store_float (cfg, bblock, (ins), *sp, (ip));     \
1789                         MONO_INST_NEW (cfg, (ins), OP_NOP);     \
1790                 }       \
1791         } while (0)
1792
1793 #define NEW_TEMPLOAD_SOFT_FLOAT(cfg,bblock,ins,num,ip) do {             \
1794         if ((ins)->opcode == CEE_LDIND_R4) {                                            \
1795             int idx = (num);                                                                            \
1796             int temp;                                                                                   \
1797             NEW_TEMPLOADA (cfg, (ins), (idx));                                                  \
1798                 temp = handle_load_float (cfg, (bblock), (ins), ip);            \
1799                 NEW_TEMPLOAD (cfg, (ins), (temp));                                                      \
1800         }                                                                                                                               \
1801         } while (0)
1802
1803 #define NEW_TEMPSTORE_SOFT_FLOAT(cfg,bblock,ins,num,val,ip) do {                \
1804         if ((ins)->opcode == CEE_STIND_R4) {                                                            \
1805             int idx = (num);                                                                            \
1806                 NEW_TEMPLOADA (cfg, (ins), (idx)); \
1807                 handle_store_float ((cfg), (bblock), (ins), (val), (ip));       \
1808         } \
1809         } while (0)
1810
1811 #else
1812
1813 #define LDLOC_SOFT_FLOAT(cfg,ins,idx,ip)
1814 #define STLOC_SOFT_FLOAT(cfg,ins,idx,ip)
1815 #define LDARG_SOFT_FLOAT(cfg,ins,idx,ip)
1816 #define STARG_SOFT_FLOAT(cfg,ins,idx,ip)
1817 #define NEW_TEMPLOAD_SOFT_FLOAT(cfg,bblock,ins,num,ip)
1818 #define NEW_TEMPSTORE_SOFT_FLOAT(cfg,bblock,ins,num,val,ip)
1819 #endif
1820
1821 #if 0
1822
1823 static const char
1824 param_table [STACK_MAX] [STACK_MAX] = {
1825         {0},
1826 };
1827
1828 static int
1829 check_values_to_signature (MonoInst *args, MonoType *this, MonoMethodSignature *sig)
1830 {
1831         int i;
1832
1833         if (sig->hasthis) {
1834                 switch (args->type) {
1835                 case STACK_I4:
1836                 case STACK_I8:
1837                 case STACK_R8:
1838                 case STACK_VTYPE:
1839                 case STACK_INV:
1840                         return 0;
1841                 }
1842                 args++;
1843         }
1844         for (i = 0; i < sig->param_count; ++i) {
1845                 switch (args [i].type) {
1846                 case STACK_INV:
1847                         return 0;
1848                 case STACK_MP:
1849                         if (!sig->params [i]->byref)
1850                                 return 0;
1851                         continue;
1852                 case STACK_OBJ:
1853                         if (sig->params [i]->byref)
1854                                 return 0;
1855                         switch (sig->params [i]->type) {
1856                         case MONO_TYPE_CLASS:
1857                         case MONO_TYPE_STRING:
1858                         case MONO_TYPE_OBJECT:
1859                         case MONO_TYPE_SZARRAY:
1860                         case MONO_TYPE_ARRAY:
1861                                 break;
1862                         default:
1863                                 return 0;
1864                         }
1865                         continue;
1866                 case STACK_R8:
1867                         if (sig->params [i]->byref)
1868                                 return 0;
1869                         if (sig->params [i]->type != MONO_TYPE_R4 && sig->params [i]->type != MONO_TYPE_R8)
1870                                 return 0;
1871                         continue;
1872                 case STACK_PTR:
1873                 case STACK_I4:
1874                 case STACK_I8:
1875                 case STACK_VTYPE:
1876                         break;
1877                 }
1878                 /*if (!param_table [args [i].type] [sig->params [i]->type])
1879                         return 0;*/
1880         }
1881         return 1;
1882 }
1883 #endif
1884
1885 static guint
1886 mini_type_to_ldind (MonoCompile* cfg, MonoType *type)
1887 {
1888         if (cfg->generic_sharing_context && !type->byref) {
1889                 /* FIXME: all the arguments must be references for now,
1890                  * later look inside cfg and see if the arg num is
1891                  * really a reference
1892                  */
1893                 if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)
1894                         return CEE_LDIND_REF;
1895         }
1896         return mono_type_to_ldind (type);
1897 }
1898
1899 guint
1900 mini_type_to_stind (MonoCompile* cfg, MonoType *type)
1901 {
1902         if (cfg->generic_sharing_context && !type->byref) {
1903                 /* FIXME: all the arguments must be references for now,
1904                  * later look inside cfg and see if the arg num is
1905                  * really a reference
1906                  */
1907                 if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)
1908                         return CEE_STIND_REF;
1909         }
1910         return mono_type_to_stind (type);
1911 }
1912
1913 int
1914 mono_op_imm_to_op (int opcode)
1915 {
1916         switch (opcode) {
1917         case OP_ADD_IMM:
1918 #if SIZEOF_VOID_P == 4
1919                 return OP_IADD;
1920 #else
1921                 return OP_LADD;
1922 #endif
1923         case OP_IADD_IMM:
1924                 return OP_IADD;
1925         case OP_LADD_IMM:
1926                 return OP_LADD;
1927         case OP_ISUB_IMM:
1928                 return OP_ISUB;
1929         case OP_LSUB_IMM:
1930                 return OP_LSUB;
1931         case OP_AND_IMM:
1932 #if SIZEOF_VOID_P == 4
1933                 return OP_IAND;
1934 #else
1935                 return OP_LAND;
1936 #endif
1937         case OP_IAND_IMM:
1938                 return OP_IAND;
1939         case OP_LAND_IMM:
1940                 return OP_LAND;
1941         case OP_IOR_IMM:
1942                 return OP_IOR;
1943         case OP_LOR_IMM:
1944                 return OP_LOR;
1945         case OP_IXOR_IMM:
1946                 return OP_IXOR;
1947         case OP_LXOR_IMM:
1948                 return OP_LXOR;
1949         case OP_ISHL_IMM:
1950                 return OP_ISHL;
1951         case OP_LSHL_IMM:
1952                 return OP_LSHL;
1953         case OP_ISHR_IMM:
1954                 return OP_ISHR;
1955         case OP_LSHR_IMM:
1956                 return OP_LSHR;
1957         case OP_ISHR_UN_IMM:
1958                 return OP_ISHR_UN;
1959         case OP_LSHR_UN_IMM:
1960                 return OP_LSHR_UN;
1961         case OP_IDIV_IMM:
1962                 return OP_IDIV;
1963         case OP_IDIV_UN_IMM:
1964                 return OP_IDIV_UN;
1965         case OP_IREM_UN_IMM:
1966                 return OP_IREM_UN;
1967         case OP_IREM_IMM:
1968                 return OP_IREM;
1969         case OP_DIV_IMM:
1970 #if SIZEOF_VOID_P == 4
1971                 return OP_IDIV;
1972 #else
1973                 return OP_LDIV;
1974 #endif
1975         case OP_REM_IMM:
1976 #if SIZEOF_VOID_P == 4
1977                 return OP_IREM;
1978 #else
1979                 return OP_LREM;
1980 #endif
1981         case OP_ADDCC_IMM:
1982                 return OP_ADDCC;
1983         case OP_ADC_IMM:
1984                 return OP_ADC;
1985         case OP_SUBCC_IMM:
1986                 return OP_SUBCC;
1987         case OP_SBB_IMM:
1988                 return OP_SBB;
1989         case OP_IADC_IMM:
1990                 return OP_IADC;
1991         case OP_ISBB_IMM:
1992                 return OP_ISBB;
1993         case OP_COMPARE_IMM:
1994                 return OP_COMPARE;
1995         case OP_ICOMPARE_IMM:
1996                 return OP_ICOMPARE;
1997         case OP_LOCALLOC_IMM:
1998                 return OP_LOCALLOC;
1999         default:
2000                 printf ("%s\n", mono_inst_name (opcode));
2001                 g_assert_not_reached ();
2002                 return -1;
2003         }
2004 }
2005
2006 /*
2007  * mono_decompose_op_imm:
2008  *
2009  *   Replace the OP_.._IMM INS with its non IMM variant.
2010  */
2011 void
2012 mono_decompose_op_imm (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *ins)
2013 {
2014         MonoInst *temp;
2015
2016         MONO_INST_NEW (cfg, temp, OP_ICONST);
2017         temp->inst_c0 = ins->inst_imm;
2018         temp->dreg = mono_regstate_next_int (cfg->rs);
2019         mono_bblock_insert_before_ins (bb, ins, temp);
2020         ins->opcode = mono_op_imm_to_op (ins->opcode);
2021         if (ins->opcode == OP_LOCALLOC)
2022                 ins->sreg1 = temp->dreg;
2023         else
2024                 ins->sreg2 = temp->dreg;
2025
2026         bb->max_vreg = MAX (bb->max_vreg, cfg->rs->next_vreg);
2027 }
2028
2029 /*
2030  * When we need a pointer to the current domain many times in a method, we
2031  * call mono_domain_get() once and we store the result in a local variable.
2032  * This function returns the variable that represents the MonoDomain*.
2033  */
2034 inline static MonoInst *
2035 mono_get_domainvar (MonoCompile *cfg)
2036 {
2037         if (!cfg->domainvar)
2038                 cfg->domainvar = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2039         return cfg->domainvar;
2040 }
2041
2042 /*
2043  * The got_var contains the address of the Global Offset Table when AOT 
2044  * compiling.
2045  */
2046 inline static MonoInst *
2047 mono_get_got_var (MonoCompile *cfg)
2048 {
2049 #ifdef MONO_ARCH_NEED_GOT_VAR
2050         if (!cfg->compile_aot)
2051                 return NULL;
2052         if (!cfg->got_var) {
2053                 cfg->got_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2054         }
2055         return cfg->got_var;
2056 #else
2057         return NULL;
2058 #endif
2059 }
2060
2061 static MonoInst *
2062 mono_get_vtable_var (MonoCompile *cfg)
2063 {
2064         g_assert (cfg->generic_sharing_context);
2065
2066         if (!cfg->rgctx_var) {
2067                 cfg->rgctx_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2068                 /* force the var to be stack allocated */
2069                 cfg->rgctx_var->flags |= MONO_INST_INDIRECT;
2070         }
2071
2072         return cfg->rgctx_var;
2073 }
2074
2075 static void
2076 set_vreg_to_inst (MonoCompile *cfg, int vreg, MonoInst *inst)
2077 {
2078         if (vreg >= cfg->vreg_to_inst_len) {
2079                 MonoInst **tmp = cfg->vreg_to_inst;
2080                 int size = cfg->vreg_to_inst_len;
2081
2082                 while (vreg >= cfg->vreg_to_inst_len)
2083                         cfg->vreg_to_inst_len = cfg->vreg_to_inst_len ? cfg->vreg_to_inst_len * 2 : 32;
2084                 cfg->vreg_to_inst = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * cfg->vreg_to_inst_len);
2085                 if (size)
2086                         memcpy (cfg->vreg_to_inst, tmp, size * sizeof (MonoInst*));
2087         }
2088         cfg->vreg_to_inst [vreg] = inst;
2089 }
2090
2091 #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)))
2092 #define mono_type_is_float(type) (!(type)->byref && (((type)->type == MONO_TYPE_R8) || ((type)->type == MONO_TYPE_R4)))
2093
2094 MonoInst*
2095 mono_compile_create_var_for_vreg (MonoCompile *cfg, MonoType *type, int opcode, int vreg)
2096 {
2097         MonoInst *inst;
2098         int num = cfg->num_varinfo;
2099         gboolean regpair;
2100
2101         if ((num + 1) >= cfg->varinfo_count) {
2102                 int orig_count = cfg->varinfo_count;
2103                 cfg->varinfo_count = cfg->varinfo_count ? (cfg->varinfo_count * 2) : 64;
2104                 cfg->varinfo = (MonoInst **)g_realloc (cfg->varinfo, sizeof (MonoInst*) * cfg->varinfo_count);
2105                 cfg->vars = (MonoMethodVar *)g_realloc (cfg->vars, sizeof (MonoMethodVar) * cfg->varinfo_count);
2106                 memset (&cfg->vars [orig_count], 0, (cfg->varinfo_count - orig_count) * sizeof (MonoMethodVar));
2107         }
2108
2109         mono_jit_stats.allocate_var++;
2110
2111         MONO_INST_NEW (cfg, inst, opcode);
2112         inst->inst_c0 = num;
2113         inst->inst_vtype = type;
2114         inst->klass = mono_class_from_mono_type (type);
2115         type_to_eval_stack_type (cfg, type, inst);
2116         /* if set to 1 the variable is native */
2117         inst->backend.is_pinvoke = 0;
2118         inst->dreg = vreg;
2119
2120         cfg->varinfo [num] = inst;
2121
2122         MONO_INIT_VARINFO (&cfg->vars [num], num);
2123
2124         if (vreg != -1)
2125                 set_vreg_to_inst (cfg, vreg, inst);
2126
2127 #if SIZEOF_VOID_P == 4
2128 #ifdef MONO_ARCH_SOFT_FLOAT
2129         regpair = mono_type_is_long (type) || mono_type_is_float (type);
2130 #else
2131         regpair = mono_type_is_long (type);
2132 #endif
2133 #else
2134         regpair = FALSE;
2135 #endif
2136
2137         if (regpair) {
2138                 MonoInst *tree;
2139
2140                 /* 
2141                  * These two cannot be allocated using create_var_for_vreg since that would
2142                  * put it into the cfg->varinfo array, confusing many parts of the JIT.
2143                  */
2144
2145                 /* 
2146                  * Set flags to VOLATILE so SSA skips it.
2147                  */
2148
2149                 if (cfg->verbose_level >= 4) {
2150                         printf ("  Create LVAR R%d (R%d, R%d)\n", inst->dreg, inst->dreg + 1, inst->dreg + 2);
2151                 }
2152
2153                 /* Allocate a dummy MonoInst for the first vreg */
2154                 MONO_INST_NEW (cfg, tree, OP_LOCAL);
2155                 tree->dreg = inst->dreg + 1;
2156                 if (cfg->opt & MONO_OPT_SSA)
2157                         tree->flags = MONO_INST_VOLATILE;
2158                 tree->inst_c0 = num;
2159                 tree->type = STACK_I4;
2160                 tree->inst_vtype = &mono_defaults.int32_class->byval_arg;
2161                 tree->klass = mono_class_from_mono_type (tree->inst_vtype);
2162
2163                 set_vreg_to_inst (cfg, inst->dreg + 1, tree);
2164
2165                 /* Allocate a dummy MonoInst for the second vreg */
2166                 MONO_INST_NEW (cfg, tree, OP_LOCAL);
2167                 tree->dreg = inst->dreg + 2;
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 + 2, tree);
2176         }
2177
2178         cfg->num_varinfo++;
2179         if (cfg->verbose_level > 2)
2180                 g_print ("created temp %d (R%d) of type %s\n", num, vreg, mono_type_get_name (type));
2181         return inst;
2182 }
2183
2184 MonoInst*
2185 mono_compile_create_var (MonoCompile *cfg, MonoType *type, int opcode)
2186 {
2187         int dreg;
2188
2189         if (mono_type_is_long (type))
2190                 dreg = mono_alloc_dreg (cfg, STACK_I8);
2191 #ifdef MONO_ARCH_SOFT_FLOAT
2192         else if (mono_type_is_float (type))
2193                 dreg = mono_alloc_dreg (cfg, STACK_R8);
2194 #endif
2195         else
2196                 /* All the others are unified */
2197                 dreg = mono_alloc_preg (cfg);
2198
2199         return mono_compile_create_var_for_vreg (cfg, type, opcode, dreg);
2200 }
2201
2202 /*
2203  * Transform a MonoInst into a load from the variable of index var_index.
2204  */
2205 void
2206 mono_compile_make_var_load (MonoCompile *cfg, MonoInst *dest, gssize var_index) {
2207         memset (dest, 0, sizeof (MonoInst));
2208         dest->ssa_op = MONO_SSA_LOAD;
2209         dest->inst_i0 = cfg->varinfo [var_index];
2210         dest->opcode = mini_type_to_ldind (cfg, dest->inst_i0->inst_vtype);
2211         type_to_eval_stack_type (cfg, dest->inst_i0->inst_vtype, dest);
2212         dest->klass = dest->inst_i0->klass;
2213 }
2214
2215 /*
2216  * Create a MonoInst that is a load from the variable of index var_index.
2217  */
2218 MonoInst*
2219 mono_compile_create_var_load (MonoCompile *cfg, gssize var_index) {
2220         MonoInst *dest;
2221         NEW_TEMPLOAD (cfg,dest,var_index);
2222         return dest;
2223 }
2224
2225 /*
2226  * Create a MonoInst that is a store of the given value into the variable of index var_index.
2227  */
2228 MonoInst*
2229 mono_compile_create_var_store (MonoCompile *cfg, gssize var_index, MonoInst *value) {
2230         MonoInst *dest;
2231         NEW_TEMPSTORE (cfg, dest, var_index, value);
2232         return dest;
2233 }
2234
2235 static MonoType*
2236 type_from_stack_type (MonoInst *ins) {
2237         switch (ins->type) {
2238         case STACK_I4: return &mono_defaults.int32_class->byval_arg;
2239         case STACK_I8: return &mono_defaults.int64_class->byval_arg;
2240         case STACK_PTR: return &mono_defaults.int_class->byval_arg;
2241         case STACK_R8: return &mono_defaults.double_class->byval_arg;
2242         case STACK_MP:
2243                 /* 
2244                  * this if used to be commented without any specific reason, but
2245                  * it breaks #80235 when commented
2246                  */
2247                 if (ins->klass)
2248                         return &ins->klass->this_arg;
2249                 else
2250                         return &mono_defaults.object_class->this_arg;
2251         case STACK_OBJ:
2252                 /* ins->klass may not be set for ldnull.
2253                  * Also, if we have a boxed valuetype, we want an object lass,
2254                  * not the valuetype class
2255                  */
2256                 if (ins->klass && !ins->klass->valuetype)
2257                         return &ins->klass->byval_arg;
2258                 return &mono_defaults.object_class->byval_arg;
2259         case STACK_VTYPE: return &ins->klass->byval_arg;
2260         default:
2261                 g_error ("stack type %d to montype not handled\n", ins->type);
2262         }
2263         return NULL;
2264 }
2265
2266 MonoType*
2267 mono_type_from_stack_type (MonoInst *ins) {
2268         return type_from_stack_type (ins);
2269 }
2270
2271 static MonoClass*
2272 array_access_to_klass (int opcode, MonoInst *array_obj)
2273 {
2274         switch (opcode) {
2275         case CEE_LDELEM_U1:
2276                 return mono_defaults.byte_class;
2277         case CEE_LDELEM_U2:
2278                 return mono_defaults.uint16_class;
2279         case CEE_LDELEM_I:
2280         case CEE_STELEM_I:
2281                 return mono_defaults.int_class;
2282         case CEE_LDELEM_I1:
2283         case CEE_STELEM_I1:
2284                 return mono_defaults.sbyte_class;
2285         case CEE_LDELEM_I2:
2286         case CEE_STELEM_I2:
2287                 return mono_defaults.int16_class;
2288         case CEE_LDELEM_I4:
2289         case CEE_STELEM_I4:
2290                 return mono_defaults.int32_class;
2291         case CEE_LDELEM_U4:
2292                 return mono_defaults.uint32_class;
2293         case CEE_LDELEM_I8:
2294         case CEE_STELEM_I8:
2295                 return mono_defaults.int64_class;
2296         case CEE_LDELEM_R4:
2297         case CEE_STELEM_R4:
2298                 return mono_defaults.single_class;
2299         case CEE_LDELEM_R8:
2300         case CEE_STELEM_R8:
2301                 return mono_defaults.double_class;
2302         case CEE_LDELEM_REF:
2303         case CEE_STELEM_REF: {
2304                 MonoClass *klass = array_obj->klass;
2305                 /* FIXME: add assert */
2306                 if (klass && klass->rank)
2307                         return klass->element_class;
2308                 return mono_defaults.object_class;
2309         }
2310         default:
2311                 g_assert_not_reached ();
2312         }
2313         return NULL;
2314 }
2315
2316 /*
2317  * mono_add_ins_to_end:
2318  *
2319  *   Same as MONO_ADD_INS, but add INST before any branches at the end of BB.
2320  */
2321 void
2322 mono_add_ins_to_end (MonoBasicBlock *bb, MonoInst *inst)
2323 {
2324         int opcode;
2325
2326         if (!bb->code) {
2327                 MONO_ADD_INS (bb, inst);
2328                 return;
2329         }
2330
2331         switch (bb->last_ins->opcode) {
2332         case OP_BR:
2333         case OP_BR_REG:
2334         case CEE_BEQ:
2335         case CEE_BGE:
2336         case CEE_BGT:
2337         case CEE_BLE:
2338         case CEE_BLT:
2339         case CEE_BNE_UN:
2340         case CEE_BGE_UN:
2341         case CEE_BGT_UN:
2342         case CEE_BLE_UN:
2343         case CEE_BLT_UN:
2344         case OP_SWITCH:
2345                 mono_bblock_insert_before_ins (bb, bb->last_ins, inst);
2346                 break;
2347         default:
2348                 if (MONO_IS_COND_BRANCH_OP (bb->last_ins)) {
2349                         /* Need to insert the ins before the compare */
2350                         if (bb->code == bb->last_ins) {
2351                                 mono_bblock_insert_before_ins (bb, bb->last_ins, inst);
2352                                 return;
2353                         }
2354
2355                         if (bb->code->next == bb->last_ins) {
2356                                 /* Only two instructions */
2357                                 opcode = bb->code->opcode;
2358
2359                                 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)) {
2360                                         /* NEW IR */
2361                                         mono_bblock_insert_before_ins (bb, bb->code, inst);
2362                                 } else {
2363                                         mono_bblock_insert_before_ins (bb, bb->last_ins, inst);
2364                                 }
2365                         } else {
2366                                 opcode = bb->last_ins->prev->opcode;
2367
2368                                 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)) {
2369                                         /* NEW IR */
2370                                         mono_bblock_insert_before_ins (bb, bb->last_ins->prev, inst);
2371                                 } else {
2372                                         mono_bblock_insert_before_ins (bb, bb->last_ins, inst);
2373                                 }                                       
2374                         }
2375                 }
2376                 else
2377                         MONO_ADD_INS (bb, inst);
2378                 break;
2379         }
2380 }
2381
2382 /**
2383  * mono_replace_ins:
2384  *
2385  *   Replace INS with its decomposition which is stored in a series of bblocks starting
2386  * at FIRST_BB and ending at LAST_BB. On enter, PREV points to the predecessor of INS. 
2387  * On return, it will be set to the last ins of the decomposition.
2388  */
2389 void
2390 mono_replace_ins (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *ins, MonoInst **prev, MonoBasicBlock *first_bb, MonoBasicBlock *last_bb)
2391 {
2392         MonoInst *next = ins->next;
2393
2394         if (next && next->opcode == OP_NOP) {
2395                 /* Avoid NOPs following branches */
2396                 ins->next = next->next;
2397                 next = next->next;
2398         }
2399
2400         if (first_bb == last_bb) {
2401                 /* 
2402                  * Only one replacement bb, merge the code into
2403                  * the current bb.
2404                  */
2405
2406                 /* Delete links between the first_bb and its successors */
2407                 while (first_bb->out_count)
2408                         mono_unlink_bblock (cfg, first_bb, first_bb->out_bb [0]);
2409
2410                 /* Head */
2411                 if (*prev) {
2412                         (*prev)->next = first_bb->code;
2413                         first_bb->code->prev = (*prev);
2414                 } else {
2415                         bb->code = first_bb->code;
2416                 }
2417
2418                 /* Tail */
2419                 last_bb->last_ins->next = next;
2420                 if (next)
2421                         next->prev = last_bb->last_ins;
2422                 else
2423                         bb->last_ins = last_bb->last_ins;
2424                 *prev = last_bb->last_ins;
2425         } else {
2426                 int i, count;
2427                 MonoBasicBlock **tmp_bblocks, *tmp;
2428                 MonoInst *last;
2429
2430                 /* Multiple BBs */
2431
2432                 /* Set region */
2433                 for (tmp = first_bb; tmp; tmp = tmp->next_bb)
2434                         tmp->region = bb->region;
2435
2436                 /* Split the original bb */
2437                 if (ins->next)
2438                         ins->next->prev = NULL;
2439                 ins->next = NULL;
2440                 bb->last_ins = ins;
2441
2442                 /* Merge the second part of the original bb into the last bb */
2443                 if (last_bb->last_ins) {
2444                         last_bb->last_ins->next = next;
2445                         if (next)
2446                                 next->prev = last_bb->last_ins;
2447                 } else {
2448                         last_bb->code = next;
2449                 }
2450
2451                 if (next) {
2452                         for (last = next; last->next != NULL; last = last->next)
2453                                 ;
2454                         last_bb->last_ins = last;
2455                 }
2456
2457                 for (i = 0; i < bb->out_count; ++i)
2458                         link_bblock (cfg, last_bb, bb->out_bb [i]);
2459
2460                 /* Merge the first (dummy) bb to the original bb */
2461                 if (*prev) {
2462                         (*prev)->next = first_bb->code;
2463                         first_bb->code->prev = (*prev);
2464                 } else {
2465                         bb->code = first_bb->code;
2466                 }
2467                 bb->last_ins = first_bb->last_ins;
2468
2469                 /* Delete the links between the original bb and its successors */
2470                 tmp_bblocks = bb->out_bb;
2471                 count = bb->out_count;
2472                 for (i = 0; i < count; ++i)
2473                         mono_unlink_bblock (cfg, bb, tmp_bblocks [i]);
2474
2475                 /* Add links between the original bb and the first_bb's successors */
2476                 for (i = 0; i < first_bb->out_count; ++i) {
2477                         MonoBasicBlock *out_bb = first_bb->out_bb [i];
2478
2479                         link_bblock (cfg, bb, out_bb);
2480                 }
2481                 /* Delete links between the first_bb and its successors */
2482                 for (i = 0; i < bb->out_count; ++i) {
2483                         MonoBasicBlock *out_bb = bb->out_bb [i];
2484
2485                         mono_unlink_bblock (cfg, first_bb, out_bb);
2486                 }
2487                 last_bb->next_bb = bb->next_bb;
2488                 bb->next_bb = first_bb->next_bb;
2489
2490                 *prev = NULL;
2491         }
2492 }
2493
2494 void
2495 mono_add_varcopy_to_end (MonoCompile *cfg, MonoBasicBlock *bb, int src, int dest)
2496 {
2497         MonoInst *inst, *load;
2498
2499         NEW_TEMPLOAD (cfg, load, src);
2500
2501         NEW_TEMPSTORE (cfg, inst, dest, load);
2502         /* FIXME: handle CEE_STIND_R4 */
2503         if (inst->opcode == CEE_STOBJ) {
2504                 NEW_TEMPLOADA (cfg, inst, dest);
2505                 handle_stobj (cfg, bb, inst, load, NULL, inst->klass, TRUE, FALSE, FALSE);
2506         } else {
2507                 inst->cil_code = NULL;
2508                 mono_add_ins_to_end (bb, inst);
2509         }
2510 }
2511
2512 /*
2513  * This function is called to handle items that are left on the evaluation stack
2514  * at basic block boundaries. What happens is that we save the values to local variables
2515  * and we reload them later when first entering the target basic block (with the
2516  * handle_loaded_temps () function).
2517  * It is also used to handle items on the stack in store opcodes, since it is
2518  * possible that the variable to be stored into is already on the stack, in
2519  * which case its old value should be used.
2520  * A single joint point will use the same variables (stored in the array bb->out_stack or
2521  * bb->in_stack, if the basic block is before or after the joint point).
2522  * If the stack merge fails at a join point, cfg->unverifiable is set.
2523  */
2524 static void
2525 handle_stack_args (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst **sp, int count)
2526 {
2527         int i, bindex;
2528         MonoBasicBlock *outb;
2529         MonoInst *inst, **locals;
2530         gboolean found;
2531
2532         if (!count)
2533                 return;
2534         if (cfg->verbose_level > 3)
2535                 g_print ("%d item(s) on exit from B%d\n", count, bb->block_num);
2536
2537         if (!bb->out_scount) {
2538                 bb->out_scount = count;
2539                 //g_print ("bblock %d has out:", bb->block_num);
2540                 found = FALSE;
2541                 for (i = 0; i < bb->out_count; ++i) {
2542                         outb = bb->out_bb [i];
2543                         /* exception handlers are linked, but they should not be considered for stack args */
2544                         if (outb->flags & BB_EXCEPTION_HANDLER)
2545                                 continue;
2546                         //g_print (" %d", outb->block_num);
2547                         if (outb->in_stack) {
2548                                 found = TRUE;
2549                                 bb->out_stack = outb->in_stack;
2550                                 break;
2551                         }
2552                 }
2553                 //g_print ("\n");
2554                 if (!found) {
2555                         bb->out_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * count);
2556                         for (i = 0; i < count; ++i) {
2557                                 /* 
2558                                  * try to reuse temps already allocated for this purpouse, if they occupy the same
2559                                  * stack slot and if they are of the same type.
2560                                  * This won't cause conflicts since if 'local' is used to 
2561                                  * store one of the values in the in_stack of a bblock, then
2562                                  * the same variable will be used for the same outgoing stack 
2563                                  * slot as well. 
2564                                  * This doesn't work when inlining methods, since the bblocks
2565                                  * in the inlined methods do not inherit their in_stack from
2566                                  * the bblock they are inlined to. See bug #58863 for an
2567                                  * example.
2568                                  * This hack is disabled since it also prevents proper tracking of types.
2569                                  */
2570 #if 1
2571                                 bb->out_stack [i] = mono_compile_create_var (cfg, type_from_stack_type (sp [i]), OP_LOCAL);
2572 #else
2573                                 if (cfg->inlined_method)
2574                                         bb->out_stack [i] = mono_compile_create_var (cfg, type_from_stack_type (sp [i]), OP_LOCAL);
2575                                 else
2576                                         bb->out_stack [i] = mono_compile_get_interface_var (cfg, i, sp [i]);
2577 #endif
2578                         }
2579                 }
2580         }
2581
2582         for (i = 0; i < bb->out_count; ++i) {
2583                 outb = bb->out_bb [i];
2584                 /* exception handlers are linked, but they should not be considered for stack args */
2585                 if (outb->flags & BB_EXCEPTION_HANDLER)
2586                         continue;
2587                 if (outb->in_scount) {
2588                         if (outb->in_scount != bb->out_scount) {
2589                                 cfg->unverifiable = TRUE;
2590                                 return;
2591                         }
2592                         continue; /* check they are the same locals */
2593                 }
2594                 outb->in_scount = count;
2595                 outb->in_stack = bb->out_stack;
2596         }
2597
2598         locals = bb->out_stack;
2599         for (i = 0; i < count; ++i) {
2600                 /* add store ops at the end of the bb, before the branch */
2601                 NEW_TEMPSTORE (cfg, inst, locals [i]->inst_c0, sp [i]);
2602                 if (inst->opcode == CEE_STOBJ) {
2603                         NEW_TEMPLOADA (cfg, inst, locals [i]->inst_c0);
2604                         handle_stobj (cfg, bb, inst, sp [i], sp [i]->cil_code, inst->klass, TRUE, FALSE, FALSE);
2605                 } else {
2606                         inst->cil_code = sp [i]->cil_code;
2607                         mono_add_ins_to_end (bb, inst);
2608                 }
2609                 if (cfg->verbose_level > 3)
2610                         g_print ("storing %d to temp %d\n", i, (int)locals [i]->inst_c0);
2611         }
2612
2613         /*
2614          * It is possible that the out bblocks already have in_stack assigned, and
2615          * the in_stacks differ. In this case, we will store to all the different 
2616          * in_stacks.
2617          */
2618
2619         found = TRUE;
2620         bindex = 0;
2621         while (found) {
2622                 /* Find a bblock which has a different in_stack */
2623                 found = FALSE;
2624                 while (bindex < bb->out_count) {
2625                         outb = bb->out_bb [bindex];
2626                         /* exception handlers are linked, but they should not be considered for stack args */
2627                         if (outb->flags & BB_EXCEPTION_HANDLER) {
2628                                 bindex++;
2629                                 continue;
2630                         }
2631                         if (outb->in_stack != locals) {
2632                                 /* 
2633                                  * Instead of storing sp [i] to locals [i], we need to store
2634                                  * locals [i] to <new locals>[i], since the sp [i] tree can't
2635                                  * be shared between trees.
2636                                  */
2637                                 for (i = 0; i < count; ++i)
2638                                         mono_add_varcopy_to_end (cfg, bb, locals [i]->inst_c0, outb->in_stack [i]->inst_c0);
2639                                 locals = outb->in_stack;
2640                                 found = TRUE;
2641                                 break;
2642                         }
2643                         bindex ++;
2644                 }
2645         }
2646 }
2647
2648 static int
2649 ret_type_to_call_opcode (MonoType *type, int calli, int virt, MonoGenericSharingContext *gsctx)
2650 {
2651         if (type->byref)
2652                 return calli? OP_CALL_REG: virt? OP_CALLVIRT: OP_CALL;
2653
2654 handle_enum:
2655         type = mini_get_basic_type_from_generic (gsctx, type);
2656         switch (type->type) {
2657         case MONO_TYPE_VOID:
2658                 return calli? OP_VOIDCALL_REG: virt? OP_VOIDCALLVIRT: OP_VOIDCALL;
2659         case MONO_TYPE_I1:
2660         case MONO_TYPE_U1:
2661         case MONO_TYPE_BOOLEAN:
2662         case MONO_TYPE_I2:
2663         case MONO_TYPE_U2:
2664         case MONO_TYPE_CHAR:
2665         case MONO_TYPE_I4:
2666         case MONO_TYPE_U4:
2667                 return calli? OP_CALL_REG: virt? OP_CALLVIRT: OP_CALL;
2668         case MONO_TYPE_I:
2669         case MONO_TYPE_U:
2670         case MONO_TYPE_PTR:
2671         case MONO_TYPE_FNPTR:
2672                 return calli? OP_CALL_REG: virt? OP_CALLVIRT: OP_CALL;
2673         case MONO_TYPE_CLASS:
2674         case MONO_TYPE_STRING:
2675         case MONO_TYPE_OBJECT:
2676         case MONO_TYPE_SZARRAY:
2677         case MONO_TYPE_ARRAY:    
2678                 return calli? OP_CALL_REG: virt? OP_CALLVIRT: OP_CALL;
2679         case MONO_TYPE_I8:
2680         case MONO_TYPE_U8:
2681                 return calli? OP_LCALL_REG: virt? OP_LCALLVIRT: OP_LCALL;
2682         case MONO_TYPE_R4:
2683         case MONO_TYPE_R8:
2684                 return calli? OP_FCALL_REG: virt? OP_FCALLVIRT: OP_FCALL;
2685         case MONO_TYPE_VALUETYPE:
2686                 if (type->data.klass->enumtype) {
2687                         type = type->data.klass->enum_basetype;
2688                         goto handle_enum;
2689                 } else
2690                         return calli? OP_VCALL_REG: virt? OP_VCALLVIRT: OP_VCALL;
2691         case MONO_TYPE_TYPEDBYREF:
2692                 return calli? OP_VCALL_REG: virt? OP_VCALLVIRT: OP_VCALL;
2693         case MONO_TYPE_GENERICINST:
2694                 type = &type->data.generic_class->container_class->byval_arg;
2695                 goto handle_enum;
2696         default:
2697                 g_error ("unknown type 0x%02x in ret_type_to_call_opcode", type->type);
2698         }
2699         return -1;
2700 }
2701
2702 void
2703 mono_create_jump_table (MonoCompile *cfg, MonoInst *label, MonoBasicBlock **bbs, int num_blocks)
2704 {
2705         MonoJumpInfo *ji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo));
2706         MonoJumpInfoBBTable *table;
2707
2708         table = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfoBBTable));
2709         table->table = bbs;
2710         table->table_size = num_blocks;
2711         
2712         ji->ip.label = label;
2713         ji->type = MONO_PATCH_INFO_SWITCH;
2714         ji->data.table = table;
2715         ji->next = cfg->patch_info;
2716         cfg->patch_info = ji;
2717 }
2718
2719 static void
2720 mono_save_token_info (MonoCompile *cfg, MonoImage *image, guint32 token, gpointer key)
2721 {
2722         if (cfg->compile_aot) {
2723                 MonoJumpInfoToken *jump_info_token = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoToken));
2724                 jump_info_token->image = image;
2725                 jump_info_token->token = token;
2726                 g_hash_table_insert (cfg->token_info_hash, key, jump_info_token);
2727         }
2728 }
2729
2730 /*
2731  * When we add a tree of instructions, we need to ensure the instructions currently
2732  * on the stack are executed before (like, if we load a value from a local).
2733  * We ensure this by saving the currently loaded values to temps and rewriting the
2734  * instructions to load the values.
2735  * This is not done for opcodes that terminate a basic block (because it's handled already
2736  * by handle_stack_args ()) and for opcodes that can't change values, like POP.
2737  */
2738 static void
2739 handle_loaded_temps (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst **stack, MonoInst **sp)
2740 {
2741         MonoInst *load, *store, *temp, *ins;
2742
2743         while (stack < sp) {
2744                 ins = *stack;
2745                 /* handle also other constants */
2746                 if ((ins->opcode != OP_ICONST) &&
2747                     /* temps never get written to again, so we can safely avoid duplicating them */
2748                     !(ins->ssa_op == MONO_SSA_LOAD && ins->inst_i0->opcode == OP_LOCAL && ins->inst_i0->flags & MONO_INST_IS_TEMP)) {
2749                         temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
2750                         temp->flags |= MONO_INST_IS_TEMP;
2751                         NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
2752                         store->cil_code = ins->cil_code;
2753                         if (store->opcode == CEE_STOBJ) {
2754                                 NEW_TEMPLOADA (cfg, store, temp->inst_c0);
2755                                 handle_stobj (cfg, bblock, store, ins, ins->cil_code, temp->klass, FALSE, FALSE, FALSE);
2756                         } else
2757                                 MONO_ADD_INS (bblock, store);
2758                         NEW_TEMPLOAD (cfg, load, temp->inst_c0);
2759                         load->cil_code = ins->cil_code;
2760                         *stack = load;
2761                 }
2762                 stack++;
2763         }
2764 }
2765
2766 /*
2767  * target_type_is_incompatible:
2768  * @cfg: MonoCompile context
2769  *
2770  * Check that the item @arg on the evaluation stack can be stored
2771  * in the target type (can be a local, or field, etc).
2772  * The cfg arg can be used to check if we need verification or just
2773  * validity checks.
2774  *
2775  * Returns: non-0 value if arg can't be stored on a target.
2776  */
2777 static int
2778 target_type_is_incompatible (MonoCompile *cfg, MonoType *target, MonoInst *arg)
2779 {
2780         MonoType *simple_type;
2781         MonoClass *klass;
2782
2783         if (target->byref) {
2784                 /* FIXME: check that the pointed to types match */
2785                 if (arg->type == STACK_MP)
2786                         return arg->klass != mono_class_from_mono_type (target);
2787                 if (arg->type == STACK_PTR)
2788                         return 0;
2789                 return 1;
2790         }
2791         simple_type = mono_type_get_underlying_type (target);
2792         switch (simple_type->type) {
2793         case MONO_TYPE_VOID:
2794                 return 1;
2795         case MONO_TYPE_I1:
2796         case MONO_TYPE_U1:
2797         case MONO_TYPE_BOOLEAN:
2798         case MONO_TYPE_I2:
2799         case MONO_TYPE_U2:
2800         case MONO_TYPE_CHAR:
2801         case MONO_TYPE_I4:
2802         case MONO_TYPE_U4:
2803                 if (arg->type != STACK_I4 && arg->type != STACK_PTR)
2804                         return 1;
2805                 return 0;
2806         case MONO_TYPE_PTR:
2807                 /* STACK_MP is needed when setting pinned locals */
2808                 if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
2809                         return 1;
2810                 return 0;
2811         case MONO_TYPE_I:
2812         case MONO_TYPE_U:
2813         case MONO_TYPE_FNPTR:
2814                 if (arg->type != STACK_I4 && arg->type != STACK_PTR)
2815                         return 1;
2816                 return 0;
2817         case MONO_TYPE_OBJECT:
2818                 if (arg->type != STACK_OBJ)
2819                         return 1;
2820                 return 0;
2821         case MONO_TYPE_STRING:
2822                 if (arg->type != STACK_OBJ)
2823                         return 1;
2824                 /* ldnull has arg->klass unset */
2825                 /*if (arg->klass && arg->klass != mono_defaults.string_class) {
2826                         G_BREAKPOINT ();
2827                         return 1;
2828                 }*/
2829                 return 0;
2830         case MONO_TYPE_CLASS:
2831         case MONO_TYPE_SZARRAY:
2832         case MONO_TYPE_ARRAY:    
2833                 if (arg->type != STACK_OBJ)
2834                         return 1;
2835                 /* FIXME: check type compatibility */
2836                 return 0;
2837         case MONO_TYPE_I8:
2838         case MONO_TYPE_U8:
2839                 if (arg->type != STACK_I8)
2840                         return 1;
2841                 return 0;
2842         case MONO_TYPE_R4:
2843         case MONO_TYPE_R8:
2844                 if (arg->type != STACK_R8)
2845                         return 1;
2846                 return 0;
2847         case MONO_TYPE_VALUETYPE:
2848                 if (arg->type != STACK_VTYPE)
2849                         return 1;
2850                 klass = mono_class_from_mono_type (simple_type);
2851                 if (klass != arg->klass)
2852                         return 1;
2853                 return 0;
2854         case MONO_TYPE_TYPEDBYREF:
2855                 if (arg->type != STACK_VTYPE)
2856                         return 1;
2857                 klass = mono_class_from_mono_type (simple_type);
2858                 if (klass != arg->klass)
2859                         return 1;
2860                 return 0;
2861         case MONO_TYPE_GENERICINST:
2862                 if (mono_type_generic_inst_is_valuetype (simple_type)) {
2863                         klass = mono_class_from_mono_type (simple_type);
2864                         if (klass->enumtype)
2865                                 return target_type_is_incompatible (cfg, klass->enum_basetype, arg);
2866                         if (arg->type != STACK_VTYPE)
2867                                 return 1;
2868                         if (klass != arg->klass)
2869                                 return 1;
2870                         return 0;
2871                 } else {
2872                         if (arg->type != STACK_OBJ)
2873                                 return 1;
2874                         /* FIXME: check type compatibility */
2875                         return 0;
2876                 }
2877         case MONO_TYPE_VAR:
2878         case MONO_TYPE_MVAR:
2879                 /* FIXME: all the arguments must be references for now,
2880                  * later look inside cfg and see if the arg num is
2881                  * really a reference
2882                  */
2883                 g_assert (cfg->generic_sharing_context);
2884                 if (arg->type != STACK_OBJ)
2885                         return 1;
2886                 return 0;
2887         default:
2888                 g_error ("unknown type 0x%02x in target_type_is_incompatible", simple_type->type);
2889         }
2890         return 1;
2891 }
2892
2893 /*
2894  * Prepare arguments for passing to a function call.
2895  * Return a non-zero value if the arguments can't be passed to the given
2896  * signature.
2897  * The type checks are not yet complete and some conversions may need
2898  * casts on 32 or 64 bit architectures.
2899  *
2900  * FIXME: implement this using target_type_is_incompatible ()
2901  */
2902 static int
2903 check_call_signature (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args)
2904 {
2905         MonoType *simple_type;
2906         int i;
2907
2908         if (sig->hasthis) {
2909                 if (args [0]->type != STACK_OBJ && args [0]->type != STACK_MP && args [0]->type != STACK_PTR)
2910                         return 1;
2911                 args++;
2912         }
2913         for (i = 0; i < sig->param_count; ++i) {
2914                 if (sig->params [i]->byref) {
2915                         if (args [i]->type != STACK_MP && args [i]->type != STACK_PTR)
2916                                 return 1;
2917                         continue;
2918                 }
2919                 simple_type = sig->params [i];
2920                 simple_type = mini_get_basic_type_from_generic (cfg->generic_sharing_context, simple_type);
2921 handle_enum:
2922                 switch (simple_type->type) {
2923                 case MONO_TYPE_VOID:
2924                         return 1;
2925                         continue;
2926                 case MONO_TYPE_I1:
2927                 case MONO_TYPE_U1:
2928                 case MONO_TYPE_BOOLEAN:
2929                 case MONO_TYPE_I2:
2930                 case MONO_TYPE_U2:
2931                 case MONO_TYPE_CHAR:
2932                 case MONO_TYPE_I4:
2933                 case MONO_TYPE_U4:
2934                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR)
2935                                 return 1;
2936                         continue;
2937                 case MONO_TYPE_I:
2938                 case MONO_TYPE_U:
2939                 case MONO_TYPE_PTR:
2940                 case MONO_TYPE_FNPTR:
2941                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR && args [i]->type != STACK_MP && args [i]->type != STACK_OBJ)
2942                                 return 1;
2943                         continue;
2944                 case MONO_TYPE_CLASS:
2945                 case MONO_TYPE_STRING:
2946                 case MONO_TYPE_OBJECT:
2947                 case MONO_TYPE_SZARRAY:
2948                 case MONO_TYPE_ARRAY:    
2949                         if (args [i]->type != STACK_OBJ)
2950                                 return 1;
2951                         continue;
2952                 case MONO_TYPE_I8:
2953                 case MONO_TYPE_U8:
2954                         if (args [i]->type != STACK_I8)
2955                                 return 1;
2956                         continue;
2957                 case MONO_TYPE_R4:
2958                 case MONO_TYPE_R8:
2959                         if (args [i]->type != STACK_R8)
2960                                 return 1;
2961                         continue;
2962                 case MONO_TYPE_VALUETYPE:
2963                         if (simple_type->data.klass->enumtype) {
2964                                 simple_type = simple_type->data.klass->enum_basetype;
2965                                 goto handle_enum;
2966                         }
2967                         if (args [i]->type != STACK_VTYPE)
2968                                 return 1;
2969                         continue;
2970                 case MONO_TYPE_TYPEDBYREF:
2971                         if (args [i]->type != STACK_VTYPE)
2972                                 return 1;
2973                         continue;
2974                 case MONO_TYPE_GENERICINST:
2975                         simple_type = &simple_type->data.generic_class->container_class->byval_arg;
2976                         goto handle_enum;
2977
2978                 default:
2979                         g_error ("unknown type 0x%02x in check_call_signature",
2980                                  simple_type->type);
2981                 }
2982         }
2983         return 0;
2984 }
2985
2986 inline static int
2987 mono_spill_call (MonoCompile *cfg, MonoBasicBlock *bblock, MonoCallInst *call, MonoMethodSignature *sig, gboolean ret_object, 
2988                  const guint8 *ip, gboolean to_end)
2989 {
2990         MonoInst *temp, *store, *ins = (MonoInst*)call;
2991         MonoType *ret = sig->ret;
2992
2993         if (!MONO_TYPE_IS_VOID (ret) || ret_object) {
2994                 if (ret_object) {
2995                         call->inst.type = STACK_OBJ;
2996                         call->inst.opcode = OP_CALL;
2997                         temp = mono_compile_create_var (cfg, &mono_defaults.string_class->byval_arg, OP_LOCAL);
2998                 } else {
2999                         type_to_eval_stack_type (cfg, ret, ins);
3000                         temp = mono_compile_create_var (cfg, ret, OP_LOCAL);
3001                 }
3002                 
3003                 temp->flags |= MONO_INST_IS_TEMP;
3004
3005                 if (MONO_TYPE_ISSTRUCT (ret)) {
3006                         MonoInst *loada, *dummy_store;
3007
3008                         /* 
3009                          * Emit a dummy store to the local holding the result so the
3010                          * liveness info remains correct.
3011                          */
3012                         NEW_DUMMY_STORE (cfg, dummy_store, temp->inst_c0);
3013                         if (to_end)
3014                                 mono_add_ins_to_end (bblock, dummy_store);
3015                         else
3016                                 MONO_ADD_INS (bblock, dummy_store);
3017
3018                         /* we use this to allocate native sized structs */
3019                         temp->backend.is_pinvoke = sig->pinvoke;
3020
3021                         NEW_TEMPLOADA (cfg, loada, temp->inst_c0);
3022                         if (call->inst.opcode == OP_VCALL || call->inst.opcode == OP_VCALL_RGCTX)
3023                                 ins->inst_left = loada;
3024                         else
3025                                 ins->inst_right = loada; /* a virtual or indirect call */
3026
3027                         if (to_end)
3028                                 mono_add_ins_to_end (bblock, ins);
3029                         else
3030                                 MONO_ADD_INS (bblock, ins);
3031                 } else {
3032                         NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
3033                         store->cil_code = ip;
3034                         
3035 #ifdef MONO_ARCH_SOFT_FLOAT
3036                         if (store->opcode == CEE_STIND_R4) {
3037                                 /*FIXME implement proper support for to_end*/
3038                                 g_assert (!to_end);
3039                                 NEW_TEMPLOADA (cfg, store, temp->inst_c0);
3040                                 handle_store_float (cfg, bblock, store, ins, ip);
3041                         } else
3042 #endif
3043                         if (to_end)
3044                                 mono_add_ins_to_end (bblock, store);
3045                         else
3046                                 MONO_ADD_INS (bblock, store);
3047                 }
3048                 return temp->inst_c0;
3049         } else {
3050                 if (to_end)
3051                         mono_add_ins_to_end (bblock, ins);
3052                 else
3053                         MONO_ADD_INS (bblock, ins);
3054                 return -1;
3055         }
3056 }
3057
3058 inline static MonoCallInst *
3059 mono_emit_call_args (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethodSignature *sig, 
3060                      MonoInst **args, int calli, int virtual, const guint8 *ip, gboolean to_end)
3061 {
3062         MonoCallInst *call;
3063         MonoInst *arg;
3064
3065         MONO_INST_NEW_CALL (cfg, call, ret_type_to_call_opcode (sig->ret, calli, virtual, cfg->generic_sharing_context));
3066
3067 #ifdef MONO_ARCH_SOFT_FLOAT
3068         /* we need to convert the r4 value to an int value */
3069         {
3070                 int i;
3071                 for (i = 0; i < sig->param_count; ++i) {
3072                         if (!sig->params [i]->byref && sig->params [i]->type == MONO_TYPE_R4) {
3073                                 MonoInst *iargs [1];
3074                                 int temp;
3075                                 iargs [0] = args [i + sig->hasthis];
3076
3077                                 temp = mono_emit_jit_icall (cfg, bblock, mono_fload_r4_arg, iargs, ip);
3078                                 NEW_TEMPLOAD (cfg, arg, temp);
3079                                 args [i + sig->hasthis] = arg;
3080                         }
3081                 }
3082         }
3083 #endif
3084
3085         call->inst.cil_code = ip;
3086         call->args = args;
3087         call->signature = sig;
3088         call = mono_arch_call_opcode (cfg, bblock, call, virtual);
3089         type_to_eval_stack_type (cfg, sig->ret, &call->inst);
3090
3091         for (arg = call->out_args; arg;) {
3092                 MonoInst *narg = arg->next;
3093                 arg->next = NULL;
3094                 if (!arg->cil_code)
3095                         arg->cil_code = ip;
3096                 if (to_end)
3097                         mono_add_ins_to_end (bblock, arg);
3098                 else
3099                         MONO_ADD_INS (bblock, arg);
3100                 arg = narg;
3101         }
3102         return call;
3103 }
3104
3105 inline static MonoCallInst*
3106 mono_emit_calli (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethodSignature *sig, 
3107                  MonoInst **args, MonoInst *addr, const guint8 *ip)
3108 {
3109         MonoCallInst *call = mono_emit_call_args (cfg, bblock, sig, args, TRUE, FALSE, ip, FALSE);
3110
3111         call->inst.inst_i0 = addr;
3112
3113         return call;
3114 }
3115
3116 inline static MonoCallInst*
3117 mono_emit_rgctx_calli (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethodSignature *sig,
3118         MonoInst **args, MonoInst *addr, MonoInst *rgctx_arg, const guint8 *ip)
3119 {
3120         MonoCallInst *call = mono_emit_calli (cfg, bblock, sig, args, addr, ip);
3121
3122         if (rgctx_arg) {
3123                 switch (call->inst.opcode) {
3124                 case OP_CALL_REG: call->inst.opcode = OP_CALL_REG_RGCTX; break;
3125                 case OP_VOIDCALL_REG: call->inst.opcode = OP_VOIDCALL_REG_RGCTX; break;
3126                 case OP_FCALL_REG: call->inst.opcode = OP_FCALL_REG_RGCTX; break;
3127                 case OP_LCALL_REG: call->inst.opcode = OP_LCALL_REG_RGCTX; break;
3128                 case OP_VCALL_REG: {
3129                         MonoInst *group;
3130
3131                         NEW_GROUP (cfg, group, call->inst.inst_left, NULL);
3132                         call->inst.inst_left = group;
3133                         call->inst.opcode = OP_VCALL_REG_RGCTX;
3134                         break;
3135                 }
3136                 default: g_assert_not_reached ();
3137                 }
3138
3139                 if (call->inst.opcode != OP_VCALL_REG_RGCTX) {
3140                         g_assert (!call->inst.inst_right);
3141                         call->inst.inst_right = rgctx_arg;
3142                 } else {
3143                         g_assert (!call->inst.inst_left->inst_right);
3144                         call->inst.inst_left->inst_right = rgctx_arg;
3145                 }
3146         }
3147
3148         return call;
3149 }
3150
3151 inline static int
3152 mono_emit_calli_spilled (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethodSignature *sig, 
3153                                                  MonoInst **args, MonoInst *addr, const guint8 *ip)
3154 {
3155         MonoCallInst *call = mono_emit_calli (cfg, bblock, sig, args, addr, ip);
3156
3157         return mono_spill_call (cfg, bblock, call, sig, FALSE, ip, FALSE);
3158 }
3159
3160 static int
3161 mono_emit_rgctx_calli_spilled (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethodSignature *sig,
3162         MonoInst **args, MonoInst *addr, MonoInst *rgctx_arg, const guint8 *ip)
3163 {
3164         MonoCallInst *call = mono_emit_rgctx_calli (cfg, bblock, sig, args, addr, rgctx_arg, ip);
3165
3166         return mono_spill_call (cfg, bblock, call, sig, FALSE, ip, FALSE);
3167 }
3168
3169 static MonoCallInst*
3170 mono_emit_method_call_full (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *method, MonoMethodSignature *sig,
3171                        MonoInst **args, const guint8 *ip, MonoInst *this, gboolean to_end)
3172 {
3173         gboolean virtual = this != NULL;
3174         MonoCallInst *call;
3175
3176         call = mono_emit_call_args (cfg, bblock, sig, args, FALSE, virtual, ip, to_end);
3177
3178         if (this && sig->hasthis && 
3179             (method->klass->marshalbyref || method->klass == mono_defaults.object_class) && 
3180             !(method->flags & METHOD_ATTRIBUTE_VIRTUAL) && !MONO_CHECK_THIS (this)) {
3181                 call->method = mono_marshal_get_remoting_invoke_with_check (method);
3182         } else {
3183                 call->method = method;
3184         }
3185         call->inst.flags |= MONO_INST_HAS_METHOD;
3186         call->inst.inst_left = this;
3187
3188         if (call->method->klass->flags & TYPE_ATTRIBUTE_INTERFACE)
3189                 /* Needed by the code generated in inssel.brg */
3190                 mono_get_got_var (cfg);
3191
3192         return call;
3193 }
3194
3195 static MonoCallInst*
3196 mono_emit_method_call (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *method, MonoMethodSignature *sig,
3197                        MonoInst **args, const guint8 *ip, MonoInst *this)
3198 {
3199         return mono_emit_method_call_full (cfg, bblock, method, sig, args, ip, this, FALSE);
3200 }
3201
3202 inline static int
3203 mono_emit_method_call_spilled (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *method,  
3204                        MonoMethodSignature *signature, MonoInst **args, const guint8 *ip, MonoInst *this)
3205 {
3206         MonoCallInst *call = mono_emit_method_call (cfg, bblock, method, signature, args, ip, this);
3207
3208         return mono_spill_call (cfg, bblock, call, signature, method->string_ctor, ip, FALSE);
3209 }
3210
3211 inline static int
3212 mono_emit_method_call_spilled_full (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *method,  
3213                        MonoMethodSignature *signature, MonoInst **args, const guint8 *ip, MonoInst *this,
3214                        gboolean ret_object, gboolean to_end)
3215 {
3216         MonoCallInst *call = mono_emit_method_call_full (cfg, bblock, method, signature, args, ip, this, to_end);
3217
3218         return mono_spill_call (cfg, bblock, call, signature, ret_object, ip, to_end);
3219 }
3220
3221 inline static int
3222 mono_emit_native_call (MonoCompile *cfg, MonoBasicBlock *bblock, gconstpointer func, MonoMethodSignature *sig,
3223                        MonoInst **args, const guint8 *ip, gboolean ret_object, gboolean to_end)
3224 {
3225         MonoCallInst *call;
3226
3227         g_assert (sig);
3228
3229         call = mono_emit_call_args (cfg, bblock, sig, args, FALSE, FALSE, ip, to_end);
3230         call->fptr = func;
3231
3232         return mono_spill_call (cfg, bblock, call, sig, ret_object, ip, to_end);
3233 }
3234
3235 inline static int
3236 mono_emit_jit_icall (MonoCompile *cfg, MonoBasicBlock *bblock, gconstpointer func, MonoInst **args, const guint8 *ip)
3237 {
3238         MonoJitICallInfo *info = mono_find_jit_icall_by_addr (func);
3239         
3240         if (!info) {
3241                 g_warning ("unregistered JIT ICall");
3242                 g_assert_not_reached ();
3243         }
3244
3245         return mono_emit_native_call (cfg, bblock, mono_icall_get_wrapper (info), info->sig, args, ip, FALSE, FALSE);
3246 }
3247
3248 static MonoCallInst*
3249 mono_emit_rgctx_method_call (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *method, MonoMethodSignature *sig,
3250                 MonoInst **args, MonoInst *rgctx_arg, MonoInst *imt_arg, const guint8 *ip, MonoInst *this)
3251 {
3252         MonoCallInst *call = mono_emit_method_call_full (cfg, bblock, method, sig, args, ip, this, FALSE);
3253
3254         g_assert (!(rgctx_arg && imt_arg));
3255
3256         if (rgctx_arg) {
3257                 switch (call->inst.opcode) {
3258                 case OP_CALL: call->inst.opcode = OP_CALL_RGCTX; break;
3259                 case OP_VOIDCALL: call->inst.opcode = OP_VOIDCALL_RGCTX; break;
3260                 case OP_FCALL: call->inst.opcode = OP_FCALL_RGCTX; break;
3261                 case OP_LCALL: call->inst.opcode = OP_LCALL_RGCTX; break;
3262                 case OP_VCALL: call->inst.opcode = OP_VCALL_RGCTX; break;
3263                 default: g_assert_not_reached ();
3264                 }
3265
3266                 if (call->inst.opcode != OP_VCALL_RGCTX) {
3267                         g_assert (!call->inst.inst_left);
3268                         call->inst.inst_left = rgctx_arg;
3269                 } else {
3270                         g_assert (!call->inst.inst_right);
3271                         call->inst.inst_right = rgctx_arg;
3272                 }
3273         } else if (imt_arg) {
3274                 switch (call->inst.opcode) {
3275                 case OP_CALLVIRT: call->inst.opcode = OP_CALLVIRT_IMT; break;
3276                 case OP_VOIDCALLVIRT: call->inst.opcode = OP_VOIDCALLVIRT_IMT; break;
3277                 case OP_FCALLVIRT: call->inst.opcode = OP_FCALLVIRT_IMT; break;
3278                 case OP_LCALLVIRT: call->inst.opcode = OP_LCALLVIRT_IMT; break;
3279                 case OP_VCALLVIRT: {
3280                         MonoInst *group;
3281
3282                         NEW_GROUP (cfg, group, call->inst.inst_left, NULL);
3283                         call->inst.inst_left = group;
3284                         call->inst.opcode = OP_VCALLVIRT_IMT;
3285                         break;
3286                 }
3287                 default: g_assert_not_reached ();
3288                 }
3289
3290                 if (call->inst.opcode != OP_VCALLVIRT_IMT) {
3291                         g_assert (!call->inst.inst_right);
3292                         call->inst.inst_right = imt_arg;
3293                 } else {
3294                         g_assert (!call->inst.inst_left->inst_right);
3295                         call->inst.inst_left->inst_right = imt_arg;
3296                 }
3297         }
3298
3299         return call;
3300 }
3301
3302 inline static int
3303 mono_emit_rgctx_method_call_spilled (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *method,  
3304                 MonoMethodSignature *signature, MonoInst **args, MonoInst *rgctx_arg, MonoInst *imt_arg,
3305                 const guint8 *ip, MonoInst *this)
3306 {
3307         MonoCallInst *call = mono_emit_rgctx_method_call (cfg, bblock, method, signature, args, rgctx_arg, imt_arg, ip, this);
3308
3309         return mono_spill_call (cfg, bblock, call, signature, method->string_ctor, ip, FALSE);
3310 }
3311
3312 static void
3313 mono_emulate_opcode (MonoCompile *cfg, MonoInst *tree, MonoInst **iargs, MonoJitICallInfo *info)
3314 {
3315         MonoInst *ins, *temp = NULL, *store, *load, *begin;
3316         MonoInst *last_arg = NULL;
3317         int nargs;
3318         MonoCallInst *call;
3319
3320         //g_print ("emulating: ");
3321         //mono_print_tree_nl (tree);
3322         MONO_INST_NEW_CALL (cfg, call, ret_type_to_call_opcode (info->sig->ret, FALSE, FALSE, cfg->generic_sharing_context));
3323         ins = (MonoInst*)call;
3324         
3325         call->inst.cil_code = tree->cil_code;
3326         call->args = iargs;
3327         call->signature = info->sig;
3328
3329         call = mono_arch_call_opcode (cfg, cfg->cbb, call, FALSE);
3330
3331         if (!MONO_TYPE_IS_VOID (info->sig->ret)) {
3332                 temp = mono_compile_create_var (cfg, info->sig->ret, OP_LOCAL);
3333                 temp->flags |= MONO_INST_IS_TEMP;
3334                 NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
3335                 /* FIXME: handle CEE_STIND_R4 */
3336                 store->cil_code = tree->cil_code;
3337         } else {
3338                 store = ins;
3339         }
3340
3341         nargs = info->sig->param_count + info->sig->hasthis;
3342
3343         for (last_arg = call->out_args; last_arg && last_arg->next; last_arg = last_arg->next) ;
3344
3345         if (nargs)
3346                 last_arg->next = store;
3347
3348         if (nargs)
3349                 begin = call->out_args;
3350         else
3351                 begin = store;
3352
3353         if (cfg->prev_ins) {
3354                 /* 
3355                  * This assumes that that in a tree, emulate_opcode is called for a
3356                  * node before it is called for its children. dec_foreach needs to
3357                  * take this into account.
3358                  */
3359                 store->next = cfg->prev_ins->next;
3360                 cfg->prev_ins->next = begin;
3361         } else {
3362                 store->next = cfg->cbb->code;
3363                 cfg->cbb->code = begin;
3364         }
3365
3366         call->fptr = mono_icall_get_wrapper (info);
3367
3368         if (!MONO_TYPE_IS_VOID (info->sig->ret)) {
3369                 NEW_TEMPLOAD (cfg, load, temp->inst_c0);
3370                 *tree = *load;
3371         }
3372 }
3373
3374 /*
3375  * This entry point could be used later for arbitrary method
3376  * redirection.
3377  */
3378 inline static int
3379 mini_redirect_call (int *temp, MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *method,  
3380                        MonoMethodSignature *signature, MonoInst **args, const guint8 *ip, MonoInst *this)
3381 {
3382
3383         if (method->klass == mono_defaults.string_class) {
3384                 /* managed string allocation support */
3385                 if (strcmp (method->name, "InternalAllocateStr") == 0) {
3386                         MonoInst *iargs [2];
3387                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
3388                         MonoMethod *managed_alloc = mono_gc_get_managed_allocator (vtable, FALSE);
3389                         if (!managed_alloc)
3390                                 return FALSE;
3391                         NEW_VTABLECONST (cfg, iargs [0], vtable);
3392                         iargs [1] = args [0];
3393                         *temp = mono_emit_method_call_spilled (cfg, bblock, managed_alloc, mono_method_signature (managed_alloc), iargs, ip, this);
3394                         return TRUE;
3395                 }
3396         }
3397         return FALSE;
3398 }
3399
3400 static MonoMethodSignature *
3401 mono_get_array_new_va_signature (int arity)
3402 {
3403         static GHashTable *sighash = NULL;
3404         MonoMethodSignature *res;
3405         int i;
3406
3407         mono_jit_lock ();
3408         if (!sighash) {
3409                 sighash = g_hash_table_new (NULL, NULL);
3410         }
3411         else if ((res = g_hash_table_lookup (sighash, GINT_TO_POINTER (arity)))) {
3412                 mono_jit_unlock ();
3413                 return res;
3414         }
3415
3416         res = mono_metadata_signature_alloc (mono_defaults.corlib, arity + 1);
3417
3418         res->pinvoke = 1;
3419 #ifdef MONO_ARCH_VARARG_ICALLS
3420         /* Only set this only some archs since not all backends can handle varargs+pinvoke */
3421         res->call_convention = MONO_CALL_VARARG;
3422 #endif
3423
3424 #ifdef PLATFORM_WIN32
3425         res->call_convention = MONO_CALL_C;
3426 #endif
3427
3428         res->params [0] = &mono_defaults.int_class->byval_arg;  
3429         for (i = 0; i < arity; i++)
3430                 res->params [i + 1] = &mono_defaults.int_class->byval_arg;
3431
3432         res->ret = &mono_defaults.object_class->byval_arg;
3433
3434         g_hash_table_insert (sighash, GINT_TO_POINTER (arity), res);
3435         mono_jit_unlock ();
3436
3437         return res;
3438 }
3439
3440 MonoJitICallInfo *
3441 mono_get_array_new_va_icall (int rank)
3442 {
3443         MonoMethodSignature *esig;
3444         char icall_name [256];
3445         char *name;
3446         MonoJitICallInfo *info;
3447
3448         /* Need to register the icall so it gets an icall wrapper */
3449         sprintf (icall_name, "ves_array_new_va_%d", rank);
3450
3451         mono_jit_lock ();
3452         info = mono_find_jit_icall_by_name (icall_name);
3453         if (info == NULL) {
3454                 esig = mono_get_array_new_va_signature (rank);
3455                 name = g_strdup (icall_name);
3456                 info = mono_register_jit_icall (mono_array_new_va, name, esig, FALSE);
3457
3458                 g_hash_table_insert (jit_icall_name_hash, name, name);
3459         }
3460         mono_jit_unlock ();
3461
3462         return info;
3463 }
3464
3465 static MonoMethod*
3466 get_memcpy_method (void)
3467 {
3468         static MonoMethod *memcpy_method = NULL;
3469         if (!memcpy_method) {
3470                 memcpy_method = mono_class_get_method_from_name (mono_defaults.string_class, "memcpy", 3);
3471                 if (!memcpy_method)
3472                         g_error ("Old corlib found. Install a new one");
3473         }
3474         return memcpy_method;
3475 }
3476
3477 static void
3478 handle_stobj (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *dest, MonoInst *src, const unsigned char *ip, MonoClass *klass, gboolean to_end, gboolean native, gboolean write_barrier) {
3479         MonoInst *iargs [3];
3480         int n;
3481         guint32 align = 0;
3482         MonoMethod *memcpy_method;
3483
3484         g_assert (klass);
3485         /*
3486          * This check breaks with spilled vars... need to handle it during verification anyway.
3487          * g_assert (klass && klass == src->klass && klass == dest->klass);
3488          */
3489
3490         if (native)
3491                 n = mono_class_native_size (klass, &align);
3492         else
3493                 n = mono_class_value_size (klass, &align);
3494
3495 #if HAVE_WRITE_BARRIERS
3496         /* if native is true there should be no references in the struct */
3497         if (write_barrier && klass->has_references && !native) {
3498                 iargs [0] = dest;
3499                 iargs [1] = src;
3500                 NEW_PCONST (cfg, iargs [2], klass);
3501
3502                 mono_emit_jit_icall (cfg, bblock, mono_value_copy, iargs, ip);
3503                 return;
3504         }
3505 #endif
3506
3507         /* FIXME: add write barrier handling */
3508         if ((cfg->opt & MONO_OPT_INTRINS) && !to_end && n <= sizeof (gpointer) * 5) {
3509                 MonoInst *inst;
3510                 if (dest->opcode == OP_LDADDR) {
3511                         /* Keep liveness info correct */
3512                         NEW_DUMMY_STORE (cfg, inst, dest->inst_i0->inst_c0);
3513                         MONO_ADD_INS (bblock, inst);
3514                 }
3515                 NEW_MEMCPY (cfg, inst, dest, src, n, align);
3516                 MONO_ADD_INS (bblock, inst);
3517                 return;
3518         }
3519         iargs [0] = dest;
3520         iargs [1] = src;
3521         NEW_ICONST (cfg, iargs [2], n);
3522
3523         memcpy_method = get_memcpy_method ();
3524         mono_emit_method_call_spilled_full (cfg, bblock, memcpy_method, memcpy_method->signature, iargs, ip, NULL, FALSE, to_end);
3525 }
3526
3527 static MonoMethod*
3528 get_memset_method (void)
3529 {
3530         static MonoMethod *memset_method = NULL;
3531         if (!memset_method) {
3532                 memset_method = mono_class_get_method_from_name (mono_defaults.string_class, "memset", 3);
3533                 if (!memset_method)
3534                         g_error ("Old corlib found. Install a new one");
3535         }
3536         return memset_method;
3537 }
3538
3539 static void
3540 handle_initobj (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *dest, const guchar *ip, MonoClass *klass, MonoInst **stack_start, MonoInst **sp)
3541 {
3542         MonoInst *iargs [3];
3543         MonoInst *ins, *zero_int32;
3544         int n;
3545         guint32 align;
3546         MonoMethod *memset_method;
3547
3548         NEW_ICONST (cfg, zero_int32, 0);
3549
3550         mono_class_init (klass);
3551         n = mono_class_value_size (klass, &align);
3552         MONO_INST_NEW (cfg, ins, 0);
3553         ins->cil_code = ip;
3554         ins->inst_left = dest;
3555         ins->inst_right = zero_int32;
3556         if (n == 1) {
3557                 ins->opcode = CEE_STIND_I1;
3558                 MONO_ADD_INS (bblock, ins);
3559         } else if ((n == 2) && (align >= 2)) {
3560                 ins->opcode = CEE_STIND_I2;
3561                 MONO_ADD_INS (bblock, ins);
3562         } else if ((n == 2) && (align >= 4)) {
3563                 ins->opcode = CEE_STIND_I4;
3564                 MONO_ADD_INS (bblock, ins);
3565         } else if (n <= sizeof (gpointer) * 5) {
3566                 NEW_MEMSET (cfg, ins, dest, 0, n, align);
3567                 MONO_ADD_INS (bblock, ins);
3568         } else {
3569                 memset_method = get_memset_method ();
3570                 handle_loaded_temps (cfg, bblock, stack_start, sp);
3571                 iargs [0] = dest;
3572                 NEW_ICONST (cfg, iargs [1], 0);
3573                 NEW_ICONST (cfg, iargs [2], n);
3574                 mono_emit_method_call_spilled (cfg, bblock, memset_method, memset_method->signature, iargs, ip, NULL);
3575         }
3576 }
3577
3578 static int
3579 handle_alloc (MonoCompile *cfg, MonoBasicBlock *bblock, MonoClass *klass, gboolean for_box, const guchar *ip)
3580 {
3581         MonoInst *iargs [2];
3582         void *alloc_ftn;
3583
3584         if (cfg->opt & MONO_OPT_SHARED) {
3585                 NEW_DOMAINCONST (cfg, iargs [0]);
3586                 NEW_CLASSCONST (cfg, iargs [1], klass);
3587
3588                 alloc_ftn = mono_object_new;
3589         } else if (cfg->compile_aot && bblock->out_of_line && klass->type_token && klass->image == mono_defaults.corlib) {
3590                 /* This happens often in argument checking code, eg. throw new FooException... */
3591                 /* Avoid relocations by calling a helper function specialized to mscorlib */
3592                 NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (klass->type_token));
3593                 return mono_emit_jit_icall (cfg, bblock, mono_helper_newobj_mscorlib, iargs, ip);
3594         } else {
3595                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
3596                 MonoMethod *managed_alloc = mono_gc_get_managed_allocator (vtable, for_box);
3597                 gboolean pass_lw;
3598
3599                 if (managed_alloc) {
3600                         NEW_VTABLECONST (cfg, iargs [0], vtable);
3601                         return mono_emit_method_call_spilled (cfg, bblock, managed_alloc, mono_method_signature (managed_alloc), iargs, ip, NULL);
3602                 }
3603                 alloc_ftn = mono_class_get_allocation_ftn (vtable, for_box, &pass_lw);
3604                 if (pass_lw) {
3605                         guint32 lw = vtable->klass->instance_size;
3606                         lw = ((lw + (sizeof (gpointer) - 1)) & ~(sizeof (gpointer) - 1)) / sizeof (gpointer);
3607                         NEW_ICONST (cfg, iargs [0], lw);
3608                         NEW_VTABLECONST (cfg, iargs [1], vtable);
3609                 }
3610                 else
3611                         NEW_VTABLECONST (cfg, iargs [0], vtable);
3612         }
3613
3614         return mono_emit_jit_icall (cfg, bblock, alloc_ftn, iargs, ip);
3615 }
3616
3617 static int
3618 handle_alloc_from_inst (MonoCompile *cfg, MonoBasicBlock *bblock, MonoClass *klass, MonoInst *data_inst,
3619                 gboolean for_box, const guchar *ip)
3620 {
3621         MonoInst *iargs [2];
3622         MonoMethod *managed_alloc = NULL;
3623         void *alloc_ftn;
3624         /*
3625           FIXME: we cannot get managed_alloc here because we can't get
3626           the class's vtable (because it's not a closed class)
3627
3628         MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
3629         MonoMethod *managed_alloc = mono_gc_get_managed_allocator (vtable, for_box);
3630         */
3631
3632         if (cfg->opt & MONO_OPT_SHARED) {
3633                 NEW_DOMAINCONST (cfg, iargs [0]);
3634                 iargs [1] = data_inst;
3635                 alloc_ftn = mono_object_new;
3636         } else {
3637                 g_assert (!cfg->compile_aot);
3638
3639                 if (managed_alloc) {
3640                         iargs [0] = data_inst;
3641                         return mono_emit_method_call_spilled (cfg, bblock, managed_alloc,
3642                                 mono_method_signature (managed_alloc), iargs, ip, NULL);
3643                 }
3644
3645                 iargs [0] = data_inst;
3646                 alloc_ftn = mono_object_new_specific;
3647         }
3648
3649         return mono_emit_jit_icall (cfg, bblock, alloc_ftn, iargs, ip);
3650 }
3651
3652 static MonoInst*
3653 handle_box_copy (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *val, const guchar *ip, MonoClass *klass, int temp)
3654 {
3655         MonoInst *dest, *vtoffset, *add, *vstore;
3656
3657         NEW_TEMPLOAD (cfg, dest, temp);
3658         NEW_ICONST (cfg, vtoffset, sizeof (MonoObject));
3659         MONO_INST_NEW (cfg, add, OP_PADD);
3660         add->inst_left = dest;
3661         add->inst_right = vtoffset;
3662         add->cil_code = ip;
3663         add->klass = klass;
3664         MONO_INST_NEW (cfg, vstore, CEE_STIND_I);
3665         vstore->opcode = mini_type_to_stind (cfg, &klass->byval_arg);
3666         vstore->cil_code = ip;
3667         vstore->inst_left = add;
3668         vstore->inst_right = val;
3669
3670 #ifdef MONO_ARCH_SOFT_FLOAT
3671         if (vstore->opcode == CEE_STIND_R4) {
3672                 handle_store_float (cfg, bblock, add, val, ip);
3673         } else
3674 #endif
3675         if (vstore->opcode == CEE_STOBJ) {
3676                 handle_stobj (cfg, bblock, add, val, ip, klass, FALSE, FALSE, TRUE);
3677         } else
3678                 MONO_ADD_INS (bblock, vstore);
3679
3680         NEW_TEMPLOAD (cfg, dest, temp);
3681         return dest;
3682 }
3683
3684 static MonoInst *
3685 handle_box (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *val, const guchar *ip, MonoClass *klass)
3686 {
3687         MonoInst *dest;
3688         int temp;
3689
3690         if (mono_class_is_nullable (klass)) {
3691                 MonoMethod* method = mono_class_get_method_from_name (klass, "Box", 1);
3692                 temp = mono_emit_method_call_spilled (cfg, bblock, method, mono_method_signature (method), &val, ip, NULL);
3693                 NEW_TEMPLOAD (cfg, dest, temp);
3694                 return dest;
3695         }
3696
3697         temp = handle_alloc (cfg, bblock, klass, TRUE, ip);
3698
3699         return handle_box_copy (cfg, bblock, val, ip, klass, temp);
3700 }
3701
3702 static MonoInst *
3703 handle_box_from_inst (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *val, const guchar *ip,
3704                 MonoClass *klass, MonoInst *data_inst)
3705 {
3706         int temp;
3707
3708         g_assert (!mono_class_is_nullable (klass));
3709
3710         temp = handle_alloc_from_inst (cfg, bblock, klass, data_inst, TRUE, ip);
3711
3712         return handle_box_copy (cfg, bblock, val, ip, klass, temp);
3713 }
3714
3715 static MonoInst*
3716 handle_delegate_ctor (MonoCompile *cfg, MonoBasicBlock *bblock, MonoClass *klass, MonoInst *target, MonoMethod *method, unsigned char *ip)
3717 {
3718         gpointer *trampoline;
3719         MonoInst *obj, *ins, *store, *offset_ins, *method_ins, *tramp_ins;
3720         int temp;
3721
3722         temp = handle_alloc (cfg, bblock, klass, FALSE, ip);
3723
3724         /* Inline the contents of mono_delegate_ctor */
3725
3726         /* Set target field */
3727         /* Optimize away setting of NULL target */
3728         if (!(target->opcode == OP_PCONST && target->inst_p0 == 0)) {
3729                 NEW_TEMPLOAD (cfg, obj, temp);
3730                 NEW_ICONST (cfg, offset_ins, G_STRUCT_OFFSET (MonoDelegate, target));
3731                 MONO_INST_NEW (cfg, ins, OP_PADD);
3732                 ins->inst_left = obj;
3733                 ins->inst_right = offset_ins;
3734
3735                 MONO_INST_NEW (cfg, store, CEE_STIND_REF);
3736                 store->inst_left = ins;
3737                 store->inst_right = target;
3738                 mono_bblock_add_inst (bblock, store);
3739         }
3740
3741         /* Set method field */
3742         NEW_TEMPLOAD (cfg, obj, temp);
3743         NEW_ICONST (cfg, offset_ins, G_STRUCT_OFFSET (MonoDelegate, method));
3744         MONO_INST_NEW (cfg, ins, OP_PADD);
3745         ins->inst_left = obj;
3746         ins->inst_right = offset_ins;
3747
3748         NEW_METHODCONST (cfg, method_ins, method);
3749
3750         MONO_INST_NEW (cfg, store, CEE_STIND_I);
3751         store->inst_left = ins;
3752         store->inst_right = method_ins;
3753         mono_bblock_add_inst (bblock, store);
3754
3755         /* Set invoke_impl field */
3756         NEW_TEMPLOAD (cfg, obj, temp);
3757         NEW_ICONST (cfg, offset_ins, G_STRUCT_OFFSET (MonoDelegate, invoke_impl));
3758         MONO_INST_NEW (cfg, ins, OP_PADD);
3759         ins->inst_left = obj;
3760         ins->inst_right = offset_ins;
3761
3762         trampoline = mono_create_delegate_trampoline (klass);
3763         NEW_AOTCONST (cfg, tramp_ins, MONO_PATCH_INFO_ABS, trampoline);
3764
3765         MONO_INST_NEW (cfg, store, CEE_STIND_I);
3766         store->inst_left = ins;
3767         store->inst_right = tramp_ins;
3768         mono_bblock_add_inst (bblock, store);
3769
3770         /* All the checks which are in mono_delegate_ctor () are done by the delegate trampoline */
3771
3772         NEW_TEMPLOAD (cfg, obj, temp);
3773
3774         return obj;
3775 }
3776
3777 static int
3778 handle_array_new (MonoCompile *cfg, MonoBasicBlock *bblock, int rank, MonoInst **sp, unsigned char *ip)
3779 {
3780         MonoJitICallInfo *info;
3781
3782         info = mono_get_array_new_va_icall (rank);
3783
3784         cfg->flags |= MONO_CFG_HAS_VARARGS;
3785
3786         /* FIXME: This uses info->sig, but it should use the signature of the wrapper */
3787         return mono_emit_native_call (cfg, bblock, mono_icall_get_wrapper (info), info->sig, sp, ip, TRUE, FALSE);
3788 }
3789
3790 static void
3791 mono_emit_load_got_addr (MonoCompile *cfg)
3792 {
3793         MonoInst *load, *store, *dummy_use;
3794         MonoInst *get_got;
3795
3796         if (!cfg->got_var || cfg->got_var_allocated)
3797                 return;
3798
3799         MONO_INST_NEW (cfg, get_got, OP_LOAD_GOTADDR);
3800         NEW_TEMPSTORE (cfg, store, cfg->got_var->inst_c0, get_got);
3801
3802         /* Add it to the start of the first bblock */
3803         if (cfg->bb_entry->code) {
3804                 store->next = cfg->bb_entry->code;
3805                 cfg->bb_entry->code = store;
3806         }
3807         else
3808                 MONO_ADD_INS (cfg->bb_entry, store);
3809
3810         cfg->got_var_allocated = TRUE;
3811
3812         /* 
3813          * Add a dummy use to keep the got_var alive, since real uses might
3814          * only be generated in the decompose or instruction selection phases.
3815          * Add it to end_bblock, so the variable's lifetime covers the whole
3816          * method.
3817          */
3818         NEW_TEMPLOAD (cfg, load, cfg->got_var->inst_c0);
3819         NEW_DUMMY_USE (cfg, dummy_use, load);
3820         MONO_ADD_INS (cfg->bb_exit, dummy_use);
3821 }
3822
3823 #define CODE_IS_STLOC(ip) (((ip) [0] >= CEE_STLOC_0 && (ip) [0] <= CEE_STLOC_3) || ((ip) [0] == CEE_STLOC_S))
3824
3825 gboolean
3826 mini_class_is_system_array (MonoClass *klass)
3827 {
3828         if (klass->parent == mono_defaults.array_class)
3829                 return TRUE;
3830         else
3831                 return FALSE;
3832 }
3833
3834 static gboolean
3835 mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method)
3836 {
3837         MonoMethodHeader *header = mono_method_get_header (method);
3838         MonoMethodSignature *signature = mono_method_signature (method);
3839         MonoVTable *vtable;
3840         int i;
3841
3842         if (cfg->generic_sharing_context)
3843                 return FALSE;
3844
3845         if (method->inline_failure)
3846                 return FALSE;
3847
3848 #ifdef MONO_ARCH_HAVE_LMF_OPS
3849         if (((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
3850                  (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) &&
3851             !MONO_TYPE_ISSTRUCT (signature->ret) && !mini_class_is_system_array (method->klass))
3852                 return TRUE;
3853 #endif
3854
3855         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
3856             (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
3857             (method->iflags & METHOD_IMPL_ATTRIBUTE_NOINLINING) ||
3858             (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) ||
3859             (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
3860             (method->klass->marshalbyref) ||
3861             !header || header->num_clauses ||
3862             /* fixme: why cant we inline valuetype returns? */
3863             MONO_TYPE_ISSTRUCT (signature->ret))
3864                 return FALSE;
3865
3866 #ifdef MONO_ARCH_SOFT_FLOAT
3867         /* this complicates things, fix later */
3868         if (signature->ret->type == MONO_TYPE_R4)
3869                 return FALSE;
3870 #endif
3871         /* its not worth to inline methods with valuetype arguments?? */
3872         for (i = 0; i < signature->param_count; i++) {
3873                 if (MONO_TYPE_ISSTRUCT (signature->params [i])) {
3874                         return FALSE;
3875                 }
3876 #ifdef MONO_ARCH_SOFT_FLOAT
3877                 /* this complicates things, fix later */
3878                 if (!signature->params [i]->byref && signature->params [i]->type == MONO_TYPE_R4)
3879                         return FALSE;
3880 #endif
3881         }
3882
3883         /* also consider num_locals? */
3884         /* Do the size check early to avoid creating vtables */
3885         if (getenv ("MONO_INLINELIMIT")) {
3886                 if (header->code_size >= atoi (getenv ("MONO_INLINELIMIT"))) {
3887                         return FALSE;
3888                 }
3889         } else if (header->code_size >= INLINE_LENGTH_LIMIT)
3890                 return FALSE;
3891
3892         /*
3893          * if we can initialize the class of the method right away, we do,
3894          * otherwise we don't allow inlining if the class needs initialization,
3895          * since it would mean inserting a call to mono_runtime_class_init()
3896          * inside the inlined code
3897          */
3898         if (!(cfg->opt & MONO_OPT_SHARED)) {
3899                 if (method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) {
3900                         if (cfg->run_cctors && method->klass->has_cctor) {
3901                                 if (!method->klass->runtime_info)
3902                                         /* No vtable created yet */
3903                                         return FALSE;
3904                                 vtable = mono_class_vtable (cfg->domain, method->klass);
3905                                 if (!vtable)
3906                                         return FALSE;
3907                                 /* This makes so that inline cannot trigger */
3908                                 /* .cctors: too many apps depend on them */
3909                                 /* running with a specific order... */
3910                                 if (! vtable->initialized)
3911                                         return FALSE;
3912                                 mono_runtime_class_init (vtable);
3913                         }
3914                 } else if (mono_class_needs_cctor_run (method->klass, NULL)) {
3915                         if (!method->klass->runtime_info)
3916                                 /* No vtable created yet */
3917                                 return FALSE;
3918                         vtable = mono_class_vtable (cfg->domain, method->klass);
3919                         if (!vtable)
3920                                 return FALSE;
3921                         if (!vtable->initialized)
3922                                 return FALSE;
3923                 }
3924         } else {
3925                 /* 
3926                  * If we're compiling for shared code
3927                  * the cctor will need to be run at aot method load time, for example,
3928                  * or at the end of the compilation of the inlining method.
3929                  */
3930                 if (mono_class_needs_cctor_run (method->klass, NULL) && !((method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT)))
3931                         return FALSE;
3932         }
3933         //if (!MONO_TYPE_IS_VOID (signature->ret)) return FALSE;
3934
3935         /*
3936          * CAS - do not inline methods with declarative security
3937          * Note: this has to be before any possible return TRUE;
3938          */
3939         if (mono_method_has_declsec (method))
3940                 return FALSE;
3941
3942         return TRUE;
3943 }
3944
3945 static gboolean
3946 mini_field_access_needs_cctor_run (MonoCompile *cfg, MonoMethod *method, MonoVTable *vtable)
3947 {
3948         if (vtable->initialized && !cfg->compile_aot)
3949                 return FALSE;
3950
3951         if (vtable->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT)
3952                 return FALSE;
3953
3954         if (!mono_class_needs_cctor_run (vtable->klass, method))
3955                 return FALSE;
3956
3957         if (! (method->flags & METHOD_ATTRIBUTE_STATIC) && (vtable->klass == method->klass))
3958                 /* The initialization is already done before the method is called */
3959                 return FALSE;
3960
3961         return TRUE;
3962 }
3963
3964 static MonoInst*
3965 mini_get_ldelema_ins (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *cmethod, MonoInst **sp, unsigned char *ip, gboolean is_set)
3966 {
3967         int temp, rank;
3968         MonoInst *addr;
3969         MonoMethod *addr_method;
3970         int element_size;
3971
3972         rank = mono_method_signature (cmethod)->param_count - (is_set? 1: 0);
3973
3974         if (rank == 1) {
3975                 MONO_INST_NEW (cfg, addr, CEE_LDELEMA);
3976                 addr->inst_left = sp [0];
3977                 addr->inst_right = sp [1];
3978                 addr->type = STACK_MP;
3979                 addr->klass = cmethod->klass->element_class;
3980                 return addr;
3981         }
3982
3983         if (rank == 2 && (cfg->opt & MONO_OPT_INTRINS)) {
3984 #if defined(MONO_ARCH_EMULATE_MUL_DIV) && !defined(MONO_ARCH_NO_EMULATE_MUL)
3985                 /* OP_LDELEMA2D depends on OP_LMUL */
3986 #else
3987                 MonoInst *indexes;
3988                 NEW_GROUP (cfg, indexes, sp [1], sp [2]);
3989                 MONO_INST_NEW (cfg, addr, OP_LDELEMA2D);
3990                 addr->inst_left = sp [0];
3991                 addr->inst_right = indexes;
3992                 addr->type = STACK_MP;
3993                 addr->klass = cmethod->klass->element_class;
3994                 return addr;
3995 #endif
3996         }
3997
3998         element_size = mono_class_array_element_size (cmethod->klass->element_class);
3999         addr_method = mono_marshal_get_array_address (rank, element_size);
4000         temp = mono_emit_method_call_spilled (cfg, bblock, addr_method, addr_method->signature, sp, ip, NULL);
4001         NEW_TEMPLOAD (cfg, addr, temp);
4002         return addr;
4003
4004 }
4005
4006 static MonoJitICallInfo **emul_opcode_map = NULL;
4007
4008 MonoJitICallInfo *
4009 mono_find_jit_opcode_emulation (int opcode)
4010 {
4011         g_assert (opcode >= 0 && opcode <= OP_LAST);
4012         if  (emul_opcode_map)
4013                 return emul_opcode_map [opcode];
4014         else
4015                 return NULL;
4016 }
4017
4018 static MonoInst*
4019 mini_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
4020 {
4021         MonoInst *ins = NULL;
4022         
4023         static MonoClass *runtime_helpers_class = NULL;
4024         if (! runtime_helpers_class)
4025                 runtime_helpers_class = mono_class_from_name (mono_defaults.corlib,
4026                         "System.Runtime.CompilerServices", "RuntimeHelpers");
4027
4028         if (cmethod->klass == mono_defaults.string_class) {
4029                 if (strcmp (cmethod->name, "get_Chars") == 0) {
4030                         MONO_INST_NEW (cfg, ins, OP_GETCHR);
4031                         ins->inst_i0 = args [0];
4032                         ins->inst_i1 = args [1];
4033                         return ins;
4034                 } else if (strcmp (cmethod->name, "get_Length") == 0) {
4035                         MONO_INST_NEW (cfg, ins, OP_STRLEN);
4036                         ins->inst_i0 = args [0];
4037                         return ins;
4038                 } else if (strcmp (cmethod->name, "InternalSetChar") == 0) {
4039                         MonoInst *get_addr;
4040                         MONO_INST_NEW (cfg, get_addr, OP_STR_CHAR_ADDR);
4041                         get_addr->inst_i0 = args [0];
4042                         get_addr->inst_i1 = args [1];
4043                         MONO_INST_NEW (cfg, ins, CEE_STIND_I2);
4044                         ins->inst_i0 = get_addr;
4045                         ins->inst_i1 = args [2];
4046                         return ins;
4047                 } else 
4048                         return NULL;
4049         } else if (cmethod->klass == mono_defaults.object_class) {
4050                 if (strcmp (cmethod->name, "GetType") == 0) {
4051                         MONO_INST_NEW (cfg, ins, OP_GETTYPE);
4052                         ins->inst_i0 = args [0];
4053                         return ins;
4054                 /* The OP_GETHASHCODE rule depends on OP_MUL */
4055 #if !defined(MONO_ARCH_EMULATE_MUL_DIV) && !defined(HAVE_MOVING_COLLECTOR)
4056                 } else if (strcmp (cmethod->name, "InternalGetHashCode") == 0) {
4057                         MONO_INST_NEW (cfg, ins, OP_GETHASHCODE);
4058                         ins->inst_i0 = args [0];
4059                         return ins;
4060 #endif
4061                 } else if (strcmp (cmethod->name, ".ctor") == 0) {
4062                         MONO_INST_NEW (cfg, ins, OP_NOP);
4063                         return ins;
4064                 } else
4065                         return NULL;
4066         } else if (cmethod->klass == mono_defaults.array_class) {
4067                 if (cmethod->name [0] != 'g')
4068                         return NULL;
4069
4070                 if (strcmp (cmethod->name, "get_Rank") == 0) {
4071                         MONO_INST_NEW (cfg, ins, OP_ARRAY_RANK);
4072                         ins->inst_i0 = args [0];
4073                         return ins;
4074                 } else if (strcmp (cmethod->name, "get_Length") == 0) {
4075                         MONO_INST_NEW (cfg, ins, CEE_LDLEN);
4076                         ins->inst_i0 = args [0];
4077                         return ins;
4078                 } else
4079                         return NULL;
4080         } else if (cmethod->klass == runtime_helpers_class) {
4081                 if (strcmp (cmethod->name, "get_OffsetToStringData") == 0) {
4082                         NEW_ICONST (cfg, ins, G_STRUCT_OFFSET (MonoString, chars));
4083                         return ins;
4084                 } else
4085                         return NULL;
4086         } else if (cmethod->klass == mono_defaults.thread_class) {
4087                 if (strcmp (cmethod->name, "get_CurrentThread") == 0 && (ins = mono_arch_get_thread_intrinsic (cfg)))
4088                         return ins;
4089                 if (strcmp (cmethod->name, "MemoryBarrier") == 0) {
4090                         MONO_INST_NEW (cfg, ins, OP_MEMORY_BARRIER);
4091                         return ins;
4092                 }
4093         } else if (mini_class_is_system_array (cmethod->klass) &&
4094                         strcmp (cmethod->name, "GetGenericValueImpl") == 0) {
4095                 MonoInst *sp [2];
4096                 MonoInst *ldelem, *store, *load;
4097                 MonoClass *eklass = mono_class_from_mono_type (fsig->params [1]);
4098                 int n;
4099                 n = mini_type_to_stind (cfg, &eklass->byval_arg);
4100                 if (n == CEE_STOBJ)
4101                         return NULL;
4102                 sp [0] = args [0];
4103                 sp [1] = args [1];
4104                 NEW_LDELEMA (cfg, ldelem, sp, eklass);
4105                 ldelem->flags |= MONO_INST_NORANGECHECK;
4106                 MONO_INST_NEW (cfg, store, n);
4107                 MONO_INST_NEW (cfg, load, mini_type_to_ldind (cfg, &eklass->byval_arg));
4108                 type_to_eval_stack_type (cfg, &eklass->byval_arg, load);
4109                 load->inst_left = ldelem;
4110                 store->inst_left = args [2];
4111                 store->inst_right = load;
4112                 return store;
4113         } else if (cmethod->klass == mono_defaults.math_class) {
4114                 /* 
4115                  * There is general branches code for Min/Max, but it does not work for 
4116                  * all inputs:
4117                  * http://everything2.com/?node_id=1051618
4118                  */
4119         } else if (cmethod->klass->image == mono_defaults.corlib &&
4120                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
4121                            (strcmp (cmethod->klass->name, "Interlocked") == 0)) {
4122                 ins = NULL;
4123
4124 #if SIZEOF_VOID_P == 8
4125                 if (strcmp (cmethod->name, "Read") == 0 && (fsig->params [0]->type == MONO_TYPE_I8)) {
4126                         /* 64 bit reads are already atomic */
4127                         MONO_INST_NEW (cfg, ins, CEE_LDIND_I8);
4128                         ins->inst_i0 = args [0];
4129                 }
4130 #endif
4131
4132 #ifdef MONO_ARCH_HAVE_ATOMIC_ADD
4133                 if (strcmp (cmethod->name, "Increment") == 0) {
4134                         MonoInst *ins_iconst;
4135                         guint32 opcode;
4136
4137                         if (fsig->params [0]->type == MONO_TYPE_I4)
4138                                 opcode = OP_ATOMIC_ADD_NEW_I4;
4139                         else if (fsig->params [0]->type == MONO_TYPE_I8)
4140                                 opcode = OP_ATOMIC_ADD_NEW_I8;
4141                         else
4142                                 g_assert_not_reached ();
4143
4144 #if SIZEOF_VOID_P == 4
4145                         if (opcode == OP_ATOMIC_ADD_NEW_I8)
4146                                 return NULL;
4147 #endif
4148
4149                         MONO_INST_NEW (cfg, ins, opcode);
4150                         MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
4151                         ins_iconst->inst_c0 = 1;
4152
4153                         ins->inst_i0 = args [0];
4154                         ins->inst_i1 = ins_iconst;
4155                 } else if (strcmp (cmethod->name, "Decrement") == 0) {
4156                         MonoInst *ins_iconst;
4157                         guint32 opcode;
4158
4159                         if (fsig->params [0]->type == MONO_TYPE_I4)
4160                                 opcode = OP_ATOMIC_ADD_NEW_I4;
4161                         else if (fsig->params [0]->type == MONO_TYPE_I8)
4162                                 opcode = OP_ATOMIC_ADD_NEW_I8;
4163                         else
4164                                 g_assert_not_reached ();
4165
4166 #if SIZEOF_VOID_P == 4
4167                         if (opcode == OP_ATOMIC_ADD_NEW_I8)
4168                                 return NULL;
4169 #endif
4170
4171                         MONO_INST_NEW (cfg, ins, opcode);
4172                         MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
4173                         ins_iconst->inst_c0 = -1;
4174
4175                         ins->inst_i0 = args [0];
4176                         ins->inst_i1 = ins_iconst;
4177                 } else if (strcmp (cmethod->name, "Add") == 0) {
4178                         guint32 opcode;
4179
4180                         if (fsig->params [0]->type == MONO_TYPE_I4)
4181                                 opcode = OP_ATOMIC_ADD_NEW_I4;
4182                         else if (fsig->params [0]->type == MONO_TYPE_I8)
4183                                 opcode = OP_ATOMIC_ADD_NEW_I8;
4184                         else
4185                                 g_assert_not_reached ();
4186
4187 #if SIZEOF_VOID_P == 4
4188                         if (opcode == OP_ATOMIC_ADD_NEW_I8)
4189                                 return NULL;
4190 #endif
4191                         
4192                         MONO_INST_NEW (cfg, ins, opcode);
4193
4194                         ins->inst_i0 = args [0];
4195                         ins->inst_i1 = args [1];
4196                 }
4197 #endif /* MONO_ARCH_HAVE_ATOMIC_ADD */
4198
4199 #ifdef MONO_ARCH_HAVE_ATOMIC_EXCHANGE
4200                 if (strcmp (cmethod->name, "Exchange") == 0) {
4201                         guint32 opcode;
4202
4203                         if (fsig->params [0]->type == MONO_TYPE_I4)
4204                                 opcode = OP_ATOMIC_EXCHANGE_I4;
4205 #if SIZEOF_VOID_P == 8
4206                         else if ((fsig->params [0]->type == MONO_TYPE_I8) ||
4207                                          (fsig->params [0]->type == MONO_TYPE_I) ||
4208                                          (fsig->params [0]->type == MONO_TYPE_OBJECT))
4209                                 opcode = OP_ATOMIC_EXCHANGE_I8;
4210 #else
4211                         else if ((fsig->params [0]->type == MONO_TYPE_I) ||
4212                                          (fsig->params [0]->type == MONO_TYPE_OBJECT))
4213                                 opcode = OP_ATOMIC_EXCHANGE_I4;
4214 #endif
4215                         else
4216                                 return NULL;
4217
4218 #if SIZEOF_VOID_P == 4
4219                         if (opcode == OP_ATOMIC_EXCHANGE_I8)
4220                                 return NULL;
4221 #endif
4222
4223                         MONO_INST_NEW (cfg, ins, opcode);
4224
4225                         ins->inst_i0 = args [0];
4226                         ins->inst_i1 = args [1];
4227                 }
4228 #endif /* MONO_ARCH_HAVE_ATOMIC_EXCHANGE */
4229
4230 #ifdef MONO_ARCH_HAVE_ATOMIC_CAS_IMM
4231                 /* 
4232                  * Can't implement CompareExchange methods this way since they have
4233                  * three arguments. We can implement one of the common cases, where the new
4234                  * value is a constant.
4235                  */
4236                 if ((strcmp (cmethod->name, "CompareExchange") == 0)) {
4237                         if (fsig->params [1]->type == MONO_TYPE_I4 && args [2]->opcode == OP_ICONST) {
4238                                 MONO_INST_NEW (cfg, ins, OP_ATOMIC_CAS_IMM_I4);
4239                                 ins->inst_i0 = args [0];
4240                                 ins->inst_i1 = args [1];
4241                                 ins->backend.data = GINT_TO_POINTER (args [2]->inst_c0);
4242                         }
4243                         /* The I8 case is hard to detect, since the arg might be a conv.i8 (iconst) tree */
4244                 }
4245 #endif /* MONO_ARCH_HAVE_ATOMIC_CAS_IMM */
4246
4247                 if (ins)
4248                         return ins;
4249         } else if (cmethod->klass->image == mono_defaults.corlib) {
4250                 if (cmethod->name [0] == 'B' && strcmp (cmethod->name, "Break") == 0
4251                                 && strcmp (cmethod->klass->name, "Debugger") == 0) {
4252                         MONO_INST_NEW (cfg, ins, OP_BREAK);
4253                         return ins;
4254                 }
4255                 if (cmethod->name [0] == 'g' && strcmp (cmethod->name, "get_IsRunningOnWindows") == 0
4256                                 && strcmp (cmethod->klass->name, "Environment") == 0) {
4257 #ifdef PLATFORM_WIN32
4258                         NEW_ICONST (cfg, ins, 1);
4259 #else
4260                         NEW_ICONST (cfg, ins, 0);
4261 #endif
4262                         return ins;
4263                 }
4264         }
4265
4266         return mono_arch_get_inst_for_method (cfg, cmethod, fsig, args);
4267 }
4268
4269 static void
4270 mono_save_args (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethodSignature *sig, MonoInst **sp, MonoInst **args)
4271 {
4272         MonoInst *store, *temp;
4273         int i;
4274
4275         g_assert (!MONO_TYPE_ISSTRUCT (sig->ret));
4276
4277         if (!sig->hasthis && sig->param_count == 0) 
4278                 return;
4279
4280         if (sig->hasthis) {
4281                 if (sp [0]->opcode == OP_ICONST) {
4282                         *args++ = sp [0];
4283                 } else {
4284                         temp = mono_compile_create_var (cfg, type_from_stack_type (*sp), OP_LOCAL);
4285                         *args++ = temp;
4286                         NEW_TEMPSTORE (cfg, store, temp->inst_c0, *sp);
4287                         /* FIXME: handle CEE_STIND_R4 */
4288                         store->cil_code = sp [0]->cil_code;
4289                         MONO_ADD_INS (bblock, store);
4290                 }
4291                 sp++;
4292         }
4293
4294         for (i = 0; i < sig->param_count; ++i) {
4295                 if (sp [0]->opcode == OP_ICONST) {
4296                         *args++ = sp [0];
4297                 } else {
4298                         temp = mono_compile_create_var (cfg, sig->params [i], OP_LOCAL);
4299                         *args++ = temp;
4300                         NEW_TEMPSTORE (cfg, store, temp->inst_c0, *sp);
4301                         store->cil_code = sp [0]->cil_code;
4302                         /* FIXME: handle CEE_STIND_R4 */
4303                         if (store->opcode == CEE_STOBJ) {
4304                                 NEW_TEMPLOADA (cfg, store, temp->inst_c0);
4305                                 handle_stobj (cfg, bblock, store, *sp, sp [0]->cil_code, temp->klass, FALSE, FALSE, FALSE);
4306 #ifdef MONO_ARCH_SOFT_FLOAT
4307                         } else if (store->opcode == CEE_STIND_R4) {
4308                                 NEW_TEMPLOADA (cfg, store, temp->inst_c0);
4309                                 handle_store_float (cfg, bblock, store, *sp, sp [0]->cil_code);
4310 #endif
4311                         } else {
4312                                 MONO_ADD_INS (bblock, store);
4313                         } 
4314                 }
4315                 sp++;
4316         }
4317 }
4318 #define MONO_INLINE_CALLED_LIMITED_METHODS 0
4319 #define MONO_INLINE_CALLER_LIMITED_METHODS 0
4320
4321 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
4322 static char*
4323 mono_inline_called_method_name_limit = NULL;
4324 static gboolean check_inline_called_method_name_limit (MonoMethod *called_method) {
4325         char *called_method_name = mono_method_full_name (called_method, TRUE);
4326         int strncmp_result;
4327         
4328         if (mono_inline_called_method_name_limit == NULL) {
4329                 char *limit_string = getenv ("MONO_INLINE_CALLED_METHOD_NAME_LIMIT");
4330                 if (limit_string != NULL) {
4331                         mono_inline_called_method_name_limit = limit_string;
4332                 } else {
4333                         mono_inline_called_method_name_limit = (char *) "";
4334                 }
4335         }
4336         
4337         strncmp_result = strncmp (called_method_name, mono_inline_called_method_name_limit, strlen (mono_inline_called_method_name_limit));
4338         g_free (called_method_name);
4339         
4340         //return (strncmp_result <= 0);
4341         return (strncmp_result == 0);
4342 }
4343 #endif
4344
4345 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
4346 static char*
4347 mono_inline_caller_method_name_limit = NULL;
4348 static gboolean check_inline_caller_method_name_limit (MonoMethod *caller_method) {
4349         char *caller_method_name = mono_method_full_name (caller_method, TRUE);
4350         int strncmp_result;
4351         
4352         if (mono_inline_caller_method_name_limit == NULL) {
4353                 char *limit_string = getenv ("MONO_INLINE_CALLER_METHOD_NAME_LIMIT");
4354                 if (limit_string != NULL) {
4355                         mono_inline_caller_method_name_limit = limit_string;
4356                 } else {
4357                         mono_inline_caller_method_name_limit = (char *) "";
4358                 }
4359         }
4360         
4361         strncmp_result = strncmp (caller_method_name, mono_inline_caller_method_name_limit, strlen (mono_inline_caller_method_name_limit));
4362         g_free (caller_method_name);
4363         
4364         //return (strncmp_result <= 0);
4365         return (strncmp_result == 0);
4366 }
4367 #endif
4368
4369 static int
4370 inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoBasicBlock *bblock, MonoInst **sp,
4371                 guchar *ip, guint real_offset, GList *dont_inline, MonoBasicBlock **last_b, gboolean inline_allways)
4372 {
4373         MonoInst *ins, *rvar = NULL;
4374         MonoMethodHeader *cheader;
4375         MonoBasicBlock *ebblock, *sbblock;
4376         int i, costs, new_locals_offset;
4377         MonoMethod *prev_inlined_method;
4378         MonoBasicBlock **prev_cil_offset_to_bb;
4379         unsigned char* prev_cil_start;
4380         guint32 prev_cil_offset_to_bb_len;
4381
4382         g_assert (cfg->exception_type == MONO_EXCEPTION_NONE);
4383
4384 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
4385         if ((! inline_allways) && ! check_inline_called_method_name_limit (cmethod))
4386                 return 0;
4387 #endif
4388 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
4389         if ((! inline_allways) && ! check_inline_caller_method_name_limit (cfg->method))
4390                 return 0;
4391 #endif
4392
4393         if (bblock->out_of_line && !inline_allways)
4394                 return 0;
4395
4396         if (cfg->verbose_level > 2)
4397                 g_print ("INLINE START %p %s -> %s\n", cmethod,  mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
4398
4399         if (!cmethod->inline_info) {
4400                 mono_jit_stats.inlineable_methods++;
4401                 cmethod->inline_info = 1;
4402         }
4403         /* allocate space to store the return value */
4404         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
4405                 rvar =  mono_compile_create_var (cfg, fsig->ret, OP_LOCAL);
4406         }
4407
4408         /* allocate local variables */
4409         cheader = mono_method_get_header (cmethod);
4410         new_locals_offset = cfg->num_varinfo;
4411         for (i = 0; i < cheader->num_locals; ++i)
4412                 mono_compile_create_var (cfg, cheader->locals [i], OP_LOCAL);
4413
4414         /* allocate starte and end blocks */
4415         sbblock = NEW_BBLOCK (cfg);
4416         sbblock->block_num = cfg->num_bblocks++;
4417         sbblock->real_offset = real_offset;
4418
4419         ebblock = NEW_BBLOCK (cfg);
4420         ebblock->block_num = cfg->num_bblocks++;
4421         ebblock->real_offset = real_offset;
4422
4423         prev_inlined_method = cfg->inlined_method;
4424         cfg->inlined_method = cmethod;
4425         prev_cil_offset_to_bb = cfg->cil_offset_to_bb;
4426         prev_cil_offset_to_bb_len = cfg->cil_offset_to_bb_len;
4427         prev_cil_start = cfg->cil_start;
4428
4429         costs = mono_method_to_ir (cfg, cmethod, sbblock, ebblock, new_locals_offset, rvar, dont_inline, sp, real_offset, *ip == CEE_CALLVIRT);
4430
4431         cfg->inlined_method = prev_inlined_method;
4432         cfg->cil_offset_to_bb = prev_cil_offset_to_bb;
4433         cfg->cil_offset_to_bb_len = prev_cil_offset_to_bb_len;
4434         cfg->cil_start = prev_cil_start;
4435
4436         if ((costs >= 0 && costs < 60) || inline_allways) {
4437                 if (cfg->verbose_level > 2)
4438                         g_print ("INLINE END %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
4439                 
4440                 mono_jit_stats.inlined_methods++;
4441
4442                 /* always add some code to avoid block split failures */
4443                 MONO_INST_NEW (cfg, ins, OP_NOP);
4444                 MONO_ADD_INS (bblock, ins);
4445                 ins->cil_code = ip;
4446
4447                 bblock->next_bb = sbblock;
4448                 link_bblock (cfg, bblock, sbblock);
4449
4450                 if (rvar) {
4451                         NEW_TEMPLOAD (cfg, ins, rvar->inst_c0);
4452                         NEW_TEMPLOAD_SOFT_FLOAT (cfg, ebblock, ins, rvar->inst_c0, ip);
4453                         *sp++ = ins;
4454                 }
4455                 *last_b = ebblock;
4456                 return costs + 1;
4457         } else {
4458                 if (cfg->verbose_level > 2)
4459                         g_print ("INLINE ABORTED %s\n", mono_method_full_name (cmethod, TRUE));
4460                 cfg->exception_type = MONO_EXCEPTION_NONE;
4461                 mono_loader_clear_error ();
4462                 cmethod->inline_failure = TRUE;
4463         }
4464         return 0;
4465 }
4466
4467 /*
4468  * Some of these comments may well be out-of-date.
4469  * Design decisions: we do a single pass over the IL code (and we do bblock 
4470  * splitting/merging in the few cases when it's required: a back jump to an IL
4471  * address that was not already seen as bblock starting point).
4472  * Code is validated as we go (full verification is still better left to metadata/verify.c).
4473  * Complex operations are decomposed in simpler ones right away. We need to let the 
4474  * arch-specific code peek and poke inside this process somehow (except when the 
4475  * optimizations can take advantage of the full semantic info of coarse opcodes).
4476  * All the opcodes of the form opcode.s are 'normalized' to opcode.
4477  * MonoInst->opcode initially is the IL opcode or some simplification of that 
4478  * (OP_LOAD, OP_STORE). The arch-specific code may rearrange it to an arch-specific 
4479  * opcode with value bigger than OP_LAST.
4480  * At this point the IR can be handed over to an interpreter, a dumb code generator
4481  * or to the optimizing code generator that will translate it to SSA form.
4482  *
4483  * Profiling directed optimizations.
4484  * We may compile by default with few or no optimizations and instrument the code
4485  * or the user may indicate what methods to optimize the most either in a config file
4486  * or through repeated runs where the compiler applies offline the optimizations to 
4487  * each method and then decides if it was worth it.
4488  *
4489  */
4490
4491 #define CHECK_TYPE(ins) if (!(ins)->type) UNVERIFIED
4492 #define CHECK_STACK(num) if ((sp - stack_start) < (num)) UNVERIFIED
4493 #define CHECK_STACK_OVF(num) if (((sp - stack_start) + (num)) > header->max_stack) UNVERIFIED
4494 #define CHECK_ARG(num) if ((unsigned)(num) >= (unsigned)num_args) UNVERIFIED
4495 #define CHECK_LOCAL(num) if ((unsigned)(num) >= (unsigned)header->num_locals) UNVERIFIED
4496 #define CHECK_OPSIZE(size) if (ip + size > end) UNVERIFIED
4497 #define CHECK_UNVERIFIABLE(cfg) if (cfg->unverifiable) UNVERIFIED
4498 #define CHECK_TYPELOAD(klass) if (!(klass) || (klass)->exception_type) {cfg->exception_ptr = klass; goto load_error;}
4499
4500 /* offset from br.s -> br like opcodes */
4501 #define BIG_BRANCH_OFFSET 13
4502
4503 static inline gboolean
4504 ip_in_bb (MonoCompile *cfg, MonoBasicBlock *bb, const guint8* ip)
4505 {
4506         MonoBasicBlock *b = cfg->cil_offset_to_bb [ip - cfg->cil_start];
4507         
4508         return b == NULL || b == bb;
4509 }
4510
4511 static int
4512 get_basic_blocks (MonoCompile *cfg, MonoMethodHeader* header, guint real_offset, unsigned char *start, unsigned char *end, unsigned char **pos)
4513 {
4514         unsigned char *ip = start;
4515         unsigned char *target;
4516         int i;
4517         guint cli_addr;
4518         MonoBasicBlock *bblock;
4519         const MonoOpcode *opcode;
4520
4521         while (ip < end) {
4522                 cli_addr = ip - start;
4523                 i = mono_opcode_value ((const guint8 **)&ip, end);
4524                 if (i < 0)
4525                         UNVERIFIED;
4526                 opcode = &mono_opcodes [i];
4527                 switch (opcode->argument) {
4528                 case MonoInlineNone:
4529                         ip++; 
4530                         break;
4531                 case MonoInlineString:
4532                 case MonoInlineType:
4533                 case MonoInlineField:
4534                 case MonoInlineMethod:
4535                 case MonoInlineTok:
4536                 case MonoInlineSig:
4537                 case MonoShortInlineR:
4538                 case MonoInlineI:
4539                         ip += 5;
4540                         break;
4541                 case MonoInlineVar:
4542                         ip += 3;
4543                         break;
4544                 case MonoShortInlineVar:
4545                 case MonoShortInlineI:
4546                         ip += 2;
4547                         break;
4548                 case MonoShortInlineBrTarget:
4549                         target = start + cli_addr + 2 + (signed char)ip [1];
4550                         GET_BBLOCK (cfg, bblock, target);
4551                         ip += 2;
4552                         if (ip < end)
4553                                 GET_BBLOCK (cfg, bblock, ip);
4554                         break;
4555                 case MonoInlineBrTarget:
4556                         target = start + cli_addr + 5 + (gint32)read32 (ip + 1);
4557                         GET_BBLOCK (cfg, bblock, target);
4558                         ip += 5;
4559                         if (ip < end)
4560                                 GET_BBLOCK (cfg, bblock, ip);
4561                         break;
4562                 case MonoInlineSwitch: {
4563                         guint32 n = read32 (ip + 1);
4564                         guint32 j;
4565                         ip += 5;
4566                         cli_addr += 5 + 4 * n;
4567                         target = start + cli_addr;
4568                         GET_BBLOCK (cfg, bblock, target);
4569                         
4570                         for (j = 0; j < n; ++j) {
4571                                 target = start + cli_addr + (gint32)read32 (ip);
4572                                 GET_BBLOCK (cfg, bblock, target);
4573                                 ip += 4;
4574                         }
4575                         break;
4576                 }
4577                 case MonoInlineR:
4578                 case MonoInlineI8:
4579                         ip += 9;
4580                         break;
4581                 default:
4582                         g_assert_not_reached ();
4583                 }
4584
4585                 if (i == CEE_THROW) {
4586                         unsigned char *bb_start = ip - 1;
4587                         
4588                         /* Find the start of the bblock containing the throw */
4589                         bblock = NULL;
4590                         while ((bb_start >= start) && !bblock) {
4591                                 bblock = cfg->cil_offset_to_bb [(bb_start) - start];
4592                                 bb_start --;
4593                         }
4594                         if (bblock)
4595                                 bblock->out_of_line = 1;
4596                 }
4597         }
4598         return 0;
4599 unverified:
4600         *pos = ip;
4601         return 1;
4602 }
4603
4604 static MonoInst*
4605 emit_tree (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *ins, const guint8* ip_next)
4606 {
4607         MonoInst *store, *temp, *load;
4608         
4609         if (ip_in_bb (cfg, bblock, ip_next) &&
4610                 (CODE_IS_STLOC (ip_next) || *ip_next == CEE_RET))
4611                         return ins;
4612         
4613         temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
4614         temp->flags |= MONO_INST_IS_TEMP;
4615         NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
4616         /* FIXME: handle CEE_STIND_R4 */
4617         store->cil_code = ins->cil_code;
4618         MONO_ADD_INS (bblock, store);
4619         NEW_TEMPLOAD (cfg, load, temp->inst_c0);
4620         load->cil_code = ins->cil_code;
4621         return load;
4622 }
4623
4624 static inline MonoMethod *
4625 mini_get_method_allow_open (MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
4626 {
4627         MonoMethod *method;
4628
4629         if (m->wrapper_type != MONO_WRAPPER_NONE)
4630                 return mono_method_get_wrapper_data (m, token);
4631
4632         method = mono_get_method_full (m->klass->image, token, klass, context);
4633
4634         return method;
4635 }
4636
4637 static inline MonoMethod *
4638 mini_get_method (MonoCompile *cfg, MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
4639 {
4640         MonoMethod *method = mini_get_method_allow_open (m, token, klass, context);
4641
4642         if (method && cfg && !cfg->generic_sharing_context && mono_class_is_open_constructed_type (&method->klass->byval_arg))
4643                 return NULL;
4644
4645         return method;
4646 }
4647
4648 static inline MonoClass*
4649 mini_get_class (MonoMethod *method, guint32 token, MonoGenericContext *context)
4650 {
4651         MonoClass *klass;
4652
4653         if (method->wrapper_type != MONO_WRAPPER_NONE)
4654                 klass = mono_method_get_wrapper_data (method, token);
4655         else
4656                 klass = mono_class_get_full (method->klass->image, token, context);
4657         if (klass)
4658                 mono_class_init (klass);
4659         return klass;
4660 }
4661
4662 /*
4663  * Returns TRUE if the JIT should abort inlining because "callee"
4664  * is influenced by security attributes.
4665  */
4666 static
4667 gboolean check_linkdemand (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee, MonoBasicBlock *bblock, unsigned char *ip)
4668 {
4669         guint32 result;
4670         
4671         if ((cfg->method != caller) && mono_method_has_declsec (callee)) {
4672                 return TRUE;
4673         }
4674         
4675         result = mono_declsec_linkdemand (cfg->domain, caller, callee);
4676         if (result == MONO_JIT_SECURITY_OK)
4677                 return FALSE;
4678
4679         if (result == MONO_JIT_LINKDEMAND_ECMA) {
4680                 /* Generate code to throw a SecurityException before the actual call/link */
4681                 MonoSecurityManager *secman = mono_security_manager_get_methods ();
4682                 MonoInst *args [2];
4683
4684                 NEW_ICONST (cfg, args [0], 4);
4685                 NEW_METHODCONST (cfg, args [1], caller);
4686                 mono_emit_method_call_spilled (cfg, bblock, secman->linkdemandsecurityexception, mono_method_signature (secman->linkdemandsecurityexception), args, ip, NULL);
4687         } else if (cfg->exception_type == MONO_EXCEPTION_NONE) {
4688                  /* don't hide previous results */
4689                 cfg->exception_type = MONO_EXCEPTION_SECURITY_LINKDEMAND;
4690                 cfg->exception_data = result;
4691                 return TRUE;
4692         }
4693         
4694         return FALSE;
4695 }
4696
4697 static MonoMethod*
4698 method_access_exception (void)
4699 {
4700         static MonoMethod *method = NULL;
4701
4702         if (!method) {
4703                 MonoSecurityManager *secman = mono_security_manager_get_methods ();
4704                 method = mono_class_get_method_from_name (secman->securitymanager,
4705                                                           "MethodAccessException", 2);
4706         }
4707         g_assert (method);
4708         return method;
4709 }
4710
4711 static void
4712 emit_throw_method_access_exception (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee,
4713                                     MonoBasicBlock *bblock, unsigned char *ip)
4714 {
4715         MonoMethod *thrower = method_access_exception ();
4716         MonoInst *args [2];
4717
4718         NEW_METHODCONST (cfg, args [0], caller);
4719         NEW_METHODCONST (cfg, args [1], callee);
4720         mono_emit_method_call_spilled (cfg, bblock, thrower,
4721                 mono_method_signature (thrower), args, ip, NULL);
4722 }
4723
4724 static MonoMethod*
4725 verification_exception (void)
4726 {
4727         static MonoMethod *method = NULL;
4728
4729         if (!method) {
4730                 MonoSecurityManager *secman = mono_security_manager_get_methods ();
4731                 method = mono_class_get_method_from_name (secman->securitymanager,
4732                                                           "VerificationException", 0);
4733         }
4734         g_assert (method);
4735         return method;
4736 }
4737
4738 static void
4739 emit_throw_verification_exception (MonoCompile *cfg, MonoBasicBlock *bblock, unsigned char *ip)
4740 {
4741         MonoMethod *thrower = verification_exception ();
4742
4743         mono_emit_method_call_spilled (cfg, bblock, thrower,
4744                 mono_method_signature (thrower),
4745                 NULL, ip, NULL);
4746 }
4747
4748 static void
4749 ensure_method_is_allowed_to_call_method (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee,
4750                                          MonoBasicBlock *bblock, unsigned char *ip)
4751 {
4752         MonoSecurityCoreCLRLevel caller_level = mono_security_core_clr_method_level (caller, TRUE);
4753         MonoSecurityCoreCLRLevel callee_level = mono_security_core_clr_method_level (callee, TRUE);
4754         gboolean is_safe = TRUE;
4755
4756         if (!(caller_level >= callee_level ||
4757                         caller_level == MONO_SECURITY_CORE_CLR_SAFE_CRITICAL ||
4758                         callee_level == MONO_SECURITY_CORE_CLR_SAFE_CRITICAL)) {
4759                 is_safe = FALSE;
4760         }
4761
4762         if (!is_safe)
4763                 emit_throw_method_access_exception (cfg, caller, callee, bblock, ip);
4764 }
4765
4766 static gboolean
4767 method_is_safe (MonoMethod *method)
4768 {
4769         /*
4770         if (strcmp (method->name, "unsafeMethod") == 0)
4771                 return FALSE;
4772         */
4773         return TRUE;
4774 }
4775
4776 /*
4777  * Check that the IL instructions at ip are the array initialization
4778  * sequence and return the pointer to the data and the size.
4779  */
4780 static const char*
4781 initialize_array_data (MonoMethod *method, gboolean aot, unsigned char *ip, MonoInst *newarr, int *out_size)
4782 {
4783         /*
4784          * newarr[System.Int32]
4785          * dup
4786          * ldtoken field valuetype ...
4787          * call void class [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype [mscorlib]System.RuntimeFieldHandle)
4788          */
4789         if (ip [0] == CEE_DUP && ip [1] == CEE_LDTOKEN && ip [5] == 0x4 && ip [6] == CEE_CALL) {
4790                 MonoClass *klass = newarr->inst_newa_class;
4791                 guint32 field_token = read32 (ip + 2);
4792                 guint32 field_index = field_token & 0xffffff;
4793                 guint32 token = read32 (ip + 7);
4794                 guint32 rva;
4795                 const char *data_ptr;
4796                 int size = 0;
4797                 MonoMethod *cmethod;
4798                 MonoClass *dummy_class;
4799                 MonoClassField *field = mono_field_from_token (method->klass->image, field_token, &dummy_class, NULL);
4800                 int dummy_align;
4801
4802                 if (!field)
4803                         return NULL;
4804
4805                 if (newarr->inst_newa_len->opcode != OP_ICONST)
4806                         return NULL;
4807                 cmethod = mini_get_method (NULL, method, token, NULL, NULL);
4808                 if (!cmethod)
4809                         return NULL;
4810                 if (strcmp (cmethod->name, "InitializeArray") || strcmp (cmethod->klass->name, "RuntimeHelpers") || cmethod->klass->image != mono_defaults.corlib)
4811                         return NULL;
4812                 switch (mono_type_get_underlying_type (&klass->byval_arg)->type) {
4813                 case MONO_TYPE_BOOLEAN:
4814                 case MONO_TYPE_I1:
4815                 case MONO_TYPE_U1:
4816                         size = 1; break;
4817                 /* we need to swap on big endian, so punt. Should we handle R4 and R8 as well? */
4818 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
4819                 case MONO_TYPE_CHAR:
4820                 case MONO_TYPE_I2:
4821                 case MONO_TYPE_U2:
4822                         size = 2; break;
4823                 case MONO_TYPE_I4:
4824                 case MONO_TYPE_U4:
4825                 case MONO_TYPE_R4:
4826                         size = 4; break;
4827                 case MONO_TYPE_R8:
4828 #ifdef ARM_FPU_FPA
4829                         return NULL; /* stupid ARM FP swapped format */
4830 #endif
4831                 case MONO_TYPE_I8:
4832                 case MONO_TYPE_U8:
4833                         size = 8; break;
4834 #endif
4835                 default:
4836                         return NULL;
4837                 }
4838                 size *= newarr->inst_newa_len->inst_c0;
4839                 if (size > mono_type_size (field->type, &dummy_align))
4840                     return NULL;
4841                 *out_size = size;
4842                 /*g_print ("optimized in %s: size: %d, numelems: %d\n", method->name, size, newarr->inst_newa_len->inst_c0);*/
4843                 field_index = read32 (ip + 2) & 0xffffff;
4844                 mono_metadata_field_info (method->klass->image, field_index - 1, NULL, &rva, NULL);
4845                 data_ptr = mono_image_rva_map (method->klass->image, rva);
4846                 /*g_print ("field: 0x%08x, rva: %d, rva_ptr: %p\n", read32 (ip + 2), rva, data_ptr);*/
4847                 /* for aot code we do the lookup on load */
4848                 if (aot && data_ptr)
4849                         return GUINT_TO_POINTER (rva);
4850                 return data_ptr;
4851         }
4852         return NULL;
4853 }
4854
4855 static void
4856 set_exception_type_from_invalid_il (MonoCompile *cfg, MonoMethod *method, unsigned char *ip)
4857 {
4858         char *method_fname = mono_method_full_name (method, TRUE);
4859         char *method_code;
4860
4861         if (mono_method_get_header (method)->code_size == 0)
4862                 method_code = g_strdup ("method body is empty.");
4863         else
4864                 method_code = mono_disasm_code_one (NULL, method, ip, NULL);
4865         cfg->exception_type = MONO_EXCEPTION_INVALID_PROGRAM;
4866         cfg->exception_message = g_strdup_printf ("Invalid IL code in %s: %s\n", method_fname, method_code);
4867         g_free (method_fname);
4868         g_free (method_code);
4869 }
4870
4871 static void
4872 set_exception_object (MonoCompile *cfg, MonoException *exception)
4873 {
4874         cfg->exception_type = MONO_EXCEPTION_OBJECT_SUPPLIED;
4875         MONO_GC_REGISTER_ROOT (cfg->exception_ptr);
4876         cfg->exception_ptr = exception;
4877 }
4878
4879 static MonoInst*
4880 get_runtime_generic_context (MonoCompile *cfg, MonoMethod *method, int context_used, MonoInst *this, unsigned char *ip)
4881 {
4882         g_assert (!method->klass->valuetype);
4883
4884         if (context_used & MONO_GENERIC_CONTEXT_USED_METHOD) {
4885                 MonoInst *mrgctx_loc, *mrgctx_var;
4886
4887                 g_assert (!this);
4888                 g_assert (method->is_inflated && mono_method_get_context (method)->method_inst);
4889
4890                 mrgctx_loc = mono_get_vtable_var (cfg);
4891                 NEW_TEMPLOAD (cfg, mrgctx_var, mrgctx_loc->inst_c0);
4892
4893                 return mrgctx_var;
4894         } else if (method->flags & METHOD_ATTRIBUTE_STATIC) {
4895                 MonoInst *vtable_loc, *vtable_var;
4896
4897                 g_assert (!this);
4898
4899                 vtable_loc = mono_get_vtable_var (cfg);
4900                 NEW_TEMPLOAD (cfg, vtable_var, vtable_loc->inst_c0);
4901
4902                 if (method->is_inflated && mono_method_get_context (method)->method_inst) {
4903                         MonoInst *mrgctx_var = vtable_var;
4904
4905                         g_assert (G_STRUCT_OFFSET (MonoMethodRuntimeGenericContext, class_vtable) == 0);
4906
4907                         MONO_INST_NEW (cfg, vtable_var, CEE_LDIND_I);
4908                         vtable_var->cil_code = ip;
4909                         vtable_var->inst_left = mrgctx_var;
4910                         vtable_var->type = STACK_PTR;
4911                 }
4912
4913                 return vtable_var;
4914         } else {
4915                 MonoInst *vtable;
4916
4917                 g_assert (this);
4918
4919                 MONO_INST_NEW (cfg, vtable, CEE_LDIND_I);
4920                 vtable->inst_left = this;
4921                 vtable->type = STACK_PTR;
4922
4923                 return vtable;
4924         }
4925 }
4926
4927 gpointer
4928 mini_create_rgctx_lazy_fetch_trampoline (guint32 offset)
4929 {
4930         static gboolean inited = FALSE;
4931         static int num_trampolines = 0;
4932
4933         gpointer tramp, ptr;
4934
4935         mono_jit_lock ();
4936         if (rgctx_lazy_fetch_trampoline_hash)
4937                 tramp = g_hash_table_lookup (rgctx_lazy_fetch_trampoline_hash, GUINT_TO_POINTER (offset));
4938         else
4939                 tramp = NULL;
4940         mono_jit_unlock ();
4941         if (tramp)
4942                 return tramp;
4943
4944         tramp = mono_arch_create_rgctx_lazy_fetch_trampoline (offset);
4945         ptr = mono_create_ftnptr (mono_get_root_domain (), tramp);
4946
4947         mono_jit_lock ();
4948         if (!rgctx_lazy_fetch_trampoline_hash)
4949                 rgctx_lazy_fetch_trampoline_hash = g_hash_table_new (NULL, NULL);
4950         g_hash_table_insert (rgctx_lazy_fetch_trampoline_hash, GUINT_TO_POINTER (offset), ptr);
4951         mono_jit_unlock ();
4952
4953         if (!inited) {
4954                 mono_counters_register ("RGCTX num lazy fetch trampolines",
4955                                 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_trampolines);
4956                 inited = TRUE;
4957         }
4958         num_trampolines++;
4959
4960         return ptr;
4961 }
4962
4963 static MonoInst*
4964 get_runtime_generic_context_other_table_ptr (MonoCompile *cfg, MonoBasicBlock *bblock,
4965         MonoInst *rgc_ptr, guint32 slot, const unsigned char *ip)
4966 {
4967         MonoMethodSignature *sig = helper_sig_rgctx_lazy_fetch_trampoline;
4968         guint8 *tramp = mini_create_rgctx_lazy_fetch_trampoline (slot);
4969         int temp;
4970         MonoInst *field;
4971
4972         temp = mono_emit_native_call (cfg, bblock, tramp, sig, &rgc_ptr, ip, FALSE, FALSE);
4973
4974         NEW_TEMPLOAD (cfg, field, temp);
4975
4976         return field;
4977 }
4978
4979 static MonoInst*
4980 get_runtime_generic_context_ptr (MonoCompile *cfg, MonoMethod *method, int context_used, MonoBasicBlock *bblock,
4981         MonoClass *klass, MonoGenericContext *generic_context, MonoInst *rgctx, int rgctx_type, unsigned char *ip)
4982 {
4983         guint32 slot = mono_method_lookup_or_register_other_info (method,
4984                 context_used & MONO_GENERIC_CONTEXT_USED_METHOD, &klass->byval_arg, rgctx_type, generic_context);
4985
4986         return get_runtime_generic_context_other_table_ptr (cfg, bblock, rgctx, slot, ip);
4987 }
4988
4989 static MonoInst*
4990 get_runtime_generic_context_method (MonoCompile *cfg, MonoMethod *method, int context_used, MonoBasicBlock *bblock,
4991         MonoMethod *cmethod, MonoGenericContext *generic_context, MonoInst *rgctx, int rgctx_type, const unsigned char *ip)
4992 {
4993         guint32 slot = mono_method_lookup_or_register_other_info (method,
4994                 context_used & MONO_GENERIC_CONTEXT_USED_METHOD, cmethod, rgctx_type, generic_context);
4995
4996         return get_runtime_generic_context_other_table_ptr (cfg, bblock, rgctx, slot, ip);
4997 }
4998
4999 static MonoInst*
5000 get_runtime_generic_context_field (MonoCompile *cfg, MonoMethod *method, int context_used, MonoBasicBlock *bblock,
5001         MonoClassField *field, MonoGenericContext *generic_context, MonoInst *rgctx, int rgctx_type,
5002         const unsigned char *ip)
5003 {
5004         guint32 slot = mono_method_lookup_or_register_other_info (method,
5005                 context_used & MONO_GENERIC_CONTEXT_USED_METHOD, field, rgctx_type, generic_context);
5006
5007         return get_runtime_generic_context_other_table_ptr (cfg, bblock, rgctx, slot, ip);
5008 }
5009
5010 static MonoInst*
5011 get_runtime_generic_context_method_rgctx (MonoCompile *cfg, MonoMethod *method, int context_used, MonoBasicBlock *bblock,
5012         MonoMethod *rgctx_method, MonoGenericContext *generic_context, MonoInst *rgctx, const unsigned char *ip)
5013 {
5014         guint32 slot = mono_method_lookup_or_register_other_info (method,
5015                 context_used & MONO_GENERIC_CONTEXT_USED_METHOD, rgctx_method,
5016                 MONO_RGCTX_INFO_METHOD_RGCTX, generic_context);
5017
5018         return get_runtime_generic_context_other_table_ptr (cfg, bblock, rgctx, slot, ip);
5019 }
5020
5021 static gboolean
5022 generic_class_is_reference_type (MonoCompile *cfg, MonoClass *klass)
5023 {
5024         MonoType *type;
5025
5026         if (cfg->generic_sharing_context)
5027                 type = mini_get_basic_type_from_generic (cfg->generic_sharing_context, &klass->byval_arg);
5028         else
5029                 type = &klass->byval_arg;
5030         return MONO_TYPE_IS_REFERENCE (type);
5031 }
5032
5033 /**
5034  * Handles unbox of a Nullable<T>, returning a temp variable where the
5035  * result is stored.  If a rgctx is passed, then shared generic code
5036  * is generated.
5037  */
5038 static int
5039 handle_unbox_nullable (MonoCompile* cfg, MonoMethod *caller_method, int context_used, MonoBasicBlock* bblock,
5040         MonoInst* val, const guchar *ip, MonoClass* klass, MonoGenericContext *generic_context, MonoInst *rgctx)
5041 {
5042         MonoMethod* method = mono_class_get_method_from_name (klass, "Unbox", 1);
5043         MonoMethodSignature *signature = mono_method_signature (method);
5044
5045         if (rgctx) {
5046                 MonoInst *addr = get_runtime_generic_context_method (cfg, caller_method, context_used, bblock, method,
5047                         generic_context, rgctx, MONO_RGCTX_INFO_GENERIC_METHOD_CODE, ip);
5048
5049                 return mono_emit_rgctx_calli_spilled (cfg, bblock, signature, &val, addr, NULL, ip);
5050         } else {
5051                 return mono_emit_method_call_spilled (cfg, bblock, method, signature, &val, ip, NULL);
5052         }
5053 }
5054
5055 static MonoInst*
5056 handle_box_nullable_from_inst (MonoCompile *cfg, MonoMethod *caller_method, int context_used, MonoBasicBlock *bblock,
5057         MonoInst *val, const guchar *ip, MonoClass *klass, MonoGenericContext *generic_context, MonoInst *rgctx)
5058 {
5059         MonoMethod* method = mono_class_get_method_from_name (klass, "Box", 1);
5060         MonoInst *dest, *method_addr;
5061         int temp;
5062
5063         g_assert (mono_class_is_nullable (klass));
5064
5065         method_addr = get_runtime_generic_context_method (cfg, caller_method, context_used, bblock, method,
5066                         generic_context, rgctx, MONO_RGCTX_INFO_GENERIC_METHOD_CODE, ip);
5067         temp = mono_emit_rgctx_calli_spilled (cfg, bblock, mono_method_signature (method), &val,
5068                         method_addr, NULL, ip);
5069         NEW_TEMPLOAD (cfg, dest, temp);
5070         return dest;
5071 }
5072
5073 static int
5074 emit_castclass (MonoClass *klass, guint32 token, int context_used, gboolean inst_is_castclass, MonoCompile *cfg,
5075                 MonoMethod *method, MonoInst **arg_array, MonoType **param_types, GList *dont_inline,
5076                 unsigned char *end, MonoMethodHeader *header, MonoGenericContext *generic_context,
5077                 MonoBasicBlock **_bblock, unsigned char **_ip, MonoInst ***_sp, int *_inline_costs, guint *_real_offset)
5078 {
5079         MonoBasicBlock *bblock = *_bblock;
5080         unsigned char *ip = *_ip;
5081         MonoInst **sp = *_sp;
5082         int inline_costs = *_inline_costs;
5083         guint real_offset = *_real_offset;
5084         int return_value = 0;
5085
5086         if (context_used) {
5087                 MonoInst *rgctx, *args [2];
5088                 int temp;
5089
5090                 g_assert (!method->klass->valuetype);
5091
5092                 /* obj */
5093                 args [0] = *sp;
5094
5095                 /* klass */
5096                 GET_RGCTX (rgctx, context_used);
5097                 args [1] = get_runtime_generic_context_ptr (cfg, method, context_used, bblock, klass,
5098                                 generic_context, rgctx, MONO_RGCTX_INFO_KLASS, ip);
5099
5100                 temp = mono_emit_jit_icall (cfg, bblock, mono_object_castclass, args, ip);
5101                 NEW_TEMPLOAD (cfg, *sp, temp);
5102
5103                 sp++;
5104                 ip += 5;
5105                 inline_costs += 2;
5106         } else if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
5107
5108                 MonoMethod *mono_castclass;
5109                 MonoInst *iargs [1];
5110                 MonoBasicBlock *ebblock;
5111                 int costs;
5112                 int temp;
5113
5114                 mono_castclass = mono_marshal_get_castclass (klass);
5115                 iargs [0] = sp [0];
5116
5117                 costs = inline_method (cfg, mono_castclass, mono_method_signature (mono_castclass), bblock,
5118                                 iargs, ip, real_offset, dont_inline, &ebblock, TRUE);
5119
5120                 g_assert (costs > 0);
5121
5122                 ip += 5;
5123                 real_offset += 5;
5124
5125                 GET_BBLOCK (cfg, bblock, ip);
5126                 ebblock->next_bb = bblock;
5127                 link_bblock (cfg, ebblock, bblock);
5128
5129                 temp = iargs [0]->inst_i0->inst_c0;
5130                 NEW_TEMPLOAD (cfg, *sp, temp);
5131
5132                 sp++;
5133                 bblock = ebblock;
5134                 inline_costs += costs;
5135         } else {
5136                 MonoInst *ins;
5137
5138                 /* Needed by the code generated in inssel.brg */
5139                 mono_get_got_var (cfg);
5140
5141                 MONO_INST_NEW (cfg, ins, CEE_CASTCLASS);
5142                 ins->type = STACK_OBJ;
5143                 ins->inst_left = *sp;
5144                 ins->klass = klass;
5145                 ins->inst_newa_class = klass;
5146                 if (inst_is_castclass)
5147                         ins->backend.record_cast_details = debug_options.better_cast_details;
5148                 if (inst_is_castclass)
5149                         *sp++ = emit_tree (cfg, bblock, ins, ip + 5);
5150                 else
5151                         *sp++ = ins;
5152                 ip += 5;
5153         }
5154
5155 do_return:
5156         *_bblock = bblock;
5157         *_ip = ip;
5158         *_sp = sp;
5159         *_inline_costs = inline_costs;
5160         *_real_offset = real_offset;
5161         return return_value;
5162 exception_exit:
5163         return_value = -2;
5164         goto do_return;
5165 unverified:
5166         return_value = -1;
5167         goto do_return;
5168 }
5169
5170 static int
5171 emit_unbox (MonoClass *klass, guint32 token, int context_used,
5172                 MonoCompile *cfg, MonoMethod *method, MonoInst **arg_array, MonoType **param_types, GList *dont_inline,
5173                 unsigned char *end, MonoMethodHeader *header, MonoGenericContext *generic_context,
5174                 MonoBasicBlock **_bblock, unsigned char **_ip, MonoInst ***_sp, int *_inline_costs, guint *_real_offset)
5175 {
5176         MonoBasicBlock *bblock = *_bblock;
5177         unsigned char *ip = *_ip;
5178         MonoInst **sp = *_sp;
5179         int inline_costs = *_inline_costs;
5180         guint real_offset = *_real_offset;
5181         int return_value = 0;
5182
5183         MonoInst *add, *vtoffset, *ins;
5184
5185         /* Needed by the code generated in inssel.brg */
5186         mono_get_got_var (cfg);
5187
5188         if (context_used) {
5189                 MonoInst *rgctx, *element_class;
5190
5191                 /* This assertion is from the unboxcast insn */
5192                 g_assert (klass->rank == 0);
5193
5194                 GET_RGCTX (rgctx, context_used);
5195                 element_class = get_runtime_generic_context_ptr (cfg, method, context_used, bblock,
5196                                 klass->element_class, generic_context, rgctx, MONO_RGCTX_INFO_KLASS, ip);
5197
5198                 MONO_INST_NEW (cfg, ins, OP_UNBOXCAST_REG);
5199                 ins->type = STACK_OBJ;
5200                 ins->inst_left = *sp;
5201                 ins->inst_right = element_class;
5202                 ins->klass = klass;
5203                 ins->cil_code = ip;
5204         } else {
5205                 MONO_INST_NEW (cfg, ins, OP_UNBOXCAST);
5206                 ins->type = STACK_OBJ;
5207                 ins->inst_left = *sp;
5208                 ins->klass = klass;
5209                 ins->inst_newa_class = klass;
5210                 ins->cil_code = ip;
5211         }
5212
5213         MONO_INST_NEW (cfg, add, OP_PADD);
5214         NEW_ICONST (cfg, vtoffset, sizeof (MonoObject));
5215         add->inst_left = ins;
5216         add->inst_right = vtoffset;
5217         add->type = STACK_MP;
5218         add->klass = klass;
5219         *sp = add;
5220
5221 do_return:
5222         *_bblock = bblock;
5223         *_ip = ip;
5224         *_sp = sp;
5225         *_inline_costs = inline_costs;
5226         *_real_offset = real_offset;
5227         return return_value;
5228 exception_exit:
5229         return_value = -2;
5230         goto do_return;
5231 }
5232
5233 gboolean
5234 mini_assembly_can_skip_verification (MonoDomain *domain, MonoMethod *method)
5235 {
5236         MonoAssembly *assembly = method->klass->image->assembly;
5237         if (method->wrapper_type != MONO_WRAPPER_NONE)
5238                 return FALSE;
5239         if (assembly->in_gac || assembly->image == mono_defaults.corlib)
5240                 return FALSE;
5241         if (mono_security_get_mode () != MONO_SECURITY_MODE_NONE)
5242                 return FALSE;
5243         return mono_assembly_has_skip_verification (assembly);
5244 }
5245
5246 /*
5247  * mini_method_verify:
5248  * 
5249  * Verify the method using the new verfier.
5250  * 
5251  * Returns true if the method is invalid. 
5252  */
5253 gboolean
5254 mini_method_verify (MonoCompile *cfg, MonoMethod *method)
5255 {
5256         GSList *tmp, *res;
5257         gboolean is_fulltrust;
5258         MonoLoaderError *error;
5259
5260         if (method->verification_success)
5261                 return FALSE;
5262
5263         is_fulltrust = mono_verifier_is_method_full_trust (method);
5264
5265         if (!mono_verifier_is_enabled_for_method (method))
5266                 return FALSE;
5267
5268         res = mono_method_verify_with_current_settings (method, cfg->skip_visibility);
5269
5270         if ((error = mono_loader_get_last_error ())) {
5271                 cfg->exception_type = error->exception_type;
5272                 if (res)
5273                         mono_free_verify_list (res);
5274                 return TRUE;
5275         }
5276
5277         if (res) { 
5278                 for (tmp = res; tmp; tmp = tmp->next) {
5279                         MonoVerifyInfoExtended *info = (MonoVerifyInfoExtended *)tmp->data;
5280                         if (info->info.status == MONO_VERIFY_ERROR) {
5281                                 cfg->exception_type = info->exception_type;
5282                                 cfg->exception_message = g_strdup (info->info.message);
5283                                 mono_free_verify_list (res);
5284                                 return TRUE;
5285                         }
5286                         if (info->info.status == MONO_VERIFY_NOT_VERIFIABLE && !is_fulltrust) {
5287                                 cfg->exception_type = info->exception_type;
5288                                 cfg->exception_message = g_strdup (info->info.message);
5289                                 mono_free_verify_list (res);
5290                                 return TRUE;
5291                         }
5292                 }
5293                 mono_free_verify_list (res);
5294         }
5295         method->verification_success = 1;
5296         return FALSE;
5297 }
5298
5299 /*
5300  * mono_method_to_ir: translates IL into basic blocks containing trees
5301  */
5302 static int
5303 mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock, 
5304                    int locals_offset, MonoInst *return_var, GList *dont_inline, MonoInst **inline_args, 
5305                    guint inline_offset, gboolean is_virtual_call)
5306 {
5307         MonoInst *zero_int32, *zero_int64, *zero_ptr, *zero_obj, *zero_r8;
5308         MonoInst *ins, **sp, **stack_start;
5309         MonoBasicBlock *bblock, *tblock = NULL, *init_localsbb = NULL;
5310         MonoMethod *cmethod, *method_definition;
5311         MonoInst **arg_array;
5312         MonoMethodHeader *header;
5313         MonoImage *image;
5314         guint32 token, ins_flag;
5315         MonoClass *klass;
5316         MonoClass *constrained_call = NULL;
5317         unsigned char *ip, *end, *target, *err_pos;
5318         static double r8_0 = 0.0;
5319         MonoMethodSignature *sig;
5320         MonoGenericContext *generic_context = NULL;
5321         MonoGenericContainer *generic_container = NULL;
5322         MonoType **param_types;
5323         GList *bb_recheck = NULL, *tmp;
5324         int i, n, start_new_bblock, ialign;
5325         int num_calls = 0, inline_costs = 0;
5326         int breakpoint_id = 0;
5327         guint32 align;
5328         guint real_offset, num_args;
5329         MonoBoolean security, pinvoke;
5330         MonoSecurityManager* secman = NULL;
5331         MonoDeclSecurityActions actions;
5332         GSList *class_inits = NULL;
5333         gboolean dont_verify, dont_verify_stloc, readonly = FALSE;
5334         int context_used;
5335
5336         /* serialization and xdomain stuff may need access to private fields and methods */
5337         dont_verify = method->klass->image->assembly->corlib_internal? TRUE: FALSE;
5338         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE;
5339         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH;
5340         dont_verify |= method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE; /* bug #77896 */
5341         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP;
5342         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP_INVOKE;
5343
5344         /* turn off visibility checks for smcs */
5345         dont_verify |= mono_security_get_mode () == MONO_SECURITY_MODE_SMCS_HACK;
5346
5347         /* still some type unsafety issues in marshal wrappers... (unknown is PtrToStructure) */
5348         dont_verify_stloc = method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE;
5349         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_UNKNOWN;
5350         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED;
5351
5352         image = method->klass->image;
5353         header = mono_method_get_header (method);
5354         generic_container = mono_method_get_generic_container (method);
5355         sig = mono_method_signature (method);
5356         num_args = sig->hasthis + sig->param_count;
5357         ip = (unsigned char*)header->code;
5358         cfg->cil_start = ip;
5359         end = ip + header->code_size;
5360         mono_jit_stats.cil_code_size += header->code_size;
5361
5362         method_definition = method;
5363         while (method_definition->is_inflated) {
5364                 MonoMethodInflated *imethod = (MonoMethodInflated *) method_definition;
5365                 method_definition = imethod->declaring;
5366         }
5367
5368         /* SkipVerification is not allowed if core-clr is enabled */
5369         if (!dont_verify && mini_assembly_can_skip_verification (cfg->domain, method)) {
5370                 dont_verify = TRUE;
5371                 dont_verify_stloc = TRUE;
5372         }
5373
5374         if (!dont_verify && mini_method_verify (cfg, method_definition))
5375                 goto exception_exit;
5376
5377         if (sig->is_inflated)
5378                 generic_context = mono_method_get_context (method);
5379         else if (generic_container)
5380                 generic_context = &generic_container->context;
5381
5382         if (!cfg->generic_sharing_context)
5383                 g_assert (!sig->has_type_parameters);
5384
5385         if (sig->generic_param_count && method->wrapper_type == MONO_WRAPPER_NONE) {
5386                 g_assert (method->is_inflated);
5387                 g_assert (mono_method_get_context (method)->method_inst);
5388         }
5389         if (method->is_inflated && mono_method_get_context (method)->method_inst)
5390                 g_assert (sig->generic_param_count);
5391
5392         if (cfg->method == method)
5393                 real_offset = 0;
5394         else
5395                 real_offset = inline_offset;
5396
5397         cfg->cil_offset_to_bb = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoBasicBlock*) * header->code_size);
5398         cfg->cil_offset_to_bb_len = header->code_size;
5399
5400         if (cfg->verbose_level > 2)
5401                 g_print ("method to IR %s\n", mono_method_full_name (method, TRUE));
5402
5403         dont_inline = g_list_prepend (dont_inline, method);
5404         if (cfg->method == method) {
5405
5406                 if (cfg->prof_options & MONO_PROFILE_INS_COVERAGE)
5407                         cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, header->code_size);
5408
5409                 /* ENTRY BLOCK */
5410                 cfg->bb_entry = start_bblock = NEW_BBLOCK (cfg);
5411                 start_bblock->cil_code = NULL;
5412                 start_bblock->cil_length = 0;
5413                 start_bblock->block_num = cfg->num_bblocks++;
5414
5415                 /* EXIT BLOCK */
5416                 cfg->bb_exit = end_bblock = NEW_BBLOCK (cfg);
5417                 end_bblock->cil_code = NULL;
5418                 end_bblock->cil_length = 0;
5419                 end_bblock->block_num = cfg->num_bblocks++;
5420                 g_assert (cfg->num_bblocks == 2);
5421
5422                 arg_array = alloca (sizeof (MonoInst *) * num_args);
5423                 for (i = num_args - 1; i >= 0; i--)
5424                         arg_array [i] = cfg->varinfo [i];
5425
5426                 if (header->num_clauses) {
5427                         cfg->spvars = g_hash_table_new (NULL, NULL);
5428                         cfg->exvars = g_hash_table_new (NULL, NULL);
5429                 }
5430                 /* handle exception clauses */
5431                 for (i = 0; i < header->num_clauses; ++i) {
5432                         MonoBasicBlock *try_bb;
5433                         MonoExceptionClause *clause = &header->clauses [i];
5434
5435                         GET_BBLOCK (cfg, try_bb, ip + clause->try_offset);
5436                         try_bb->real_offset = clause->try_offset;
5437                         GET_BBLOCK (cfg, tblock, ip + clause->handler_offset);
5438                         tblock->real_offset = clause->handler_offset;
5439                         tblock->flags |= BB_EXCEPTION_HANDLER;
5440
5441                         link_bblock (cfg, try_bb, tblock);
5442
5443                         if (*(ip + clause->handler_offset) == CEE_POP)
5444                                 tblock->flags |= BB_EXCEPTION_DEAD_OBJ;
5445
5446                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY ||
5447                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER ||
5448                             clause->flags == MONO_EXCEPTION_CLAUSE_FAULT) {
5449                                 MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
5450                                 MONO_ADD_INS (tblock, ins);
5451
5452                                 /* todo: is a fault block unsafe to optimize? */
5453                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
5454                                         tblock->flags |= BB_EXCEPTION_UNSAFE;
5455                         }
5456
5457
5458                         /*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);
5459                           while (p < end) {
5460                           g_print ("%s", mono_disasm_code_one (NULL, method, p, &p));
5461                           }*/
5462                         /* catch and filter blocks get the exception object on the stack */
5463                         if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE ||
5464                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
5465                                 MonoInst *load, *dummy_use;
5466
5467                                 /* mostly like handle_stack_args (), but just sets the input args */
5468                                 /* g_print ("handling clause at IL_%04x\n", clause->handler_offset); */
5469                                 tblock->in_scount = 1;
5470                                 tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
5471                                 tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
5472
5473                                 /* 
5474                                  * Add a dummy use for the exvar so its liveness info will be
5475                                  * correct.
5476                                  */
5477                                 NEW_TEMPLOAD (cfg, load, tblock->in_stack [0]->inst_c0);
5478                                 NEW_DUMMY_USE (cfg, dummy_use, load);
5479                                 MONO_ADD_INS (tblock, dummy_use);
5480                                 
5481                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
5482                                         GET_BBLOCK (cfg, tblock, ip + clause->data.filter_offset);
5483                                         tblock->real_offset = clause->data.filter_offset;
5484                                         tblock->in_scount = 1;
5485                                         tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
5486                                         /* The filter block shares the exvar with the handler block */
5487                                         tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
5488                                         MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
5489                                         MONO_ADD_INS (tblock, ins);
5490                                 }
5491                         }
5492
5493                         if (clause->flags != MONO_EXCEPTION_CLAUSE_FILTER &&
5494                                         clause->data.catch_class &&
5495                                         cfg->generic_sharing_context &&
5496                                         mono_class_check_context_used (clause->data.catch_class)) {
5497                                 if (mono_method_get_context (method)->method_inst)
5498                                         GENERIC_SHARING_FAILURE (CEE_NOP);
5499
5500                                 /*
5501                                  * In shared generic code with catch
5502                                  * clauses containing type variables
5503                                  * the exception handling code has to
5504                                  * be able to get to the rgctx.
5505                                  * Therefore we have to make sure that
5506                                  * the vtable/mrgctx argument (for
5507                                  * static or generic methods) or the
5508                                  * "this" argument (for non-static
5509                                  * methods) are live.
5510                                  */
5511                                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
5512                                                 mini_method_get_context (method)->method_inst) {
5513                                         mono_get_vtable_var (cfg);
5514                                 } else {
5515                                         MonoInst *this, *dummy_use;
5516                                         MonoType *this_type;
5517
5518                                         if (method->klass->valuetype)
5519                                                 this_type = &method->klass->this_arg;
5520                                         else
5521                                                 this_type = &method->klass->byval_arg;
5522
5523                                         if (arg_array [0]->opcode == OP_ICONST) {
5524                                                 this = arg_array [0];
5525                                         } else {
5526                                                 this = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));
5527                                                 this->ssa_op = MONO_SSA_LOAD;
5528                                                 this->inst_i0 = arg_array [0];
5529                                                 this->opcode = mini_type_to_ldind ((cfg), this->inst_i0->inst_vtype);
5530                                                 type_to_eval_stack_type ((cfg), this_type, this);
5531                                                 this->klass = this->inst_i0->klass;
5532                                         }
5533
5534                                         NEW_DUMMY_USE (cfg, dummy_use, this);
5535                                         MONO_ADD_INS (tblock, dummy_use);
5536                                 }
5537                         }
5538                 }
5539         } else {
5540                 arg_array = alloca (sizeof (MonoInst *) * num_args);
5541                 mono_save_args (cfg, start_bblock, sig, inline_args, arg_array);
5542         }
5543
5544         /* FIRST CODE BLOCK */
5545         bblock = NEW_BBLOCK (cfg);
5546         bblock->cil_code = ip;
5547
5548         ADD_BBLOCK (cfg, bblock);
5549
5550         if (cfg->method == method) {
5551                 breakpoint_id = mono_debugger_method_has_breakpoint (method);
5552                 if (breakpoint_id && (mono_debug_format != MONO_DEBUG_FORMAT_DEBUGGER)) {
5553                         MONO_INST_NEW (cfg, ins, OP_BREAK);
5554                         MONO_ADD_INS (bblock, ins);
5555                 }
5556         }
5557
5558         if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS)
5559                 secman = mono_security_manager_get_methods ();
5560
5561         security = (secman && mono_method_has_declsec (method));
5562         /* at this point having security doesn't mean we have any code to generate */
5563         if (security && (cfg->method == method)) {
5564                 /* Only Demand, NonCasDemand and DemandChoice requires code generation.
5565                  * And we do not want to enter the next section (with allocation) if we
5566                  * have nothing to generate */
5567                 security = mono_declsec_get_demands (method, &actions);
5568         }
5569
5570         /* we must Demand SecurityPermission.Unmanaged before P/Invoking */
5571         pinvoke = (secman && (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE));
5572         if (pinvoke) {
5573                 MonoMethod *wrapped = mono_marshal_method_from_wrapper (method);
5574                 if (wrapped && (wrapped->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
5575                         MonoCustomAttrInfo* custom = mono_custom_attrs_from_method (wrapped);
5576
5577                         /* unless the method or it's class has the [SuppressUnmanagedCodeSecurity] attribute */
5578                         if (custom && mono_custom_attrs_has_attr (custom, secman->suppressunmanagedcodesecurity)) {
5579                                 pinvoke = FALSE;
5580                         }
5581                         if (custom)
5582                                 mono_custom_attrs_free (custom);
5583
5584                         if (pinvoke) {
5585                                 custom = mono_custom_attrs_from_class (wrapped->klass);
5586                                 if (custom && mono_custom_attrs_has_attr (custom, secman->suppressunmanagedcodesecurity)) {
5587                                         pinvoke = FALSE;
5588                                 }
5589                                 if (custom)
5590                                         mono_custom_attrs_free (custom);
5591                         }
5592                 } else {
5593                         /* not a P/Invoke after all */
5594                         pinvoke = FALSE;
5595                 }
5596         }
5597         
5598         if ((header->init_locals || (cfg->method == method && (cfg->opt & MONO_OPT_SHARED))) || cfg->compile_aot || security || pinvoke) {
5599                 /* we use a separate basic block for the initialization code */
5600                 cfg->bb_init = init_localsbb = NEW_BBLOCK (cfg);
5601                 init_localsbb->real_offset = real_offset;
5602                 start_bblock->next_bb = init_localsbb;
5603                 init_localsbb->next_bb = bblock;
5604                 link_bblock (cfg, start_bblock, init_localsbb);
5605                 link_bblock (cfg, init_localsbb, bblock);
5606                 init_localsbb->block_num = cfg->num_bblocks++;
5607         } else {
5608                 start_bblock->next_bb = bblock;
5609                 link_bblock (cfg, start_bblock, bblock);
5610         }
5611
5612         /* at this point we know, if security is TRUE, that some code needs to be generated */
5613         if (security && (cfg->method == method)) {
5614                 MonoInst *args [2];
5615
5616                 mono_jit_stats.cas_demand_generation++;
5617
5618                 if (actions.demand.blob) {
5619                         /* Add code for SecurityAction.Demand */
5620                         NEW_DECLSECCONST (cfg, args[0], image, actions.demand);
5621                         NEW_ICONST (cfg, args [1], actions.demand.size);
5622                         /* Calls static void SecurityManager.InternalDemand (byte* permissions, int size); */
5623                         mono_emit_method_call_spilled (cfg, init_localsbb, secman->demand, mono_method_signature (secman->demand), args, ip, NULL);
5624                 }
5625                 if (actions.noncasdemand.blob) {
5626                         /* CLR 1.x uses a .noncasdemand (but 2.x doesn't) */
5627                         /* For Mono we re-route non-CAS Demand to Demand (as the managed code must deal with it anyway) */
5628                         NEW_DECLSECCONST (cfg, args[0], image, actions.noncasdemand);
5629                         NEW_ICONST (cfg, args [1], actions.noncasdemand.size);
5630                         /* Calls static void SecurityManager.InternalDemand (byte* permissions, int size); */
5631                         mono_emit_method_call_spilled (cfg, init_localsbb, secman->demand, mono_method_signature (secman->demand), args, ip, NULL);
5632                 }
5633                 if (actions.demandchoice.blob) {
5634                         /* New in 2.0, Demand must succeed for one of the permissions (i.e. not all) */
5635                         NEW_DECLSECCONST (cfg, args[0], image, actions.demandchoice);
5636                         NEW_ICONST (cfg, args [1], actions.demandchoice.size);
5637                         /* Calls static void SecurityManager.InternalDemandChoice (byte* permissions, int size); */
5638                         mono_emit_method_call_spilled (cfg, init_localsbb, secman->demandchoice, mono_method_signature (secman->demandchoice), args, ip, NULL);
5639                 }
5640         }
5641
5642         /* we must Demand SecurityPermission.Unmanaged before p/invoking */
5643         if (pinvoke) {
5644                 mono_emit_method_call_spilled (cfg, init_localsbb, secman->demandunmanaged, mono_method_signature (secman->demandunmanaged), NULL, ip, NULL);
5645         }
5646
5647         if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR) {
5648                 if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
5649                         MonoMethod *wrapped = mono_marshal_method_from_wrapper (method);
5650                         if (wrapped && (wrapped->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
5651                                 if (!(method->klass && method->klass->image &&
5652                                                 mono_security_core_clr_is_platform_image (method->klass->image))) {
5653                                         emit_throw_method_access_exception (cfg, method, wrapped, bblock, ip);
5654                                 }
5655                         }
5656                 }
5657                 if (!method_is_safe (method))
5658                         emit_throw_verification_exception (cfg, bblock, ip);
5659         }
5660
5661         if (header->code_size == 0)
5662                 UNVERIFIED;
5663
5664         if (get_basic_blocks (cfg, header, real_offset, ip, end, &err_pos)) {
5665                 ip = err_pos;
5666                 UNVERIFIED;
5667         }
5668
5669         if (cfg->method == method)
5670                 mono_debug_init_method (cfg, bblock, breakpoint_id);
5671
5672         param_types = mono_mempool_alloc (cfg->mempool, sizeof (MonoType*) * num_args);
5673         if (sig->hasthis)
5674                 param_types [0] = method->klass->valuetype?&method->klass->this_arg:&method->klass->byval_arg;
5675         for (n = 0; n < sig->param_count; ++n)
5676                 param_types [n + sig->hasthis] = sig->params [n];
5677         for (n = 0; n < header->num_locals; ++n) {
5678                 if (header->locals [n]->type == MONO_TYPE_VOID && !header->locals [n]->byref)
5679                         UNVERIFIED;
5680         }
5681         class_inits = NULL;
5682
5683         /* do this somewhere outside - not here */
5684         NEW_ICONST (cfg, zero_int32, 0);
5685         NEW_ICONST (cfg, zero_int64, 0);
5686         zero_int64->type = STACK_I8;
5687         NEW_PCONST (cfg, zero_ptr, 0);
5688         NEW_PCONST (cfg, zero_obj, 0);
5689         zero_obj->type = STACK_OBJ;
5690
5691         MONO_INST_NEW (cfg, zero_r8, OP_R8CONST);
5692         zero_r8->type = STACK_R8;
5693         zero_r8->inst_p0 = &r8_0;
5694
5695         /* add a check for this != NULL to inlined methods */
5696         if (is_virtual_call) {
5697                 MONO_INST_NEW (cfg, ins, OP_CHECK_THIS);
5698                 NEW_ARGLOAD (cfg, ins->inst_left, 0);
5699                 ins->cil_code = ip;
5700                 MONO_ADD_INS (bblock, ins);
5701         }
5702
5703         /* we use a spare stack slot in SWITCH and NEWOBJ and others */
5704         stack_start = sp = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (header->max_stack + 1));
5705
5706         ins_flag = 0;
5707         start_new_bblock = 0;
5708         while (ip < end) {
5709
5710                 if (cfg->method == method)
5711                         real_offset = ip - header->code;
5712                 else
5713                         real_offset = inline_offset;
5714                 cfg->ip = ip;
5715
5716                 context_used = 0;
5717
5718                 if (start_new_bblock) {
5719                         bblock->cil_length = ip - bblock->cil_code;
5720                         if (start_new_bblock == 2) {
5721                                 g_assert (ip == tblock->cil_code);
5722                         } else {
5723                                 GET_BBLOCK (cfg, tblock, ip);
5724                         }
5725                         bblock->next_bb = tblock;
5726                         bblock = tblock;
5727                         start_new_bblock = 0;
5728                         for (i = 0; i < bblock->in_scount; ++i) {
5729                                 if (cfg->verbose_level > 3)
5730                                         g_print ("loading %d from temp %d\n", i, (int)bblock->in_stack [i]->inst_c0);                                           
5731                                 NEW_TEMPLOAD (cfg, ins, bblock->in_stack [i]->inst_c0);
5732                                 *sp++ = ins;
5733                         }
5734                         g_slist_free (class_inits);
5735                         class_inits = NULL;
5736                 } else {
5737                         if ((tblock = cfg->cil_offset_to_bb [ip - cfg->cil_start]) && (tblock != bblock)) {
5738                                 link_bblock (cfg, bblock, tblock);
5739                                 if (sp != stack_start) {
5740                                         handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
5741                                         sp = stack_start;
5742                                         CHECK_UNVERIFIABLE (cfg);
5743                                 }
5744                                 bblock->next_bb = tblock;
5745                                 bblock = tblock;
5746                                 for (i = 0; i < bblock->in_scount; ++i) {
5747                                         if (cfg->verbose_level > 3)
5748                                                 g_print ("loading %d from temp %d\n", i, (int)bblock->in_stack [i]->inst_c0);                                           
5749                                         NEW_TEMPLOAD (cfg, ins, bblock->in_stack [i]->inst_c0);
5750                                         *sp++ = ins;
5751                                 }
5752                                 g_slist_free (class_inits);
5753                                 class_inits = NULL;
5754                         }
5755                 }
5756
5757                 bblock->real_offset = real_offset;
5758
5759                 if ((cfg->method == method) && cfg->coverage_info) {
5760                         MonoInst *store, *one;
5761                         guint32 cil_offset = ip - header->code;
5762                         cfg->coverage_info->data [cil_offset].cil_code = ip;
5763
5764                         /* TODO: Use an increment here */
5765                         NEW_ICONST (cfg, one, 1);
5766                         one->cil_code = ip;
5767
5768                         NEW_PCONST (cfg, ins, &(cfg->coverage_info->data [cil_offset].count));
5769                         ins->cil_code = ip;
5770
5771                         MONO_INST_NEW (cfg, store, CEE_STIND_I);
5772                         store->inst_left = ins;
5773                         store->inst_right = one;
5774
5775                         MONO_ADD_INS (bblock, store);
5776                 }
5777
5778                 if (cfg->verbose_level > 3)
5779                         g_print ("converting (in B%d: stack: %d) %s", bblock->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
5780
5781                 switch (*ip) {
5782                 case CEE_NOP:
5783                         MONO_INST_NEW (cfg, ins, OP_NOP);
5784                         ip++;
5785                         MONO_ADD_INS (bblock, ins);
5786                         break;
5787                 case CEE_BREAK:
5788                         MONO_INST_NEW (cfg, ins, OP_BREAK);
5789                         ip++;
5790                         MONO_ADD_INS (bblock, ins);
5791                         break;
5792                 case CEE_LDARG_0:
5793                 case CEE_LDARG_1:
5794                 case CEE_LDARG_2:
5795                 case CEE_LDARG_3:
5796                         CHECK_STACK_OVF (1);
5797                         n = (*ip)-CEE_LDARG_0;
5798                         CHECK_ARG (n);
5799                         NEW_ARGLOAD (cfg, ins, n);
5800                         LDARG_SOFT_FLOAT (cfg, ins, n, ip);
5801                         ip++;
5802                         *sp++ = ins;
5803                         break;
5804                 case CEE_LDLOC_0:
5805                 case CEE_LDLOC_1:
5806                 case CEE_LDLOC_2:
5807                 case CEE_LDLOC_3:
5808                         CHECK_STACK_OVF (1);
5809                         n = (*ip)-CEE_LDLOC_0;
5810                         CHECK_LOCAL (n);
5811                         NEW_LOCLOAD (cfg, ins, n);
5812                         LDLOC_SOFT_FLOAT (cfg, ins, n, ip);
5813                         ip++;
5814                         *sp++ = ins;
5815                         break;
5816                 case CEE_STLOC_0:
5817                 case CEE_STLOC_1:
5818                 case CEE_STLOC_2:
5819                 case CEE_STLOC_3:
5820                         CHECK_STACK (1);
5821                         n = (*ip)-CEE_STLOC_0;
5822                         CHECK_LOCAL (n);
5823                         --sp;
5824                         handle_loaded_temps (cfg, bblock, stack_start, sp);
5825                         NEW_LOCSTORE (cfg, ins, n, *sp);
5826                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
5827                                 UNVERIFIED;
5828                         STLOC_SOFT_FLOAT (cfg, ins, n, ip);
5829                         if (ins->opcode == CEE_STOBJ) {
5830                                 NEW_LOCLOADA (cfg, ins, n);
5831                                 handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE, FALSE);
5832                         } else
5833                                 MONO_ADD_INS (bblock, ins);
5834                         ++ip;
5835                         inline_costs += 1;
5836                         break;
5837                 case CEE_LDARG_S:
5838                         CHECK_OPSIZE (2);
5839                         CHECK_STACK_OVF (1);
5840                         CHECK_ARG (ip [1]);
5841                         NEW_ARGLOAD (cfg, ins, ip [1]);
5842                         LDARG_SOFT_FLOAT (cfg, ins, ip [1], ip);
5843                         *sp++ = ins;
5844                         ip += 2;
5845                         break;
5846                 case CEE_LDARGA_S:
5847                         CHECK_OPSIZE (2);
5848                         CHECK_STACK_OVF (1);
5849                         CHECK_ARG (ip [1]);
5850                         NEW_ARGLOADA (cfg, ins, ip [1]);
5851                         *sp++ = ins;
5852                         ip += 2;
5853                         break;
5854                 case CEE_STARG_S:
5855                         CHECK_OPSIZE (2);
5856                         CHECK_STACK (1);
5857                         --sp;
5858                         CHECK_ARG (ip [1]);
5859                         NEW_ARGSTORE (cfg, ins, ip [1], *sp);
5860                         handle_loaded_temps (cfg, bblock, stack_start, sp);
5861                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [ip [1]], *sp))
5862                                 UNVERIFIED;
5863                         STARG_SOFT_FLOAT (cfg, ins, ip [1], ip);
5864                         if (ins->opcode == CEE_STOBJ) {
5865                                 NEW_ARGLOADA (cfg, ins, ip [1]);
5866                                 handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE, FALSE);
5867                         } else
5868                                 MONO_ADD_INS (bblock, ins);
5869                         ip += 2;
5870                         break;
5871                 case CEE_LDLOC_S:
5872                         CHECK_OPSIZE (2);
5873                         CHECK_STACK_OVF (1);
5874                         CHECK_LOCAL (ip [1]);
5875                         NEW_LOCLOAD (cfg, ins, ip [1]);
5876                         LDLOC_SOFT_FLOAT (cfg, ins, ip [1], ip);
5877                         *sp++ = ins;
5878                         ip += 2;
5879                         break;
5880                 case CEE_LDLOCA_S:
5881                         CHECK_OPSIZE (2);
5882                         CHECK_STACK_OVF (1);
5883                         CHECK_LOCAL (ip [1]);
5884                         NEW_LOCLOADA (cfg, ins, ip [1]);
5885                         *sp++ = ins;
5886                         ip += 2;
5887                         break;
5888                 case CEE_STLOC_S:
5889                         CHECK_OPSIZE (2);
5890                         CHECK_STACK (1);
5891                         --sp;
5892                         handle_loaded_temps (cfg, bblock, stack_start, sp);
5893                         CHECK_LOCAL (ip [1]);
5894                         NEW_LOCSTORE (cfg, ins, ip [1], *sp);
5895                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [ip [1]], *sp))
5896                                 UNVERIFIED;
5897                         STLOC_SOFT_FLOAT (cfg, ins, ip [1], ip);
5898                         if (ins->opcode == CEE_STOBJ) {
5899                                 NEW_LOCLOADA (cfg, ins, ip [1]);
5900                                 handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE, FALSE);
5901                         } else
5902                                 MONO_ADD_INS (bblock, ins);
5903                         ip += 2;
5904                         inline_costs += 1;
5905                         break;
5906                 case CEE_LDNULL:
5907                         CHECK_STACK_OVF (1);
5908                         NEW_PCONST (cfg, ins, NULL);
5909                         ins->type = STACK_OBJ;
5910                         ++ip;
5911                         *sp++ = ins;
5912                         break;
5913                 case CEE_LDC_I4_M1:
5914                         CHECK_STACK_OVF (1);
5915                         NEW_ICONST (cfg, ins, -1);
5916                         ++ip;
5917                         *sp++ = ins;
5918                         break;
5919                 case CEE_LDC_I4_0:
5920                 case CEE_LDC_I4_1:
5921                 case CEE_LDC_I4_2:
5922                 case CEE_LDC_I4_3:
5923                 case CEE_LDC_I4_4:
5924                 case CEE_LDC_I4_5:
5925                 case CEE_LDC_I4_6:
5926                 case CEE_LDC_I4_7:
5927                 case CEE_LDC_I4_8:
5928                         CHECK_STACK_OVF (1);
5929                         NEW_ICONST (cfg, ins, (*ip) - CEE_LDC_I4_0);
5930                         ++ip;
5931                         *sp++ = ins;
5932                         break;
5933                 case CEE_LDC_I4_S:
5934                         CHECK_OPSIZE (2);
5935                         CHECK_STACK_OVF (1);
5936                         ++ip;
5937                         NEW_ICONST (cfg, ins, *((signed char*)ip));
5938                         ++ip;
5939                         *sp++ = ins;
5940                         break;
5941                 case CEE_LDC_I4:
5942                         CHECK_OPSIZE (5);
5943                         CHECK_STACK_OVF (1);
5944                         NEW_ICONST (cfg, ins, (gint32)read32 (ip + 1));
5945                         ip += 5;
5946                         *sp++ = ins;
5947                         break;
5948                 case CEE_LDC_I8:
5949                         CHECK_OPSIZE (9);
5950                         CHECK_STACK_OVF (1);
5951                         MONO_INST_NEW (cfg, ins, OP_I8CONST);
5952                         ins->type = STACK_I8;
5953                         ++ip;
5954                         ins->inst_l = (gint64)read64 (ip);
5955                         ip += 8;
5956                         *sp++ = ins;
5957                         break;
5958                 case CEE_LDC_R4: {
5959                         float *f;
5960                         /* we should really allocate this only late in the compilation process */
5961                         mono_domain_lock (cfg->domain);
5962                         f = mono_mempool_alloc (cfg->domain->mp, sizeof (float));
5963                         mono_domain_unlock (cfg->domain);
5964                         CHECK_OPSIZE (5);
5965                         CHECK_STACK_OVF (1);
5966                         MONO_INST_NEW (cfg, ins, OP_R4CONST);
5967                         ins->type = STACK_R8;
5968                         ++ip;
5969                         readr4 (ip, f);
5970                         ins->inst_p0 = f;
5971
5972                         ip += 4;
5973                         *sp++ = ins;                    
5974                         break;
5975                 }
5976                 case CEE_LDC_R8: {
5977                         double *d;
5978                         mono_domain_lock (cfg->domain);
5979                         d = mono_mempool_alloc (cfg->domain->mp, sizeof (double));
5980                         mono_domain_unlock (cfg->domain);
5981                         CHECK_OPSIZE (9);
5982                         CHECK_STACK_OVF (1);
5983                         MONO_INST_NEW (cfg, ins, OP_R8CONST);
5984                         ins->type = STACK_R8;
5985                         ++ip;
5986                         readr8 (ip, d);
5987                         ins->inst_p0 = d;
5988
5989                         ip += 8;
5990                         *sp++ = ins;                    
5991                         break;
5992                 }
5993                 case CEE_DUP: {
5994                         MonoInst *temp, *store;
5995                         CHECK_STACK (1);
5996                         CHECK_STACK_OVF (1);
5997                         sp--;
5998                         ins = *sp;
5999                 
6000                         /* 
6001                          * small optimization: if the loaded value was from a local already,
6002                          * just load it twice.
6003                          */
6004                         if (ins->ssa_op == MONO_SSA_LOAD && 
6005                             (ins->inst_i0->opcode == OP_LOCAL || ins->inst_i0->opcode == OP_ARG)) {
6006                                 sp++;
6007                                 MONO_INST_NEW (cfg, temp, 0);
6008                                 *temp = *ins;
6009                                 *sp++ = temp;
6010                         } else {
6011                                 temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
6012                                 temp->flags |= MONO_INST_IS_TEMP;
6013                                 NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
6014                                 /* FIXME: handle CEE_STIND_R4 */
6015                                 if (store->opcode == CEE_STOBJ) {
6016                                         NEW_TEMPLOADA (cfg, store, temp->inst_c0);
6017                                         handle_stobj (cfg, bblock, store, sp [0], sp [0]->cil_code, store->klass, TRUE, FALSE, FALSE);
6018                                 } else {
6019                                         MONO_ADD_INS (bblock, store);
6020                                 }
6021                                 NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
6022                                 *sp++ = ins;
6023                                 NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
6024                                 *sp++ = ins;
6025                         }
6026                         ++ip;
6027                         inline_costs += 2;
6028                         break;
6029                 }
6030                 case CEE_POP:
6031                         CHECK_STACK (1);
6032                         MONO_INST_NEW (cfg, ins, CEE_POP);
6033                         MONO_ADD_INS (bblock, ins);
6034                         ip++;
6035                         --sp;
6036                         ins->inst_i0 = *sp;
6037                         break;
6038                 case CEE_JMP:
6039                         CHECK_OPSIZE (5);
6040                         if (stack_start != sp)
6041                                 UNVERIFIED;
6042                         MONO_INST_NEW (cfg, ins, OP_JMP);
6043                         token = read32 (ip + 1);
6044                         /* FIXME: check the signature matches */
6045                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
6046
6047                         if (!cmethod)
6048                                 goto load_error;
6049
6050                         if (cfg->generic_sharing_context && mono_method_check_context_used (cmethod))
6051                                 GENERIC_SHARING_FAILURE (CEE_JMP);
6052
6053                         if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS) {
6054                                 if (check_linkdemand (cfg, method, cmethod, bblock, ip))
6055                                         INLINE_FAILURE;
6056                                 CHECK_CFG_EXCEPTION;
6057                         }
6058
6059                         ins->inst_p0 = cmethod;
6060                         MONO_ADD_INS (bblock, ins);
6061                         ip += 5;
6062                         start_new_bblock = 1;
6063                         break;
6064                 case CEE_CALLI:
6065                 case CEE_CALL:
6066                 case CEE_CALLVIRT: {
6067                         MonoInst *addr = NULL;
6068                         MonoMethodSignature *fsig = NULL;
6069                         int temp, array_rank = 0;
6070                         int virtual = *ip == CEE_CALLVIRT;
6071                         gboolean no_spill;
6072                         gboolean pass_imt_from_rgctx = FALSE;
6073                         MonoInst *imt_arg = NULL;
6074                         gboolean pass_vtable = FALSE;
6075                         gboolean pass_mrgctx = FALSE;
6076                         MonoInst *vtable_arg = NULL;
6077                         gboolean check_this = FALSE;
6078
6079                         CHECK_OPSIZE (5);
6080                         token = read32 (ip + 1);
6081
6082                         if (*ip == CEE_CALLI) {
6083                                 cmethod = NULL;
6084                                 CHECK_STACK (1);
6085                                 --sp;
6086                                 addr = *sp;
6087                                 if (method->wrapper_type != MONO_WRAPPER_NONE)
6088                                         fsig = (MonoMethodSignature *)mono_method_get_wrapper_data (method, token);
6089                                 else
6090                                         fsig = mono_metadata_parse_signature (image, token);
6091
6092                                 n = fsig->param_count + fsig->hasthis;
6093                         } else {
6094                                 MonoMethod *cil_method;
6095                                 
6096                                 if (method->wrapper_type != MONO_WRAPPER_NONE) {
6097                                         cmethod =  (MonoMethod *)mono_method_get_wrapper_data (method, token);
6098                                         cil_method = cmethod;
6099                                 } else if (constrained_call) {
6100                                         cmethod = mono_get_method_constrained (image, token, constrained_call, generic_context, &cil_method);
6101                                         cil_method = cmethod;
6102                                 } else {
6103                                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
6104                                         cil_method = cmethod;
6105                                 }
6106
6107                                 if (!cmethod)
6108                                         goto load_error;
6109                                 if (!dont_verify && !cfg->skip_visibility) {
6110                                         MonoMethod *target_method = cil_method;
6111                                         if (method->is_inflated) {
6112                                                 target_method = mini_get_method_allow_open (method, token, NULL, &(mono_method_get_generic_container (method_definition)->context));
6113                                         }
6114                                         if (!mono_method_can_access_method (method_definition, target_method) &&
6115                                                 !mono_method_can_access_method (method, cil_method))
6116                                                 METHOD_ACCESS_FAILURE;
6117                                 }
6118
6119                                 if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR)
6120                                         ensure_method_is_allowed_to_call_method (cfg, method, cil_method, bblock, ip);
6121
6122                                 if (!virtual && (cmethod->flags & METHOD_ATTRIBUTE_ABSTRACT))
6123                                         /* MS.NET seems to silently convert this to a callvirt */
6124                                         virtual = 1;
6125
6126                                 if (!cmethod->klass->inited){
6127                                         if (!mono_class_init (cmethod->klass))
6128                                                 goto load_error;
6129                                 }
6130
6131                                 if (mono_method_signature (cmethod)->pinvoke) {
6132                                         MonoMethod *wrapper = mono_marshal_get_native_wrapper (cmethod, check_for_pending_exc, FALSE);
6133                                         fsig = mono_method_signature (wrapper);
6134                                 } else if (constrained_call) {
6135                                         fsig = mono_method_signature (cmethod);
6136                                 } else {
6137                                         fsig = mono_method_get_signature_full (cmethod, image, token, generic_context);
6138                                 }
6139
6140                                 mono_save_token_info (cfg, image, token, cmethod);
6141
6142                                 n = fsig->param_count + fsig->hasthis;
6143
6144                                 if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS) {
6145                                         if (check_linkdemand (cfg, method, cmethod, bblock, ip))
6146                                                 INLINE_FAILURE;
6147                                         CHECK_CFG_EXCEPTION;
6148                                 }
6149
6150                                 if (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL &&
6151                                     mini_class_is_system_array (cmethod->klass)) {
6152                                         array_rank = cmethod->klass->rank;
6153                                 }
6154
6155                                 if (cmethod->string_ctor)
6156                                         g_assert_not_reached ();
6157
6158                         }
6159
6160                         if (!cfg->generic_sharing_context && cmethod && cmethod->klass->generic_container)
6161                                 UNVERIFIED;
6162
6163                         if (!cfg->generic_sharing_context && cmethod)
6164                                 g_assert (!mono_method_check_context_used (cmethod));
6165
6166                         CHECK_STACK (n);
6167
6168                         //g_assert (!virtual || fsig->hasthis);
6169
6170                         sp -= n;
6171
6172                         if (constrained_call) {
6173                                 /*
6174                                  * We have the `constrained.' prefix opcode.
6175                                  */
6176                                 if (constrained_call->valuetype && !cmethod->klass->valuetype) {
6177                                         MonoInst *load;
6178                                         /*
6179                                          * The type parameter is instantiated as a valuetype,
6180                                          * but that type doesn't override the method we're
6181                                          * calling, so we need to box `this'.
6182                                          * sp [0] is a pointer to the data: we need the value
6183                                          * in handle_box (), so load it here.
6184                                          */
6185                                         MONO_INST_NEW (cfg, load, mini_type_to_ldind (cfg, &constrained_call->byval_arg));
6186                                         type_to_eval_stack_type (cfg, &constrained_call->byval_arg, load);
6187                                         load->inst_left = sp [0];
6188                                         sp [0] = handle_box (cfg, bblock, load, ip, constrained_call);
6189                                 } else if (!constrained_call->valuetype) {
6190                                         MonoInst *ins;
6191
6192                                         /*
6193                                          * The type parameter is instantiated as a reference
6194                                          * type.  We have a managed pointer on the stack, so
6195                                          * we need to dereference it here.
6196                                          */
6197
6198                                         MONO_INST_NEW (cfg, ins, CEE_LDIND_REF);
6199                                         ins->inst_i0 = sp [0];
6200                                         ins->type = STACK_OBJ;
6201                                         ins->klass = mono_class_from_mono_type (&constrained_call->byval_arg);
6202                                         sp [0] = ins;
6203                                 } else if (cmethod->klass->valuetype)
6204                                         virtual = 0;
6205                                 constrained_call = NULL;
6206                         }
6207
6208                         if (*ip != CEE_CALLI && check_call_signature (cfg, fsig, sp))
6209                                 UNVERIFIED;
6210
6211                         if (cmethod && (cmethod->flags & METHOD_ATTRIBUTE_STATIC) &&
6212                                         (cmethod->klass->generic_class || cmethod->klass->generic_container)) {
6213                                 gboolean sharing_enabled = mono_class_generic_sharing_enabled (cmethod->klass);
6214                                 MonoGenericContext *context = mini_class_get_context (cmethod->klass);
6215                                 gboolean context_sharable = mono_generic_context_is_sharable (context, TRUE);
6216
6217                                 /*
6218                                  * Pass vtable iff target method might
6219                                  * be shared, which means that sharing
6220                                  * is enabled for its class and its
6221                                  * context is sharable (and it's not a
6222                                  * generic method).
6223                                  */
6224                                 if (sharing_enabled && context_sharable &&
6225                                         !(mini_method_get_context (cmethod) && mini_method_get_context (cmethod)->method_inst))
6226                                         pass_vtable = TRUE;
6227                         }
6228
6229                         if (cmethod && mini_method_get_context (cmethod) &&
6230                                         mini_method_get_context (cmethod)->method_inst) {
6231                                 gboolean sharing_enabled = mono_class_generic_sharing_enabled (cmethod->klass);
6232                                 MonoGenericContext *context = mini_method_get_context (cmethod);
6233                                 gboolean context_sharable = mono_generic_context_is_sharable (context, TRUE);
6234
6235                                 g_assert (!pass_vtable);
6236
6237                                 if (sharing_enabled && context_sharable)
6238                                         pass_mrgctx = TRUE;
6239                         }
6240
6241                         if (cfg->generic_sharing_context && cmethod) {
6242                                 MonoGenericContext *cmethod_context = mono_method_get_context (cmethod);
6243
6244                                 context_used = mono_method_check_context_used (cmethod);
6245
6246                                 if (context_used && (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
6247                                         /* Generic method interface
6248                                            calls are resolved via a
6249                                            helper function and don't
6250                                            need an imt. */
6251                                         if (!cmethod_context || !cmethod_context->method_inst)
6252                                                 pass_imt_from_rgctx = TRUE;
6253                                 }
6254
6255                                 /*
6256                                  * If a shared method calls another
6257                                  * shared method then the caller must
6258                                  * have a generic sharing context
6259                                  * because the magic trampoline
6260                                  * requires it.  FIXME: We shouldn't
6261                                  * have to force the vtable/mrgctx
6262                                  * variable here.  Instead there
6263                                  * should be a flag in the cfg to
6264                                  * request a generic sharing context.
6265                                  */
6266                                 if (context_used && method->flags & METHOD_ATTRIBUTE_STATIC)
6267                                         mono_get_vtable_var (cfg);
6268                         }
6269
6270                         if (pass_vtable) {
6271                                 if (context_used) {
6272                                         MonoInst *rgctx;
6273
6274                                         GET_RGCTX (rgctx, context_used);
6275                                         vtable_arg = get_runtime_generic_context_ptr (cfg, method, context_used,
6276                                                 bblock, cmethod->klass, generic_context, rgctx, MONO_RGCTX_INFO_VTABLE, ip);
6277                                 } else {
6278                                         MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
6279                                         
6280                                         CHECK_TYPELOAD (cmethod->klass);
6281                                         NEW_VTABLECONST (cfg, vtable_arg, vtable);
6282                                 }
6283                         }
6284
6285                         if (pass_mrgctx) {
6286                                 g_assert (!vtable_arg);
6287
6288                                 if (context_used) {
6289                                         MonoInst *rgctx;
6290
6291                                         GET_RGCTX (rgctx, context_used);
6292                                         vtable_arg = get_runtime_generic_context_method_rgctx (cfg, method,
6293                                                 context_used, bblock, cmethod, generic_context, rgctx, ip);
6294                                 } else {
6295                                         MonoMethodRuntimeGenericContext *mrgctx;
6296
6297                                         mrgctx = mono_method_lookup_rgctx (mono_class_vtable (cfg->domain, cmethod->klass),
6298                                                 mini_method_get_context (cmethod)->method_inst);
6299
6300                                         NEW_PCONST (cfg, vtable_arg, mrgctx);
6301                                 }
6302
6303                                 if (!(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
6304                                                 (cmethod->flags & METHOD_ATTRIBUTE_FINAL)) {
6305                                         if (virtual)
6306                                                 check_this = TRUE;
6307                                         virtual = 0;
6308                                 }
6309                         }
6310
6311                         if (pass_imt_from_rgctx) {
6312                                 MonoInst *rgctx;
6313
6314                                 g_assert (!pass_vtable);
6315                                 g_assert (cmethod);
6316
6317                                 GET_RGCTX (rgctx, context_used);
6318                                 imt_arg = get_runtime_generic_context_method (cfg, method, context_used, bblock, cmethod,
6319                                                 generic_context, rgctx, MONO_RGCTX_INFO_METHOD, ip);
6320                         }
6321
6322                         if (check_this) {
6323                                 MonoInst *check;
6324
6325                                 MONO_INST_NEW (cfg, check, OP_CHECK_THIS_PASSTHROUGH);
6326                                 check->cil_code = ip;
6327                                 check->inst_left = sp [0];
6328                                 check->type = sp [0]->type;
6329                                 sp [0] = check;
6330                         }
6331
6332                         if (cmethod && virtual && 
6333                             (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) && 
6334                             !((cmethod->flags & METHOD_ATTRIBUTE_FINAL) && 
6335                               cmethod->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK) &&
6336                             mono_method_signature (cmethod)->generic_param_count) {
6337                                 MonoInst *this_temp, *this_arg_temp, *store;
6338                                 MonoInst *iargs [4];
6339
6340                                 g_assert (mono_method_signature (cmethod)->is_inflated);
6341                                 /* Prevent inlining of methods that contain indirect calls */
6342                                 INLINE_FAILURE;
6343
6344                                 this_temp = mono_compile_create_var (cfg, type_from_stack_type (sp [0]), OP_LOCAL);
6345                                 NEW_TEMPSTORE (cfg, store, this_temp->inst_c0, sp [0]);
6346                                 MONO_ADD_INS (bblock, store);
6347
6348                                 /* FIXME: This should be a managed pointer */
6349                                 this_arg_temp = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
6350
6351                                 /* Because of the PCONST below */
6352                                 cfg->disable_aot = TRUE;
6353                                 NEW_TEMPLOAD (cfg, iargs [0], this_temp->inst_c0);
6354                                 if (context_used) {
6355                                         MonoInst *rgctx;
6356
6357                                         GET_RGCTX (rgctx, context_used);
6358                                         iargs [1] = get_runtime_generic_context_method (cfg, method, context_used,
6359                                                         bblock, cmethod,
6360                                                         generic_context, rgctx, MONO_RGCTX_INFO_METHOD, ip);
6361                                         NEW_TEMPLOADA (cfg, iargs [2], this_arg_temp->inst_c0);
6362                                         temp = mono_emit_jit_icall (cfg, bblock,
6363                                                 mono_helper_compile_generic_method_wo_context, iargs, ip);
6364                                 } else {
6365                                         NEW_METHODCONST (cfg, iargs [1], cmethod);
6366                                         NEW_PCONST (cfg, iargs [2], mono_method_get_context (cmethod));
6367                                         NEW_TEMPLOADA (cfg, iargs [3], this_arg_temp->inst_c0);
6368                                         temp = mono_emit_jit_icall (cfg, bblock, mono_helper_compile_generic_method,
6369                                                 iargs, ip);
6370                                 }
6371
6372                                 NEW_TEMPLOAD (cfg, addr, temp);
6373                                 NEW_TEMPLOAD (cfg, sp [0], this_arg_temp->inst_c0);
6374
6375                                 if ((temp = mono_emit_calli_spilled (cfg, bblock, fsig, sp, addr, ip)) != -1) {
6376                                         NEW_TEMPLOAD (cfg, *sp, temp);
6377                                         sp++;
6378                                 }
6379
6380                                 ip += 5;
6381                                 ins_flag = 0;
6382                                 break;
6383                         }
6384
6385                         /* FIXME: runtime generic context pointer for jumps? */
6386                         /* FIXME: handle this for generic sharing eventually */
6387                         if ((ins_flag & MONO_INST_TAILCALL) && !cfg->generic_sharing_context && !vtable_arg && cmethod && (*ip == CEE_CALL) &&
6388                                  (mono_metadata_signature_equal (mono_method_signature (method), mono_method_signature (cmethod)))) {
6389                                 int i;
6390
6391                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
6392                                 INLINE_FAILURE;
6393                                 /* FIXME: This assumes the two methods has the same number and type of arguments */
6394                                 /*
6395                                  * We implement tail calls by storing the actual arguments into the 
6396                                  * argument variables, then emitting a OP_JMP. Since the actual arguments
6397                                  * can refer to the arg variables, we have to spill them.
6398                                  */
6399                                 handle_loaded_temps (cfg, bblock, sp, sp + n);
6400                                 for (i = 0; i < n; ++i) {
6401                                         /* Prevent argument from being register allocated */
6402                                         arg_array [i]->flags |= MONO_INST_VOLATILE;
6403
6404                                         /* Check if argument is the same */
6405                                         /* 
6406                                          * FIXME: This loses liveness info, so it can only be done if the
6407                                          * argument is not register allocated.
6408                                          */
6409                                         NEW_ARGLOAD (cfg, ins, i);
6410                                         if ((ins->opcode == sp [i]->opcode) && (ins->inst_i0 == sp [i]->inst_i0))
6411                                                 continue;
6412
6413                                         NEW_ARGSTORE (cfg, ins, i, sp [i]);
6414                                         /* FIXME: handle CEE_STIND_R4 */
6415                                         if (ins->opcode == CEE_STOBJ) {
6416                                                 NEW_ARGLOADA (cfg, ins, i);
6417                                                 handle_stobj (cfg, bblock, ins, sp [i], sp [i]->cil_code, ins->klass, FALSE, FALSE, FALSE);
6418                                         }
6419                                         else
6420                                                 MONO_ADD_INS (bblock, ins);
6421                                 }
6422                                 MONO_INST_NEW (cfg, ins, OP_JMP);
6423                                 ins->inst_p0 = cmethod;
6424                                 ins->inst_p1 = arg_array [0];
6425                                 MONO_ADD_INS (bblock, ins);
6426                                 link_bblock (cfg, bblock, end_bblock);                  
6427                                 start_new_bblock = 1;
6428                                 /* skip CEE_RET as well */
6429                                 ip += 6;
6430                                 ins_flag = 0;
6431                                 break;
6432                         }
6433                         if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_get_inst_for_method (cfg, cmethod, fsig, sp))) {
6434                                 if (MONO_TYPE_IS_VOID (fsig->ret)) {
6435                                         MONO_ADD_INS (bblock, ins);
6436                                 } else {
6437                                         type_to_eval_stack_type (cfg, fsig->ret, ins);
6438                                         *sp = ins;
6439                                         sp++;
6440                                 }
6441
6442                                 ip += 5;
6443                                 ins_flag = 0;
6444                                 break;
6445                         }
6446
6447                         handle_loaded_temps (cfg, bblock, stack_start, sp);
6448
6449                         if ((cfg->opt & MONO_OPT_INLINE) && cmethod && //!check_this &&
6450                             (!virtual || !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) || (cmethod->flags & METHOD_ATTRIBUTE_FINAL)) && 
6451                             mono_method_check_inlining (cfg, cmethod) &&
6452                                  !g_list_find (dont_inline, cmethod)) {
6453                                 int costs;
6454                                 MonoBasicBlock *ebblock;
6455                                 gboolean allways = FALSE;
6456
6457                                 if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
6458                                         (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
6459                                         /* Prevent inlining of methods that call wrappers */
6460                                         INLINE_FAILURE;
6461                                         cmethod = mono_marshal_get_native_wrapper (cmethod, check_for_pending_exc, FALSE);
6462                                         allways = TRUE;
6463                                 }
6464
6465                                 if ((costs = inline_method (cfg, cmethod, fsig, bblock, sp, ip, real_offset, dont_inline, &ebblock, allways))) {
6466                                         ip += 5;
6467                                         real_offset += 5;
6468
6469                                         GET_BBLOCK (cfg, bblock, ip);
6470                                         ebblock->next_bb = bblock;
6471                                         link_bblock (cfg, ebblock, bblock);
6472
6473                                         if (!MONO_TYPE_IS_VOID (fsig->ret))
6474                                                 sp++;
6475
6476                                         /* indicates start of a new block, and triggers a load of all 
6477                                            stack arguments at bb boundarie */
6478                                         bblock = ebblock;
6479
6480                                         inline_costs += costs;
6481                                         ins_flag = 0;
6482                                         break;
6483                                 }
6484                         }
6485                         
6486                         inline_costs += 10 * num_calls++;
6487
6488                         /* tail recursion elimination */
6489                         if ((cfg->opt & MONO_OPT_TAILC) && *ip == CEE_CALL && cmethod == method && ip [5] == CEE_RET &&
6490                                         !vtable_arg) {
6491                                 gboolean has_vtargs = FALSE;
6492                                 int i;
6493                                 
6494                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
6495                                 INLINE_FAILURE;
6496                                 /* keep it simple */
6497                                 for (i =  fsig->param_count - 1; i >= 0; i--) {
6498                                         if (MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->params [i])) 
6499                                                 has_vtargs = TRUE;
6500                                 }
6501
6502                                 if (!has_vtargs) {
6503                                         for (i = 0; i < n; ++i) {
6504                                                 /* FIXME: handle CEE_STIND_R4 */
6505                                                 NEW_ARGSTORE (cfg, ins, i, sp [i]);
6506                                                 MONO_ADD_INS (bblock, ins);
6507                                         }
6508                                         MONO_INST_NEW (cfg, ins, OP_BR);
6509                                         MONO_ADD_INS (bblock, ins);
6510                                         tblock = start_bblock->out_bb [0];
6511                                         link_bblock (cfg, bblock, tblock);
6512                                         ins->inst_target_bb = tblock;
6513                                         start_new_bblock = 1;
6514
6515                                         /* skip the CEE_RET, too */
6516                                         if (ip_in_bb (cfg, bblock, ip + 5))
6517                                                 ip += 6;
6518                                         else
6519                                                 ip += 5;
6520                                         ins_flag = 0;
6521                                         break;
6522                                 }
6523                         }
6524
6525                         if (ip_in_bb (cfg, bblock, ip + 5) 
6526                                 && (!MONO_TYPE_ISSTRUCT (fsig->ret))
6527                                 && (!MONO_TYPE_IS_VOID (fsig->ret) || (cmethod && cmethod->string_ctor))
6528                                 && (CODE_IS_STLOC (ip + 5) || ip [5] == CEE_POP || ip [5] == CEE_RET))
6529                                 /* No need to spill */
6530                                 no_spill = TRUE;
6531                         else
6532                                 no_spill = FALSE;
6533
6534                         /* FIXME: only do this for generic methods if
6535                            they are not shared! */
6536                         if (context_used &&
6537                                         (cmethod->klass->valuetype ||
6538                                         (cmethod->is_inflated && mono_method_get_context (cmethod)->method_inst && !pass_mrgctx) ||
6539                                         ((cmethod->flags & METHOD_ATTRIBUTE_STATIC) &&
6540                                                 mono_class_generic_sharing_enabled (cmethod->klass)) ||
6541                                         (!imt_arg && !mono_method_is_generic_sharable_impl (cmethod, TRUE) &&
6542                                                 (!virtual || cmethod->flags & METHOD_ATTRIBUTE_FINAL ||
6543                                                 !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))))) {
6544                                 MonoInst *rgctx;
6545
6546                                 INLINE_FAILURE;
6547
6548                                 g_assert (cfg->generic_sharing_context && cmethod);
6549                                 g_assert (!addr);
6550
6551                                 /*
6552                                  * We are compiling a call to
6553                                  * non-shared generic code from shared
6554                                  * code, which means that we have to
6555                                  * look up the method in the rgctx and
6556                                  * do an indirect call.
6557                                  */
6558                                 GET_RGCTX (rgctx, context_used);
6559                                 addr = get_runtime_generic_context_method (cfg, method, context_used, bblock, cmethod,
6560                                                 generic_context, rgctx, MONO_RGCTX_INFO_GENERIC_METHOD_CODE, ip);
6561
6562                         }
6563
6564                         if (addr) {
6565                                 g_assert (!imt_arg);
6566
6567                                 if (*ip == CEE_CALL) {
6568                                         g_assert (context_used);
6569                                 } else if (*ip == CEE_CALLI) {
6570                                         g_assert (!vtable_arg);
6571                                 } else {
6572                                         g_assert (cmethod->flags & METHOD_ATTRIBUTE_FINAL ||
6573                                                         !(cmethod->flags & METHOD_ATTRIBUTE_FINAL));
6574                                 }
6575
6576                                 /* Prevent inlining of methods with indirect calls */
6577                                 INLINE_FAILURE;
6578                                 if (no_spill) {
6579                                         ins = (MonoInst*)mono_emit_rgctx_calli (cfg, bblock, fsig, sp, addr, vtable_arg, ip);
6580                                         *sp++ = ins;                                    
6581                                 } else {
6582                                         temp = mono_emit_rgctx_calli_spilled (cfg, bblock, fsig, sp, addr, vtable_arg, ip);
6583                                         if (temp != -1) {
6584                                                 NEW_TEMPLOAD (cfg, *sp, temp);
6585                                                 NEW_TEMPLOAD_SOFT_FLOAT (cfg, bblock, *sp, temp, ip);
6586                                                 sp++;
6587                                         }
6588                                 }                       
6589                         } else if (array_rank) {
6590                                 MonoInst *addr;
6591
6592                                 if (strcmp (cmethod->name, "Set") == 0) { /* array Set */ 
6593                                         if (sp [fsig->param_count]->type == STACK_OBJ) {
6594                                                 MonoInst *iargs [2];
6595                                                 MonoInst *array, *to_store, *store;
6596
6597                                                 handle_loaded_temps (cfg, bblock, stack_start, sp);
6598                                                 
6599                                                 array = mono_compile_create_var (cfg, type_from_stack_type (sp [0]), OP_LOCAL);
6600                                                 NEW_TEMPSTORE (cfg, store, array->inst_c0, sp [0]);
6601                                                 MONO_ADD_INS (bblock, store);
6602                                                 NEW_TEMPLOAD (cfg, iargs [0], array->inst_c0);
6603
6604                                                 to_store = mono_compile_create_var (cfg, type_from_stack_type (sp [fsig->param_count]), OP_LOCAL);
6605                                                 NEW_TEMPSTORE (cfg, store, to_store->inst_c0, sp [fsig->param_count]);
6606                                                 /* FIXME: handle CEE_STIND_R4 */
6607                                                 MONO_ADD_INS (bblock, store);
6608                                                 NEW_TEMPLOAD (cfg, iargs [1], to_store->inst_c0);
6609
6610                                                 /*
6611                                                  * We first save the args for the call so that the args are copied to the stack
6612                                                  * and a new instruction tree for them is created. If we don't do this,
6613                                                  * the same MonoInst is added to two different trees and this is not 
6614                                                  * allowed by burg.
6615                                                  */
6616                                                 mono_emit_jit_icall (cfg, bblock, mono_helper_stelem_ref_check, iargs, ip);
6617
6618                                                 NEW_TEMPLOAD (cfg, sp [0], array->inst_c0);
6619                                                 NEW_TEMPLOAD (cfg, sp [fsig->param_count], to_store->inst_c0);
6620                                         }
6621
6622                                         addr = mini_get_ldelema_ins (cfg, bblock, cmethod, sp, ip, TRUE);
6623                                         NEW_INDSTORE (cfg, ins, addr, sp [fsig->param_count], fsig->params [fsig->param_count - 1]);
6624                                         /* FIXME: handle CEE_STIND_R4 */
6625                                         if (ins->opcode == CEE_STOBJ) {
6626                                                 handle_stobj (cfg, bblock, addr, sp [fsig->param_count], ip, mono_class_from_mono_type (fsig->params [fsig->param_count-1]), FALSE, FALSE, TRUE);
6627                                         } else {
6628                                                 MONO_ADD_INS (bblock, ins);
6629                                         }
6630
6631                                 } else if (strcmp (cmethod->name, "Get") == 0) { /* array Get */
6632                                         addr = mini_get_ldelema_ins (cfg, bblock, cmethod, sp, ip, FALSE);
6633                                         NEW_INDLOAD (cfg, ins, addr, fsig->ret);
6634
6635                                         *sp++ = ins;
6636                                 } else if (strcmp (cmethod->name, "Address") == 0) { /* array Address */
6637                                         if (!cmethod->klass->element_class->valuetype && !readonly) {
6638                                                 MonoInst* check;
6639                                                 //* Needed by the code generated in inssel.brg * /
6640                                                 mono_get_got_var (cfg);
6641
6642                                                 MONO_INST_NEW (cfg, check, OP_CHECK_ARRAY_TYPE);
6643                                                 check->klass = cmethod->klass;
6644                                                 check->inst_left = sp [0];
6645                                                 check->type = STACK_OBJ;
6646                                                 sp [0] = check;
6647                                         }
6648
6649                                         readonly = FALSE;
6650                                         addr = mini_get_ldelema_ins (cfg, bblock, cmethod, sp, ip, FALSE);
6651                                         *sp++ = addr;
6652                                 } else {
6653                                         g_assert_not_reached ();
6654                                 }
6655
6656                         } else {
6657                                 /* Prevent inlining of methods which call other methods */
6658                                 INLINE_FAILURE;
6659                                 if (mini_redirect_call (&temp, cfg, bblock, cmethod, fsig, sp, ip, virtual ? sp [0] : NULL)) {
6660                                         if (temp != -1) {
6661                                                 NEW_TEMPLOAD (cfg, *sp, temp);
6662                                                 sp++;
6663                                         }
6664                                 } else if (no_spill) {
6665                                         ins = (MonoInst*)mono_emit_rgctx_method_call (cfg, bblock, cmethod, fsig, sp,
6666                                                         vtable_arg, imt_arg, ip, virtual ? sp [0] : NULL);
6667                                         *sp++ = ins;
6668                                 } else {
6669                                         if ((temp = mono_emit_rgctx_method_call_spilled (cfg, bblock, cmethod, fsig, sp,
6670                                                         vtable_arg, imt_arg, ip, virtual ? sp [0] : NULL)) != -1) {
6671                                                 MonoInst *load;
6672                                                 NEW_TEMPLOAD (cfg, load, temp);
6673
6674 #ifdef MONO_ARCH_SOFT_FLOAT
6675                                                 if (load->opcode == CEE_LDIND_R4) {
6676                                                         NEW_TEMPLOADA (cfg, load, temp);
6677                                                         temp = handle_load_float (cfg, bblock, load, ip);
6678                                                         NEW_TEMPLOAD (cfg, load, temp);
6679                                                 }
6680 #endif
6681                                                 *sp++ = load;
6682                                         }
6683                                 }
6684                         }
6685
6686                         ip += 5;
6687                         ins_flag = 0;
6688                         break;
6689                 }
6690                 case CEE_RET:
6691                         if (cfg->method != method) {
6692                                 /* return from inlined method */
6693                                 if (return_var) {
6694                                         MonoInst *store;
6695                                         CHECK_STACK (1);
6696                                         --sp;
6697                                         //g_assert (returnvar != -1);
6698                                         NEW_TEMPSTORE (cfg, store, return_var->inst_c0, *sp);
6699                                         store->cil_code = sp [0]->cil_code;
6700                                         if (store->opcode == CEE_STOBJ) {
6701                                                 g_assert_not_reached ();
6702                                                 NEW_TEMPLOADA (cfg, store, return_var->inst_c0);
6703                                                 /* FIXME: it is possible some optimization will pass the a heap pointer for the struct address, so we'll need the write barrier */
6704                                                 handle_stobj (cfg, bblock, store, *sp, sp [0]->cil_code, return_var->klass, FALSE, FALSE, FALSE);
6705 #ifdef MONO_ARCH_SOFT_FLOAT
6706                                         } else if (store->opcode == CEE_STIND_R4) {
6707                                                 NEW_TEMPLOADA (cfg, store, return_var->inst_c0);
6708                                                 handle_store_float (cfg, bblock, store, *sp, sp [0]->cil_code);
6709 #endif
6710                                         } else
6711                                                 MONO_ADD_INS (bblock, store);
6712                                 } 
6713                         } else {
6714                                 if (cfg->ret) {
6715                                         g_assert (!return_var);
6716                                         CHECK_STACK (1);
6717                                         --sp;
6718                                         MONO_INST_NEW (cfg, ins, OP_NOP);
6719                                         ins->opcode = mini_type_to_stind (cfg, mono_method_signature (method)->ret);
6720                                         if (ins->opcode == CEE_STOBJ) {
6721                                                 NEW_RETLOADA (cfg, ins);
6722                                                 /* FIXME: it is possible some optimization will pass the a heap pointer for the struct address, so we'll need the write barrier */
6723                                                 handle_stobj (cfg, bblock, ins, *sp, ip, cfg->ret->klass, FALSE, FALSE, FALSE);
6724                                         } else {
6725                                                 ins->opcode = OP_SETRET;
6726                                                 ins->inst_i0 = *sp;;
6727                                                 ins->inst_i1 = NULL;
6728                                                 MONO_ADD_INS (bblock, ins);
6729                                         }
6730                                 }
6731                         }
6732                         if (sp != stack_start)
6733                                 UNVERIFIED;
6734                         MONO_INST_NEW (cfg, ins, OP_BR);
6735                         ip++;
6736                         ins->inst_target_bb = end_bblock;
6737                         MONO_ADD_INS (bblock, ins);
6738                         link_bblock (cfg, bblock, end_bblock);
6739                         start_new_bblock = 1;
6740                         break;
6741                 case CEE_BR_S:
6742                         CHECK_OPSIZE (2);
6743                         MONO_INST_NEW (cfg, ins, OP_BR);
6744                         ip++;
6745                         MONO_ADD_INS (bblock, ins);
6746                         target = ip + 1 + (signed char)(*ip);
6747                         ++ip;
6748                         GET_BBLOCK (cfg, tblock, target);
6749                         link_bblock (cfg, bblock, tblock);
6750                         CHECK_BBLOCK (target, ip, tblock);
6751                         ins->inst_target_bb = tblock;
6752                         if (sp != stack_start) {
6753                                 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
6754                                 sp = stack_start;
6755                                 CHECK_UNVERIFIABLE (cfg);
6756                         }
6757                         start_new_bblock = 1;
6758                         inline_costs += BRANCH_COST;
6759                         break;
6760                 case CEE_BRFALSE_S:
6761                 case CEE_BRTRUE_S:
6762                         CHECK_OPSIZE (2);
6763                         CHECK_STACK (1);
6764                         if (sp [-1]->type == STACK_VTYPE || sp [-1]->type == STACK_R8)
6765                                 UNVERIFIED;
6766                         MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
6767                         ip++;
6768                         target = ip + 1 + *(signed char*)ip;
6769                         ip++;
6770                         ADD_UNCOND (ins->opcode == CEE_BRTRUE);
6771                         if (sp != stack_start) {
6772                                 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
6773                                 sp = stack_start;
6774                                 CHECK_UNVERIFIABLE (cfg);
6775                         }
6776                         inline_costs += BRANCH_COST;
6777                         break;
6778                 case CEE_BEQ_S:
6779                 case CEE_BGE_S:
6780                 case CEE_BGT_S:
6781                 case CEE_BLE_S:
6782                 case CEE_BLT_S:
6783                 case CEE_BNE_UN_S:
6784                 case CEE_BGE_UN_S:
6785                 case CEE_BGT_UN_S:
6786                 case CEE_BLE_UN_S:
6787                 case CEE_BLT_UN_S:
6788                         CHECK_OPSIZE (2);
6789                         CHECK_STACK (2);
6790                         MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
6791                         ip++;
6792                         target = ip + 1 + *(signed char*)ip;
6793                         ip++;
6794 #ifdef MONO_ARCH_SOFT_FLOAT
6795                         if (sp [-1]->type == STACK_R8 || sp [-2]->type == STACK_R8) {
6796                                 ins->opcode = condbr_to_fp_br (ins->opcode);
6797                                 sp -= 2;
6798                                 ins->inst_left = sp [0];
6799                                 ins->inst_right = sp [1];
6800                                 ins->type = STACK_I4;
6801                                 *sp++ = emit_tree (cfg, bblock, ins, ins->cil_code);
6802                                 MONO_INST_NEW (cfg, ins, CEE_BRTRUE);
6803                                 ADD_UNCOND (TRUE);
6804                         } else {
6805                                 ADD_BINCOND (NULL);
6806                         }
6807 #else
6808                         ADD_BINCOND (NULL);
6809 #endif
6810                         if (sp != stack_start) {
6811                                 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
6812                                 sp = stack_start;
6813                                 CHECK_UNVERIFIABLE (cfg);
6814                         }
6815                         inline_costs += BRANCH_COST;
6816                         break;
6817                 case CEE_BR:
6818                         CHECK_OPSIZE (5);
6819                         MONO_INST_NEW (cfg, ins, OP_BR);
6820                         ip++;
6821                         MONO_ADD_INS (bblock, ins);
6822                         target = ip + 4 + (gint32)read32(ip);
6823                         ip += 4;
6824                         GET_BBLOCK (cfg, tblock, target);
6825                         link_bblock (cfg, bblock, tblock);
6826                         CHECK_BBLOCK (target, ip, tblock);
6827                         ins->inst_target_bb = tblock;
6828                         if (sp != stack_start) {
6829                                 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
6830                                 sp = stack_start;
6831                                 CHECK_UNVERIFIABLE (cfg);
6832                         }
6833                         start_new_bblock = 1;
6834                         inline_costs += BRANCH_COST;
6835                         break;
6836                 case CEE_BRFALSE:
6837                 case CEE_BRTRUE:
6838                         CHECK_OPSIZE (5);
6839                         CHECK_STACK (1);
6840                         if (sp [-1]->type == STACK_VTYPE || sp [-1]->type == STACK_R8)
6841                                 UNVERIFIED;
6842                         MONO_INST_NEW (cfg, ins, *ip);
6843                         ip++;
6844                         target = ip + 4 + (gint32)read32(ip);
6845                         ip += 4;
6846                         ADD_UNCOND(ins->opcode == CEE_BRTRUE);
6847                         if (sp != stack_start) {
6848                                 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
6849                                 sp = stack_start;
6850                                 CHECK_UNVERIFIABLE (cfg);
6851                         }
6852                         inline_costs += BRANCH_COST;
6853                         break;
6854                 case CEE_BEQ:
6855                 case CEE_BGE:
6856                 case CEE_BGT:
6857                 case CEE_BLE:
6858                 case CEE_BLT:
6859                 case CEE_BNE_UN:
6860                 case CEE_BGE_UN:
6861                 case CEE_BGT_UN:
6862                 case CEE_BLE_UN:
6863                 case CEE_BLT_UN:
6864                         CHECK_OPSIZE (5);
6865                         CHECK_STACK (2);
6866                         MONO_INST_NEW (cfg, ins, *ip);
6867                         ip++;
6868                         target = ip + 4 + (gint32)read32(ip);
6869                         ip += 4;
6870 #ifdef MONO_ARCH_SOFT_FLOAT
6871                         if (sp [-1]->type == STACK_R8 || sp [-2]->type == STACK_R8) {
6872                                 ins->opcode = condbr_to_fp_br (ins->opcode);
6873                                 sp -= 2;
6874                                 ins->inst_left = sp [0];
6875                                 ins->inst_right = sp [1];
6876                                 ins->type = STACK_I4;
6877                                 *sp++ = emit_tree (cfg, bblock, ins, ins->cil_code);
6878                                 MONO_INST_NEW (cfg, ins, CEE_BRTRUE);
6879                                 ADD_UNCOND (TRUE);
6880                         } else {
6881                                 ADD_BINCOND (NULL);
6882                         }
6883 #else
6884                         ADD_BINCOND (NULL);
6885 #endif
6886                         if (sp != stack_start) {
6887                                 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
6888                                 sp = stack_start;
6889                                 CHECK_UNVERIFIABLE (cfg);
6890                         }
6891                         inline_costs += BRANCH_COST;
6892                         break;
6893                 case CEE_SWITCH:
6894                         CHECK_OPSIZE (5);
6895                         CHECK_STACK (1);
6896                         n = read32 (ip + 1);
6897                         MONO_INST_NEW (cfg, ins, OP_SWITCH);
6898                         --sp;
6899                         ins->inst_left = *sp;
6900                         if ((ins->inst_left->type != STACK_I4) && (ins->inst_left->type != STACK_PTR)) 
6901                                 UNVERIFIED;
6902                         ip += 5;
6903                         CHECK_OPSIZE (n * sizeof (guint32));
6904                         target = ip + n * sizeof (guint32);
6905                         MONO_ADD_INS (bblock, ins);
6906                         GET_BBLOCK (cfg, tblock, target);
6907                         link_bblock (cfg, bblock, tblock);
6908                         ins->klass = GUINT_TO_POINTER (n);
6909                         ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * (n + 1));
6910                         ins->inst_many_bb [n] = tblock;
6911
6912                         for (i = 0; i < n; ++i) {
6913                                 GET_BBLOCK (cfg, tblock, target + (gint32)read32(ip));
6914                                 link_bblock (cfg, bblock, tblock);
6915                                 ins->inst_many_bb [i] = tblock;
6916                                 ip += 4;
6917                         }
6918                         if (sp != stack_start) {
6919                                 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
6920                                 sp = stack_start;
6921                                 CHECK_UNVERIFIABLE (cfg);
6922                         }
6923                         /* Needed by the code generated in inssel.brg */
6924                         mono_get_got_var (cfg);
6925                         inline_costs += (BRANCH_COST * 2);
6926                         break;
6927                 case CEE_LDIND_I1:
6928                 case CEE_LDIND_U1:
6929                 case CEE_LDIND_I2:
6930                 case CEE_LDIND_U2:
6931                 case CEE_LDIND_I4:
6932                 case CEE_LDIND_U4:
6933                 case CEE_LDIND_I8:
6934                 case CEE_LDIND_I:
6935                 case CEE_LDIND_R4:
6936                 case CEE_LDIND_R8:
6937                 case CEE_LDIND_REF:
6938                         CHECK_STACK (1);
6939                         MONO_INST_NEW (cfg, ins, *ip);
6940                         --sp;
6941                         ins->inst_i0 = *sp;
6942                         *sp++ = ins;
6943                         ins->type = ldind_type [*ip - CEE_LDIND_I1];
6944                         ins->flags |= ins_flag;
6945                         ins_flag = 0;
6946                         if (ins->type == STACK_OBJ)
6947                                 ins->klass = mono_defaults.object_class;
6948 #ifdef MONO_ARCH_SOFT_FLOAT
6949                         if (*ip == CEE_LDIND_R4) {
6950                                 int temp;
6951                                 --sp;
6952                                 temp = handle_load_float (cfg, bblock, ins->inst_i0, ip);
6953                                 NEW_TEMPLOAD (cfg, *sp, temp);
6954                                 sp++;
6955                         }
6956 #endif
6957                         ++ip;
6958                         break;
6959                 case CEE_STIND_REF:
6960                 case CEE_STIND_I1:
6961                 case CEE_STIND_I2:
6962                 case CEE_STIND_I4:
6963                 case CEE_STIND_I8:
6964                 case CEE_STIND_R4:
6965                 case CEE_STIND_R8:
6966                         CHECK_STACK (2);
6967 #ifdef MONO_ARCH_SOFT_FLOAT
6968                         if (*ip == CEE_STIND_R4) {
6969                                 sp -= 2;
6970                                 handle_store_float (cfg, bblock, sp [0], sp [1], ip);
6971                                 ip++;
6972                                 break;
6973                         }
6974 #endif
6975 #if HAVE_WRITE_BARRIERS
6976                         if (*ip == CEE_STIND_REF && method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER && !((sp [-1]->opcode == OP_PCONST) && (sp [-1]->inst_p0 == 0))) {
6977                                 /* insert call to write barrier */
6978                                 MonoMethod *write_barrier = mono_marshal_get_write_barrier ();
6979                                 sp -= 2;
6980                                 mono_emit_method_call_spilled (cfg, bblock, write_barrier, mono_method_signature (write_barrier), sp, ip, NULL);
6981                                 ip++;
6982                                 break;
6983                         }
6984 #endif
6985                         MONO_INST_NEW (cfg, ins, *ip);
6986                         ip++;
6987                         sp -= 2;
6988                         handle_loaded_temps (cfg, bblock, stack_start, sp);
6989                         MONO_ADD_INS (bblock, ins);
6990                         ins->inst_i0 = sp [0];
6991                         ins->inst_i1 = sp [1];
6992                         ins->flags |= ins_flag;
6993                         ins_flag = 0;
6994                         inline_costs += 1;
6995                         break;
6996                 case CEE_MUL:
6997                         CHECK_STACK (2);
6998                         ADD_BINOP (*ip);
6999
7000 #ifdef MONO_ARCH_NO_EMULATE_MUL_IMM
7001                         /* FIXME: This breaks with ssapre (mono -O=ssapre loader.exe) */
7002                         if ((ins->inst_right->opcode == OP_ICONST) && !(cfg->opt & MONO_OPT_SSAPRE)) {
7003                                 switch (ins->opcode) {
7004                                 case CEE_MUL:
7005                                         ins->opcode = OP_IMUL_IMM;
7006                                         ins->inst_imm = ins->inst_right->inst_c0;
7007                                         break;
7008                                 case OP_LMUL:
7009                                         ins->opcode = OP_LMUL_IMM;
7010                                         ins->inst_imm = ins->inst_right->inst_c0;
7011                                         break;
7012                                 default:
7013                                         g_assert_not_reached ();
7014                                 }
7015                         }
7016 #endif
7017
7018                         if (mono_find_jit_opcode_emulation (ins->opcode)) {
7019                                 --sp;
7020                                 *sp++ = emit_tree (cfg, bblock, ins, ip + 1);
7021                         }
7022                         ip++;
7023                         break;
7024                 case CEE_ADD:
7025                 case CEE_SUB:
7026                 case CEE_DIV:
7027                 case CEE_DIV_UN:
7028                 case CEE_REM:
7029                 case CEE_REM_UN:
7030                 case CEE_AND:
7031                 case CEE_OR:
7032                 case CEE_XOR:
7033                 case CEE_SHL:
7034                 case CEE_SHR:
7035                 case CEE_SHR_UN:
7036                         CHECK_STACK (2);
7037                         ADD_BINOP (*ip);
7038                         /* special case that gives a nice speedup and happens to workaorund a ppc jit but (for the release)
7039                          * later apply the speedup to the left shift as well
7040                          * See BUG# 57957.
7041                          */
7042                         if ((ins->opcode == OP_LSHR_UN) && (ins->type == STACK_I8) 
7043                                         && (ins->inst_right->opcode == OP_ICONST) && (ins->inst_right->inst_c0 == 32)) {
7044                                 ins->opcode = OP_LSHR_UN_32;
7045                                 /*g_print ("applied long shr speedup to %s\n", cfg->method->name);*/
7046                                 ip++;
7047                                 break;
7048                         }
7049                         if (mono_find_jit_opcode_emulation (ins->opcode)) {
7050                                 --sp;
7051                                 *sp++ = emit_tree (cfg, bblock, ins, ip + 1);
7052                         }
7053                         ip++;
7054                         break;
7055                 case CEE_NEG:
7056                 case CEE_NOT:
7057                 case CEE_CONV_I1:
7058                 case CEE_CONV_I2:
7059                 case CEE_CONV_I4:
7060                 case CEE_CONV_R4:
7061                 case CEE_CONV_R8:
7062                 case CEE_CONV_U4:
7063                 case CEE_CONV_I8:
7064                 case CEE_CONV_U8:
7065                 case CEE_CONV_OVF_I8:
7066                 case CEE_CONV_OVF_U8:
7067                 case CEE_CONV_R_UN:
7068                         CHECK_STACK (1);
7069                         ADD_UNOP (*ip);
7070
7071 #ifdef MONO_ARCH_SOFT_FLOAT
7072                         /*
7073                          * Its rather hard to emit the soft float code during the decompose
7074                          * pass, so avoid it in some specific cases.
7075                          */
7076                         if (ins->opcode == OP_LCONV_TO_R4) {
7077                                 MonoInst *conv;
7078
7079                                 ins->opcode = OP_LCONV_TO_R8;
7080                                 ins->type = STACK_R8;
7081
7082                                 --sp;
7083                                 *sp++ = emit_tree (cfg, bblock, ins, ip + 1);
7084
7085                                 MONO_INST_NEW (cfg, conv, CEE_CONV_R4);
7086                                 conv->inst_left = sp [-1];
7087                                 conv->type = STACK_R8;
7088                                 sp [-1] = ins;
7089
7090                                 ip++;
7091                                 break;
7092                         }
7093 #endif
7094
7095                         if (mono_find_jit_opcode_emulation (ins->opcode)) {
7096                                 --sp;
7097                                 *sp++ = emit_tree (cfg, bblock, ins, ip + 1);
7098                         }
7099                         ip++;                   
7100                         break;
7101                 case CEE_CONV_OVF_I4:
7102                 case CEE_CONV_OVF_I1:
7103                 case CEE_CONV_OVF_I2:
7104                 case CEE_CONV_OVF_I:
7105                 case CEE_CONV_OVF_U:
7106                         CHECK_STACK (1);
7107
7108                         if (sp [-1]->type == STACK_R8) {
7109                                 ADD_UNOP (CEE_CONV_OVF_I8);
7110                                 ADD_UNOP (*ip);
7111                         } else {
7112                                 ADD_UNOP (*ip);
7113                         }
7114
7115                         ip++;
7116                         break;
7117                 case CEE_CONV_OVF_U1:
7118                 case CEE_CONV_OVF_U2:
7119                 case CEE_CONV_OVF_U4:
7120                         CHECK_STACK (1);
7121
7122                         if (sp [-1]->type == STACK_R8) {
7123                                 ADD_UNOP (CEE_CONV_OVF_U8);
7124                                 ADD_UNOP (*ip);
7125                         } else {
7126                                 ADD_UNOP (*ip);
7127                         }
7128
7129                         ip++;
7130                         break;
7131                 case CEE_CONV_OVF_I1_UN:
7132                 case CEE_CONV_OVF_I2_UN:
7133                 case CEE_CONV_OVF_I4_UN:
7134                 case CEE_CONV_OVF_I8_UN:
7135                 case CEE_CONV_OVF_U1_UN:
7136                 case CEE_CONV_OVF_U2_UN:
7137                 case CEE_CONV_OVF_U4_UN:
7138                 case CEE_CONV_OVF_U8_UN:
7139                 case CEE_CONV_OVF_I_UN:
7140                 case CEE_CONV_OVF_U_UN:
7141                         CHECK_STACK (1);
7142                         ADD_UNOP (*ip);
7143                         ip++;
7144                         break;
7145                 case CEE_CPOBJ:
7146                         CHECK_OPSIZE (5);
7147                         CHECK_STACK (2);
7148                         token = read32 (ip + 1);
7149                         klass = mini_get_class (method, token, generic_context);
7150                         CHECK_TYPELOAD (klass);
7151                         sp -= 2;
7152                         if (generic_class_is_reference_type (cfg, klass)) {
7153                                 MonoInst *store, *load;
7154                                 MONO_INST_NEW (cfg, load, CEE_LDIND_REF);
7155                                 load->inst_i0 = sp [1];
7156                                 load->type = STACK_OBJ;
7157                                 load->klass = klass;
7158                                 load->flags |= ins_flag;
7159                                 MONO_INST_NEW (cfg, store, CEE_STIND_REF);
7160                                 handle_loaded_temps (cfg, bblock, stack_start, sp);
7161                                 MONO_ADD_INS (bblock, store);
7162                                 store->inst_i0 = sp [0];
7163                                 store->inst_i1 = load;
7164                                 store->flags |= ins_flag;
7165                         } else {
7166                                 guint32 align;
7167
7168                                 n = mono_class_value_size (klass, &align);
7169                                 if ((cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 5) {
7170                                         MonoInst *copy;
7171                                         NEW_MEMCPY (cfg, copy, sp [0], sp [1], n, align);
7172                                         MONO_ADD_INS (bblock, copy);
7173                                 } else {
7174                                         MonoMethod *memcpy_method = get_memcpy_method ();
7175                                         MonoInst *iargs [3];
7176                                         iargs [0] = sp [0];
7177                                         iargs [1] = sp [1];
7178                                         NEW_ICONST (cfg, iargs [2], n);
7179
7180                                         mono_emit_method_call_spilled (cfg, bblock, memcpy_method, memcpy_method->signature, iargs, ip, NULL);
7181                                 }
7182                         }
7183                         ins_flag = 0;
7184                         ip += 5;
7185                         break;
7186                 case CEE_LDOBJ: {
7187                         MonoInst *iargs [3];
7188                         int loc_index = -1;
7189                         int stloc_len = 0;
7190                         guint32 align;
7191
7192                         CHECK_OPSIZE (5);
7193                         CHECK_STACK (1);
7194                         --sp;
7195                         token = read32 (ip + 1);
7196                         klass = mini_get_class (method, token, generic_context);
7197                         CHECK_TYPELOAD (klass);
7198                         if (generic_class_is_reference_type (cfg, klass)) {
7199                                 MONO_INST_NEW (cfg, ins, CEE_LDIND_REF);
7200                                 ins->inst_i0 = sp [0];
7201                                 ins->type = STACK_OBJ;
7202                                 ins->klass = klass;
7203                                 ins->flags |= ins_flag;
7204                                 ins_flag = 0;
7205                                 *sp++ = ins;
7206                                 ip += 5;
7207                                 break;
7208                         }
7209
7210                         /* Optimize the common ldobj+stloc combination */
7211                         switch (ip [5]) {
7212                         case CEE_STLOC_S:
7213                                 loc_index = ip [6];
7214                                 stloc_len = 2;
7215                                 break;
7216                         case CEE_STLOC_0:
7217                         case CEE_STLOC_1:
7218                         case CEE_STLOC_2:
7219                         case CEE_STLOC_3:
7220                                 loc_index = ip [5] - CEE_STLOC_0;
7221                                 stloc_len = 1;
7222                                 break;
7223                         default:
7224                                 break;
7225                         }
7226
7227                         if ((loc_index != -1) && ip_in_bb (cfg, bblock, ip + 5)) {
7228                                 CHECK_LOCAL (loc_index);
7229                                 NEW_LOCSTORE (cfg, ins, loc_index, *sp);
7230
7231                                 /* FIXME: handle CEE_STIND_R4 */
7232                                 if (ins->opcode == CEE_STOBJ) {
7233                                         handle_loaded_temps (cfg, bblock, stack_start, sp);
7234                                         g_assert (ins->opcode == CEE_STOBJ);
7235                                         NEW_LOCLOADA (cfg, ins, loc_index);
7236                                         handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE, FALSE);
7237                                         ip += 5;
7238                                         ip += stloc_len;
7239                                         break;
7240                                 }
7241                         }
7242
7243                         n = mono_class_value_size (klass, &align);
7244                         ins = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
7245                         NEW_TEMPLOADA (cfg, iargs [0], ins->inst_c0);
7246                         if ((cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 5) {
7247                                 MonoInst *copy;
7248                                 NEW_MEMCPY (cfg, copy, iargs [0], *sp, n, align);
7249                                 MONO_ADD_INS (bblock, copy);
7250                         } else {
7251                                 MonoMethod *memcpy_method = get_memcpy_method ();
7252                                 iargs [1] = *sp;
7253                                 NEW_ICONST (cfg, iargs [2], n);
7254
7255                                 mono_emit_method_call_spilled (cfg, bblock, memcpy_method, memcpy_method->signature, iargs, ip, NULL);
7256                         }
7257                         NEW_TEMPLOAD (cfg, *sp, ins->inst_c0);
7258                         ++sp;
7259                         ip += 5;
7260                         ins_flag = 0;
7261                         inline_costs += 1;
7262                         break;
7263                 }
7264                 case CEE_LDSTR:
7265                         CHECK_STACK_OVF (1);
7266                         CHECK_OPSIZE (5);
7267                         n = read32 (ip + 1);
7268
7269                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
7270                                 /* FIXME: moving GC */
7271                                 NEW_PCONST (cfg, ins, mono_method_get_wrapper_data (method, n));
7272                                 ins->type = STACK_OBJ;
7273                                 ins->klass = mono_defaults.string_class;
7274                                 *sp = ins;
7275                         }
7276                         else if (method->wrapper_type != MONO_WRAPPER_NONE) {
7277                                 int temp;
7278                                 MonoInst *iargs [1];
7279
7280                                 NEW_PCONST (cfg, iargs [0], mono_method_get_wrapper_data (method, n));                          
7281                                 temp = mono_emit_jit_icall (cfg, bblock, mono_string_new_wrapper, iargs, ip);
7282                                 NEW_TEMPLOAD (cfg, *sp, temp);
7283
7284                         } else {
7285
7286                                 if (cfg->opt & MONO_OPT_SHARED) {
7287                                         int temp;
7288                                         MonoInst *iargs [3];
7289                                         MonoInst* domain_var;
7290                                         
7291                                         if (cfg->compile_aot) {
7292                                                 /* FIXME: bug when inlining methods from different assemblies (n is a token valid just in one). */
7293                                                 cfg->ldstr_list = g_list_prepend (cfg->ldstr_list, GINT_TO_POINTER (n));
7294                                         }
7295                                         /* avoid depending on undefined C behavior in sequence points */
7296                                         domain_var = mono_get_domainvar (cfg);
7297                                         NEW_TEMPLOAD (cfg, iargs [0], domain_var->inst_c0);
7298                                         NEW_IMAGECONST (cfg, iargs [1], image);
7299                                         NEW_ICONST (cfg, iargs [2], mono_metadata_token_index (n));
7300                                         temp = mono_emit_jit_icall (cfg, bblock, mono_ldstr, iargs, ip);
7301                                         NEW_TEMPLOAD (cfg, *sp, temp);
7302                                         mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
7303                                 } else {
7304                                         if (bblock->out_of_line) {
7305                                                 MonoInst *iargs [2];
7306                                                 int temp;
7307
7308                                                 if (cfg->method->klass->image == mono_defaults.corlib) {
7309                                                         /* 
7310                                                          * Avoid relocations and save some code size by using a 
7311                                                          * version of helper_ldstr specialized to mscorlib.
7312                                                          */
7313                                                         NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (n));
7314                                                         temp = mono_emit_jit_icall (cfg, bblock, mono_helper_ldstr_mscorlib, iargs, ip);
7315                                                 } else {
7316                                                         /* Avoid creating the string object */
7317                                                         NEW_IMAGECONST (cfg, iargs [0], image);
7318                                                         NEW_ICONST (cfg, iargs [1], mono_metadata_token_index (n));
7319                                                         temp = mono_emit_jit_icall (cfg, bblock, mono_helper_ldstr, iargs, ip);
7320                                                 }
7321                                                 NEW_TEMPLOAD (cfg, *sp, temp);
7322                                         } 
7323                                         else
7324                                         if (cfg->compile_aot) {
7325                                                 NEW_LDSTRCONST (cfg, ins, image, n);
7326                                                 *sp = ins;
7327                                         } 
7328                                         else {
7329                                                 NEW_PCONST (cfg, ins, NULL);
7330                                                 ins->type = STACK_OBJ;
7331                                                 ins->inst_p0 = mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
7332                                                 ins->klass = mono_defaults.string_class;
7333                                                 *sp = ins;
7334                                         }
7335                                 }
7336                         }
7337
7338                         sp++;
7339                         ip += 5;
7340                         break;
7341                 case CEE_NEWOBJ: {
7342                         MonoInst *iargs [2];
7343                         MonoMethodSignature *fsig;
7344                         MonoInst this_ins;
7345                         int temp;
7346
7347                         CHECK_OPSIZE (5);
7348                         token = read32 (ip + 1);
7349                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
7350                         if (!cmethod)
7351                                 goto load_error;
7352                         fsig = mono_method_get_signature (cmethod, image, token);
7353
7354                         mono_save_token_info (cfg, image, token, cmethod);
7355
7356                         if (!mono_class_init (cmethod->klass))
7357                                 goto load_error;
7358
7359                         if (cfg->generic_sharing_context)
7360                                 context_used = mono_method_check_context_used (cmethod);
7361
7362                         if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS) {
7363                                 if (check_linkdemand (cfg, method, cmethod, bblock, ip))
7364                                         INLINE_FAILURE;
7365                                 CHECK_CFG_EXCEPTION;
7366                         } else if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR) {
7367                                 ensure_method_is_allowed_to_call_method (cfg, method, cmethod, bblock, ip);
7368                         }
7369
7370                         n = fsig->param_count;
7371                         CHECK_STACK (n);
7372  
7373                         /* 
7374                          * Generate smaller code for the common newobj <exception> instruction in
7375                          * argument checking code.
7376                          */
7377                         if (bblock->out_of_line && cmethod->klass->image == mono_defaults.corlib && n <= 2 && 
7378                                 ((n < 1) || (!fsig->params [0]->byref && fsig->params [0]->type == MONO_TYPE_STRING)) && 
7379                                 ((n < 2) || (!fsig->params [1]->byref && fsig->params [1]->type == MONO_TYPE_STRING))) {
7380                                 MonoInst *iargs [3];
7381                                 int temp;
7382                                 
7383                                 sp -= n;
7384
7385                                 NEW_ICONST (cfg, iargs [0], cmethod->klass->type_token);
7386                                 switch (n) {
7387                                 case 0:
7388                                         temp = mono_emit_jit_icall (cfg, bblock, mono_create_corlib_exception_0, iargs, ip);
7389                                         break;
7390                                 case 1:
7391                                         iargs [1] = sp [0];
7392                                         temp = mono_emit_jit_icall (cfg, bblock, mono_create_corlib_exception_1, iargs, ip);
7393                                         break;
7394                                 case 2:
7395                                         iargs [1] = sp [0];
7396                                         iargs [2] = sp [1];
7397                                         temp = mono_emit_jit_icall (cfg, bblock, mono_create_corlib_exception_2, iargs, ip);
7398                                         break;
7399                                 default:
7400                                         g_assert_not_reached ();
7401                                 }
7402                                 NEW_TEMPLOAD (cfg, ins, temp);
7403                                 *sp ++ = ins;
7404
7405                                 ip += 5;
7406                                 inline_costs += 5;
7407                                 break;
7408                         }
7409
7410                         /* move the args to allow room for 'this' in the first position */
7411                         while (n--) {
7412                                 --sp;
7413                                 sp [1] = sp [0];
7414                         }
7415
7416                         /* check_call_signature () requires sp[0] to be set */
7417                         this_ins.type = STACK_OBJ;
7418                         sp [0] = &this_ins;
7419                         if (check_call_signature (cfg, fsig, sp))
7420                                 UNVERIFIED;
7421
7422                         handle_loaded_temps (cfg, bblock, stack_start, sp);
7423
7424                         if (mini_class_is_system_array (cmethod->klass)) {
7425                                 g_assert (!context_used);
7426
7427                                 NEW_METHODCONST (cfg, *sp, cmethod);
7428
7429                                 if (fsig->param_count == 2)
7430                                         /* Avoid varargs in the common case */
7431                                         temp = mono_emit_jit_icall (cfg, bblock, mono_array_new_2, sp, ip);
7432                                 else
7433                                         temp = handle_array_new (cfg, bblock, fsig->param_count, sp, ip);
7434                         } else if (cmethod->string_ctor) {
7435                                 g_assert (!context_used);
7436
7437                                 /* we simply pass a null pointer */
7438                                 NEW_PCONST (cfg, *sp, NULL); 
7439                                 /* now call the string ctor */
7440                                 temp = mono_emit_method_call_spilled (cfg, bblock, cmethod, fsig, sp, ip, NULL);
7441                         } else {
7442                                 MonoInst* callvirt_this_arg = NULL;
7443                                 
7444                                 if (cmethod->klass->valuetype) {
7445                                         iargs [0] = mono_compile_create_var (cfg, &cmethod->klass->byval_arg, OP_LOCAL);
7446                                         temp = iargs [0]->inst_c0;
7447
7448                                         NEW_TEMPLOADA (cfg, *sp, temp);
7449
7450                                         handle_initobj (cfg, bblock, *sp, NULL, cmethod->klass, stack_start, sp);
7451
7452                                         NEW_TEMPLOADA (cfg, *sp, temp);
7453
7454                                         /* 
7455                                          * The code generated by mini_emit_virtual_call () expects
7456                                          * iargs [0] to be a boxed instance, but luckily the vcall
7457                                          * will be transformed into a normal call there.
7458                                          */
7459                                 } else if (context_used) {
7460                                         MonoInst *rgctx, *data;
7461                                         int rgctx_info;
7462
7463                                         GET_RGCTX (rgctx, context_used);
7464                                         if (cfg->opt & MONO_OPT_SHARED)
7465                                                 rgctx_info = MONO_RGCTX_INFO_KLASS;
7466                                         else
7467                                                 rgctx_info = MONO_RGCTX_INFO_VTABLE;
7468                                         data = get_runtime_generic_context_ptr (cfg, method, context_used, bblock,
7469                                                 cmethod->klass, generic_context, rgctx, rgctx_info, ip);
7470
7471                                         temp = handle_alloc_from_inst (cfg, bblock, cmethod->klass, data, FALSE, ip);
7472                                         NEW_TEMPLOAD (cfg, *sp, temp);
7473                                 } else {
7474                                         MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
7475
7476                                         CHECK_TYPELOAD (cmethod->klass);
7477                                         if (mini_field_access_needs_cctor_run (cfg, method, vtable) && !(g_slist_find (class_inits, vtable))) {
7478                                                 guint8 *tramp = mono_create_class_init_trampoline (vtable);
7479                                                 mono_emit_native_call (cfg, bblock, tramp, 
7480                                                                                            helper_sig_class_init_trampoline,
7481                                                                                            NULL, ip, FALSE, FALSE);
7482                                                 if (cfg->verbose_level > 2)
7483                                                         g_print ("class %s.%s needs init call for ctor\n", cmethod->klass->name_space, cmethod->klass->name);
7484                                                 class_inits = g_slist_prepend (class_inits, vtable);
7485                                         }
7486                                         temp = handle_alloc (cfg, bblock, cmethod->klass, FALSE, ip);
7487                                         NEW_TEMPLOAD (cfg, *sp, temp);
7488                                 }
7489
7490                                 /* Avoid virtual calls to ctors if possible */
7491                                 if (cmethod->klass->marshalbyref)
7492                                         callvirt_this_arg = sp [0];
7493                                 
7494                                 if ((cfg->opt & MONO_OPT_INLINE) && cmethod && !context_used &&
7495                                     mono_method_check_inlining (cfg, cmethod) &&
7496                                     !mono_class_is_subclass_of (cmethod->klass, mono_defaults.exception_class, FALSE) &&
7497                                     !g_list_find (dont_inline, cmethod)) {
7498                                         int costs;
7499                                         MonoBasicBlock *ebblock;
7500                                         if ((costs = inline_method (cfg, cmethod, fsig, bblock, sp, ip, real_offset, dont_inline, &ebblock, FALSE))) {
7501
7502                                                 ip += 5;
7503                                                 real_offset += 5;
7504                                                 
7505                                                 GET_BBLOCK (cfg, bblock, ip);
7506                                                 ebblock->next_bb = bblock;
7507                                                 link_bblock (cfg, ebblock, bblock);
7508
7509                                                 NEW_TEMPLOAD (cfg, *sp, temp);
7510                                                 sp++;
7511
7512                                                 /* indicates start of a new block, and triggers a load 
7513                                                    of all stack arguments at bb boundarie */
7514                                                 bblock = ebblock;
7515
7516                                                 inline_costs += costs;
7517                                                 break;
7518                                                 
7519                                         } else {
7520                                                 /* Prevent inlining of methods which call other methods */
7521                                                 INLINE_FAILURE;
7522                                                 mono_emit_method_call_spilled (cfg, bblock, cmethod, fsig, sp, ip, callvirt_this_arg);
7523                                         }
7524                                 } else if (context_used &&
7525                                                 (cmethod->klass->valuetype ||
7526                                                 !mono_method_is_generic_sharable_impl (cmethod, TRUE))) {
7527                                         MonoInst *rgctx, *cmethod_addr;
7528
7529                                         g_assert (!callvirt_this_arg);
7530
7531                                         GET_RGCTX (rgctx, context_used);
7532                                         cmethod_addr = get_runtime_generic_context_method (cfg, method, context_used,
7533                                                         bblock, cmethod,
7534                                                         generic_context, rgctx, MONO_RGCTX_INFO_GENERIC_METHOD_CODE, ip);
7535
7536                                         mono_emit_calli_spilled (cfg, bblock, fsig, sp, cmethod_addr, ip);
7537                                 } else {
7538                                         /* Prevent inlining of methods which call other methods */
7539                                         INLINE_FAILURE;
7540                                         /* now call the actual ctor */
7541                                         mono_emit_method_call_spilled (cfg, bblock, cmethod, fsig, sp, ip, callvirt_this_arg);
7542                                 }
7543                         }
7544
7545                         NEW_TEMPLOAD (cfg, *sp, temp);
7546                         sp++;
7547                         
7548                         ip += 5;
7549                         inline_costs += 5;
7550                         break;
7551                 }
7552                 case CEE_ISINST:
7553                         CHECK_STACK (1);
7554                         --sp;
7555                         CHECK_OPSIZE (5);
7556                         token = read32 (ip + 1);
7557                         klass = mini_get_class (method, token, generic_context);
7558                         CHECK_TYPELOAD (klass);
7559                         if (sp [0]->type != STACK_OBJ)
7560                                 UNVERIFIED;
7561
7562                         if (cfg->generic_sharing_context)
7563                                 context_used = mono_class_check_context_used (klass);
7564
7565                         /* Needed by the code generated in inssel.brg */
7566                         if (!context_used)
7567                                 mono_get_got_var (cfg);
7568
7569                         if (context_used) {
7570                                 MonoInst *rgctx, *args [2];
7571                                 int temp;
7572
7573                                 /* obj */
7574                                 args [0] = *sp;
7575
7576                                 /* klass */
7577                                 GET_RGCTX (rgctx, context_used);
7578                                 args [1] = get_runtime_generic_context_ptr (cfg, method, context_used, bblock, klass,
7579                                         generic_context, rgctx, MONO_RGCTX_INFO_KLASS, ip);
7580
7581                                 temp = mono_emit_jit_icall (cfg, bblock, mono_object_isinst, args, ip);
7582                                 NEW_TEMPLOAD (cfg, *sp, temp);
7583
7584                                 sp++;
7585                                 ip += 5;
7586                                 inline_costs += 2;
7587                         } else if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
7588                         
7589                                 MonoMethod *mono_isinst;
7590                                 MonoInst *iargs [1];
7591                                 MonoBasicBlock *ebblock;
7592                                 int costs;
7593                                 int temp;
7594                                 
7595                                 mono_isinst = mono_marshal_get_isinst (klass); 
7596                                 iargs [0] = sp [0];
7597                                 
7598                                 costs = inline_method (cfg, mono_isinst, mono_method_signature (mono_isinst), bblock, 
7599                                                        iargs, ip, real_offset, dont_inline, &ebblock, TRUE);
7600                         
7601                                 g_assert (costs > 0);
7602                                 
7603                                 ip += 5;
7604                                 real_offset += 5;
7605                         
7606                                 GET_BBLOCK (cfg, bblock, ip);
7607                                 ebblock->next_bb = bblock;
7608                                 link_bblock (cfg, ebblock, bblock);
7609
7610                                 temp = iargs [0]->inst_i0->inst_c0;
7611                                 NEW_TEMPLOAD (cfg, *sp, temp);
7612                                 
7613                                 sp++;
7614                                 bblock = ebblock;
7615                                 inline_costs += costs;
7616                         } else {
7617                                 MONO_INST_NEW (cfg, ins, *ip);
7618                                 ins->type = STACK_OBJ;
7619                                 ins->inst_left = *sp;
7620                                 ins->inst_newa_class = klass;
7621                                 ins->klass = klass;
7622                                 *sp++ = emit_tree (cfg, bblock, ins, ip + 5);
7623                                 ip += 5;
7624                         }
7625                         break;
7626                 case CEE_UNBOX_ANY: {
7627                         MonoInst *iargs [3];
7628                         guint32 align;
7629
7630                         CHECK_STACK (1);
7631                         --sp;
7632                         CHECK_OPSIZE (5);
7633                         token = read32 (ip + 1);
7634                         klass = mini_get_class (method, token, generic_context);
7635                         CHECK_TYPELOAD (klass);
7636
7637                         if (cfg->generic_sharing_context)
7638                                 context_used = mono_class_check_context_used (klass);
7639
7640                         if (generic_class_is_reference_type (cfg, klass)) {
7641                                 switch (emit_castclass (klass, token, context_used, FALSE,
7642                                                 cfg, method, arg_array, param_types, dont_inline, end, header,
7643                                                 generic_context, &bblock, &ip, &sp, &inline_costs, &real_offset)) {
7644                                 case 0: break;
7645                                 case -1: goto unverified;
7646                                 case -2: goto exception_exit;
7647                                 default: g_assert_not_reached ();
7648                                 }
7649                                 break;
7650                         }
7651
7652                         if (mono_class_is_nullable (klass)) {
7653                                 int v;
7654                                 MonoInst *rgctx = NULL;
7655
7656                                 if (context_used)
7657                                         GET_RGCTX (rgctx, context_used);
7658
7659                                 v = handle_unbox_nullable (cfg, method, context_used, bblock, *sp, ip, klass,
7660                                         generic_context, rgctx);
7661                                 NEW_TEMPLOAD (cfg, *sp, v);
7662                                 sp ++;
7663                                 ip += 5;
7664                                 break;
7665                         }
7666
7667                         switch (emit_unbox (klass, token, context_used,
7668                                         cfg, method, arg_array, param_types, dont_inline, end, header,
7669                                         generic_context, &bblock, &ip, &sp, &inline_costs, &real_offset)) {
7670                         case 0: break;
7671                         case -1: goto unverified;
7672                         case -2: goto exception_exit;
7673                         default: g_assert_not_reached ();
7674                         }
7675                         ip += 5;
7676                         /* LDOBJ impl */
7677                         n = mono_class_value_size (klass, &align);
7678                         ins = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
7679                         NEW_TEMPLOADA (cfg, iargs [0], ins->inst_c0);
7680                         if ((cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 5) {
7681                                 MonoInst *copy;
7682                                 NEW_MEMCPY (cfg, copy, iargs [0], *sp, n, align);
7683                                 MONO_ADD_INS (bblock, copy);
7684                         } else {
7685                                 MonoMethod *memcpy_method = get_memcpy_method ();
7686                                 iargs [1] = *sp;
7687                                 NEW_ICONST (cfg, iargs [2], n);
7688
7689                                 mono_emit_method_call_spilled (cfg, bblock, memcpy_method, memcpy_method->signature, iargs, ip, NULL);
7690                         }
7691                         NEW_TEMPLOAD (cfg, *sp, ins->inst_c0);
7692                         ++sp;
7693                         inline_costs += 2;
7694                         break;
7695                 }
7696                 case CEE_UNBOX:
7697                         CHECK_STACK (1);
7698                         --sp;
7699                         CHECK_OPSIZE (5);
7700                         token = read32 (ip + 1);
7701                         klass = mini_get_class (method, token, generic_context);
7702                         CHECK_TYPELOAD (klass);
7703
7704                         if (cfg->generic_sharing_context)
7705                                 context_used = mono_class_check_context_used (klass);
7706
7707                         if (mono_class_is_nullable (klass)) {
7708                                 int v;
7709                                 MonoInst *rgctx = NULL;
7710
7711                                 if (context_used)
7712                                         GET_RGCTX (rgctx, context_used);
7713                                 v = handle_unbox_nullable (cfg, method, context_used, bblock, *sp, ip, klass,
7714                                         generic_context, rgctx);
7715                                 NEW_TEMPLOAD (cfg, *sp, v);
7716                                 sp ++;
7717                                 ip += 5;
7718                                 break;
7719                         }
7720
7721                         switch (emit_unbox (klass, token, context_used,
7722                                         cfg, method, arg_array, param_types, dont_inline, end, header,
7723                                         generic_context, &bblock, &ip, &sp, &inline_costs, &real_offset)) {
7724                         case 0: break;
7725                         case -1: goto unverified;
7726                         case -2: goto exception_exit;
7727                         default: g_assert_not_reached ();
7728                         }
7729
7730                         sp++;
7731                         ip += 5;
7732                         inline_costs += 2;
7733                         break;
7734                 case CEE_CASTCLASS:
7735                         CHECK_STACK (1);
7736                         --sp;
7737                         CHECK_OPSIZE (5);
7738                         token = read32 (ip + 1);
7739                         klass = mini_get_class (method, token, generic_context);
7740                         CHECK_TYPELOAD (klass);
7741                         if (sp [0]->type != STACK_OBJ)
7742                                 UNVERIFIED;
7743
7744                         if (cfg->generic_sharing_context)
7745                                 context_used = mono_class_check_context_used (klass);
7746
7747                         switch (emit_castclass (klass, token, context_used, TRUE,
7748                                         cfg, method, arg_array, param_types, dont_inline, end, header,
7749                                         generic_context, &bblock, &ip, &sp, &inline_costs, &real_offset)) {
7750                         case 0: break;
7751                         case -1: goto unverified;
7752                         case -2: goto exception_exit;
7753                         default: g_assert_not_reached ();
7754                         }
7755                         break;
7756                 case CEE_THROW:
7757                         CHECK_STACK (1);
7758                         MONO_INST_NEW (cfg, ins, OP_THROW);
7759                         --sp;
7760                         ins->inst_left = *sp;
7761                         ip++;
7762                         bblock->out_of_line = TRUE;
7763                         MONO_ADD_INS (bblock, ins);
7764                         MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
7765                         ins->cil_code = ip - 1;
7766                         MONO_ADD_INS (bblock, ins);
7767                         sp = stack_start;
7768                         
7769                         link_bblock (cfg, bblock, end_bblock);
7770                         start_new_bblock = 1;
7771                         break;
7772                 case CEE_LDFLD:
7773                 case CEE_LDFLDA:
7774                 case CEE_STFLD: {
7775                         MonoInst *offset_ins;
7776                         MonoClassField *field;
7777                         MonoBasicBlock *ebblock;
7778                         int costs;
7779                         guint foffset;
7780
7781                         if (*ip == CEE_STFLD) {
7782                                 CHECK_STACK (2);
7783                                 sp -= 2;
7784                         } else {
7785                                 CHECK_STACK (1);
7786                                 --sp;
7787                         }
7788                         if (sp [0]->type == STACK_I4 || sp [0]->type == STACK_I8 || sp [0]->type == STACK_R8)
7789                                 UNVERIFIED;
7790                         if (*ip != CEE_LDFLD && sp [0]->type == STACK_VTYPE)
7791                                 UNVERIFIED;
7792                         CHECK_OPSIZE (5);
7793                         token = read32 (ip + 1);
7794                         if (method->wrapper_type != MONO_WRAPPER_NONE) {
7795                                 field = mono_method_get_wrapper_data (method, token);
7796                                 klass = field->parent;
7797                         } else {
7798                                 field = mono_field_from_token (image, token, &klass, generic_context);
7799                         }
7800                         if (!field)
7801                                 goto load_error;
7802                         mono_class_init (klass);
7803                         if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_field (method, field))
7804                                 FIELD_ACCESS_FAILURE;
7805
7806                         foffset = klass->valuetype? field->offset - sizeof (MonoObject): field->offset;
7807                         /* FIXME: mark instructions for use in SSA */
7808                         if (*ip == CEE_STFLD) {
7809                                 if (target_type_is_incompatible (cfg, field->type, sp [1]))
7810                                         UNVERIFIED;
7811                                 if ((klass->marshalbyref && !MONO_CHECK_THIS (sp [0])) || klass->contextbound || klass == mono_defaults.marshalbyrefobject_class) {
7812                                         MonoMethod *stfld_wrapper = mono_marshal_get_stfld_wrapper (field->type); 
7813                                         MonoInst *iargs [5];
7814
7815                                         iargs [0] = sp [0];
7816                                         NEW_CLASSCONST (cfg, iargs [1], klass);
7817                                         NEW_FIELDCONST (cfg, iargs [2], field);
7818                                         NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : 
7819                                                     field->offset);
7820                                         iargs [4] = sp [1];
7821
7822                                         if (cfg->opt & MONO_OPT_INLINE) {
7823                                                 costs = inline_method (cfg, stfld_wrapper, mono_method_signature (stfld_wrapper), bblock, 
7824                                                                 iargs, ip, real_offset, dont_inline, &ebblock, TRUE);
7825                                                 g_assert (costs > 0);
7826                                                       
7827                                                 ip += 5;
7828                                                 real_offset += 5;
7829
7830                                                 GET_BBLOCK (cfg, bblock, ip);
7831                                                 ebblock->next_bb = bblock;
7832                                                 link_bblock (cfg, ebblock, bblock);
7833
7834                                                 /* indicates start of a new block, and triggers a load 
7835                                                    of all stack arguments at bb boundarie */
7836                                                 bblock = ebblock;
7837
7838                                                 inline_costs += costs;
7839                                                 break;
7840                                         } else {
7841                                                 mono_emit_method_call_spilled (cfg, bblock, stfld_wrapper, mono_method_signature (stfld_wrapper), iargs, ip, NULL);
7842                                         }
7843 #if HAVE_WRITE_BARRIERS
7844                                 } else if (mini_type_to_stind (cfg, field->type) == CEE_STIND_REF && !(sp [1]->opcode == OP_PCONST && sp [1]->inst_c0 == 0)) {
7845                                         /* insert call to write barrier */
7846                                         MonoMethod *write_barrier = mono_marshal_get_write_barrier ();
7847                                         MonoInst *iargs [2];
7848                                         NEW_ICONST (cfg, offset_ins, foffset);
7849                                         MONO_INST_NEW (cfg, ins, OP_PADD);
7850                                         ins->inst_left = *sp;
7851                                         ins->inst_right = offset_ins;
7852                                         ins->type = STACK_MP;
7853                                         ins->klass = mono_defaults.object_class;
7854                                         iargs [0] = ins;
7855                                         iargs [1] = sp [1];
7856                                         mono_emit_method_call_spilled (cfg, bblock, write_barrier, mono_method_signature (write_barrier), iargs, ip, NULL);
7857 #endif
7858 #ifdef MONO_ARCH_SOFT_FLOAT
7859                                 } else if (mini_type_to_stind (cfg, field->type) == CEE_STIND_R4) {
7860                                         NEW_ICONST (cfg, offset_ins, foffset);
7861                                         MONO_INST_NEW (cfg, ins, OP_PADD);
7862                                         ins->inst_left = *sp;
7863                                         ins->inst_right = offset_ins;
7864                                         ins->type = STACK_MP;
7865                                         ins->klass = mono_defaults.object_class;
7866                                         handle_store_float (cfg, bblock, ins, sp [1], ip);
7867 #endif
7868                                 } else {
7869                                         MonoInst *store;
7870                                         NEW_ICONST (cfg, offset_ins, foffset);
7871                                         MONO_INST_NEW (cfg, ins, OP_PADD);
7872                                         ins->inst_left = *sp;
7873                                         ins->inst_right = offset_ins;
7874                                         ins->type = STACK_MP;
7875
7876                                         MONO_INST_NEW (cfg, store, mini_type_to_stind (cfg, field->type));
7877                                         store->inst_left = ins;
7878                                         store->inst_right = sp [1];
7879                                         handle_loaded_temps (cfg, bblock, stack_start, sp);
7880                                         store->flags |= ins_flag;
7881                                         ins_flag = 0;
7882                                         if (store->opcode == CEE_STOBJ) {
7883                                                 handle_stobj (cfg, bblock, ins, sp [1], ip, 
7884                                                               mono_class_from_mono_type (field->type), FALSE, FALSE, TRUE);
7885                                         } else
7886                                                 MONO_ADD_INS (bblock, store);
7887                                 }
7888                         } else {
7889                                 if ((klass->marshalbyref && !MONO_CHECK_THIS (sp [0])) || klass->contextbound || klass == mono_defaults.marshalbyrefobject_class) {
7890                                         MonoMethod *wrapper = (*ip == CEE_LDFLDA) ? mono_marshal_get_ldflda_wrapper (field->type) : mono_marshal_get_ldfld_wrapper (field->type); 
7891                                         MonoInst *iargs [4];
7892                                         int temp;
7893                                         
7894                                         iargs [0] = sp [0];
7895                                         NEW_CLASSCONST (cfg, iargs [1], klass);
7896                                         NEW_FIELDCONST (cfg, iargs [2], field);
7897                                         NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset);
7898                                         if ((cfg->opt & MONO_OPT_INLINE) && !MONO_TYPE_ISSTRUCT (mono_method_signature (wrapper)->ret)) {
7899                                                 costs = inline_method (cfg, wrapper, mono_method_signature (wrapper), bblock, 
7900                                                                 iargs, ip, real_offset, dont_inline, &ebblock, TRUE);
7901                                                 g_assert (costs > 0);
7902                                                       
7903                                                 ip += 5;
7904                                                 real_offset += 5;
7905
7906                                                 GET_BBLOCK (cfg, bblock, ip);
7907                                                 ebblock->next_bb = bblock;
7908                                                 link_bblock (cfg, ebblock, bblock);
7909
7910                                                 temp = iargs [0]->inst_i0->inst_c0;
7911
7912                                                 NEW_TEMPLOAD (cfg, *sp, temp);
7913                                                 sp++;
7914
7915                                                 /* indicates start of a new block, and triggers a load of
7916                                                    all stack arguments at bb boundarie */
7917                                                 bblock = ebblock;
7918                                                 
7919                                                 inline_costs += costs;
7920                                                 break;
7921                                         } else {
7922                                                 temp = mono_emit_method_call_spilled (cfg, bblock, wrapper, mono_method_signature (wrapper), iargs, ip, NULL);
7923                                                 NEW_TEMPLOAD (cfg, *sp, temp);
7924                                                 NEW_TEMPLOAD_SOFT_FLOAT (cfg, bblock, *sp, temp, ip);
7925                                                 sp++;
7926                                         }
7927                                 } else {
7928                                         NEW_ICONST (cfg, offset_ins, foffset);
7929                                         MONO_INST_NEW (cfg, ins, OP_PADD);
7930                                         ins->inst_left = *sp;
7931                                         ins->inst_right = offset_ins;
7932                                         ins->type = STACK_MP;
7933
7934                                         if (*ip == CEE_LDFLDA) {
7935                                                 ins->klass = mono_class_from_mono_type (field->type);
7936                                                 *sp++ = ins;
7937                                         } else {
7938                                                 MonoInst *load;
7939                                                 MONO_INST_NEW (cfg, load, mini_type_to_ldind (cfg, field->type));
7940                                                 type_to_eval_stack_type (cfg, field->type, load);
7941                                                 load->inst_left = ins;
7942                                                 load->flags |= ins_flag;
7943                                                 ins_flag = 0;
7944 #ifdef MONO_ARCH_SOFT_FLOAT
7945                                                 if (mini_type_to_ldind (cfg, field->type) == CEE_LDIND_R4) {
7946                                                         int temp;
7947                                                         temp = handle_load_float (cfg, bblock, ins, ip);
7948                                                         NEW_TEMPLOAD (cfg, *sp, temp);
7949                                                         sp++;
7950                                                 } else
7951 #endif
7952                                                 *sp++ = load;
7953                                         }
7954                                 }
7955                         }
7956                         ip += 5;
7957                         break;
7958                 }
7959                 case CEE_LDSFLD:
7960                 case CEE_LDSFLDA:
7961                 case CEE_STSFLD: {
7962                         MonoClassField *field;
7963                         gboolean is_special_static;
7964                         gpointer addr = NULL;
7965
7966                         CHECK_OPSIZE (5);
7967                         token = read32 (ip + 1);
7968                         if (method->wrapper_type != MONO_WRAPPER_NONE) {
7969                                 field = mono_method_get_wrapper_data (method, token);
7970                                 klass = field->parent;
7971                         }
7972                         else
7973                                 field = mono_field_from_token (image, token, &klass, generic_context);
7974                         if (!field)
7975                                 goto load_error;
7976                         mono_class_init (klass);
7977                         if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_field (method, field))
7978                                 FIELD_ACCESS_FAILURE;
7979
7980                         /*
7981                          * We can only support shared generic static
7982                          * field access on architectures where the
7983                          * trampoline code has been extended to handle
7984                          * the generic class init.
7985                          */
7986 #ifndef MONO_ARCH_VTABLE_REG
7987                         GENERIC_SHARING_FAILURE (*ip);
7988 #endif
7989
7990                         if (cfg->generic_sharing_context)
7991                                 context_used = mono_class_check_context_used (klass);
7992
7993                         g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
7994
7995                         if ((*ip) == CEE_STSFLD)
7996                                 handle_loaded_temps (cfg, bblock, stack_start, sp);
7997
7998                         is_special_static = mono_class_field_is_special_static (field);
7999
8000                         if ((cfg->opt & MONO_OPT_SHARED) ||
8001                                         (cfg->compile_aot && is_special_static) ||
8002                                         (context_used && is_special_static)) {
8003                                 int temp;
8004                                 MonoInst *iargs [2];
8005
8006                                 g_assert (field->parent);
8007                                 if ((cfg->opt & MONO_OPT_SHARED) || cfg->compile_aot) {
8008                                         MonoInst *domain_var;
8009                                         /* avoid depending on undefined C behavior in sequence points */
8010                                         domain_var = mono_get_domainvar (cfg);
8011                                         NEW_TEMPLOAD (cfg, iargs [0], domain_var->inst_c0);
8012                                 } else {
8013                                         NEW_DOMAINCONST (cfg, iargs [0]);
8014                                 }
8015                                 if (context_used) {
8016                                         MonoInst *rgctx;
8017
8018                                         GET_RGCTX (rgctx, context_used);
8019                                         iargs [1] = get_runtime_generic_context_field (cfg, method, context_used,
8020                                                         bblock, field,
8021                                                         generic_context, rgctx, MONO_RGCTX_INFO_CLASS_FIELD, ip);
8022                                 } else {
8023                                         NEW_FIELDCONST (cfg, iargs [1], field);
8024                                 }
8025                                 temp = mono_emit_jit_icall (cfg, bblock, mono_class_static_field_address, iargs, ip);
8026                                 NEW_TEMPLOAD (cfg, ins, temp);
8027                         } else if (context_used) {
8028                                 MonoInst *rgctx, *static_data;
8029
8030                                 /*
8031                                 g_print ("sharing static field access in %s.%s.%s - depth %d offset %d\n",
8032                                         method->klass->name_space, method->klass->name, method->name,
8033                                         depth, field->offset);
8034                                 */
8035
8036                                 if (mono_class_needs_cctor_run (klass, method)) {
8037                                         MonoMethodSignature *sig = helper_sig_generic_class_init_trampoline;
8038                                         MonoCallInst *call;
8039                                         MonoInst *vtable, *rgctx;
8040
8041                                         GET_RGCTX (rgctx, context_used);
8042                                         vtable = get_runtime_generic_context_ptr (cfg, method, context_used, bblock, klass,
8043                                                         generic_context, rgctx, MONO_RGCTX_INFO_VTABLE, ip);
8044
8045                                         call = mono_emit_call_args (cfg, bblock, sig, NULL, FALSE, FALSE, ip, FALSE);
8046                                         call->inst.opcode = OP_TRAMPCALL_VTABLE;
8047                                         call->fptr = mono_get_trampoline_code (MONO_TRAMPOLINE_GENERIC_CLASS_INIT);
8048
8049                                         call->inst.inst_left = vtable;
8050
8051                                         mono_spill_call (cfg, bblock, call, sig, FALSE, ip, FALSE);
8052                                 }
8053
8054                                 /*
8055                                  * The pointer we're computing here is
8056                                  *
8057                                  *   super_info.static_data + field->offset
8058                                  */
8059                                 GET_RGCTX (rgctx, context_used);
8060                                 static_data = get_runtime_generic_context_ptr (cfg, method, context_used, bblock, klass,
8061                                         generic_context, rgctx, MONO_RGCTX_INFO_STATIC_DATA, ip);
8062
8063                                 if (field->offset == 0) {
8064                                         ins = static_data;
8065                                 } else {
8066                                         MonoInst *field_offset;
8067
8068                                         NEW_ICONST (cfg, field_offset, field->offset);
8069
8070                                         MONO_INST_NEW (cfg, ins, OP_PADD);
8071                                         ins->inst_left = static_data;
8072                                         ins->inst_right = field_offset;
8073                                         ins->type = STACK_PTR;
8074                                         ins->klass = klass;
8075                                 }
8076                         } else {
8077                                 MonoVTable *vtable;
8078
8079                                 vtable = mono_class_vtable (cfg->domain, klass);
8080                                 CHECK_TYPELOAD (klass);
8081                                 if (!is_special_static) {
8082                                         if (mini_field_access_needs_cctor_run (cfg, method, vtable) && !(g_slist_find (class_inits, vtable))) {
8083                                                 guint8 *tramp = mono_create_class_init_trampoline (vtable);
8084                                                 mono_emit_native_call (cfg, bblock, tramp, 
8085                                                                                            helper_sig_class_init_trampoline,
8086                                                                                            NULL, ip, FALSE, FALSE);
8087                                                 if (cfg->verbose_level > 2)
8088                                                         g_print ("class %s.%s needs init call for %s\n", klass->name_space, klass->name, field->name);
8089                                                 class_inits = g_slist_prepend (class_inits, vtable);
8090                                         } else {
8091                                                 if (cfg->run_cctors) {
8092                                                         MonoException *ex;
8093                                                         /* This makes so that inline cannot trigger */
8094                                                         /* .cctors: too many apps depend on them */
8095                                                         /* running with a specific order... */
8096                                                         if (! vtable->initialized)
8097                                                                 INLINE_FAILURE;
8098                                                         ex = mono_runtime_class_init_full (vtable, FALSE);
8099                                                         if (ex) {
8100                                                                 set_exception_object (cfg, ex);
8101                                                                 goto exception_exit;
8102                                                         }                                       
8103                                                 }
8104                                         }
8105                                         addr = (char*)vtable->data + field->offset;
8106
8107                                         if (cfg->compile_aot)
8108                                                 NEW_SFLDACONST (cfg, ins, field);
8109                                         else
8110                                                 NEW_PCONST (cfg, ins, addr);
8111                                 } else {
8112                                         int temp;
8113                                         MonoInst *iargs [1];
8114
8115                                         /* The special_static_fields
8116                                          * field is init'd in
8117                                          * mono_class_vtable, so it
8118                                          * needs to be called here.
8119                                          */
8120                                         if (!(cfg->opt & MONO_OPT_SHARED)) {
8121                                                 mono_class_vtable (cfg->domain, klass);
8122                                                 CHECK_TYPELOAD (klass);
8123                                         }
8124                                         mono_domain_lock (cfg->domain);
8125                                         if (cfg->domain->special_static_fields)
8126                                                 addr = g_hash_table_lookup (cfg->domain->special_static_fields, field);
8127                                         mono_domain_unlock (cfg->domain);
8128
8129                                         /* 
8130                                          * insert call to mono_threads_get_static_data (GPOINTER_TO_UINT (addr)) 
8131                                          * This could be later optimized to do just a couple of
8132                                          * memory dereferences with constant offsets.
8133                                          */
8134                                         NEW_ICONST (cfg, iargs [0], GPOINTER_TO_UINT (addr));
8135                                         temp = mono_emit_jit_icall (cfg, bblock, mono_get_special_static_data, iargs, ip);
8136                                         NEW_TEMPLOAD (cfg, ins, temp);
8137                                 }
8138                         }
8139
8140                         /* FIXME: mark instructions for use in SSA */
8141                         if (*ip == CEE_LDSFLDA) {
8142                                 ins->klass = mono_class_from_mono_type (field->type);
8143                                 *sp++ = ins;
8144                         } else if (*ip == CEE_STSFLD) {
8145                                 MonoInst *store;
8146                                 CHECK_STACK (1);
8147                                 sp--;
8148                                 MONO_INST_NEW (cfg, store, mini_type_to_stind (cfg, field->type));
8149                                 store->inst_left = ins;
8150                                 store->inst_right = sp [0];
8151                                 store->flags |= ins_flag;
8152                                 ins_flag = 0;
8153
8154 #ifdef MONO_ARCH_SOFT_FLOAT
8155                                 if (store->opcode == CEE_STIND_R4)
8156                                         handle_store_float (cfg, bblock, ins, sp [0], ip);
8157                                 else
8158 #endif
8159                                 if (store->opcode == CEE_STOBJ) {
8160                                         handle_stobj (cfg, bblock, ins, sp [0], ip, mono_class_from_mono_type (field->type), FALSE, FALSE, FALSE);
8161                                 } else
8162                                         MONO_ADD_INS (bblock, store);
8163                         } else {
8164                                 gboolean is_const = FALSE;
8165                                 MonoVTable *vtable = NULL;
8166
8167                                 if (!context_used)
8168                                         vtable = mono_class_vtable (cfg->domain, klass);
8169
8170                                 CHECK_TYPELOAD (klass);
8171                                 if (!context_used && !((cfg->opt & MONO_OPT_SHARED) || cfg->compile_aot) && 
8172                                     vtable->initialized && (field->type->attrs & FIELD_ATTRIBUTE_INIT_ONLY)) {
8173                                         gpointer addr = (char*)vtable->data + field->offset;
8174                                         int ro_type = field->type->type;
8175                                         if (ro_type == MONO_TYPE_VALUETYPE && field->type->data.klass->enumtype) {
8176                                                 ro_type = field->type->data.klass->enum_basetype->type;
8177                                         }
8178                                         /* g_print ("RO-FIELD %s.%s:%s\n", klass->name_space, klass->name, field->name);*/
8179                                         is_const = TRUE;
8180                                         switch (ro_type) {
8181                                         case MONO_TYPE_BOOLEAN:
8182                                         case MONO_TYPE_U1:
8183                                                 NEW_ICONST (cfg, *sp, *((guint8 *)addr));
8184                                                 sp++;
8185                                                 break;
8186                                         case MONO_TYPE_I1:
8187                                                 NEW_ICONST (cfg, *sp, *((gint8 *)addr));
8188                                                 sp++;
8189                                                 break;                                          
8190                                         case MONO_TYPE_CHAR:
8191                                         case MONO_TYPE_U2:
8192                                                 NEW_ICONST (cfg, *sp, *((guint16 *)addr));
8193                                                 sp++;
8194                                                 break;
8195                                         case MONO_TYPE_I2:
8196                                                 NEW_ICONST (cfg, *sp, *((gint16 *)addr));
8197                                                 sp++;
8198                                                 break;
8199                                                 break;
8200                                         case MONO_TYPE_I4:
8201                                                 NEW_ICONST (cfg, *sp, *((gint32 *)addr));
8202                                                 sp++;
8203                                                 break;                                          
8204                                         case MONO_TYPE_U4:
8205                                                 NEW_ICONST (cfg, *sp, *((guint32 *)addr));
8206                                                 sp++;
8207                                                 break;
8208 #ifndef HAVE_MOVING_COLLECTOR
8209                                         case MONO_TYPE_I:
8210                                         case MONO_TYPE_U:
8211                                         case MONO_TYPE_STRING:
8212                                         case MONO_TYPE_OBJECT:
8213                                         case MONO_TYPE_CLASS:
8214                                         case MONO_TYPE_SZARRAY:
8215                                         case MONO_TYPE_PTR:
8216                                         case MONO_TYPE_FNPTR:
8217                                         case MONO_TYPE_ARRAY:
8218                                                 NEW_PCONST (cfg, *sp, *((gpointer *)addr));
8219                                                 type_to_eval_stack_type (cfg, field->type, *sp);
8220                                                 sp++;
8221                                                 break;
8222 #endif
8223                                         case MONO_TYPE_I8:
8224                                         case MONO_TYPE_U8:
8225                                                 MONO_INST_NEW (cfg, *sp, OP_I8CONST);
8226                                                 sp [0]->type = STACK_I8;
8227                                                 sp [0]->inst_l = *((gint64 *)addr);
8228                                                 sp++;
8229                                                 break;
8230                                         case MONO_TYPE_R4:
8231                                         case MONO_TYPE_R8:
8232                                         case MONO_TYPE_VALUETYPE:
8233                                         default:
8234                                                 is_const = FALSE;
8235                                                 break;
8236                                         }
8237                                 }
8238
8239                                 if (!is_const) {
8240                                         MonoInst *load;
8241                                         CHECK_STACK_OVF (1);
8242                                         MONO_INST_NEW (cfg, load, mini_type_to_ldind (cfg, field->type));
8243                                         type_to_eval_stack_type (cfg, field->type, load);
8244                                         load->inst_left = ins;
8245                                         load->flags |= ins_flag;
8246 #ifdef MONO_ARCH_SOFT_FLOAT
8247                                         if (load->opcode == CEE_LDIND_R4) {
8248                                                 int temp;
8249                                                 temp = handle_load_float (cfg, bblock, ins, ip);
8250                                                 NEW_TEMPLOAD (cfg, load, temp);
8251                                         }
8252 #endif
8253                                         *sp++ = load;
8254                                         ins_flag = 0;
8255                                 }
8256                         }
8257                         ip += 5;
8258                         break;
8259                 }
8260                 case CEE_STOBJ:
8261                         CHECK_STACK (2);
8262                         sp -= 2;
8263                         CHECK_OPSIZE (5);
8264                         token = read32 (ip + 1);
8265                         klass = mini_get_class (method, token, generic_context);
8266                         CHECK_TYPELOAD (klass);
8267                         n = mini_type_to_stind (cfg, &klass->byval_arg);
8268                         /* FIXME: handle CEE_STIND_R4 */
8269                         if (n == CEE_STOBJ) {
8270                                 handle_stobj (cfg, bblock, sp [0], sp [1], ip, klass, FALSE, FALSE, TRUE);
8271                         } else {
8272                                 /* FIXME: should check item at sp [1] is compatible with the type of the store. */
8273                                 MonoInst *store;
8274                                 MONO_INST_NEW (cfg, store, n);
8275                                 store->inst_left = sp [0];
8276                                 store->inst_right = sp [1];
8277                                 store->flags |= ins_flag;
8278                                 MONO_ADD_INS (bblock, store);
8279                         }
8280                         ins_flag = 0;
8281                         ip += 5;
8282                         inline_costs += 1;
8283                         break;
8284                 case CEE_BOX: {
8285                         MonoInst *val;
8286
8287                         CHECK_STACK (1);
8288                         --sp;
8289                         val = *sp;
8290                         CHECK_OPSIZE (5);
8291                         token = read32 (ip + 1);
8292                         klass = mini_get_class (method, token, generic_context);
8293                         CHECK_TYPELOAD (klass);
8294
8295                         if (cfg->generic_sharing_context)
8296                                 context_used =  mono_class_check_context_used (klass);
8297
8298                         if (generic_class_is_reference_type (cfg, klass)) {
8299                                 *sp++ = val;
8300                                 ip += 5;
8301                                 break;
8302                         }
8303                         if (klass == mono_defaults.void_class)
8304                                 UNVERIFIED;
8305                         if (target_type_is_incompatible (cfg, &klass->byval_arg, *sp))
8306                                 UNVERIFIED;
8307                         /* frequent check in generic code: box (struct), brtrue */
8308                         if (!mono_class_is_nullable (klass) &&
8309                             ip + 5 < end && ip_in_bb (cfg, bblock, ip + 5) && (ip [5] == CEE_BRTRUE || ip [5] == CEE_BRTRUE_S)) {
8310                                 /*g_print ("box-brtrue opt at 0x%04x in %s\n", real_offset, method->name);*/
8311                                 MONO_INST_NEW (cfg, ins, CEE_POP);
8312                                 MONO_ADD_INS (bblock, ins);
8313                                 ins->inst_i0 = *sp;
8314                                 ip += 5;
8315                                 cfg->ip = ip;
8316                                 MONO_INST_NEW (cfg, ins, OP_BR);
8317                                 MONO_ADD_INS (bblock, ins);
8318                                 if (*ip == CEE_BRTRUE_S) {
8319                                         CHECK_OPSIZE (2);
8320                                         ip++;
8321                                         target = ip + 1 + (signed char)(*ip);
8322                                         ip++;
8323                                 } else {
8324                                         CHECK_OPSIZE (5);
8325                                         ip++;
8326                                         target = ip + 4 + (gint)(read32 (ip));
8327                                         ip += 4;
8328                                 }
8329                                 GET_BBLOCK (cfg, tblock, target);
8330                                 link_bblock (cfg, bblock, tblock);
8331                                 CHECK_BBLOCK (target, ip, tblock);
8332                                 ins->inst_target_bb = tblock;
8333                                 GET_BBLOCK (cfg, tblock, ip);
8334                                 link_bblock (cfg, bblock, tblock);
8335                                 if (sp != stack_start) {
8336                                         handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
8337                                         sp = stack_start;
8338                                         CHECK_UNVERIFIABLE (cfg);
8339                                 }
8340                                 start_new_bblock = 1;
8341                                 break;
8342                         }
8343                         if (context_used) {
8344                                 MonoInst *rgctx;
8345
8346                                 if (mono_class_is_nullable (klass)) {
8347                                         GET_RGCTX (rgctx, context_used);
8348                                         *sp++ = handle_box_nullable_from_inst (cfg, method, context_used, bblock, val,
8349                                                         ip, klass, generic_context, rgctx);
8350                                 } else {
8351                                         MonoInst *data;
8352                                         int rgctx_info;
8353
8354                                         GET_RGCTX (rgctx, context_used);
8355                                         if (cfg->opt & MONO_OPT_SHARED)
8356                                                 rgctx_info = MONO_RGCTX_INFO_KLASS;
8357                                         else
8358                                                 rgctx_info = MONO_RGCTX_INFO_VTABLE;
8359                                         data = get_runtime_generic_context_ptr (cfg, method, context_used, bblock, klass,
8360                                                         generic_context, rgctx, rgctx_info, ip);
8361
8362                                         *sp++ = handle_box_from_inst (cfg, bblock, val, ip, klass, data);
8363                                 }
8364                         } else {
8365                                 *sp++ = handle_box (cfg, bblock, val, ip, klass);
8366                         }
8367                         ip += 5;
8368                         inline_costs += 1;
8369                         break;
8370                 }
8371                 case CEE_NEWARR:
8372                         CHECK_STACK (1);
8373                         --sp;
8374
8375                         CHECK_OPSIZE (5);
8376                         token = read32 (ip + 1);
8377
8378                         /* allocate the domainvar - becaus this is used in decompose_foreach */
8379                         if (cfg->opt & MONO_OPT_SHARED) {
8380                                 mono_get_domainvar (cfg);
8381                                 /* LAME-IR: Mark it as used since otherwise it will be optimized away */
8382                                 cfg->domainvar->flags |= MONO_INST_VOLATILE;
8383                         }
8384
8385                         /* Ditto */
8386                         mono_get_got_var (cfg);
8387
8388                         klass = mini_get_class (method, token, generic_context);
8389                         CHECK_TYPELOAD (klass);
8390
8391                         if (cfg->generic_sharing_context)
8392                                 context_used = mono_class_check_context_used (klass);
8393
8394                         if (context_used) {
8395                                 MonoInst *rgctx, *args [3];
8396                                 int temp;
8397
8398                                 /* domain */
8399                                 /* FIXME: what about domain-neutral code? */
8400                                 NEW_DOMAINCONST (cfg, args [0]);
8401
8402                                 /* klass */
8403                                 GET_RGCTX (rgctx, context_used);
8404                                 args [1] = get_runtime_generic_context_ptr (cfg, method, context_used, bblock, klass,
8405                                         generic_context, rgctx, MONO_RGCTX_INFO_KLASS, ip);
8406
8407                                 /* array len */
8408                                 args [2] = *sp;
8409
8410                                 temp = mono_emit_jit_icall (cfg, bblock, mono_array_new, args, ip);
8411                                 NEW_TEMPLOAD (cfg, ins, temp);
8412                         } else {
8413                                 MONO_INST_NEW (cfg, ins, *ip);
8414                                 ins->inst_newa_class = klass;
8415                                 ins->inst_newa_len = *sp;
8416                                 ins->type = STACK_OBJ;
8417                                 ins->klass = mono_array_class_get (klass, 1);
8418                         }
8419
8420                         ip += 5;
8421                         *sp++ = ins;
8422                         /* 
8423                          * we store the object so calls to create the array are not interleaved
8424                          * with the arguments of other calls.
8425                          */
8426                         if (1) {
8427                                 MonoInst *store, *temp, *load;
8428                                 const char *data_ptr;
8429                                 int data_size = 0;
8430                                 --sp;
8431                                 temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
8432                                 NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
8433                                 store->cil_code = ins->cil_code;
8434                                 MONO_ADD_INS (bblock, store);
8435                                 /* 
8436                                  * we inline/optimize the initialization sequence if possible.
8437                                  * we should also allocate the array as not cleared, since we spend as much time clearing to 0 as initializing
8438                                  * for small sizes open code the memcpy
8439                                  * ensure the rva field is big enough
8440                                  */
8441                                 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))) {
8442                                         MonoMethod *memcpy_method = get_memcpy_method ();
8443                                         MonoInst *data_offset, *add;
8444                                         MonoInst *iargs [3];
8445                                         NEW_ICONST (cfg, iargs [2], data_size);
8446                                         NEW_TEMPLOAD (cfg, load, temp->inst_c0);
8447                                         load->cil_code = ins->cil_code;
8448                                         NEW_ICONST (cfg, data_offset, G_STRUCT_OFFSET (MonoArray, vector));
8449                                         MONO_INST_NEW (cfg, add, OP_PADD);
8450                                         add->inst_left = load;
8451                                         add->inst_right = data_offset;
8452                                         iargs [0] = add;
8453                                         if (cfg->compile_aot) {
8454                                                 NEW_AOTCONST_TOKEN (cfg, iargs [1], MONO_PATCH_INFO_RVA, method->klass->image, GPOINTER_TO_UINT(data_ptr), STACK_PTR, NULL);
8455                                         } else {
8456                                                 NEW_PCONST (cfg, iargs [1], (char*)data_ptr);
8457                                         }
8458                                         mono_emit_method_call_spilled (cfg, bblock, memcpy_method, memcpy_method->signature, iargs, ip, NULL);
8459                                         ip += 11;
8460                                 }
8461                                 NEW_TEMPLOAD (cfg, load, temp->inst_c0);
8462                                 load->cil_code = ins->cil_code;
8463                                 *sp++ = load;
8464                         }
8465                         inline_costs += 1;
8466                         break;
8467                 case CEE_LDLEN:
8468                         CHECK_STACK (1);
8469                         --sp;
8470                         if (sp [0]->type != STACK_OBJ)
8471                                 UNVERIFIED;
8472                         MONO_INST_NEW (cfg, ins, *ip);
8473                         ip++;
8474                         ins->inst_left = *sp;
8475                         ins->type = STACK_PTR;
8476                         *sp++ = ins;
8477                         break;
8478                 case CEE_LDELEMA:
8479                         CHECK_STACK (2);
8480                         sp -= 2;
8481                         CHECK_OPSIZE (5);
8482                         if (sp [0]->type != STACK_OBJ)
8483                                 UNVERIFIED;
8484
8485                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
8486                         CHECK_TYPELOAD (klass);
8487                         /* we need to make sure that this array is exactly the type it needs
8488                          * to be for correctness. the wrappers are lax with their usage
8489                          * so we need to ignore them here
8490                          */
8491                         if (!klass->valuetype && method->wrapper_type == MONO_WRAPPER_NONE && !readonly) {
8492                                 MonoInst* check;
8493
8494                                 /* Needed by the code generated in inssel.brg */
8495                                 mono_get_got_var (cfg);
8496
8497                                 MONO_INST_NEW (cfg, check, OP_CHECK_ARRAY_TYPE);
8498                                 check->klass = mono_array_class_get (klass, 1);
8499                                 check->inst_left = sp [0];
8500                                 check->type = STACK_OBJ;
8501                                 sp [0] = check;
8502                         }
8503                         
8504                         readonly = FALSE;
8505                         mono_class_init (klass);
8506                         NEW_LDELEMA (cfg, ins, sp, klass);
8507                         *sp++ = ins;
8508                         ip += 5;
8509                         break;
8510                 case CEE_LDELEM_ANY: {
8511                         MonoInst *load;
8512                         CHECK_STACK (2);
8513                         sp -= 2;
8514                         if (sp [0]->type != STACK_OBJ)
8515                                 UNVERIFIED;
8516                         CHECK_OPSIZE (5);
8517                         token = read32 (ip + 1);
8518                         klass = mini_get_class (method, token, generic_context);
8519                         CHECK_TYPELOAD (klass);
8520                         mono_class_init (klass);
8521                         NEW_LDELEMA (cfg, load, sp, klass);
8522                         MONO_INST_NEW (cfg, ins, mini_type_to_ldind (cfg, &klass->byval_arg));
8523                         ins->inst_left = load;
8524                         *sp++ = ins;
8525                         type_to_eval_stack_type (cfg, &klass->byval_arg, ins);
8526                         ip += 5;
8527                         break;
8528                 }
8529                 case CEE_LDELEM_I1:
8530                 case CEE_LDELEM_U1:
8531                 case CEE_LDELEM_I2:
8532                 case CEE_LDELEM_U2:
8533                 case CEE_LDELEM_I4:
8534                 case CEE_LDELEM_U4:
8535                 case CEE_LDELEM_I8:
8536                 case CEE_LDELEM_I:
8537                 case CEE_LDELEM_R4:
8538                 case CEE_LDELEM_R8:
8539                 case CEE_LDELEM_REF: {
8540                         MonoInst *load;
8541                         /*
8542                          * translate to:
8543                          * ldind.x (ldelema (array, index))
8544                          * ldelema does the bounds check
8545                          */
8546                         CHECK_STACK (2);
8547                         sp -= 2;
8548                         if (sp [0]->type != STACK_OBJ)
8549                                 UNVERIFIED;
8550                         klass = array_access_to_klass (*ip, sp [0]);
8551                         NEW_LDELEMA (cfg, load, sp, klass);
8552 #ifdef MONO_ARCH_SOFT_FLOAT
8553                         if (*ip == CEE_LDELEM_R4) {
8554                                 int temp;
8555                                 temp = handle_load_float (cfg, bblock, load, ip);
8556                                 NEW_TEMPLOAD (cfg, *sp, temp);
8557                                 sp++;
8558                                 ++ip;
8559                                 break;
8560                         }
8561 #endif
8562                         MONO_INST_NEW (cfg, ins, ldelem_to_ldind [*ip - CEE_LDELEM_I1]);
8563                         ins->inst_left = load;
8564                         *sp++ = ins;
8565                         ins->type = ldind_type [ins->opcode - CEE_LDIND_I1];
8566                         ins->klass = klass;
8567                         ++ip;
8568                         break;
8569                 }
8570                 case CEE_STELEM_I:
8571                 case CEE_STELEM_I1:
8572                 case CEE_STELEM_I2:
8573                 case CEE_STELEM_I4:
8574                 case CEE_STELEM_I8:
8575                 case CEE_STELEM_R4:
8576                 case CEE_STELEM_R8: {
8577                         MonoInst *load;
8578                         /*
8579                          * translate to:
8580                          * stind.x (ldelema (array, index), val)
8581                          * ldelema does the bounds check
8582                          */
8583                         CHECK_STACK (3);
8584                         sp -= 3;
8585                         if (sp [0]->type != STACK_OBJ)
8586                                 UNVERIFIED;
8587                         klass = array_access_to_klass (*ip, sp [0]);
8588                         NEW_LDELEMA (cfg, load, sp, klass);
8589 #ifdef MONO_ARCH_SOFT_FLOAT
8590                         if (*ip == CEE_STELEM_R4) {
8591                                 handle_store_float (cfg, bblock, load, sp [2], ip);
8592                                 ip++;
8593                                 break;
8594                         }
8595 #endif
8596                         MONO_INST_NEW (cfg, ins, stelem_to_stind [*ip - CEE_STELEM_I]);
8597                         ins->inst_left = load;
8598                         ins->inst_right = sp [2];
8599                         ++ip;
8600                         handle_loaded_temps (cfg, bblock, stack_start, sp);
8601                         MONO_ADD_INS (bblock, ins);
8602                         inline_costs += 1;
8603                         break;
8604                 }
8605                 case CEE_STELEM_ANY: {
8606                         MonoInst *load;
8607                         /*
8608                          * translate to:
8609                          * stind.x (ldelema (array, index), val)
8610                          * ldelema does the bounds check
8611                          */
8612                         CHECK_STACK (3);
8613                         sp -= 3;
8614                         if (sp [0]->type != STACK_OBJ)
8615                                 UNVERIFIED;
8616                         CHECK_OPSIZE (5);
8617                         token = read32 (ip + 1);
8618                         klass = mini_get_class (method, token, generic_context);
8619                         CHECK_TYPELOAD (klass);
8620                         mono_class_init (klass);
8621                         if (generic_class_is_reference_type (cfg, klass)) {
8622                                 /* storing a NULL doesn't need any of the complex checks in stelemref */
8623                                 if (sp [2]->opcode == OP_PCONST && sp [2]->inst_p0 == NULL) {
8624                                         MonoInst *load;
8625                                         NEW_LDELEMA (cfg, load, sp, mono_defaults.object_class);
8626                                         MONO_INST_NEW (cfg, ins, stelem_to_stind [*ip - CEE_STELEM_I]);
8627                                         ins->inst_left = load;
8628                                         ins->inst_right = sp [2];
8629                                         MONO_ADD_INS (bblock, ins);
8630                                 } else {
8631                                         MonoMethod* helper = mono_marshal_get_stelemref ();
8632                                         MonoInst *iargs [3];
8633                                         handle_loaded_temps (cfg, bblock, stack_start, sp);
8634
8635                                         iargs [2] = sp [2];
8636                                         iargs [1] = sp [1];
8637                                         iargs [0] = sp [0];
8638
8639                                         mono_emit_method_call_spilled (cfg, bblock, helper, mono_method_signature (helper), iargs, ip, NULL);
8640                                 }
8641                         } else {
8642                                 NEW_LDELEMA (cfg, load, sp, klass);
8643
8644                                 n = mini_type_to_stind (cfg, &klass->byval_arg);
8645                                 /* FIXME: CEE_STIND_R4 */
8646                                 if (n == CEE_STOBJ)
8647                                         handle_stobj (cfg, bblock, load, sp [2], ip, klass, FALSE, FALSE, TRUE);
8648                                 else {
8649                                         MONO_INST_NEW (cfg, ins, n);
8650                                         ins->inst_left = load;
8651                                         ins->inst_right = sp [2];
8652                                         handle_loaded_temps (cfg, bblock, stack_start, sp);
8653                                         MONO_ADD_INS (bblock, ins);
8654                                 }
8655                         }
8656                         ip += 5;
8657                         inline_costs += 1;
8658                         break;
8659                 }
8660                 case CEE_STELEM_REF: {
8661                         MonoInst *iargs [3];
8662                         MonoMethod* helper = mono_marshal_get_stelemref ();
8663
8664                         CHECK_STACK (3);
8665                         sp -= 3;
8666                         if (sp [0]->type != STACK_OBJ)
8667                                 UNVERIFIED;
8668                         if (sp [2]->type != STACK_OBJ)
8669                                 UNVERIFIED;
8670
8671                         handle_loaded_temps (cfg, bblock, stack_start, sp);
8672
8673                         /* storing a NULL doesn't need any of the complex checks in stelemref */
8674                         if (sp [2]->opcode == OP_PCONST && sp [2]->inst_p0 == NULL) {
8675                                 MonoInst *load;
8676                                 NEW_LDELEMA (cfg, load, sp, mono_defaults.object_class);
8677                                 MONO_INST_NEW (cfg, ins, stelem_to_stind [*ip - CEE_STELEM_I]);
8678                                 ins->inst_left = load;
8679                                 ins->inst_right = sp [2];
8680                                 MONO_ADD_INS (bblock, ins);
8681                         } else {
8682                                 iargs [2] = sp [2];
8683                                 iargs [1] = sp [1];
8684                                 iargs [0] = sp [0];
8685                         
8686                                 mono_emit_method_call_spilled (cfg, bblock, helper, mono_method_signature (helper), iargs, ip, NULL);
8687                                 inline_costs += 1;
8688                         }
8689
8690                         ++ip;
8691                         break;
8692                 }
8693                 case CEE_CKFINITE: {
8694                         MonoInst *store, *temp;
8695                         CHECK_STACK (1);
8696
8697                         /* this instr. can throw exceptions as side effect,
8698                          * so we cant eliminate dead code which contains CKFINITE opdodes.
8699                          * Spilling to memory makes sure that we always perform
8700                          * this check */
8701
8702                         
8703                         MONO_INST_NEW (cfg, ins, OP_CKFINITE);
8704                         ins->inst_left = sp [-1];
8705                         temp = mono_compile_create_var (cfg, &mono_defaults.double_class->byval_arg, OP_LOCAL);
8706
8707                         NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
8708                         MONO_ADD_INS (bblock, store);
8709
8710                         NEW_TEMPLOAD (cfg, sp [-1], temp->inst_c0);
8711                        
8712                         ++ip;
8713                         break;
8714                 }
8715                 case CEE_REFANYVAL:
8716                         CHECK_STACK (1);
8717                         --sp;
8718                         CHECK_OPSIZE (5);
8719                         token = read32 (ip + 1);
8720                         klass = mono_class_get_full (image, token, generic_context);
8721                         CHECK_TYPELOAD (klass);
8722                         mono_class_init (klass);
8723
8724                         /* Needed by the code generated in inssel.brg */
8725                         mono_get_got_var (cfg);
8726
8727                         if (cfg->generic_sharing_context) {
8728                                 context_used = mono_class_check_context_used (klass);
8729                                 if (context_used && cfg->compile_aot)
8730                                         GENERIC_SHARING_FAILURE (*ip);
8731                         }
8732
8733                         if (context_used) {
8734                                 MonoInst *rgctx;
8735
8736                                 MONO_INST_NEW (cfg, ins, OP_REFANYVAL_REG);
8737                                 ins->type = STACK_MP;
8738                                 ins->inst_left = *sp;
8739                                 ins->klass = klass;
8740
8741                                 GET_RGCTX (rgctx, context_used);
8742                                 ins->inst_right = get_runtime_generic_context_ptr (cfg, method, context_used,
8743                                                 bblock, klass, generic_context, rgctx, MONO_RGCTX_INFO_KLASS, ip);
8744                         } else {
8745                                 MONO_INST_NEW (cfg, ins, *ip);
8746                                 ins->type = STACK_MP;
8747                                 ins->inst_left = *sp;
8748                                 ins->klass = klass;
8749                                 ins->inst_newa_class = klass;
8750                         }
8751                         ip += 5;
8752                         *sp++ = ins;
8753                         break;
8754                 case CEE_MKREFANY: {
8755                         MonoInst *loc;
8756
8757                         CHECK_STACK (1);
8758                         --sp;
8759                         CHECK_OPSIZE (5);
8760                         token = read32 (ip + 1);
8761                         klass = mono_class_get_full (image, token, generic_context);
8762                         CHECK_TYPELOAD (klass);
8763                         mono_class_init (klass);
8764
8765                         if (cfg->generic_sharing_context) {
8766                                 context_used = mono_class_check_context_used (klass);
8767                                 if (context_used && cfg->compile_aot)
8768                                         GENERIC_SHARING_FAILURE (CEE_MKREFANY);
8769                         }
8770
8771                         loc = mono_compile_create_var (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL);
8772                         if (context_used) {
8773                                 MonoInst *rgctx, *klass_type, *klass_klass, *loc_load;
8774
8775                                 GET_RGCTX (rgctx, context_used);
8776                                 klass_klass = get_runtime_generic_context_ptr (cfg, method, context_used, bblock, klass,
8777                                                 generic_context, rgctx, MONO_RGCTX_INFO_KLASS, ip);
8778                                 GET_RGCTX (rgctx, context_used);
8779                                 klass_type = get_runtime_generic_context_ptr (cfg, method, context_used, bblock, klass,
8780                                                 generic_context, rgctx, MONO_RGCTX_INFO_TYPE, ip);
8781
8782                                 NEW_TEMPLOADA (cfg, loc_load, loc->inst_c0);
8783
8784                                 MONO_INST_NEW (cfg, ins, OP_MKREFANY_REGS);
8785                                 NEW_GROUP (cfg, ins->inst_left, klass_type, klass_klass);
8786                                 NEW_GROUP (cfg, ins->inst_right, *sp, loc_load);
8787                         } else {
8788                                 MonoInst *klassconst;
8789
8790                                 NEW_PCONST (cfg, klassconst, klass);
8791
8792                                 MONO_INST_NEW (cfg, ins, *ip);
8793                                 NEW_TEMPLOADA (cfg, ins->inst_right, loc->inst_c0);
8794                                 NEW_GROUP (cfg, ins->inst_left, *sp, klassconst);
8795                         }
8796
8797                         MONO_ADD_INS (bblock, ins);
8798
8799                         NEW_TEMPLOAD (cfg, *sp, loc->inst_c0);
8800                         ++sp;
8801                         ip += 5;
8802                         break;
8803                 }
8804                 case CEE_LDTOKEN: {
8805                         gpointer handle;
8806                         MonoClass *handle_class;
8807
8808                         CHECK_STACK_OVF (1);
8809
8810                         CHECK_OPSIZE (5);
8811                         n = read32 (ip + 1);
8812
8813                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
8814                                 handle = mono_method_get_wrapper_data (method, n);
8815                                 handle_class = mono_method_get_wrapper_data (method, n + 1);
8816                                 if (handle_class == mono_defaults.typehandle_class)
8817                                         handle = &((MonoClass*)handle)->byval_arg;
8818                         }
8819                         else {
8820                                 handle = mono_ldtoken (image, n, &handle_class, generic_context);
8821                         }
8822                         if (!handle)
8823                                 goto load_error;
8824                         mono_class_init (handle_class);
8825
8826                         if (cfg->generic_sharing_context) {
8827                                 if (handle_class == mono_defaults.typehandle_class) {
8828                                         /* If we get a MONO_TYPE_CLASS
8829                                            then we need to provide the
8830                                            open type, not an
8831                                            instantiation of it. */
8832                                         if (mono_type_get_type (handle) == MONO_TYPE_CLASS)
8833                                                 context_used = 0;
8834                                         else
8835                                                 context_used = mono_class_check_context_used (mono_class_from_mono_type (handle));
8836                                 } else if (handle_class == mono_defaults.fieldhandle_class)
8837                                         context_used = mono_class_check_context_used (((MonoClassField*)handle)->parent);
8838                                 else if (handle_class == mono_defaults.methodhandle_class)
8839                                         context_used = mono_method_check_context_used (handle);
8840                                 else
8841                                         g_assert_not_reached ();
8842                         }
8843
8844                         if (cfg->opt & MONO_OPT_SHARED) {
8845                                 int temp;
8846                                 MonoInst *res, *store, *addr, *vtvar, *iargs [3];
8847                                 int method_context_used;
8848
8849                                 if (cfg->generic_sharing_context)
8850                                         method_context_used = mono_method_check_context_used (method);
8851                                 else
8852                                         method_context_used = 0;
8853
8854                                 vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL); 
8855
8856                                 NEW_IMAGECONST (cfg, iargs [0], image);
8857                                 NEW_ICONST (cfg, iargs [1], n);
8858                                 if (method_context_used) {
8859                                         MonoInst *rgctx;
8860
8861                                         GET_RGCTX (rgctx, method_context_used);
8862                                         iargs [2] = get_runtime_generic_context_method (cfg, method, method_context_used,
8863                                                         bblock, method,
8864                                                         generic_context, rgctx, MONO_RGCTX_INFO_METHOD, ip);
8865                                         temp = mono_emit_jit_icall (cfg, bblock, mono_ldtoken_wrapper_generic_shared,
8866                                                         iargs, ip);
8867                                 } else {
8868                                         NEW_PCONST (cfg, iargs [2], generic_context);
8869                                         temp = mono_emit_jit_icall (cfg, bblock, mono_ldtoken_wrapper, iargs, ip);
8870                                 }
8871                                 NEW_TEMPLOAD (cfg, res, temp);
8872                                 NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
8873                                 NEW_INDSTORE (cfg, store, addr, res, &mono_defaults.int_class->byval_arg);
8874                                 MONO_ADD_INS (bblock, store);
8875                                 NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
8876                         } else {
8877                                 if ((ip + 10 < end) && ip_in_bb (cfg, bblock, ip + 5) &&
8878                                         handle_class == mono_defaults.typehandle_class &&
8879                                         ((ip [5] == CEE_CALL) || (ip [5] == CEE_CALLVIRT)) && 
8880                                         (cmethod = mini_get_method (cfg, method, read32 (ip + 6), NULL, generic_context)) &&
8881                                         (cmethod->klass == mono_defaults.monotype_class->parent) &&
8882                                         (strcmp (cmethod->name, "GetTypeFromHandle") == 0)) {
8883                                         MonoClass *tclass = mono_class_from_mono_type (handle);
8884                                         mono_class_init (tclass);
8885                                         if (context_used) {
8886                                                 MonoInst *rgctx;
8887
8888                                                 g_assert (!cfg->compile_aot);
8889
8890                                                 GET_RGCTX (rgctx, context_used);
8891                                                 ins = get_runtime_generic_context_ptr (cfg, method, context_used, bblock, tclass,
8892                                                         generic_context, rgctx, MONO_RGCTX_INFO_REFLECTION_TYPE, ip);
8893                                         } else if (cfg->compile_aot) {
8894                                                 /*
8895                                                  * FIXME: We would have to include the context into the
8896                                                  * aot constant too (tests/generic-array-type.2.exe).
8897                                                  */
8898                                                 if (generic_context)
8899                                                         cfg->disable_aot = TRUE;
8900                                                 NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, image, n);
8901                                         } else {
8902                                                 NEW_PCONST (cfg, ins, mono_type_get_object (cfg->domain, handle));
8903                                         }
8904                                         ins->type = STACK_OBJ;
8905                                         ins->klass = cmethod->klass;
8906                                         ip += 5;
8907                                 } else {
8908                                         MonoInst *store, *addr, *vtvar;
8909
8910                                         if (context_used) {
8911                                                         MonoInst *rgctx;
8912
8913                                                 g_assert (!cfg->compile_aot);
8914
8915                                                 GET_RGCTX (rgctx, context_used);
8916                                                 if (handle_class == mono_defaults.typehandle_class) {
8917                                                         ins = get_runtime_generic_context_ptr (cfg, method,
8918                                                                         context_used, bblock,
8919                                                                         mono_class_from_mono_type (handle), generic_context,
8920                                                                         rgctx, MONO_RGCTX_INFO_TYPE, ip);
8921                                                 } else if (handle_class == mono_defaults.methodhandle_class) {
8922                                                         ins = get_runtime_generic_context_method (cfg, method,
8923                                                                         context_used, bblock, handle, generic_context,
8924                                                                         rgctx, MONO_RGCTX_INFO_METHOD, ip);
8925                                                 } else if (handle_class == mono_defaults.fieldhandle_class) {
8926                                                         ins = get_runtime_generic_context_field (cfg, method,
8927                                                                         context_used, bblock, handle, generic_context,
8928                                                                         rgctx, MONO_RGCTX_INFO_CLASS_FIELD, ip);
8929                                                 } else {
8930                                                         g_assert_not_reached ();
8931                                                 }
8932                                         }
8933                                         else if (cfg->compile_aot) {
8934                                                 NEW_LDTOKENCONST (cfg, ins, image, n);
8935                                         } else {
8936                                                 NEW_PCONST (cfg, ins, handle);
8937                                         }
8938                                         vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL);
8939                                         NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
8940                                         NEW_INDSTORE (cfg, store, addr, ins, &mono_defaults.int_class->byval_arg);
8941                                         MONO_ADD_INS (bblock, store);
8942                                         NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
8943                                 }
8944                         }
8945
8946                         *sp++ = ins;
8947                         ip += 5;
8948                         break;
8949                 }
8950                 case CEE_CONV_U2:
8951                 case CEE_CONV_U1:
8952                 case CEE_CONV_I:
8953                         CHECK_STACK (1);
8954                         ADD_UNOP (*ip);
8955                         ip++;
8956                         break;
8957                 case CEE_ADD_OVF:
8958                 case CEE_ADD_OVF_UN:
8959                 case CEE_MUL_OVF:
8960                 case CEE_MUL_OVF_UN:
8961                 case CEE_SUB_OVF:
8962                 case CEE_SUB_OVF_UN:
8963                         CHECK_STACK (2);
8964                         ADD_BINOP (*ip);
8965                         if (mono_find_jit_opcode_emulation (ins->opcode)) {
8966                                 --sp;
8967                                 *sp++ = emit_tree (cfg, bblock, ins, ip + 1);
8968                         }
8969                         ip++;
8970                         break;
8971                 case CEE_ENDFINALLY:
8972                         MONO_INST_NEW (cfg, ins, OP_ENDFINALLY);
8973                         MONO_ADD_INS (bblock, ins);
8974                         ip++;
8975                         start_new_bblock = 1;
8976
8977                         /*
8978                          * Control will leave the method so empty the stack, otherwise
8979                          * the next basic block will start with a nonempty stack.
8980                          */
8981                         while (sp != stack_start) {
8982                                 MONO_INST_NEW (cfg, ins, CEE_POP);
8983                                 sp--;
8984                                 ins->inst_i0 = *sp;
8985                                 MONO_ADD_INS (bblock, ins);
8986                         }
8987                         break;
8988                 case CEE_LEAVE:
8989                 case CEE_LEAVE_S: {
8990                         GList *handlers;
8991
8992                         if (*ip == CEE_LEAVE) {
8993                                 CHECK_OPSIZE (5);
8994                                 target = ip + 5 + (gint32)read32(ip + 1);
8995                         } else {
8996                                 CHECK_OPSIZE (2);
8997                                 target = ip + 2 + (signed char)(ip [1]);
8998                         }
8999
9000                         /* empty the stack */
9001                         while (sp != stack_start) {
9002                                 MONO_INST_NEW (cfg, ins, CEE_POP);
9003                                 sp--;
9004                                 ins->inst_i0 = *sp;
9005                                 MONO_ADD_INS (bblock, ins);
9006                         }
9007
9008                         /* 
9009                          * If this leave statement is in a catch block, check for a
9010                          * pending exception, and rethrow it if necessary.
9011                          */
9012                         for (i = 0; i < header->num_clauses; ++i) {
9013                                 MonoExceptionClause *clause = &header->clauses [i];
9014
9015                                 /* 
9016                                  * Use <= in the final comparison to handle clauses with multiple
9017                                  * leave statements, like in bug #78024.
9018                                  * The ordering of the exception clauses guarantees that we find the
9019                                  * innermost clause.
9020                                  */
9021                                 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)) {
9022                                         int temp;
9023                                         MonoInst *load;
9024
9025                                         NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, clause->handler_offset)->inst_c0);
9026
9027                                         temp = mono_emit_jit_icall (cfg, bblock, mono_thread_get_undeniable_exception, NULL, ip);
9028                                         NEW_TEMPLOAD (cfg, *sp, temp);
9029                                 
9030                                         MONO_INST_NEW (cfg, ins, OP_THROW_OR_NULL);
9031                                         ins->inst_left = *sp;
9032                                         ins->inst_right = load;
9033                                         MONO_ADD_INS (bblock, ins);
9034                                 }
9035                         }
9036
9037                         if ((handlers = mono_find_final_block (cfg, ip, target, MONO_EXCEPTION_CLAUSE_FINALLY))) {
9038                                 GList *tmp;
9039                                 for (tmp = handlers; tmp; tmp = tmp->next) {
9040                                         tblock = tmp->data;
9041                                         link_bblock (cfg, bblock, tblock);
9042                                         MONO_INST_NEW (cfg, ins, OP_CALL_HANDLER);
9043                                         ins->inst_target_bb = tblock;
9044                                         MONO_ADD_INS (bblock, ins);
9045                                 }
9046                                 g_list_free (handlers);
9047                         } 
9048
9049                         MONO_INST_NEW (cfg, ins, OP_BR);
9050                         MONO_ADD_INS (bblock, ins);
9051                         GET_BBLOCK (cfg, tblock, target);
9052                         link_bblock (cfg, bblock, tblock);
9053                         CHECK_BBLOCK (target, ip, tblock);
9054                         ins->inst_target_bb = tblock;
9055                         start_new_bblock = 1;
9056
9057                         if (*ip == CEE_LEAVE)
9058                                 ip += 5;
9059                         else
9060                                 ip += 2;
9061
9062                         break;
9063                 }
9064                 case CEE_STIND_I:
9065                         CHECK_STACK (2);
9066                         MONO_INST_NEW (cfg, ins, *ip);
9067                         sp -= 2;
9068                         handle_loaded_temps (cfg, bblock, stack_start, sp);
9069                         MONO_ADD_INS (bblock, ins);
9070                         ip++;
9071                         ins->inst_i0 = sp [0];
9072                         ins->inst_i1 = sp [1];
9073                         inline_costs += 1;
9074                         break;
9075                 case CEE_CONV_U:
9076                         CHECK_STACK (1);
9077                         ADD_UNOP (*ip);
9078                         ip++;
9079                         break;
9080                 /* trampoline mono specific opcodes */
9081                 case MONO_CUSTOM_PREFIX: {
9082
9083                         g_assert (method->wrapper_type != MONO_WRAPPER_NONE);
9084
9085                         CHECK_OPSIZE (2);
9086                         switch (ip [1]) {
9087
9088                         case CEE_MONO_ICALL: {
9089                                 int temp;
9090                                 gpointer func;
9091                                 MonoJitICallInfo *info;
9092
9093                                 token = read32 (ip + 2);
9094                                 func = mono_method_get_wrapper_data (method, token);
9095                                 info = mono_find_jit_icall_by_addr (func);
9096                                 if (info == NULL){
9097                                         g_error ("An attempt has been made to perform an icall to address %p, "
9098                                                  "but the address has not been registered as an icall\n", info);
9099                                         g_assert_not_reached ();
9100                                 }
9101
9102                                 CHECK_STACK (info->sig->param_count);
9103                                 sp -= info->sig->param_count;
9104
9105                                 temp = mono_emit_jit_icall (cfg, bblock, info->func, sp, ip);
9106                                 if (!MONO_TYPE_IS_VOID (info->sig->ret)) {
9107                                         NEW_TEMPLOAD (cfg, *sp, temp);
9108                                         sp++;
9109                                 }
9110
9111                                 ip += 6;
9112                                 inline_costs += 10 * num_calls++;
9113
9114                                 break;
9115                         }
9116                         case CEE_MONO_LDPTR: {
9117                                 gpointer ptr;
9118
9119                                 CHECK_STACK_OVF (1);
9120                                 CHECK_OPSIZE (6);
9121                                 token = read32 (ip + 2);
9122
9123                                 ptr = mono_method_get_wrapper_data (method, token);
9124                                 if (cfg->compile_aot && (cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE || cfg->method->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE)) {
9125                                         MonoMethod *wrapped = mono_marshal_method_from_wrapper (cfg->method);
9126
9127                                         if (wrapped && ptr != NULL && mono_lookup_internal_call (wrapped) == ptr) {
9128                                                 NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_ICALL_ADDR, wrapped);
9129                                                 *sp++ = ins;
9130                                                 ip += 6;
9131                                                 break;
9132                                         }
9133
9134                                         if ((method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) && (strstr (method->name, "__icall_wrapper_") == method->name)) {
9135                                                 MonoJitICallInfo *callinfo;
9136                                                 const char *icall_name;
9137
9138                                                 icall_name = method->name + strlen ("__icall_wrapper_");
9139                                                 g_assert (icall_name);
9140                                                 callinfo = mono_find_jit_icall_by_name (icall_name);
9141                                                 g_assert (callinfo);
9142
9143                                                 if (ptr == callinfo->func) {
9144                                                         /* Will be transformed into an AOTCONST later */
9145                                                         NEW_PCONST (cfg, ins, ptr);
9146                                                         *sp++ = ins;
9147                                                         ip += 6;
9148                                                         break;
9149                                                 }
9150                                         }
9151                                 }
9152                                 /* FIXME: Generalize this */
9153                                 if (cfg->compile_aot && ptr == mono_thread_interruption_request_flag ()) {
9154                                         NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG, NULL);
9155                                         *sp++ = ins;
9156                                         ip += 6;
9157                                         break;
9158                                 }
9159                                 NEW_PCONST (cfg, ins, ptr);
9160                                 *sp++ = ins;
9161                                 ip += 6;
9162                                 inline_costs += 10 * num_calls++;
9163                                 /* Can't embed random pointers into AOT code */
9164                                 cfg->disable_aot = 1;
9165                                 break;
9166                         }
9167                         case CEE_MONO_ICALL_ADDR: {
9168                                 MonoMethod *cmethod;
9169
9170                                 CHECK_STACK_OVF (1);
9171                                 CHECK_OPSIZE (6);
9172                                 token = read32 (ip + 2);
9173
9174                                 cmethod = mono_method_get_wrapper_data (method, token);
9175
9176                                 g_assert (cfg->compile_aot);
9177
9178                                 NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_ICALL_ADDR, cmethod);
9179                                 *sp++ = ins;
9180                                 ip += 6;
9181                                 break;
9182                         }
9183                         case CEE_MONO_VTADDR:
9184                                 CHECK_STACK (1);
9185                                 --sp;
9186                                 MONO_INST_NEW (cfg, ins, OP_VTADDR);
9187                                 ins->type = STACK_MP;
9188                                 ins->inst_left = *sp;
9189                                 *sp++ = ins;
9190                                 ip += 2;
9191                                 break;
9192                         case CEE_MONO_NEWOBJ: {
9193                                 MonoInst *iargs [2];
9194                                 int temp;
9195                                 CHECK_STACK_OVF (1);
9196                                 CHECK_OPSIZE (6);
9197                                 token = read32 (ip + 2);
9198                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
9199                                 mono_class_init (klass);
9200                                 NEW_DOMAINCONST (cfg, iargs [0]);
9201                                 NEW_CLASSCONST (cfg, iargs [1], klass);
9202                                 temp = mono_emit_jit_icall (cfg, bblock, mono_object_new, iargs, ip);
9203                                 NEW_TEMPLOAD (cfg, *sp, temp);
9204                                 sp++;
9205                                 ip += 6;
9206                                 inline_costs += 10 * num_calls++;
9207                                 break;
9208                         }
9209                         case CEE_MONO_OBJADDR:
9210                                 CHECK_STACK (1);
9211                                 --sp;
9212                                 MONO_INST_NEW (cfg, ins, OP_OBJADDR);
9213                                 ins->type = STACK_MP;
9214                                 ins->inst_left = *sp;
9215                                 *sp++ = ins;
9216                                 ip += 2;
9217                                 break;
9218                         case CEE_MONO_LDNATIVEOBJ:
9219                                 CHECK_STACK (1);
9220                                 CHECK_OPSIZE (6);
9221                                 token = read32 (ip + 2);
9222                                 klass = mono_method_get_wrapper_data (method, token);
9223                                 g_assert (klass->valuetype);
9224                                 mono_class_init (klass);
9225                                 NEW_INDLOAD (cfg, ins, sp [-1], &klass->byval_arg);
9226                                 sp [-1] = ins;
9227                                 ip += 6;
9228                                 break;
9229                         case CEE_MONO_RETOBJ:
9230                                 g_assert (cfg->ret);
9231                                 g_assert (mono_method_signature (method)->pinvoke); 
9232                                 CHECK_STACK (1);
9233                                 --sp;
9234                                 
9235                                 CHECK_OPSIZE (6);
9236                                 token = read32 (ip + 2);    
9237                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
9238
9239                                 NEW_RETLOADA (cfg, ins);
9240                                 handle_stobj (cfg, bblock, ins, *sp, ip, klass, FALSE, TRUE, FALSE);
9241                                 
9242                                 if (sp != stack_start)
9243                                         UNVERIFIED;
9244                                 
9245                                 MONO_INST_NEW (cfg, ins, OP_BR);
9246                                 ins->inst_target_bb = end_bblock;
9247                                 MONO_ADD_INS (bblock, ins);
9248                                 link_bblock (cfg, bblock, end_bblock);
9249                                 start_new_bblock = 1;
9250                                 ip += 6;
9251                                 break;
9252                         case CEE_MONO_CISINST:
9253                         case CEE_MONO_CCASTCLASS: {
9254                                 int token;
9255                                 CHECK_STACK (1);
9256                                 --sp;
9257                                 CHECK_OPSIZE (6);
9258                                 token = read32 (ip + 2);
9259                                 /* Needed by the code generated in inssel.brg */
9260                                 mono_get_got_var (cfg);
9261
9262 #ifdef __i386__
9263                                 /* 
9264                                  * The code generated for CCASTCLASS has too much register pressure
9265                                  * (obj+vtable+ibitmap_byte_reg+iid_reg), leading to the usual
9266                                  * branches-inside-bblocks problem.
9267                                  */
9268                                 cfg->disable_aot = TRUE;
9269 #endif
9270                 
9271                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
9272                                 MONO_INST_NEW (cfg, ins, (ip [1] == CEE_MONO_CISINST) ? OP_CISINST : OP_CCASTCLASS);
9273                                 ins->type = STACK_I4;
9274                                 ins->inst_left = *sp;
9275                                 ins->inst_newa_class = klass;
9276                                 *sp++ = emit_tree (cfg, bblock, ins, ip + 6);
9277                                 ip += 6;
9278                                 break;
9279                         }
9280                         case CEE_MONO_SAVE_LMF:
9281                         case CEE_MONO_RESTORE_LMF:
9282 #ifdef MONO_ARCH_HAVE_LMF_OPS
9283                                 MONO_INST_NEW (cfg, ins, (ip [1] == CEE_MONO_SAVE_LMF) ? OP_SAVE_LMF : OP_RESTORE_LMF);
9284                                 MONO_ADD_INS (bblock, ins);
9285                                 cfg->need_lmf_area = TRUE;
9286 #endif
9287                                 ip += 2;
9288                                 break;
9289                         case CEE_MONO_CLASSCONST:
9290                                 CHECK_STACK_OVF (1);
9291                                 CHECK_OPSIZE (6);
9292                                 token = read32 (ip + 2);
9293                                 NEW_CLASSCONST (cfg, ins, mono_method_get_wrapper_data (method, token));
9294                                 *sp++ = ins;
9295                                 ip += 6;
9296                                 inline_costs += 10 * num_calls++;
9297                                 break;
9298                         case CEE_MONO_NOT_TAKEN:
9299                                 bblock->out_of_line = TRUE;
9300                                 ip += 2;
9301                                 break;
9302                         case CEE_MONO_TLS:
9303                                 CHECK_STACK_OVF (1);
9304                                 CHECK_OPSIZE (6);
9305                                 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
9306                                 ins->inst_offset = (gint32)read32 (ip + 2);
9307                                 ins->type = STACK_PTR;
9308                                 *sp++ = ins;
9309                                 ip += 6;
9310                                 break;
9311                         default:
9312                                 g_error ("opcode 0x%02x 0x%02x not handled", MONO_CUSTOM_PREFIX, ip [1]);
9313                                 break;
9314                         }
9315                         break;
9316                 }
9317                 case CEE_PREFIX1: {
9318                         CHECK_OPSIZE (2);
9319                         switch (ip [1]) {
9320                         case CEE_ARGLIST: {
9321                                 /* somewhat similar to LDTOKEN */
9322                                 MonoInst *addr, *vtvar;
9323                                 CHECK_STACK_OVF (1);
9324                                 vtvar = mono_compile_create_var (cfg, &mono_defaults.argumenthandle_class->byval_arg, OP_LOCAL); 
9325
9326                                 NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
9327                                 MONO_INST_NEW (cfg, ins, OP_ARGLIST);
9328                                 ins->inst_left = addr;
9329                                 MONO_ADD_INS (bblock, ins);
9330                                 NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
9331                                 *sp++ = ins;
9332                                 ip += 2;
9333                                 break;
9334                         }
9335                         case CEE_CEQ:
9336                         case CEE_CGT:
9337                         case CEE_CGT_UN:
9338                         case CEE_CLT:
9339                         case CEE_CLT_UN: {
9340                                 MonoInst *cmp;
9341                                 CHECK_STACK (2);
9342                                 /*
9343                                  * The following transforms:
9344                                  *    CEE_CEQ    into OP_CEQ
9345                                  *    CEE_CGT    into OP_CGT
9346                                  *    CEE_CGT_UN into OP_CGT_UN
9347                                  *    CEE_CLT    into OP_CLT
9348                                  *    CEE_CLT_UN into OP_CLT_UN
9349                                  */
9350                                 MONO_INST_NEW (cfg, cmp, (OP_CEQ - CEE_CEQ) + ip [1]);
9351                                 
9352                                 MONO_INST_NEW (cfg, ins, cmp->opcode);
9353                                 sp -= 2;
9354                                 cmp->inst_i0 = sp [0];
9355                                 cmp->inst_i1 = sp [1];
9356                                 type_from_op (cmp);
9357                                 CHECK_TYPE (cmp);
9358                                 ins->type = STACK_I4;
9359                                 ins->inst_i0 = cmp;
9360 #if MONO_ARCH_SOFT_FLOAT
9361                                 if (sp [0]->type == STACK_R8) {
9362                                         cmp->type = STACK_I4;
9363                                         *sp++ = emit_tree (cfg, bblock, cmp, ip + 2);
9364                                         ip += 2;
9365                                         break;
9366                                 }
9367 #endif
9368                                 if ((sp [0]->type == STACK_I8) || ((sizeof (gpointer) == 8) && ((sp [0]->type == STACK_PTR) || (sp [0]->type == STACK_OBJ) || (sp [0]->type == STACK_MP))))
9369                                         cmp->opcode = OP_LCOMPARE;
9370                                 else
9371                                         cmp->opcode = OP_COMPARE;
9372                                 *sp++ = ins;
9373                                 /* spill it to reduce the expression complexity
9374                                  * and workaround bug 54209 
9375                                  */
9376                                 if (cmp->inst_left->type == STACK_I8) {
9377                                         --sp;
9378                                         *sp++ = emit_tree (cfg, bblock, ins, ip + 2);
9379                                 }
9380                                 ip += 2;
9381                                 break;
9382                         }
9383                         case CEE_LDFTN: {
9384                                 MonoInst *argconst;
9385                                 MonoMethod *cil_method, *ctor_method;
9386                                 int temp;
9387                                 gboolean is_shared = FALSE;
9388
9389                                 CHECK_STACK_OVF (1);
9390                                 CHECK_OPSIZE (6);
9391                                 n = read32 (ip + 2);
9392                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
9393                                 if (!cmethod)
9394                                         goto load_error;
9395                                 mono_class_init (cmethod->klass);
9396
9397                                 if (cfg->generic_sharing_context)
9398                                         context_used = mono_method_check_context_used (cmethod);
9399
9400                                 if (mono_class_generic_sharing_enabled (cmethod->klass)) {
9401                                         if ((cmethod->flags & METHOD_ATTRIBUTE_STATIC) &&
9402                                                         (cmethod->klass->generic_class ||
9403                                                         cmethod->klass->generic_container)) {
9404                                                 is_shared = TRUE;
9405                                         }
9406                                         if (cmethod->is_inflated && mono_method_get_context (cmethod)->method_inst)
9407                                                 is_shared = TRUE;
9408                                 }
9409
9410                                 cil_method = cmethod;
9411                                 if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_method (method, cmethod))
9412                                         METHOD_ACCESS_FAILURE;
9413                                 if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS) {
9414                                         if (check_linkdemand (cfg, method, cmethod, bblock, ip))
9415                                                 INLINE_FAILURE;
9416                                         CHECK_CFG_EXCEPTION;
9417                                 } else if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR) {
9418                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod, bblock, ip);
9419                                 }
9420
9421                                 /* 
9422                                  * Optimize the common case of ldftn+delegate creation
9423                                  */
9424 #if defined(MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE) && !defined(HAVE_WRITE_BARRIERS)
9425                                 /* FIXME: SGEN support */
9426                                 /* FIXME: handle shared static generic methods */
9427                                 /* FIXME: handle this in shared code */
9428                                 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)) {
9429                                         MonoInst *target_ins;
9430
9431                                         ip += 6;
9432                                         if (cfg->verbose_level > 3)
9433                                                 g_print ("converting (in B%d: stack: %d) %s", bblock->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
9434                                         target_ins = sp [-1];
9435                                         sp --;
9436                                         *sp = handle_delegate_ctor (cfg, bblock, ctor_method->klass, target_ins, cmethod, ip);
9437                                         ip += 5;                                        
9438                                         sp ++;
9439                                         break;
9440                                 }
9441 #endif
9442
9443                                 handle_loaded_temps (cfg, bblock, stack_start, sp);
9444
9445                                 if (context_used) {
9446                                         MonoInst *rgctx;
9447
9448                                         if (is_shared)
9449                                                 cmethod = mono_marshal_get_static_rgctx_invoke (cmethod);
9450
9451                                         GET_RGCTX (rgctx, context_used);
9452                                         argconst = get_runtime_generic_context_method (cfg, method, context_used,
9453                                                         bblock, cmethod,
9454                                                         generic_context, rgctx, MONO_RGCTX_INFO_METHOD, ip);
9455                                 } else if (is_shared) {
9456                                         NEW_METHODCONST (cfg, argconst, mono_marshal_get_static_rgctx_invoke (cmethod));
9457                                 } else {
9458                                         NEW_METHODCONST (cfg, argconst, cmethod);
9459                                 }
9460                                 if (method->wrapper_type != MONO_WRAPPER_SYNCHRONIZED)
9461                                         temp = mono_emit_jit_icall (cfg, bblock, mono_ldftn, &argconst, ip);
9462                                 else
9463                                         temp = mono_emit_jit_icall (cfg, bblock, mono_ldftn_nosync, &argconst, ip);
9464                                 NEW_TEMPLOAD (cfg, *sp, temp);
9465                                 sp ++;
9466                                 
9467                                 ip += 6;
9468                                 inline_costs += 10 * num_calls++;
9469                                 break;
9470                         }
9471                         case CEE_LDVIRTFTN: {
9472                                 MonoInst *args [2];
9473                                 int temp;
9474
9475                                 CHECK_STACK (1);
9476                                 CHECK_OPSIZE (6);
9477                                 n = read32 (ip + 2);
9478                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
9479                                 if (!cmethod)
9480                                         goto load_error;
9481                                 mono_class_init (cmethod->klass);
9482
9483                                 if (cfg->generic_sharing_context)
9484                                         context_used = mono_method_check_context_used (cmethod);
9485
9486                                 if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS) {
9487                                         if (check_linkdemand (cfg, method, cmethod, bblock, ip))
9488                                                 INLINE_FAILURE;
9489                                         CHECK_CFG_EXCEPTION;
9490                                 } else if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR) {
9491                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod, bblock, ip);
9492                                 }
9493
9494                                 handle_loaded_temps (cfg, bblock, stack_start, sp);
9495
9496                                 --sp;
9497                                 args [0] = *sp;
9498                                 if (context_used) {
9499                                         MonoInst *rgctx;
9500
9501                                         GET_RGCTX (rgctx, context_used);
9502                                         args [1] = get_runtime_generic_context_method (cfg, method, context_used,
9503                                                         bblock, cmethod,
9504                                                         generic_context, rgctx, MONO_RGCTX_INFO_METHOD, ip);
9505                                         temp = mono_emit_jit_icall (cfg, bblock, mono_ldvirtfn_gshared, args, ip);
9506                                 } else {
9507                                         NEW_METHODCONST (cfg, args [1], cmethod);
9508                                         temp = mono_emit_jit_icall (cfg, bblock, mono_ldvirtfn, args, ip);
9509                                 }
9510                                 NEW_TEMPLOAD (cfg, *sp, temp);
9511                                 sp ++;
9512
9513                                 ip += 6;
9514                                 inline_costs += 10 * num_calls++;
9515                                 break;
9516                         }
9517                         case CEE_LDARG:
9518                                 CHECK_STACK_OVF (1);
9519                                 CHECK_OPSIZE (4);
9520                                 n = read16 (ip + 2);
9521                                 CHECK_ARG (n);
9522                                 NEW_ARGLOAD (cfg, ins, n);
9523                                 LDARG_SOFT_FLOAT (cfg, ins, n, ip);
9524                                 *sp++ = ins;
9525                                 ip += 4;
9526                                 break;
9527                         case CEE_LDARGA:
9528                                 CHECK_STACK_OVF (1);
9529                                 CHECK_OPSIZE (4);
9530                                 n = read16 (ip + 2);
9531                                 CHECK_ARG (n);
9532                                 NEW_ARGLOADA (cfg, ins, n);
9533                                 *sp++ = ins;
9534                                 ip += 4;
9535                                 break;
9536                         case CEE_STARG:
9537                                 CHECK_STACK (1);
9538                                 --sp;
9539                                 handle_loaded_temps (cfg, bblock, stack_start, sp);
9540                                 CHECK_OPSIZE (4);
9541                                 n = read16 (ip + 2);
9542                                 CHECK_ARG (n);
9543                                 NEW_ARGSTORE (cfg, ins, n, *sp);
9544                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [n], *sp))
9545                                         UNVERIFIED;
9546                                 STARG_SOFT_FLOAT (cfg, ins, n, ip);
9547                                 if (ins->opcode == CEE_STOBJ) {
9548                                         NEW_ARGLOADA (cfg, ins, n);
9549                                         handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE, FALSE);
9550                                 } else
9551                                         MONO_ADD_INS (bblock, ins);
9552                                 ip += 4;
9553                                 break;
9554                         case CEE_LDLOC:
9555                                 CHECK_STACK_OVF (1);
9556                                 CHECK_OPSIZE (4);
9557                                 n = read16 (ip + 2);
9558                                 CHECK_LOCAL (n);
9559                                 NEW_LOCLOAD (cfg, ins, n);
9560                                 LDLOC_SOFT_FLOAT (cfg, ins, n, ip);
9561                                 *sp++ = ins;
9562                                 ip += 4;
9563                                 break;
9564                         case CEE_LDLOCA:
9565                                 CHECK_STACK_OVF (1);
9566                                 CHECK_OPSIZE (4);
9567                                 n = read16 (ip + 2);
9568                                 CHECK_LOCAL (n);
9569                                 NEW_LOCLOADA (cfg, ins, n);
9570                                 *sp++ = ins;
9571                                 ip += 4;
9572                                 break;
9573                         case CEE_STLOC:
9574                                 CHECK_STACK (1);
9575                                 --sp;
9576                                 CHECK_OPSIZE (4);
9577                                 n = read16 (ip + 2);
9578                                 CHECK_LOCAL (n);
9579                                 handle_loaded_temps (cfg, bblock, stack_start, sp);
9580                                 NEW_LOCSTORE (cfg, ins, n, *sp);
9581                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
9582                                         UNVERIFIED;
9583                                 STLOC_SOFT_FLOAT (cfg, ins, n, ip);
9584                                 if (ins->opcode == CEE_STOBJ) {
9585                                         NEW_LOCLOADA (cfg, ins, n);
9586                                         handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE, FALSE);
9587                                 } else
9588                                         MONO_ADD_INS (bblock, ins);
9589                                 ip += 4;
9590                                 inline_costs += 1;
9591                                 break;
9592                         case CEE_LOCALLOC:
9593                                 CHECK_STACK (1);
9594                                 --sp;
9595                                 if (sp != stack_start) 
9596                                         UNVERIFIED;
9597                                 if (cfg->method != method) 
9598                                         /* 
9599                                          * Inlining this into a loop in a parent could lead to 
9600                                          * stack overflows which is different behavior than the
9601                                          * non-inlined case, thus disable inlining in this case.
9602                                          */
9603                                         goto inline_failure;
9604                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
9605                                 ins->inst_left = *sp;
9606                                 ins->type = STACK_PTR;
9607
9608                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
9609                                 if (header->init_locals)
9610                                         ins->flags |= MONO_INST_INIT;
9611
9612                                 *sp++ = ins;
9613                                 ip += 2;
9614                                 /* FIXME: set init flag if locals init is set in this method */
9615                                 break;
9616                         case CEE_ENDFILTER: {
9617                                 MonoExceptionClause *clause, *nearest;
9618                                 int cc, nearest_num;
9619
9620                                 CHECK_STACK (1);
9621                                 --sp;
9622                                 if ((sp != stack_start) || (sp [0]->type != STACK_I4)) 
9623                                         UNVERIFIED;
9624                                 MONO_INST_NEW (cfg, ins, OP_ENDFILTER);
9625                                 ins->inst_left = *sp;
9626                                 MONO_ADD_INS (bblock, ins);
9627                                 start_new_bblock = 1;
9628                                 ip += 2;
9629
9630                                 nearest = NULL;
9631                                 nearest_num = 0;
9632                                 for (cc = 0; cc < header->num_clauses; ++cc) {
9633                                         clause = &header->clauses [cc];
9634                                         if ((clause->flags & MONO_EXCEPTION_CLAUSE_FILTER) &&
9635                                                 ((ip - header->code) > clause->data.filter_offset && (ip - header->code) <= clause->handler_offset) &&
9636                                             (!nearest || (clause->data.filter_offset < nearest->data.filter_offset))) {
9637                                                 nearest = clause;
9638                                                 nearest_num = cc;
9639                                         }
9640                                 }
9641                                 g_assert (nearest);
9642                                 if ((ip - header->code) != nearest->handler_offset)
9643                                         UNVERIFIED;
9644
9645                                 break;
9646                         }
9647                         case CEE_UNALIGNED_:
9648                                 ins_flag |= MONO_INST_UNALIGNED;
9649                                 /* FIXME: record alignment? we can assume 1 for now */
9650                                 CHECK_OPSIZE (3);
9651                                 ip += 3;
9652                                 break;
9653                         case CEE_VOLATILE_:
9654                                 ins_flag |= MONO_INST_VOLATILE;
9655                                 ip += 2;
9656                                 break;
9657                         case CEE_TAIL_:
9658                                 ins_flag   |= MONO_INST_TAILCALL;
9659                                 cfg->flags |= MONO_CFG_HAS_TAIL;
9660                                 /* Can't inline tail calls at this time */
9661                                 inline_costs += 100000;
9662                                 ip += 2;
9663                                 break;
9664                         case CEE_INITOBJ:
9665                                 CHECK_STACK (1);
9666                                 --sp;
9667                                 CHECK_OPSIZE (6);
9668                                 token = read32 (ip + 2);
9669                                 klass = mini_get_class (method, token, generic_context);
9670                                 CHECK_TYPELOAD (klass);
9671
9672                                 if (generic_class_is_reference_type (cfg, klass)) {
9673                                         MonoInst *store, *load;
9674                                         NEW_PCONST (cfg, load, NULL);
9675                                         load->type = STACK_OBJ;
9676                                         load->klass = klass;
9677                                         MONO_INST_NEW (cfg, store, CEE_STIND_REF);
9678                                         handle_loaded_temps (cfg, bblock, stack_start, sp);
9679                                         MONO_ADD_INS (bblock, store);
9680                                         store->inst_i0 = sp [0];
9681                                         store->inst_i1 = load;
9682                                 } else {
9683                                         handle_initobj (cfg, bblock, *sp, NULL, klass, stack_start, sp);
9684                                 }
9685                                 ip += 6;
9686                                 inline_costs += 1;
9687                                 break;
9688                         case CEE_CONSTRAINED_:
9689                                 /* FIXME: implement */
9690                                 CHECK_OPSIZE (6);
9691                                 token = read32 (ip + 2);
9692                                 constrained_call = mono_class_get_full (image, token, generic_context);
9693                                 CHECK_TYPELOAD (constrained_call);
9694                                 ip += 6;
9695                                 break;
9696                         case CEE_CPBLK:
9697                         case CEE_INITBLK: {
9698                                 MonoInst *iargs [3];
9699                                 CHECK_STACK (3);
9700                                 sp -= 3;
9701                                 if ((cfg->opt & MONO_OPT_INTRINS) && (ip [1] == CEE_CPBLK) && (sp [2]->opcode == OP_ICONST) && ((n = sp [2]->inst_c0) <= sizeof (gpointer) * 5)) {
9702                                         MonoInst *copy;
9703                                         NEW_MEMCPY (cfg, copy, sp [0], sp [1], n, 0);
9704                                         MONO_ADD_INS (bblock, copy);
9705                                         ip += 2;
9706                                         break;
9707                                 }
9708                                 iargs [0] = sp [0];
9709                                 iargs [1] = sp [1];
9710                                 iargs [2] = sp [2];
9711                                 handle_loaded_temps (cfg, bblock, stack_start, sp);
9712                                 if (ip [1] == CEE_CPBLK) {
9713                                         MonoMethod *memcpy_method = get_memcpy_method ();
9714                                         mono_emit_method_call_spilled (cfg, bblock, memcpy_method, memcpy_method->signature, iargs, ip, NULL);
9715                                 } else {
9716                                         MonoMethod *memset_method = get_memset_method ();
9717                                         mono_emit_method_call_spilled (cfg, bblock, memset_method, memset_method->signature, iargs, ip, NULL);
9718                                 }
9719                                 ip += 2;
9720                                 inline_costs += 1;
9721                                 break;
9722                         }
9723                         case CEE_NO_:
9724                                 CHECK_OPSIZE (3);
9725                                 if (ip [2] & 0x1)
9726                                         ins_flag |= MONO_INST_NOTYPECHECK;
9727                                 if (ip [2] & 0x2)
9728                                         ins_flag |= MONO_INST_NORANGECHECK;
9729                                 /* we ignore the no-nullcheck for now since we
9730                                  * really do it explicitly only when doing callvirt->call
9731                                  */
9732                                 ip += 3;
9733                                 break;
9734                         case CEE_RETHROW: {
9735                                 MonoInst *load;
9736                                 int handler_offset = -1;
9737
9738                                 for (i = 0; i < header->num_clauses; ++i) {
9739                                         MonoExceptionClause *clause = &header->clauses [i];
9740                                         if (MONO_OFFSET_IN_HANDLER (clause, ip - header->code) && !(clause->flags & MONO_EXCEPTION_CLAUSE_FINALLY))
9741                                                 handler_offset = clause->handler_offset;
9742                                 }
9743
9744                                 bblock->flags |= BB_EXCEPTION_UNSAFE;
9745
9746                                 g_assert (handler_offset != -1);
9747
9748                                 NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, handler_offset)->inst_c0);
9749                                 MONO_INST_NEW (cfg, ins, OP_RETHROW);
9750                                 ins->inst_left = load;
9751                                 MONO_ADD_INS (bblock, ins);
9752                                 sp = stack_start;
9753                                 link_bblock (cfg, bblock, end_bblock);
9754                                 start_new_bblock = 1;
9755                                 ip += 2;
9756                                 break;
9757                         }
9758                         case CEE_SIZEOF:
9759                                 CHECK_STACK_OVF (1);
9760                                 CHECK_OPSIZE (6);
9761                                 token = read32 (ip + 2);
9762                                 /* FIXXME: handle generics. */
9763                                 if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC) {
9764                                         MonoType *type = mono_type_create_from_typespec (image, token);
9765                                         token = mono_type_size (type, &ialign);
9766                                 } else {
9767                                         MonoClass *klass = mono_class_get_full (image, token, generic_context);
9768                                         CHECK_TYPELOAD (klass);
9769                                         mono_class_init (klass);
9770                                         token = mono_class_value_size (klass, &align);
9771                                 }
9772                                 NEW_ICONST (cfg, ins, token);
9773                                 *sp++= ins;
9774                                 ip += 6;
9775                                 break;
9776                         case CEE_REFANYTYPE:
9777                                 CHECK_STACK (1);
9778                                 MONO_INST_NEW (cfg, ins, OP_REFANYTYPE);
9779                                 --sp;
9780                                 ins->type = STACK_MP;
9781                                 ins->inst_left = *sp;
9782                                 ins->type = STACK_VTYPE;
9783                                 ins->klass = mono_defaults.typehandle_class;
9784                                 ip += 2;
9785                                 *sp++ = ins;
9786                                 break;
9787                         case CEE_READONLY_:
9788                                 readonly = TRUE;
9789                                 ip += 2;
9790                                 break;
9791                         default:
9792                                 g_error ("opcode 0xfe 0x%02x not handled", ip [1]);
9793                         }
9794                         break;
9795                 }
9796                 default:
9797                         g_error ("opcode 0x%02x not handled", *ip);
9798                 }
9799         }
9800         if (start_new_bblock != 1)
9801                 UNVERIFIED;
9802
9803         bblock->cil_length = ip - bblock->cil_code;
9804         bblock->next_bb = end_bblock;
9805
9806         if (cfg->method == method && cfg->domainvar) {
9807                 MonoInst *store;
9808                 MonoInst *get_domain;
9809                 
9810                 if (! (get_domain = mono_arch_get_domain_intrinsic (cfg))) {
9811                         MonoCallInst *call;
9812                         
9813                         MONO_INST_NEW_CALL (cfg, call, OP_CALL);
9814                         call->signature = helper_sig_domain_get;
9815                         call->inst.type = STACK_PTR;
9816                         call->fptr = mono_domain_get;
9817                         get_domain = (MonoInst*)call;
9818                 }
9819                 
9820                 NEW_TEMPSTORE (cfg, store, cfg->domainvar->inst_c0, get_domain);
9821                 MONO_ADD_INS (init_localsbb, store);
9822         }
9823
9824         if (cfg->method == method && cfg->got_var)
9825                 mono_emit_load_got_addr (cfg);
9826
9827         if (header->init_locals) {
9828                 MonoInst *store;
9829                 cfg->ip = header->code;
9830                 for (i = 0; i < header->num_locals; ++i) {
9831                         MonoType *ptype = header->locals [i];
9832                         int t = ptype->type;
9833                         if (t == MONO_TYPE_VALUETYPE && ptype->data.klass->enumtype)
9834                                 t = ptype->data.klass->enum_basetype->type;
9835                         if (ptype->byref) {
9836                                 NEW_PCONST (cfg, ins, NULL);
9837                                 NEW_LOCSTORE (cfg, store, i, ins);
9838                                 MONO_ADD_INS (init_localsbb, store);
9839                         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
9840                                 NEW_ICONST (cfg, ins, 0);
9841                                 NEW_LOCSTORE (cfg, store, i, ins);
9842                                 MONO_ADD_INS (init_localsbb, store);
9843                         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
9844                                 MONO_INST_NEW (cfg, ins, OP_I8CONST);
9845                                 ins->type = STACK_I8;
9846                                 ins->inst_l = 0;
9847                                 NEW_LOCSTORE (cfg, store, i, ins);
9848                                 MONO_ADD_INS (init_localsbb, store);
9849                         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
9850 #ifdef MONO_ARCH_SOFT_FLOAT
9851                                 /* FIXME: handle init of R4 */
9852 #else
9853                                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
9854                                 ins->type = STACK_R8;
9855                                 ins->inst_p0 = (void*)&r8_0;
9856                                 NEW_LOCSTORE (cfg, store, i, ins);
9857                                 MONO_ADD_INS (init_localsbb, store);
9858 #endif
9859                         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
9860                                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (ptype))) {
9861                                 NEW_LOCLOADA (cfg, ins, i);
9862                                 handle_initobj (cfg, init_localsbb, ins, NULL, mono_class_from_mono_type (ptype), NULL, NULL);
9863                         } else {
9864                                 NEW_PCONST (cfg, ins, NULL);
9865                                 NEW_LOCSTORE (cfg, store, i, ins);
9866                                 MONO_ADD_INS (init_localsbb, store);
9867                         }
9868                 }
9869         }
9870
9871         cfg->ip = NULL;
9872
9873         /* resolve backward branches in the middle of an existing basic block */
9874         for (tmp = bb_recheck; tmp; tmp = tmp->next) {
9875                 bblock = tmp->data;
9876                 /*g_print ("need recheck in %s at IL_%04x\n", method->name, bblock->cil_code - header->code);*/
9877                 tblock = find_previous (cfg->cil_offset_to_bb, header->code_size, start_bblock, bblock->cil_code);
9878                 if (tblock != start_bblock) {
9879                         int l;
9880                         split_bblock (cfg, tblock, bblock);
9881                         l = bblock->cil_code - header->code;
9882                         bblock->cil_length = tblock->cil_length - l;
9883                         tblock->cil_length = l;
9884                 } else {
9885                         g_print ("recheck failed.\n");
9886                 }
9887         }
9888
9889         if (cfg->method == method) {
9890                 MonoBasicBlock *bb;
9891                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
9892                         bb->region = mono_find_block_region (cfg, bb->real_offset);
9893                         if (cfg->spvars)
9894                                 mono_create_spvar_for_region (cfg, bb->region);
9895                         if (cfg->verbose_level > 2)
9896                                 g_print ("REGION BB%d IL_%04x ID_%08X\n", bb->block_num, bb->real_offset, bb->region);
9897                 }
9898         }
9899
9900         g_slist_free (class_inits);
9901         dont_inline = g_list_remove (dont_inline, method);
9902
9903         if (inline_costs < 0) {
9904                 char *mname;
9905
9906                 /* Method is too large */
9907                 mname = mono_method_full_name (method, TRUE);
9908                 cfg->exception_type = MONO_EXCEPTION_INVALID_PROGRAM;
9909                 cfg->exception_message = g_strdup_printf ("Method %s is too complex.", mname);
9910                 g_free (mname);
9911                 return -1;
9912         }
9913
9914         return inline_costs;
9915
9916  exception_exit:
9917         g_assert (cfg->exception_type != MONO_EXCEPTION_NONE);
9918         g_slist_free (class_inits);
9919         dont_inline = g_list_remove (dont_inline, method);
9920         return -1;
9921
9922  inline_failure:
9923         g_slist_free (class_inits);
9924         dont_inline = g_list_remove (dont_inline, method);
9925         return -1;
9926
9927  load_error:
9928         g_slist_free (class_inits);
9929         dont_inline = g_list_remove (dont_inline, method);
9930         cfg->exception_type = MONO_EXCEPTION_TYPE_LOAD;
9931         return -1;
9932
9933  unverified:
9934         g_slist_free (class_inits);
9935         dont_inline = g_list_remove (dont_inline, method);
9936         set_exception_type_from_invalid_il (cfg, method, ip);
9937         return -1;
9938 }
9939
9940 void
9941 mono_print_tree (MonoInst *tree) {
9942         int arity;
9943
9944         if (!tree)
9945                 return;
9946
9947         arity = mono_burg_arity [tree->opcode];
9948
9949         printf (" %s%s", arity?"(":"",  mono_inst_name (tree->opcode));
9950
9951         switch (tree->opcode) {
9952         case OP_ICONST:
9953                 printf ("[%d]", (int)tree->inst_c0);
9954                 break;
9955         case OP_I8CONST:
9956                 printf ("[%lld]", (long long)tree->inst_l);
9957                 break;
9958         case OP_R8CONST:
9959                 printf ("[%f]", *(double*)tree->inst_p0);
9960                 break;
9961         case OP_R4CONST:
9962                 printf ("[%f]", *(float*)tree->inst_p0);
9963                 break;
9964         case OP_ARG:
9965         case OP_LOCAL:
9966                 printf ("[%d]", (int)tree->inst_c0);
9967                 break;
9968         case OP_REGOFFSET:
9969                 if (tree->inst_offset < 0)
9970                         printf ("[-0x%x(%s)]", (int)(-tree->inst_offset), mono_arch_regname (tree->inst_basereg));
9971                 else
9972                         printf ("[0x%x(%s)]", (int)(tree->inst_offset), mono_arch_regname (tree->inst_basereg));
9973                 break;
9974         case OP_REGVAR:
9975                 printf ("[%s]", mono_arch_regname (tree->dreg));
9976                 break;
9977         case CEE_NEWARR:
9978                 printf ("[%s]",  tree->inst_newa_class->name);
9979                 mono_print_tree (tree->inst_newa_len);
9980                 break;
9981         case OP_CALL:
9982         case OP_CALLVIRT:
9983         case OP_FCALL:
9984         case OP_FCALLVIRT:
9985         case OP_LCALL:
9986         case OP_LCALLVIRT:
9987         case OP_VCALL:
9988         case OP_VCALLVIRT:
9989         case OP_VOIDCALL:
9990         case OP_VOIDCALLVIRT:
9991         case OP_TRAMPCALL_VTABLE: {
9992                 MonoCallInst *call = (MonoCallInst*)tree;
9993                 if (call->method)
9994                         printf ("[%s]", call->method->name);
9995                 else if (call->fptr) {
9996                         MonoJitICallInfo *info = mono_find_jit_icall_by_addr (call->fptr);
9997                         if (info)
9998                                 printf ("[%s]", info->name);
9999                 }
10000                 break;
10001         }
10002         case OP_PHI: {
10003                 int i;
10004                 printf ("[%d (", (int)tree->inst_c0);
10005                 for (i = 0; i < tree->inst_phi_args [0]; i++) {
10006                         if (i)
10007                                 printf (", ");
10008                         printf ("%d", tree->inst_phi_args [i + 1]);
10009                 }
10010                 printf (")]");
10011                 break;
10012         }
10013         case OP_RENAME:
10014         case OP_RETARG:
10015         case OP_NOP:
10016         case OP_JMP:
10017         case OP_BREAK:
10018                 break;
10019         case OP_LOAD_MEMBASE:
10020         case OP_LOADI4_MEMBASE:
10021         case OP_LOADU4_MEMBASE:
10022         case OP_LOADU1_MEMBASE:
10023         case OP_LOADI1_MEMBASE:
10024         case OP_LOADU2_MEMBASE:
10025         case OP_LOADI2_MEMBASE:
10026                 printf ("[%s] <- [%s + 0x%x]", mono_arch_regname (tree->dreg), mono_arch_regname (tree->inst_basereg), (int)tree->inst_offset);
10027                 break;
10028         case OP_BR:
10029         case OP_CALL_HANDLER:
10030                 printf ("[B%d]", tree->inst_target_bb->block_num);
10031                 break;
10032         case OP_SWITCH:
10033         case CEE_ISINST:
10034         case CEE_CASTCLASS:
10035         case OP_OUTARG:
10036         case OP_CALL_REG:
10037         case OP_FCALL_REG:
10038         case OP_LCALL_REG:
10039         case OP_VCALL_REG:
10040         case OP_VOIDCALL_REG:
10041                 mono_print_tree (tree->inst_left);
10042                 break;
10043         case CEE_BNE_UN:
10044         case CEE_BEQ:
10045         case CEE_BLT:
10046         case CEE_BLT_UN:
10047         case CEE_BGT:
10048         case CEE_BGT_UN:
10049         case CEE_BGE:
10050         case CEE_BGE_UN:
10051         case CEE_BLE:
10052         case CEE_BLE_UN:
10053                 printf ("[B%dB%d]", tree->inst_true_bb->block_num, tree->inst_false_bb->block_num);
10054                 mono_print_tree (tree->inst_left);
10055                 break;
10056         default:
10057                 if (!mono_arch_print_tree(tree, arity)) {
10058                         if (arity) {
10059                                 mono_print_tree (tree->inst_left);
10060                                 if (arity > 1)
10061                                         mono_print_tree (tree->inst_right);
10062                         }
10063                 }
10064                 break;
10065         }
10066
10067         if (arity)
10068                 printf (")");
10069 }
10070
10071 void
10072 mono_print_tree_nl (MonoInst *tree)
10073 {
10074         mono_print_tree (tree);
10075         printf ("\n");
10076 }
10077
10078 static void
10079 create_helper_signature (void)
10080 {
10081         helper_sig_domain_get = mono_create_icall_signature ("ptr");
10082         helper_sig_class_init_trampoline = mono_create_icall_signature ("void");
10083         helper_sig_generic_class_init_trampoline = mono_create_icall_signature ("void");
10084         helper_sig_rgctx_lazy_fetch_trampoline = mono_create_icall_signature ("ptr ptr");
10085 }
10086
10087 gconstpointer
10088 mono_icall_get_wrapper (MonoJitICallInfo* callinfo)
10089 {
10090         char *name;
10091         MonoMethod *wrapper;
10092         gconstpointer trampoline;
10093         MonoDomain *domain = mono_get_root_domain ();
10094         
10095         if (callinfo->wrapper) {
10096                 return callinfo->wrapper;
10097         }
10098
10099         if (callinfo->trampoline)
10100                 return callinfo->trampoline;
10101
10102         /* 
10103          * We use the lock on the root domain instead of the JIT lock to protect 
10104          * callinfo->trampoline, since we do a lot of stuff inside the critical section.
10105          */
10106         mono_domain_lock (domain);
10107
10108         if (callinfo->trampoline) {
10109                 mono_domain_unlock (domain);
10110                 return callinfo->trampoline;
10111         }
10112
10113         name = g_strdup_printf ("__icall_wrapper_%s", callinfo->name);
10114         wrapper = mono_marshal_get_icall_wrapper (callinfo->sig, name, callinfo->func, check_for_pending_exc);
10115         g_free (name);
10116
10117         trampoline = mono_create_ftnptr (domain, mono_create_jit_trampoline_in_domain (domain, wrapper, TRUE));
10118         mono_register_jit_icall_wrapper (callinfo, trampoline);
10119
10120         callinfo->trampoline = trampoline;
10121
10122         mono_domain_unlock (domain);
10123         
10124         return callinfo->trampoline;
10125 }
10126
10127 static void
10128 mono_dynamic_code_hash_insert (MonoDomain *domain, MonoMethod *method, MonoJitDynamicMethodInfo *ji)
10129 {
10130         if (!domain->dynamic_code_hash)
10131                 domain->dynamic_code_hash = g_hash_table_new (NULL, NULL);
10132         g_hash_table_insert (domain->dynamic_code_hash, method, ji);
10133 }
10134
10135 static MonoJitDynamicMethodInfo*
10136 mono_dynamic_code_hash_lookup (MonoDomain *domain, MonoMethod *method)
10137 {
10138         MonoJitDynamicMethodInfo *res;
10139
10140         if (domain->dynamic_code_hash)
10141                 res = g_hash_table_lookup (domain->dynamic_code_hash, method);
10142         else
10143                 res = NULL;
10144         return res;
10145 }
10146
10147 typedef struct {
10148         MonoClass *vtype;
10149         GList *active, *inactive;
10150         GSList *slots;
10151 } StackSlotInfo;
10152
10153 static inline GSList*
10154 g_slist_prepend_mempool (MonoMemPool *mp, GSList   *list,
10155                                                  gpointer  data)
10156 {
10157   GSList *new_list;
10158
10159   new_list = mono_mempool_alloc (mp, sizeof (GSList));
10160   new_list->data = data;
10161   new_list->next = list;
10162
10163   return new_list;
10164 }
10165
10166 static gint 
10167 compare_by_interval_start_pos_func (gconstpointer a, gconstpointer b)
10168 {
10169         MonoMethodVar *v1 = (MonoMethodVar*)a;
10170         MonoMethodVar *v2 = (MonoMethodVar*)b;
10171
10172         if (v1 == v2)
10173                 return 0;
10174         else if (v1->interval->range && v2->interval->range)
10175                 return v1->interval->range->from - v2->interval->range->from;
10176         else if (v1->interval->range)
10177                 return -1;
10178         else
10179                 return 1;
10180 }
10181
10182 #if 0
10183 #define LSCAN_DEBUG(a) do { a; } while (0)
10184 #else
10185 #define LSCAN_DEBUG(a)
10186 #endif
10187
10188 static gint32*
10189 mono_allocate_stack_slots_full2 (MonoCompile *cfg, gboolean backward, guint32 *stack_size, guint32 *stack_align)
10190 {
10191         int i, slot, offset, size;
10192         guint32 align;
10193         MonoMethodVar *vmv;
10194         MonoInst *inst;
10195         gint32 *offsets;
10196         GList *vars = NULL, *l, *unhandled;
10197         StackSlotInfo *scalar_stack_slots, *vtype_stack_slots, *slot_info;
10198         MonoType *t;
10199         int nvtypes;
10200
10201         LSCAN_DEBUG (printf ("Allocate Stack Slots 2 for %s:\n", mono_method_full_name (cfg->method, TRUE)));
10202
10203         scalar_stack_slots = mono_mempool_alloc0 (cfg->mempool, sizeof (StackSlotInfo) * MONO_TYPE_PINNED);
10204         vtype_stack_slots = NULL;
10205         nvtypes = 0;
10206
10207         offsets = mono_mempool_alloc (cfg->mempool, sizeof (gint32) * cfg->num_varinfo);
10208         for (i = 0; i < cfg->num_varinfo; ++i)
10209                 offsets [i] = -1;
10210
10211         for (i = cfg->locals_start; i < cfg->num_varinfo; i++) {
10212                 inst = cfg->varinfo [i];
10213                 vmv = MONO_VARINFO (cfg, i);
10214
10215                 if ((inst->flags & MONO_INST_IS_DEAD) || inst->opcode == OP_REGVAR || inst->opcode == OP_REGOFFSET)
10216                         continue;
10217
10218                 vars = g_list_prepend (vars, vmv);
10219         }
10220
10221         vars = g_list_sort (g_list_copy (vars), compare_by_interval_start_pos_func);
10222
10223         /* Sanity check */
10224         /*
10225         i = 0;
10226         for (unhandled = vars; unhandled; unhandled = unhandled->next) {
10227                 MonoMethodVar *current = unhandled->data;
10228
10229                 if (current->interval->range) {
10230                         g_assert (current->interval->range->from >= i);
10231                         i = current->interval->range->from;
10232                 }
10233         }
10234         */
10235
10236         offset = 0;
10237         *stack_align = 0;
10238         for (unhandled = vars; unhandled; unhandled = unhandled->next) {
10239                 MonoMethodVar *current = unhandled->data;
10240
10241                 vmv = current;
10242                 inst = cfg->varinfo [vmv->idx];
10243
10244                 /* inst->backend.is_pinvoke indicates native sized value types, this is used by the
10245                 * pinvoke wrappers when they call functions returning structures */
10246                 if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->inst_vtype->type != MONO_TYPE_TYPEDBYREF)
10247                         size = mono_class_native_size (inst->inst_vtype->data.klass, &align);
10248                 else {
10249                         int ialign;
10250
10251                         size = mono_type_size (inst->inst_vtype, &ialign);
10252                         align = ialign;
10253                 }
10254
10255                 t = mono_type_get_underlying_type (inst->inst_vtype);
10256                 switch (t->type) {
10257                 case MONO_TYPE_GENERICINST:
10258                         if (!mono_type_generic_inst_is_valuetype (t)) {
10259                                 slot_info = &scalar_stack_slots [t->type];
10260                                 break;
10261                         }
10262                         /* Fall through */
10263                 case MONO_TYPE_VALUETYPE:
10264                         if (!vtype_stack_slots)
10265                                 vtype_stack_slots = mono_mempool_alloc0 (cfg->mempool, sizeof (StackSlotInfo) * 256);
10266                         for (i = 0; i < nvtypes; ++i)
10267                                 if (t->data.klass == vtype_stack_slots [i].vtype)
10268                                         break;
10269                         if (i < nvtypes)
10270                                 slot_info = &vtype_stack_slots [i];
10271                         else {
10272                                 g_assert (nvtypes < 256);
10273                                 vtype_stack_slots [nvtypes].vtype = t->data.klass;
10274                                 slot_info = &vtype_stack_slots [nvtypes];
10275                                 nvtypes ++;
10276                         }
10277                         break;
10278                 case MONO_TYPE_CLASS:
10279                 case MONO_TYPE_OBJECT:
10280                 case MONO_TYPE_ARRAY:
10281                 case MONO_TYPE_SZARRAY:
10282                 case MONO_TYPE_STRING:
10283                 case MONO_TYPE_PTR:
10284                 case MONO_TYPE_I:
10285                 case MONO_TYPE_U:
10286 #if SIZEOF_VOID_P == 4
10287                 case MONO_TYPE_I4:
10288 #else
10289                 case MONO_TYPE_I8:
10290                         /* Share non-float stack slots of the same size */
10291                         slot_info = &scalar_stack_slots [MONO_TYPE_CLASS];
10292                         break;
10293 #endif
10294                 default:
10295                         slot_info = &scalar_stack_slots [t->type];
10296                 }
10297
10298                 slot = 0xffffff;
10299                 if (cfg->comp_done & MONO_COMP_LIVENESS) {
10300                         int pos;
10301                         gboolean changed;
10302
10303                         //printf ("START  %2d %08x %08x\n",  vmv->idx, vmv->range.first_use.abs_pos, vmv->range.last_use.abs_pos);
10304
10305                         if (!current->interval->range) {
10306                                 if (inst->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT))
10307                                         pos = ~0;
10308                                 else {
10309                                         /* Dead */
10310                                         inst->flags |= MONO_INST_IS_DEAD;
10311                                         continue;
10312                                 }
10313                         }
10314                         else
10315                                 pos = current->interval->range->from;
10316
10317                         LSCAN_DEBUG (printf ("process R%d ", inst->dreg));
10318                         if (current->interval->range)
10319                                 LSCAN_DEBUG (mono_linterval_print (current->interval));
10320                         LSCAN_DEBUG (printf ("\n"));
10321
10322                         /* Check for intervals in active which expired or inactive */
10323                         changed = TRUE;
10324                         /* FIXME: Optimize this */
10325                         while (changed) {
10326                                 changed = FALSE;
10327                                 for (l = slot_info->active; l != NULL; l = l->next) {
10328                                         MonoMethodVar *v = (MonoMethodVar*)l->data;
10329
10330                                         if (v->interval->last_range->to < pos) {
10331                                                 slot_info->active = g_list_delete_link (slot_info->active, l);
10332                                                 slot_info->slots = g_slist_prepend_mempool (cfg->mempool, slot_info->slots, GINT_TO_POINTER (offsets [v->idx]));
10333                                                 LSCAN_DEBUG (printf ("Interval R%d has expired, adding 0x%x to slots\n", cfg->varinfo [v->idx]->dreg, offsets [v->idx]));
10334                                                 changed = TRUE;
10335                                                 break;
10336                                         }
10337                                         else if (!mono_linterval_covers (v->interval, pos)) {
10338                                                 slot_info->inactive = g_list_append (slot_info->inactive, v);
10339                                                 slot_info->active = g_list_delete_link (slot_info->active, l);
10340                                                 LSCAN_DEBUG (printf ("Interval R%d became inactive\n", cfg->varinfo [v->idx]->dreg));
10341                                                 changed = TRUE;
10342                                                 break;
10343                                         }
10344                                 }
10345                         }
10346
10347                         /* Check for intervals in inactive which expired or active */
10348                         changed = TRUE;
10349                         /* FIXME: Optimize this */
10350                         while (changed) {
10351                                 changed = FALSE;
10352                                 for (l = slot_info->inactive; l != NULL; l = l->next) {
10353                                         MonoMethodVar *v = (MonoMethodVar*)l->data;
10354
10355                                         if (v->interval->last_range->to < pos) {
10356                                                 slot_info->inactive = g_list_delete_link (slot_info->inactive, l);
10357                                                 // FIXME: Enabling this seems to cause impossible to debug crashes
10358                                                 //slot_info->slots = g_slist_prepend_mempool (cfg->mempool, slot_info->slots, GINT_TO_POINTER (offsets [v->idx]));
10359                                                 LSCAN_DEBUG (printf ("Interval R%d has expired, adding 0x%x to slots\n", cfg->varinfo [v->idx]->dreg, offsets [v->idx]));
10360                                                 changed = TRUE;
10361                                                 break;
10362                                         }
10363                                         else if (mono_linterval_covers (v->interval, pos)) {
10364                                                 slot_info->active = g_list_append (slot_info->active, v);
10365                                                 slot_info->inactive = g_list_delete_link (slot_info->inactive, l);
10366                                                 LSCAN_DEBUG (printf ("\tInterval R%d became active\n", cfg->varinfo [v->idx]->dreg));
10367                                                 changed = TRUE;
10368                                                 break;
10369                                         }
10370                                 }
10371                         }
10372
10373                         /* 
10374                          * This also handles the case when the variable is used in an
10375                          * exception region, as liveness info is not computed there.
10376                          */
10377                         /* 
10378                          * FIXME: All valuetypes are marked as INDIRECT because of LDADDR
10379                          * opcodes.
10380                          */
10381                         if (! (inst->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT))) {
10382                                 if (slot_info->slots) {
10383                                         slot = GPOINTER_TO_INT (slot_info->slots->data);
10384
10385                                         slot_info->slots = slot_info->slots->next;
10386                                 }
10387
10388                                 /* FIXME: We might want to consider the inactive intervals as well if slot_info->slots is empty */
10389
10390                                 slot_info->active = mono_varlist_insert_sorted (cfg, slot_info->active, vmv, TRUE);
10391                         }
10392                 }
10393
10394 #if 0
10395                 {
10396                         static int count = 0;
10397                         count ++;
10398
10399                         if (count == atoi (getenv ("COUNT3")))
10400                                 printf ("LAST: %s\n", mono_method_full_name (cfg->method, TRUE));
10401                         if (count > atoi (getenv ("COUNT3")))
10402                                 slot = 0xffffff;
10403                         else {
10404                                 mono_print_tree_nl (inst);
10405                                 }
10406                 }
10407 #endif
10408
10409                 LSCAN_DEBUG (printf ("R%d %s -> 0x%x\n", inst->dreg, mono_type_full_name (t), slot));
10410
10411                 if (slot == 0xffffff) {
10412                         /*
10413                          * Allways allocate valuetypes to sizeof (gpointer) to allow more
10414                          * efficient copying (and to work around the fact that OP_MEMCPY
10415                          * and OP_MEMSET ignores alignment).
10416                          */
10417                         if (MONO_TYPE_ISSTRUCT (t))
10418                                 align = sizeof (gpointer);
10419
10420                         if (backward) {
10421                                 offset += size;
10422                                 offset += align - 1;
10423                                 offset &= ~(align - 1);
10424                                 slot = offset;
10425                         }
10426                         else {
10427                                 offset += align - 1;
10428                                 offset &= ~(align - 1);
10429                                 slot = offset;
10430                                 offset += size;
10431                         }
10432
10433                         if (*stack_align == 0)
10434                                 *stack_align = align;
10435                 }
10436
10437                 offsets [vmv->idx] = slot;
10438         }
10439         g_list_free (vars);
10440         for (i = 0; i < MONO_TYPE_PINNED; ++i) {
10441                 if (scalar_stack_slots [i].active)
10442                         g_list_free (scalar_stack_slots [i].active);
10443         }
10444         for (i = 0; i < nvtypes; ++i) {
10445                 if (vtype_stack_slots [i].active)
10446                         g_list_free (vtype_stack_slots [i].active);
10447         }
10448
10449         mono_jit_stats.locals_stack_size += offset;
10450
10451         *stack_size = offset;
10452         return offsets;
10453 }
10454
10455 /*
10456  *  mono_allocate_stack_slots_full:
10457  *
10458  *  Allocate stack slots for all non register allocated variables using a
10459  * linear scan algorithm.
10460  * Returns: an array of stack offsets.
10461  * STACK_SIZE is set to the amount of stack space needed.
10462  * STACK_ALIGN is set to the alignment needed by the locals area.
10463  */
10464 gint32*
10465 mono_allocate_stack_slots_full (MonoCompile *cfg, gboolean backward, guint32 *stack_size, guint32 *stack_align)
10466 {
10467         int i, slot, offset, size;
10468         guint32 align;
10469         MonoMethodVar *vmv;
10470         MonoInst *inst;
10471         gint32 *offsets;
10472         GList *vars = NULL, *l;
10473         StackSlotInfo *scalar_stack_slots, *vtype_stack_slots, *slot_info;
10474         MonoType *t;
10475         int nvtypes;
10476
10477         if ((cfg->num_varinfo > 0) && MONO_VARINFO (cfg, 0)->interval)
10478                 return mono_allocate_stack_slots_full2 (cfg, backward, stack_size, stack_align);
10479
10480         scalar_stack_slots = mono_mempool_alloc0 (cfg->mempool, sizeof (StackSlotInfo) * MONO_TYPE_PINNED);
10481         vtype_stack_slots = NULL;
10482         nvtypes = 0;
10483
10484         offsets = mono_mempool_alloc (cfg->mempool, sizeof (gint32) * cfg->num_varinfo);
10485         for (i = 0; i < cfg->num_varinfo; ++i)
10486                 offsets [i] = -1;
10487
10488         for (i = cfg->locals_start; i < cfg->num_varinfo; i++) {
10489                 inst = cfg->varinfo [i];
10490                 vmv = MONO_VARINFO (cfg, i);
10491
10492                 if ((inst->flags & MONO_INST_IS_DEAD) || inst->opcode == OP_REGVAR || inst->opcode == OP_REGOFFSET)
10493                         continue;
10494
10495                 vars = g_list_prepend (vars, vmv);
10496         }
10497
10498         vars = mono_varlist_sort (cfg, vars, 0);
10499         offset = 0;
10500         *stack_align = 0;
10501         for (l = vars; l; l = l->next) {
10502                 vmv = l->data;
10503                 inst = cfg->varinfo [vmv->idx];
10504
10505                 /* inst->backend.is_pinvoke indicates native sized value types, this is used by the
10506                 * pinvoke wrappers when they call functions returning structures */
10507                 if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->inst_vtype->type != MONO_TYPE_TYPEDBYREF)
10508                         size = mono_class_native_size (inst->inst_vtype->data.klass, &align);
10509                 else {
10510                         int ialign;
10511
10512                         size = mono_type_size (inst->inst_vtype, &ialign);
10513                         align = ialign;
10514                 }
10515
10516                 t = mono_type_get_underlying_type (inst->inst_vtype);
10517                 if (t->byref) {
10518                         slot_info = &scalar_stack_slots [MONO_TYPE_I];
10519                 } else {
10520                         switch (t->type) {
10521                         case MONO_TYPE_GENERICINST:
10522                                 if (!mono_type_generic_inst_is_valuetype (t)) {
10523                                         slot_info = &scalar_stack_slots [t->type];
10524                                         break;
10525                                 }
10526                                 /* Fall through */
10527                         case MONO_TYPE_VALUETYPE:
10528                                 if (!vtype_stack_slots)
10529                                         vtype_stack_slots = mono_mempool_alloc0 (cfg->mempool, sizeof (StackSlotInfo) * 256);
10530                                 for (i = 0; i < nvtypes; ++i)
10531                                         if (t->data.klass == vtype_stack_slots [i].vtype)
10532                                                 break;
10533                                 if (i < nvtypes)
10534                                         slot_info = &vtype_stack_slots [i];
10535                                 else {
10536                                         g_assert (nvtypes < 256);
10537                                         vtype_stack_slots [nvtypes].vtype = t->data.klass;
10538                                         slot_info = &vtype_stack_slots [nvtypes];
10539                                         nvtypes ++;
10540                                 }
10541                                 break;
10542                         case MONO_TYPE_CLASS:
10543                         case MONO_TYPE_OBJECT:
10544                         case MONO_TYPE_ARRAY:
10545                         case MONO_TYPE_SZARRAY:
10546                         case MONO_TYPE_STRING:
10547                         case MONO_TYPE_PTR:
10548                         case MONO_TYPE_I:
10549                         case MONO_TYPE_U:
10550 #if SIZEOF_VOID_P == 4
10551                         case MONO_TYPE_I4:
10552 #else
10553                         case MONO_TYPE_I8:
10554 #endif
10555                                 /* Share non-float stack slots of the same size */
10556                                 slot_info = &scalar_stack_slots [MONO_TYPE_CLASS];
10557                                 break;
10558                         default:
10559                                 slot_info = &scalar_stack_slots [t->type];
10560                         }
10561                 }
10562
10563                 slot = 0xffffff;
10564                 if (cfg->comp_done & MONO_COMP_LIVENESS) {
10565                         //printf ("START  %2d %08x %08x\n",  vmv->idx, vmv->range.first_use.abs_pos, vmv->range.last_use.abs_pos);
10566                         
10567                         /* expire old intervals in active */
10568                         while (slot_info->active) {
10569                                 MonoMethodVar *amv = (MonoMethodVar *)slot_info->active->data;
10570
10571                                 if (amv->range.last_use.abs_pos > vmv->range.first_use.abs_pos)
10572                                         break;
10573
10574                                 //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);
10575
10576                                 slot_info->active = g_list_delete_link (slot_info->active, slot_info->active);
10577                                 slot_info->slots = g_slist_prepend_mempool (cfg->mempool, slot_info->slots, GINT_TO_POINTER (offsets [amv->idx]));
10578                         }
10579
10580                         /* 
10581                          * This also handles the case when the variable is used in an
10582                          * exception region, as liveness info is not computed there.
10583                          */
10584                         /* 
10585                          * FIXME: All valuetypes are marked as INDIRECT because of LDADDR
10586                          * opcodes.
10587                          */
10588                         if (! (inst->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT))) {
10589                                 if (slot_info->slots) {
10590                                         slot = GPOINTER_TO_INT (slot_info->slots->data);
10591
10592                                         slot_info->slots = slot_info->slots->next;
10593                                 }
10594
10595                                 slot_info->active = mono_varlist_insert_sorted (cfg, slot_info->active, vmv, TRUE);
10596                         }
10597                 }
10598
10599                 {
10600                         static int count = 0;
10601                         count ++;
10602
10603                         /*
10604                         if (count == atoi (getenv ("COUNT")))
10605                                 printf ("LAST: %s\n", mono_method_full_name (cfg->method, TRUE));
10606                         if (count > atoi (getenv ("COUNT")))
10607                                 slot = 0xffffff;
10608                         else {
10609                                 mono_print_tree_nl (inst);
10610                                 }
10611                         */
10612                 }
10613
10614                 if (cfg->disable_reuse_stack_slots)
10615                         slot = 0xffffff;
10616
10617                 if (slot == 0xffffff) {
10618                         /*
10619                          * Allways allocate valuetypes to sizeof (gpointer) to allow more
10620                          * efficient copying (and to work around the fact that OP_MEMCPY
10621                          * and OP_MEMSET ignores alignment).
10622                          */
10623                         if (MONO_TYPE_ISSTRUCT (t))
10624                                 align = sizeof (gpointer);
10625
10626                         if (backward) {
10627                                 offset += size;
10628                                 offset += align - 1;
10629                                 offset &= ~(align - 1);
10630                                 slot = offset;
10631                         }
10632                         else {
10633                                 offset += align - 1;
10634                                 offset &= ~(align - 1);
10635                                 slot = offset;
10636                                 offset += size;
10637                         }
10638
10639                         if (*stack_align == 0)
10640                                 *stack_align = align;
10641                 }
10642
10643                 offsets [vmv->idx] = slot;
10644         }
10645         g_list_free (vars);
10646         for (i = 0; i < MONO_TYPE_PINNED; ++i) {
10647                 if (scalar_stack_slots [i].active)
10648                         g_list_free (scalar_stack_slots [i].active);
10649         }
10650         for (i = 0; i < nvtypes; ++i) {
10651                 if (vtype_stack_slots [i].active)
10652                         g_list_free (vtype_stack_slots [i].active);
10653         }
10654
10655         mono_jit_stats.locals_stack_size += offset;
10656
10657         *stack_size = offset;
10658         return offsets;
10659 }
10660
10661 gint32*
10662 mono_allocate_stack_slots (MonoCompile *m, guint32 *stack_size, guint32 *stack_align)
10663 {
10664         return mono_allocate_stack_slots_full (m, TRUE, stack_size, stack_align);
10665 }
10666
10667 void
10668 mono_register_opcode_emulation (int opcode, const char *name, const char *sigstr, gpointer func, gboolean no_throw)
10669 {
10670         MonoJitICallInfo *info;
10671         MonoMethodSignature *sig = mono_create_icall_signature (sigstr);
10672
10673         if (!emul_opcode_map)
10674                 emul_opcode_map = g_new0 (MonoJitICallInfo*, OP_LAST + 1);
10675
10676         g_assert (!sig->hasthis);
10677         g_assert (sig->param_count < 3);
10678
10679         info = mono_register_jit_icall (func, name, sig, no_throw);
10680
10681         emul_opcode_map [opcode] = info;
10682 }
10683
10684 static void
10685 register_icall (gpointer func, const char *name, const char *sigstr, gboolean save)
10686 {
10687         MonoMethodSignature *sig;
10688
10689         if (sigstr)
10690                 sig = mono_create_icall_signature (sigstr);
10691         else
10692                 sig = NULL;
10693
10694         mono_register_jit_icall (func, name, sig, save);
10695 }
10696
10697 static void
10698 decompose_foreach (MonoInst *tree, gpointer data) 
10699 {
10700         static MonoJitICallInfo *newarr_info = NULL;
10701         static MonoJitICallInfo *newarr_specific_info = NULL;
10702         MonoJitICallInfo *info;
10703         int i;
10704
10705         switch (tree->opcode) {
10706         case CEE_NEWARR: {
10707                 MonoCompile *cfg = data;
10708                 MonoInst *iargs [3];
10709
10710                 if (!newarr_info) {
10711                         newarr_info = mono_find_jit_icall_by_addr (mono_array_new);
10712                         g_assert (newarr_info);
10713                         newarr_specific_info = mono_find_jit_icall_by_addr (mono_array_new_specific);
10714                         g_assert (newarr_specific_info);
10715                 }
10716
10717                 if (cfg->opt & MONO_OPT_SHARED) {
10718                         NEW_DOMAINCONST (cfg, iargs [0]);
10719                         NEW_CLASSCONST (cfg, iargs [1], tree->inst_newa_class);
10720                         iargs [2] = tree->inst_newa_len;
10721
10722                         info = newarr_info;
10723                 }
10724                 else {
10725                         MonoVTable *vtable = mono_class_vtable (cfg->domain, mono_array_class_get (tree->inst_newa_class, 1));
10726
10727                         g_assert (vtable);
10728                         NEW_VTABLECONST (cfg, iargs [0], vtable);
10729                         iargs [1] = tree->inst_newa_len;
10730
10731                         info = newarr_specific_info;
10732                 }
10733
10734                 mono_emulate_opcode (cfg, tree, iargs, info);
10735
10736                 /* Need to decompose arguments after the the opcode is decomposed */
10737                 for (i = 0; i < info->sig->param_count; ++i)
10738                         dec_foreach (iargs [i], cfg);
10739                 break;
10740         }
10741 #ifdef MONO_ARCH_SOFT_FLOAT
10742         case OP_FBEQ:
10743         case OP_FBGE:
10744         case OP_FBGT:
10745         case OP_FBLE:
10746         case OP_FBLT:
10747         case OP_FBNE_UN:
10748         case OP_FBGE_UN:
10749         case OP_FBGT_UN:
10750         case OP_FBLE_UN:
10751         case OP_FBLT_UN: {
10752                 if ((info = mono_find_jit_opcode_emulation (tree->opcode))) {
10753                         MonoCompile *cfg = data;
10754                         MonoInst *iargs [2];
10755                 
10756                         iargs [0] = tree->inst_i0;
10757                         iargs [1] = tree->inst_i1;
10758                 
10759                         mono_emulate_opcode (cfg, tree, iargs, info);
10760
10761                         dec_foreach (iargs [0], cfg);
10762                         dec_foreach (iargs [1], cfg);
10763                         break;
10764                 } else {
10765                         g_assert_not_reached ();
10766                 }
10767                 break;
10768         }
10769         case OP_FCEQ:
10770         case OP_FCGT:
10771         case OP_FCGT_UN:
10772         case OP_FCLT:
10773         case OP_FCLT_UN: {
10774                 if ((info = mono_find_jit_opcode_emulation (tree->opcode))) {
10775                         MonoCompile *cfg = data;
10776                         MonoInst *iargs [2];
10777
10778                         /* the args are in the compare opcode ... */
10779                         iargs [0] = tree->inst_i0;
10780                         iargs [1] = tree->inst_i1;
10781                 
10782                         mono_emulate_opcode (cfg, tree, iargs, info);
10783
10784                         dec_foreach (iargs [0], cfg);
10785                         dec_foreach (iargs [1], cfg);
10786                         break;
10787                 } else {
10788                         g_assert_not_reached ();
10789                 }
10790                 break;
10791         }
10792 #endif
10793
10794         default:
10795                 break;
10796         }
10797 }
10798
10799 void
10800 mono_inst_foreach (MonoInst *tree, MonoInstFunc func, gpointer data) {
10801
10802         switch (mono_burg_arity [tree->opcode]) {
10803         case 0: break;
10804         case 1: 
10805                 mono_inst_foreach (tree->inst_left, func, data);
10806                 break;
10807         case 2: 
10808                 mono_inst_foreach (tree->inst_left, func, data);
10809                 mono_inst_foreach (tree->inst_right, func, data);
10810                 break;
10811         default:
10812                 g_assert_not_reached ();
10813         }
10814         func (tree, data);
10815 }
10816
10817 G_GNUC_UNUSED
10818 static void
10819 mono_print_bb_code (MonoBasicBlock *bb)
10820 {
10821         MonoInst *c;
10822
10823         MONO_BB_FOR_EACH_INS (bb, c) {
10824                 mono_print_tree (c);
10825                 g_print ("\n");
10826         }
10827 }
10828
10829 static void
10830 print_dfn (MonoCompile *cfg) {
10831         int i, j;
10832         char *code;
10833         MonoBasicBlock *bb;
10834         MonoInst *c;
10835
10836         g_print ("IR code for method %s\n", mono_method_full_name (cfg->method, TRUE));
10837
10838         for (i = 0; i < cfg->num_bblocks; ++i) {
10839                 bb = cfg->bblocks [i];
10840                 /*if (bb->cil_code) {
10841                         char* code1, *code2;
10842                         code1 = mono_disasm_code_one (NULL, cfg->method, bb->cil_code, NULL);
10843                         if (bb->last_ins->cil_code)
10844                                 code2 = mono_disasm_code_one (NULL, cfg->method, bb->last_ins->cil_code, NULL);
10845                         else
10846                                 code2 = g_strdup ("");
10847
10848                         code1 [strlen (code1) - 1] = 0;
10849                         code = g_strdup_printf ("%s -> %s", code1, code2);
10850                         g_free (code1);
10851                         g_free (code2);
10852                 } else*/
10853                         code = g_strdup ("\n");
10854                 g_print ("\nBB%d (%d) (len: %d): %s", bb->block_num, i, bb->cil_length, code);
10855                 MONO_BB_FOR_EACH_INS (bb, c) {
10856                         if (cfg->new_ir) {
10857                                 mono_print_ins_index (-1, c);
10858                         } else {
10859                                 mono_print_tree (c);
10860                                 g_print ("\n");
10861                         }
10862                 }
10863
10864                 g_print ("\tprev:");
10865                 for (j = 0; j < bb->in_count; ++j) {
10866                         g_print (" BB%d", bb->in_bb [j]->block_num);
10867                 }
10868                 g_print ("\t\tsucc:");
10869                 for (j = 0; j < bb->out_count; ++j) {
10870                         g_print (" BB%d", bb->out_bb [j]->block_num);
10871                 }
10872                 g_print ("\n\tidom: BB%d\n", bb->idom? bb->idom->block_num: -1);
10873
10874                 if (bb->idom)
10875                         g_assert (mono_bitset_test_fast (bb->dominators, bb->idom->dfn));
10876
10877                 if (bb->dominators)
10878                         mono_blockset_print (cfg, bb->dominators, "\tdominators", bb->idom? bb->idom->dfn: -1);
10879                 if (bb->dfrontier)
10880                         mono_blockset_print (cfg, bb->dfrontier, "\tdfrontier", -1);
10881                 g_free (code);
10882         }
10883
10884         g_print ("\n");
10885 }
10886
10887 void
10888 mono_bblock_add_inst (MonoBasicBlock *bb, MonoInst *inst)
10889 {
10890         MONO_ADD_INS (bb, inst);
10891 }
10892
10893 void
10894 mono_bblock_insert_after_ins (MonoBasicBlock *bb, MonoInst *ins, MonoInst *ins_to_insert)
10895 {
10896         if (ins == NULL) {
10897                 ins = bb->code;
10898                 bb->code = ins_to_insert;
10899
10900                 /* Link with next */
10901                 ins_to_insert->next = ins;
10902                 if (ins)
10903                         ins->prev = ins_to_insert;
10904
10905                 if (bb->last_ins == NULL)
10906                         bb->last_ins = ins_to_insert;
10907         } else {
10908                 /* Link with next */
10909                 ins_to_insert->next = ins->next;
10910                 if (ins->next)
10911                         ins->next->prev = ins_to_insert;
10912
10913                 /* Link with previous */
10914                 ins->next = ins_to_insert;
10915                 ins_to_insert->prev = ins;
10916
10917                 if (bb->last_ins == ins)
10918                         bb->last_ins = ins_to_insert;
10919         }
10920 }
10921
10922 void
10923 mono_bblock_insert_before_ins (MonoBasicBlock *bb, MonoInst *ins, MonoInst *ins_to_insert)
10924 {
10925         if (ins == NULL) {
10926                 NOT_IMPLEMENTED;
10927                 ins = bb->code;
10928                 bb->code = ins_to_insert;
10929                 ins_to_insert->next = ins;
10930                 if (bb->last_ins == NULL)
10931                         bb->last_ins = ins_to_insert;
10932         } else {
10933                 /* Link with previous */
10934                 if (ins->prev)
10935                         ins->prev->next = ins_to_insert;
10936                 ins_to_insert->prev = ins->prev;
10937
10938                 /* Link with next */
10939                 ins->prev = ins_to_insert;
10940                 ins_to_insert->next = ins;
10941
10942                 if (bb->code == ins)
10943                         bb->code = ins_to_insert;
10944         }
10945 }
10946
10947 /*
10948  * mono_verify_bblock:
10949  *
10950  *   Verify that the next and prev pointers are consistent inside the instructions in BB.
10951  */
10952 void
10953 mono_verify_bblock (MonoBasicBlock *bb)
10954 {
10955         MonoInst *ins, *prev;
10956
10957         prev = NULL;
10958         for (ins = bb->code; ins; ins = ins->next) {
10959                 g_assert (ins->prev == prev);
10960                 prev = ins;
10961         }
10962         if (bb->last_ins)
10963                 g_assert (!bb->last_ins->next);
10964 }
10965
10966 /*
10967  * mono_verify_cfg:
10968  *
10969  *   Perform consistency checks on the JIT data structures and the IR
10970  */
10971 void
10972 mono_verify_cfg (MonoCompile *cfg)
10973 {
10974         MonoBasicBlock *bb;
10975
10976         for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
10977                 mono_verify_bblock (bb);
10978 }
10979
10980 void
10981 mono_destroy_compile (MonoCompile *cfg)
10982 {
10983         //mono_mempool_stats (cfg->mempool);
10984         mono_free_loop_info (cfg);
10985         if (cfg->rs)
10986                 mono_regstate_free (cfg->rs);
10987         if (cfg->spvars)
10988                 g_hash_table_destroy (cfg->spvars);
10989         if (cfg->exvars)
10990                 g_hash_table_destroy (cfg->exvars);
10991         mono_mempool_destroy (cfg->mempool);
10992         g_list_free (cfg->ldstr_list);
10993         g_hash_table_destroy (cfg->token_info_hash);
10994
10995         g_free (cfg->reverse_inst_list);
10996
10997         g_free (cfg->varinfo);
10998         g_free (cfg->vars);
10999         g_free (cfg->exception_message);
11000         g_free (cfg);
11001 }
11002
11003 #ifdef HAVE_KW_THREAD
11004 static __thread gpointer mono_lmf_addr MONO_TLS_FAST;
11005 #ifdef MONO_ARCH_ENABLE_MONO_LMF_VAR
11006 /* 
11007  * When this is defined, the current lmf is stored in this tls variable instead of in 
11008  * jit_tls->lmf.
11009  */
11010 static __thread gpointer mono_lmf MONO_TLS_FAST;
11011 #endif
11012 #endif
11013
11014 guint32
11015 mono_get_jit_tls_key (void)
11016 {
11017         return mono_jit_tls_id;
11018 }
11019
11020 gint32
11021 mono_get_jit_tls_offset (void)
11022 {
11023 #ifdef HAVE_KW_THREAD
11024         int offset;
11025         MONO_THREAD_VAR_OFFSET (mono_jit_tls, offset);
11026         return offset;
11027 #else
11028         return -1;
11029 #endif
11030 }
11031
11032 gint32
11033 mono_get_lmf_tls_offset (void)
11034 {
11035 #if defined(HAVE_KW_THREAD) && defined(MONO_ARCH_ENABLE_MONO_LMF_VAR)
11036         int offset;
11037         MONO_THREAD_VAR_OFFSET(mono_lmf,offset);
11038         return offset;
11039 #else
11040         return -1;
11041 #endif
11042 }
11043
11044 gint32
11045 mono_get_lmf_addr_tls_offset (void)
11046 {
11047         int offset;
11048         MONO_THREAD_VAR_OFFSET(mono_lmf_addr,offset);
11049         return offset;
11050 }
11051
11052 MonoLMF *
11053 mono_get_lmf (void)
11054 {
11055 #if defined(HAVE_KW_THREAD) && defined(MONO_ARCH_ENABLE_MONO_LMF_VAR)
11056         return mono_lmf;
11057 #else
11058         MonoJitTlsData *jit_tls;
11059
11060         if ((jit_tls = TlsGetValue (mono_jit_tls_id)))
11061                 return jit_tls->lmf;
11062
11063         g_assert_not_reached ();
11064         return NULL;
11065 #endif
11066 }
11067
11068 MonoLMF **
11069 mono_get_lmf_addr (void)
11070 {
11071 #ifdef HAVE_KW_THREAD
11072         return mono_lmf_addr;
11073 #else
11074         MonoJitTlsData *jit_tls;
11075
11076         if ((jit_tls = TlsGetValue (mono_jit_tls_id)))
11077                 return &jit_tls->lmf;
11078
11079         g_assert_not_reached ();
11080         return NULL;
11081 #endif
11082 }
11083
11084 /* Called by native->managed wrappers */
11085 void
11086 mono_jit_thread_attach (MonoDomain *domain)
11087 {
11088 #ifdef HAVE_KW_THREAD
11089         if (!mono_lmf_addr) {
11090                 mono_thread_attach (domain);
11091         }
11092 #else
11093         if (!TlsGetValue (mono_jit_tls_id))
11094                 mono_thread_attach (domain);
11095 #endif
11096         if (mono_domain_get () != domain)
11097                 mono_domain_set (domain, TRUE);
11098 }       
11099
11100 /**
11101  * mono_thread_abort:
11102  * @obj: exception object
11103  *
11104  * abort the thread, print exception information and stack trace
11105  */
11106 static void
11107 mono_thread_abort (MonoObject *obj)
11108 {
11109         /* MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id); */
11110         
11111         /* handle_remove should be eventually called for this thread, too
11112         g_free (jit_tls);*/
11113
11114         if ((mono_runtime_unhandled_exception_policy_get () == MONO_UNHANLED_POLICY_LEGACY) ||
11115                         (obj->vtable->klass == mono_defaults.threadabortexception_class)) {
11116                 mono_thread_exit ();
11117         } else {
11118                 exit (mono_environment_exitcode_get ());
11119         }
11120 }
11121
11122 static void*
11123 setup_jit_tls_data (gpointer stack_start, gpointer abort_func)
11124 {
11125         MonoJitTlsData *jit_tls;
11126         MonoLMF *lmf;
11127
11128         jit_tls = TlsGetValue (mono_jit_tls_id);
11129         if (jit_tls)
11130                 return jit_tls;
11131
11132         jit_tls = g_new0 (MonoJitTlsData, 1);
11133
11134         TlsSetValue (mono_jit_tls_id, jit_tls);
11135
11136 #ifdef HAVE_KW_THREAD
11137         mono_jit_tls = jit_tls;
11138 #endif
11139
11140         jit_tls->abort_func = abort_func;
11141         jit_tls->end_of_stack = stack_start;
11142
11143         lmf = g_new0 (MonoLMF, 1);
11144 #ifdef MONO_ARCH_INIT_TOP_LMF_ENTRY
11145         MONO_ARCH_INIT_TOP_LMF_ENTRY (lmf);
11146 #else
11147         lmf->ebp = -1;
11148 #endif
11149
11150         jit_tls->first_lmf = lmf;
11151
11152 #if defined(HAVE_KW_THREAD) && defined(MONO_ARCH_ENABLE_MONO_LMF_VAR)
11153         /* jit_tls->lmf is unused */
11154         mono_lmf = lmf;
11155         mono_lmf_addr = &mono_lmf;
11156 #else
11157 #if defined(HAVE_KW_THREAD)
11158         mono_lmf_addr = &jit_tls->lmf;  
11159 #endif
11160
11161         jit_tls->lmf = lmf;
11162 #endif
11163
11164         mono_arch_setup_jit_tls_data (jit_tls);
11165         mono_setup_altstack (jit_tls);
11166
11167         return jit_tls;
11168 }
11169
11170 static void
11171 mono_thread_start_cb (gsize tid, gpointer stack_start, gpointer func)
11172 {
11173         MonoThread *thread;
11174         void *jit_tls = setup_jit_tls_data (stack_start, mono_thread_abort);
11175         thread = mono_thread_current ();
11176         mono_debugger_thread_created (tid, thread, jit_tls);
11177         if (thread)
11178                 thread->jit_data = jit_tls;
11179 }
11180
11181 void (*mono_thread_attach_aborted_cb ) (MonoObject *obj) = NULL;
11182
11183 static void
11184 mono_thread_abort_dummy (MonoObject *obj)
11185 {
11186   if (mono_thread_attach_aborted_cb)
11187     mono_thread_attach_aborted_cb (obj);
11188   else
11189     mono_thread_abort (obj);
11190 }
11191
11192 static void
11193 mono_thread_attach_cb (gsize tid, gpointer stack_start)
11194 {
11195         MonoThread *thread;
11196         void *jit_tls = setup_jit_tls_data (stack_start, mono_thread_abort_dummy);
11197         thread = mono_thread_current ();
11198         mono_debugger_thread_created (tid, thread, (MonoJitTlsData *) jit_tls);
11199         if (thread)
11200                 thread->jit_data = jit_tls;
11201         if (mono_profiler_get_events () & MONO_PROFILE_STATISTICAL)
11202                 setup_stat_profiler ();
11203 }
11204
11205 static void
11206 mini_thread_cleanup (MonoThread *thread)
11207 {
11208         MonoJitTlsData *jit_tls = thread->jit_data;
11209
11210         if (jit_tls) {
11211                 mono_debugger_thread_cleanup (jit_tls);
11212                 mono_arch_free_jit_tls_data (jit_tls);
11213
11214                 mono_free_altstack (jit_tls);
11215                 g_free (jit_tls->first_lmf);
11216                 g_free (jit_tls);
11217                 thread->jit_data = NULL;
11218                 TlsSetValue (mono_jit_tls_id, NULL);
11219         }
11220 }
11221
11222 static MonoInst*
11223 mono_create_tls_get (MonoCompile *cfg, int offset)
11224 {
11225 #ifdef MONO_ARCH_HAVE_TLS_GET
11226         MonoInst* ins;
11227         
11228         if (offset == -1)
11229                 return NULL;
11230         
11231         MONO_INST_NEW (cfg, ins, OP_TLS_GET);
11232         ins->dreg = mono_regstate_next_int (cfg->rs);
11233         ins->inst_offset = offset;
11234         return ins;
11235 #else
11236         return NULL;
11237 #endif
11238 }
11239
11240 MonoInst*
11241 mono_get_jit_tls_intrinsic (MonoCompile *cfg)
11242 {
11243         return mono_create_tls_get (cfg, mono_get_jit_tls_offset ());
11244 }
11245
11246 void
11247 mono_add_patch_info (MonoCompile *cfg, int ip, MonoJumpInfoType type, gconstpointer target)
11248 {
11249         MonoJumpInfo *ji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo));
11250
11251         ji->ip.i = ip;
11252         ji->type = type;
11253         ji->data.target = target;
11254         ji->next = cfg->patch_info;
11255
11256         cfg->patch_info = ji;
11257 }
11258
11259 MonoJumpInfo *
11260 mono_patch_info_list_prepend (MonoJumpInfo *list, int ip, MonoJumpInfoType type, gconstpointer target)
11261 {
11262         MonoJumpInfo *ji = g_new0 (MonoJumpInfo, 1);
11263
11264         ji->ip.i = ip;
11265         ji->type = type;
11266         ji->data.target = target;
11267         ji->next = list;
11268
11269         return ji;
11270 }
11271
11272 void
11273 mono_remove_patch_info (MonoCompile *cfg, int ip)
11274 {
11275         MonoJumpInfo **ji = &cfg->patch_info;
11276
11277         while (*ji) {
11278                 if ((*ji)->ip.i == ip)
11279                         *ji = (*ji)->next;
11280                 else
11281                         ji = &((*ji)->next);
11282         }
11283 }
11284
11285 /**
11286  * mono_patch_info_dup_mp:
11287  *
11288  * Make a copy of PATCH_INFO, allocating memory from the mempool MP.
11289  */
11290 MonoJumpInfo*
11291 mono_patch_info_dup_mp (MonoMemPool *mp, MonoJumpInfo *patch_info)
11292 {
11293         MonoJumpInfo *res = mono_mempool_alloc (mp, sizeof (MonoJumpInfo));
11294         memcpy (res, patch_info, sizeof (MonoJumpInfo));
11295
11296         switch (patch_info->type) {
11297         case MONO_PATCH_INFO_RVA:
11298         case MONO_PATCH_INFO_LDSTR:
11299         case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
11300         case MONO_PATCH_INFO_LDTOKEN:
11301         case MONO_PATCH_INFO_DECLSEC:
11302                 res->data.token = mono_mempool_alloc (mp, sizeof (MonoJumpInfoToken));
11303                 memcpy (res->data.token, patch_info->data.token, sizeof (MonoJumpInfoToken));
11304                 break;
11305         case MONO_PATCH_INFO_SWITCH:
11306                 res->data.table = mono_mempool_alloc (mp, sizeof (MonoJumpInfoBBTable));
11307                 memcpy (res->data.table, patch_info->data.table, sizeof (MonoJumpInfoBBTable));
11308                 break;
11309         default:
11310                 break;
11311         }
11312
11313         return res;
11314 }
11315
11316 guint
11317 mono_patch_info_hash (gconstpointer data)
11318 {
11319         const MonoJumpInfo *ji = (MonoJumpInfo*)data;
11320
11321         switch (ji->type) {
11322         case MONO_PATCH_INFO_RVA:
11323         case MONO_PATCH_INFO_LDSTR:
11324         case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
11325         case MONO_PATCH_INFO_LDTOKEN:
11326         case MONO_PATCH_INFO_DECLSEC:
11327                 return (ji->type << 8) | ji->data.token->token;
11328         case MONO_PATCH_INFO_VTABLE:
11329         case MONO_PATCH_INFO_CLASS:
11330         case MONO_PATCH_INFO_IID:
11331         case MONO_PATCH_INFO_ADJUSTED_IID:
11332                 return (ji->type << 8) | (gssize)ji->data.klass;
11333         case MONO_PATCH_INFO_FIELD:
11334         case MONO_PATCH_INFO_SFLDA:
11335                 return (ji->type << 8) | (gssize)ji->data.field;
11336         case MONO_PATCH_INFO_METHODCONST:
11337         case MONO_PATCH_INFO_METHOD:
11338         case MONO_PATCH_INFO_METHOD_JUMP:
11339                 return (ji->type << 8) | (gssize)ji->data.method;
11340         case MONO_PATCH_INFO_IMAGE:
11341                 return (ji->type << 8) | (gssize)ji->data.image;                
11342         default:
11343                 return (ji->type << 8);
11344         }
11345 }
11346
11347 /* 
11348  * mono_patch_info_equal:
11349  * 
11350  * This might fail to recognize equivalent patches, i.e. floats, so its only
11351  * usable in those cases where this is not a problem, i.e. sharing GOT slots
11352  * in AOT.
11353  */
11354 gint
11355 mono_patch_info_equal (gconstpointer ka, gconstpointer kb)
11356 {
11357         const MonoJumpInfo *ji1 = (MonoJumpInfo*)ka;
11358         const MonoJumpInfo *ji2 = (MonoJumpInfo*)kb;
11359
11360         if (ji1->type != ji2->type)
11361                 return 0;
11362
11363         switch (ji1->type) {
11364         case MONO_PATCH_INFO_RVA:
11365         case MONO_PATCH_INFO_LDSTR:
11366         case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
11367         case MONO_PATCH_INFO_LDTOKEN:
11368         case MONO_PATCH_INFO_DECLSEC:
11369                 if ((ji1->data.token->image != ji2->data.token->image) ||
11370                         (ji1->data.token->token != ji2->data.token->token))
11371                         return 0;
11372                 break;
11373         default:
11374                 if (ji1->data.name != ji2->data.name)
11375                         return 0;
11376                 break;
11377         }
11378
11379         return 1;
11380 }
11381
11382 gpointer
11383 mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *patch_info, gboolean run_cctors)
11384 {
11385         unsigned char *ip = patch_info->ip.i + code;
11386         gconstpointer target = NULL;
11387
11388         switch (patch_info->type) {
11389         case MONO_PATCH_INFO_BB:
11390                 g_assert (patch_info->data.bb->native_offset);
11391                 target = patch_info->data.bb->native_offset + code;
11392                 break;
11393         case MONO_PATCH_INFO_ABS:
11394                 target = patch_info->data.target;
11395                 break;
11396         case MONO_PATCH_INFO_LABEL:
11397                 target = patch_info->data.inst->inst_c0 + code;
11398                 break;
11399         case MONO_PATCH_INFO_IP:
11400                 target = ip;
11401                 break;
11402         case MONO_PATCH_INFO_METHOD_REL:
11403                 target = code + patch_info->data.offset;
11404                 break;
11405         case MONO_PATCH_INFO_INTERNAL_METHOD: {
11406                 MonoJitICallInfo *mi = mono_find_jit_icall_by_name (patch_info->data.name);
11407                 if (!mi) {
11408                         g_warning ("unknown MONO_PATCH_INFO_INTERNAL_METHOD %s", patch_info->data.name);
11409                         g_assert_not_reached ();
11410                 }
11411                 target = mono_icall_get_wrapper (mi);
11412                 break;
11413         }
11414         case MONO_PATCH_INFO_METHOD_JUMP: {
11415                 GSList *list;
11416
11417                 /* get the trampoline to the method from the domain */
11418                 target = mono_create_jump_trampoline (domain, patch_info->data.method, TRUE);
11419                 if (!domain->jump_target_hash)
11420                         domain->jump_target_hash = g_hash_table_new (NULL, NULL);
11421                 list = g_hash_table_lookup (domain->jump_target_hash, patch_info->data.method);
11422                 list = g_slist_prepend (list, ip);
11423                 g_hash_table_insert (domain->jump_target_hash, patch_info->data.method, list);
11424                 break;
11425         }
11426         case MONO_PATCH_INFO_METHOD:
11427                 if (patch_info->data.method == method) {
11428                         target = code;
11429                 } else {
11430                         /* get the trampoline to the method from the domain */
11431                         if (method && method->wrapper_type == MONO_WRAPPER_STATIC_RGCTX_INVOKE) {
11432                                 target = mono_create_jit_trampoline_in_domain (mono_domain_get (),
11433                                         patch_info->data.method, FALSE);
11434                         } else {
11435                                 target = mono_create_jit_trampoline (patch_info->data.method);
11436                         }
11437                 }
11438                 break;
11439         case MONO_PATCH_INFO_SWITCH: {
11440                 gpointer *jump_table;
11441                 int i;
11442
11443                 if (method && method->dynamic) {
11444                         jump_table = mono_code_manager_reserve (mono_dynamic_code_hash_lookup (domain, method)->code_mp, sizeof (gpointer) * patch_info->data.table->table_size);
11445                 } else {
11446                         mono_domain_lock (domain);
11447                         if (mono_aot_only)
11448                                 jump_table = mono_mempool_alloc (domain->mp, sizeof (gpointer) * patch_info->data.table->table_size);
11449                         else
11450                                 jump_table = mono_code_manager_reserve (domain->code_mp, sizeof (gpointer) * patch_info->data.table->table_size);
11451                         mono_domain_unlock (domain);
11452                 }
11453
11454                 for (i = 0; i < patch_info->data.table->table_size; i++)
11455                         jump_table [i] = code + GPOINTER_TO_INT (patch_info->data.table->table [i]);
11456                 target = jump_table;
11457                 break;
11458         }
11459         case MONO_PATCH_INFO_METHODCONST:
11460         case MONO_PATCH_INFO_CLASS:
11461         case MONO_PATCH_INFO_IMAGE:
11462         case MONO_PATCH_INFO_FIELD:
11463                 target = patch_info->data.target;
11464                 break;
11465         case MONO_PATCH_INFO_IID:
11466                 mono_class_init (patch_info->data.klass);
11467                 target = GINT_TO_POINTER ((int)patch_info->data.klass->interface_id);
11468                 break;
11469         case MONO_PATCH_INFO_ADJUSTED_IID:
11470                 mono_class_init (patch_info->data.klass);
11471                 target = GINT_TO_POINTER ((int)(-((patch_info->data.klass->interface_id + 1) * SIZEOF_VOID_P)));
11472                 break;
11473         case MONO_PATCH_INFO_VTABLE:
11474                 target = mono_class_vtable (domain, patch_info->data.klass);
11475                 g_assert (target);
11476                 break;
11477         case MONO_PATCH_INFO_CLASS_INIT: {
11478                 MonoVTable *vtable = mono_class_vtable (domain, patch_info->data.klass);
11479
11480                 g_assert (vtable);
11481                 target = mono_create_class_init_trampoline (vtable);
11482                 break;
11483         }
11484         case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE:
11485                 target = mono_create_delegate_trampoline (patch_info->data.klass);
11486                 break;
11487         case MONO_PATCH_INFO_SFLDA: {
11488                 MonoVTable *vtable = mono_class_vtable (domain, patch_info->data.field->parent);
11489
11490                 g_assert (vtable);
11491                 if (!vtable->initialized && !(vtable->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) && (method && mono_class_needs_cctor_run (vtable->klass, method)))
11492                         /* Done by the generated code */
11493                         ;
11494                 else {
11495                         if (run_cctors)
11496                                 mono_runtime_class_init (vtable);
11497                 }
11498                 target = (char*)vtable->data + patch_info->data.field->offset;
11499                 break;
11500         }
11501         case MONO_PATCH_INFO_RVA:
11502                 target = mono_image_rva_map (patch_info->data.token->image, patch_info->data.token->token);
11503                 break;
11504         case MONO_PATCH_INFO_R4:
11505         case MONO_PATCH_INFO_R8:
11506                 target = patch_info->data.target;
11507                 break;
11508         case MONO_PATCH_INFO_EXC_NAME:
11509                 target = patch_info->data.name;
11510                 break;
11511         case MONO_PATCH_INFO_LDSTR:
11512                 target =
11513                         mono_ldstr (domain, patch_info->data.token->image, 
11514                                                 mono_metadata_token_index (patch_info->data.token->token));
11515                 break;
11516         case MONO_PATCH_INFO_TYPE_FROM_HANDLE: {
11517                 gpointer handle;
11518                 MonoClass *handle_class;
11519
11520                 handle = mono_ldtoken (patch_info->data.token->image, 
11521                                        patch_info->data.token->token, &handle_class, NULL);
11522                 mono_class_init (handle_class);
11523                 mono_class_init (mono_class_from_mono_type (handle));
11524
11525                 target =
11526                         mono_type_get_object (domain, handle);
11527                 break;
11528         }
11529         case MONO_PATCH_INFO_LDTOKEN: {
11530                 gpointer handle;
11531                 MonoClass *handle_class;
11532                 
11533                 handle = mono_ldtoken (patch_info->data.token->image,
11534                                        patch_info->data.token->token, &handle_class, NULL);
11535                 mono_class_init (handle_class);
11536                 
11537                 target = handle;
11538                 break;
11539         }
11540         case MONO_PATCH_INFO_DECLSEC:
11541                 target = (mono_metadata_blob_heap (patch_info->data.token->image, patch_info->data.token->token) + 2);
11542                 break;
11543         case MONO_PATCH_INFO_ICALL_ADDR:
11544                 target = mono_lookup_internal_call (patch_info->data.method);
11545                 /* run_cctors == 0 -> AOT */
11546                 if (!target && run_cctors)
11547                         g_error ("Unregistered icall '%s'\n", mono_method_full_name (patch_info->data.method, TRUE));
11548                 break;
11549         case MONO_PATCH_INFO_JIT_ICALL_ADDR: {
11550                 MonoJitICallInfo *mi = mono_find_jit_icall_by_name (patch_info->data.name);
11551                 if (!mi) {
11552                         g_warning ("unknown MONO_PATCH_INFO_JIT_ICALL_ADDR %s", patch_info->data.name);
11553                         g_assert_not_reached ();
11554                 }
11555                 target = mi->func;
11556                 break;
11557         }
11558         case MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG:
11559                 target = mono_thread_interruption_request_flag ();
11560                 break;
11561         case MONO_PATCH_INFO_BB_OVF:
11562         case MONO_PATCH_INFO_EXC_OVF:
11563         case MONO_PATCH_INFO_GOT_OFFSET:
11564         case MONO_PATCH_INFO_NONE:
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 nullify_basic_block (MonoBasicBlock *bb) 
11649 {
11650         bb->in_count = 0;
11651         bb->out_count = 0;
11652         bb->in_bb = NULL;
11653         bb->out_bb = NULL;
11654         bb->next_bb = NULL;
11655         bb->code = bb->last_ins = NULL;
11656         bb->cil_code = NULL;
11657 }
11658
11659 static void 
11660 replace_out_block (MonoBasicBlock *bb, MonoBasicBlock *orig,  MonoBasicBlock *repl)
11661 {
11662         int i;
11663
11664         for (i = 0; i < bb->out_count; i++) {
11665                 MonoBasicBlock *ob = bb->out_bb [i];
11666                 if (ob == orig) {
11667                         if (!repl) {
11668                                 if (bb->out_count > 1) {
11669                                         bb->out_bb [i] = bb->out_bb [bb->out_count - 1];
11670                                 }
11671                                 bb->out_count--;
11672                         } else {
11673                                 bb->out_bb [i] = repl;
11674                         }
11675                 }
11676         }
11677 }
11678
11679 static void 
11680 replace_in_block (MonoBasicBlock *bb, MonoBasicBlock *orig, MonoBasicBlock *repl)
11681 {
11682         int i;
11683
11684         for (i = 0; i < bb->in_count; i++) {
11685                 MonoBasicBlock *ib = bb->in_bb [i];
11686                 if (ib == orig) {
11687                         if (!repl) {
11688                                 if (bb->in_count > 1) {
11689                                         bb->in_bb [i] = bb->in_bb [bb->in_count - 1];
11690                                 }
11691                                 bb->in_count--;
11692                         } else {
11693                                 bb->in_bb [i] = repl;
11694                         }
11695                 }
11696         }
11697 }
11698
11699 static void
11700 replace_out_block_in_code (MonoBasicBlock *bb, MonoBasicBlock *orig, MonoBasicBlock *repl) {
11701         MonoInst *ins;
11702         
11703         for (ins = bb->code; ins != NULL; ins = ins->next) {
11704                 switch (ins->opcode) {
11705                 case OP_BR:
11706                         if (ins->inst_target_bb == orig)
11707                                 ins->inst_target_bb = repl;
11708                         break;
11709                 case OP_CALL_HANDLER:
11710                         if (ins->inst_target_bb == orig)
11711                                 ins->inst_target_bb = repl;
11712                         break;
11713                 case OP_SWITCH: {
11714                         int i;
11715                         int n = GPOINTER_TO_INT (ins->klass);
11716                         for (i = 0; i < n; i++ ) {
11717                                 if (ins->inst_many_bb [i] == orig)
11718                                         ins->inst_many_bb [i] = repl;
11719                         }
11720                         break;
11721                 }
11722                 default:
11723                         if (MONO_IS_COND_BRANCH_OP (ins)) {
11724                                 if (ins->inst_true_bb == orig)
11725                                         ins->inst_true_bb = repl;
11726                                 if (ins->inst_false_bb == orig)
11727                                         ins->inst_false_bb = repl;
11728                         } else if (MONO_IS_JUMP_TABLE (ins)) {
11729                                 int i;
11730                                 MonoJumpInfoBBTable *table = MONO_JUMP_TABLE_FROM_INS (ins);
11731                                 for (i = 0; i < table->table_size; i++ ) {
11732                                         if (table->table [i] == orig)
11733                                                 table->table [i] = repl;
11734                                 }
11735                         }
11736
11737                         break;
11738                 }
11739         }
11740 }
11741
11742 /**
11743   * Check if a bb is useless (is just made of NOPs and ends with an
11744   * unconditional branch, or nothing).
11745   * If it is so, unlink it from the CFG and nullify it, and return TRUE.
11746   * Otherwise, return FALSE;
11747   */
11748 static gboolean
11749 remove_block_if_useless (MonoCompile *cfg, MonoBasicBlock *bb, MonoBasicBlock *previous_bb) {
11750         MonoBasicBlock *target_bb = NULL;
11751         MonoInst *inst;
11752
11753         /* Do not touch handlers */
11754         if (bb->region != -1) {
11755                 bb->not_useless = TRUE;
11756                 return FALSE;
11757         }
11758         
11759         MONO_BB_FOR_EACH_INS (bb, inst) {
11760                 switch (inst->opcode) {
11761                 case OP_NOP:
11762                         break;
11763                 case OP_BR:
11764                         target_bb = inst->inst_target_bb;
11765                         break;
11766                 default:
11767                         bb->not_useless = TRUE;
11768                         return FALSE;
11769                 }
11770         }
11771         
11772         if (target_bb == NULL) {
11773                 if ((bb->out_count == 1) && (bb->out_bb [0] == bb->next_bb)) {
11774                         target_bb = bb->next_bb;
11775                 } else {
11776                         /* Do not touch empty BBs that do not "fall through" to their next BB (like the exit BB) */
11777                         return FALSE;
11778                 }
11779         }
11780         
11781         /* Do not touch BBs following a switch (they are the "default" branch) */
11782         if ((previous_bb->last_ins != NULL) && (previous_bb->last_ins->opcode == OP_SWITCH)) {
11783                 return FALSE;
11784         }
11785         
11786         /* Do not touch BBs following the entry BB and jumping to something that is not */
11787         /* thiry "next" bb (the entry BB cannot contain the branch) */
11788         if ((previous_bb == cfg->bb_entry) && (bb->next_bb != target_bb)) {
11789                 return FALSE;
11790         }
11791
11792         /* 
11793          * Do not touch BBs following a try block as the code in 
11794          * mini_method_compile needs them to compute the length of the try block.
11795          */
11796         if (MONO_BBLOCK_IS_IN_REGION (previous_bb, MONO_REGION_TRY))
11797                 return FALSE;
11798         
11799         /* Check that there is a target BB, and that bb is not an empty loop (Bug 75061) */
11800         if ((target_bb != NULL) && (target_bb != bb)) {
11801                 int i;
11802
11803                 if (cfg->verbose_level > 1) {
11804                         printf ("remove_block_if_useless, removed BB%d\n", bb->block_num);
11805                 }
11806                 
11807                 /* unlink_bblock () modifies the bb->in_bb array so can't use a for loop here */
11808                 while (bb->in_count) {
11809                         MonoBasicBlock *in_bb = bb->in_bb [0];
11810                         mono_unlink_bblock (cfg, in_bb, bb);
11811                         link_bblock (cfg, in_bb, target_bb);
11812                         replace_out_block_in_code (in_bb, bb, target_bb);
11813                 }
11814                 
11815                 mono_unlink_bblock (cfg, bb, target_bb);
11816                 
11817                 if ((previous_bb != cfg->bb_entry) &&
11818                                 (previous_bb->region == bb->region) &&
11819                                 ((previous_bb->last_ins == NULL) ||
11820                                 ((previous_bb->last_ins->opcode != OP_BR) &&
11821                                 (! (MONO_IS_COND_BRANCH_OP (previous_bb->last_ins))) &&
11822                                 (previous_bb->last_ins->opcode != OP_SWITCH)))) {
11823                         for (i = 0; i < previous_bb->out_count; i++) {
11824                                 if (previous_bb->out_bb [i] == target_bb) {
11825                                         MonoInst *jump;
11826                                         MONO_INST_NEW (cfg, jump, OP_BR);
11827                                         MONO_ADD_INS (previous_bb, jump);
11828                                         jump->cil_code = previous_bb->cil_code;
11829                                         jump->inst_target_bb = target_bb;
11830                                         break;
11831                                 }
11832                         }
11833                 }
11834                 
11835                 previous_bb->next_bb = bb->next_bb;
11836                 nullify_basic_block (bb);
11837                 
11838                 return TRUE;
11839         } else {
11840                 return FALSE;
11841         }
11842 }
11843
11844 void
11845 mono_merge_basic_blocks (MonoCompile *cfg, MonoBasicBlock *bb, MonoBasicBlock *bbn) 
11846 {
11847         MonoInst *inst;
11848         MonoBasicBlock *prev_bb;
11849         int i;
11850
11851         bb->has_array_access |= bbn->has_array_access;
11852         bb->extended |= bbn->extended;
11853
11854         mono_unlink_bblock (cfg, bb, bbn);
11855         for (i = 0; i < bbn->out_count; ++i)
11856                 mono_link_bblock (cfg, bb, bbn->out_bb [i]);
11857         while (bbn->out_count)
11858                 mono_unlink_bblock (cfg, bbn, bbn->out_bb [0]);
11859
11860         /* Handle the branch at the end of the bb */
11861         for (inst = bb->code; inst != NULL; inst = inst->next) {
11862                 if (inst->opcode == OP_CALL_HANDLER) {
11863                         g_assert (inst->inst_target_bb == bbn);
11864                         NULLIFY_INS (inst);
11865                 }
11866                 if (MONO_IS_JUMP_TABLE (inst)) {
11867                         int i;
11868                         MonoJumpInfoBBTable *table = MONO_JUMP_TABLE_FROM_INS (inst);
11869                         for (i = 0; i < table->table_size; i++ ) {
11870                                 /* Might be already NULL from a previous merge */
11871                                 if (table->table [i])
11872                                         g_assert (table->table [i] == bbn);
11873                                 table->table [i] = NULL;
11874                         }
11875                         /* Can't nullify this as later instructions depend on it */
11876                 }
11877         }
11878         if (bb->last_ins && MONO_IS_COND_BRANCH_OP (bb->last_ins)) {
11879                 g_assert (bb->last_ins->inst_false_bb == bbn);
11880                 bb->last_ins->inst_false_bb = NULL;
11881                 bb->extended = TRUE;
11882         } else if (bb->last_ins && MONO_IS_BRANCH_OP (bb->last_ins)) {
11883                 NULLIFY_INS (bb->last_ins);
11884         }
11885
11886         if (bb->last_ins) {
11887                 if (bbn->code) {
11888                         bb->last_ins->next = bbn->code;
11889                         bbn->code->prev = bb->last_ins;
11890                         bb->last_ins = bbn->last_ins;
11891                 }
11892         } else {
11893                 bb->code = bbn->code;
11894                 bb->last_ins = bbn->last_ins;
11895         }
11896         for (prev_bb = cfg->bb_entry; prev_bb && prev_bb->next_bb != bbn; prev_bb = prev_bb->next_bb)
11897                 ;
11898         if (prev_bb) {
11899                 prev_bb->next_bb = bbn->next_bb;
11900         } else {
11901                 /* bbn might not be in the bb list yet */
11902                 if (bb->next_bb == bbn)
11903                         bb->next_bb = bbn->next_bb;
11904         }
11905         nullify_basic_block (bbn);
11906 }
11907
11908 static void
11909 move_basic_block_to_end (MonoCompile *cfg, MonoBasicBlock *bb)
11910 {
11911         MonoBasicBlock *bbn, *next;
11912
11913         next = bb->next_bb;
11914
11915         /* Find the previous */
11916         for (bbn = cfg->bb_entry; bbn->next_bb && bbn->next_bb != bb; bbn = bbn->next_bb)
11917                 ;
11918         if (bbn->next_bb) {
11919                 bbn->next_bb = bb->next_bb;
11920         }
11921
11922         /* Find the last */
11923         for (bbn = cfg->bb_entry; bbn->next_bb; bbn = bbn->next_bb)
11924                 ;
11925         bbn->next_bb = bb;
11926         bb->next_bb = NULL;
11927
11928         /* Add a branch */
11929         if (next && (!bb->last_ins || ((bb->last_ins->opcode != OP_NOT_REACHED) && (bb->last_ins->opcode != OP_BR) && (bb->last_ins->opcode != OP_BR_REG) && (!MONO_IS_COND_BRANCH_OP (bb->last_ins))))) {
11930                 MonoInst *ins;
11931
11932                 MONO_INST_NEW (cfg, ins, OP_BR);
11933                 MONO_ADD_INS (bb, ins);
11934                 link_bblock (cfg, bb, next);
11935                 ins->inst_target_bb = next;
11936         }               
11937 }
11938
11939 /*
11940  * mono_remove_block:
11941  *
11942  *   Remove BB from the control flow graph
11943  */
11944 void
11945 mono_remove_bblock (MonoCompile *cfg, MonoBasicBlock *bb) 
11946 {
11947         MonoBasicBlock *tmp_bb;
11948
11949         for (tmp_bb = cfg->bb_entry; tmp_bb && tmp_bb->next_bb != bb; tmp_bb = tmp_bb->next_bb)
11950                 ;
11951
11952         g_assert (tmp_bb);
11953         tmp_bb->next_bb = bb->next_bb;
11954 }
11955
11956 /* checks that a and b represent the same instructions, conservatively,
11957  * it can return FALSE also for two trees that are equal.
11958  * FIXME: also make sure there are no side effects.
11959  */
11960 static int
11961 same_trees (MonoInst *a, MonoInst *b)
11962 {
11963         int arity;
11964         if (a->opcode != b->opcode)
11965                 return FALSE;
11966         arity = mono_burg_arity [a->opcode];
11967         if (arity == 1) {
11968                 if (a->ssa_op == b->ssa_op && a->ssa_op == MONO_SSA_LOAD && a->inst_i0 == b->inst_i0)
11969                         return TRUE;
11970                 return same_trees (a->inst_left, b->inst_left);
11971         } else if (arity == 2) {
11972                 return same_trees (a->inst_left, b->inst_left) && same_trees (a->inst_right, b->inst_right);
11973         } else if (arity == 0) {
11974                 switch (a->opcode) {
11975                 case OP_ICONST:
11976                         return a->inst_c0 == b->inst_c0;
11977                 default:
11978                         return FALSE;
11979                 }
11980         }
11981         return FALSE;
11982 }
11983
11984 static int
11985 get_unsigned_condbranch (int opcode)
11986 {
11987         switch (opcode) {
11988         case CEE_BLE: return CEE_BLE_UN;
11989         case CEE_BLT: return CEE_BLT_UN;
11990         case CEE_BGE: return CEE_BGE_UN;
11991         case CEE_BGT: return CEE_BGT_UN;
11992         }
11993         g_assert_not_reached ();
11994         return 0;
11995 }
11996
11997 static int
11998 tree_is_unsigned (MonoInst* ins) {
11999         switch (ins->opcode) {
12000         case OP_ICONST:
12001                 return (int)ins->inst_c0 >= 0;
12002         /* array lengths are positive as are string sizes */
12003         case CEE_LDLEN:
12004         case OP_STRLEN:
12005                 return TRUE;
12006         case CEE_CONV_U1:
12007         case CEE_CONV_U2:
12008         case CEE_CONV_U4:
12009         case CEE_CONV_OVF_U1:
12010         case CEE_CONV_OVF_U2:
12011         case CEE_CONV_OVF_U4:
12012                 return TRUE;
12013         case CEE_LDIND_U1:
12014         case CEE_LDIND_U2:
12015         case CEE_LDIND_U4:
12016                 return TRUE;
12017         default:
12018                 return FALSE;
12019         }
12020 }
12021
12022 /* check if an unsigned compare can be used instead of two signed compares
12023  * for (val < 0 || val > limit) conditionals.
12024  * Returns TRUE if the optimization has been applied.
12025  * Note that this can't be applied if the second arg is not positive...
12026  */
12027 static int
12028 try_unsigned_compare (MonoCompile *cfg, MonoBasicBlock *bb)
12029 {
12030         MonoBasicBlock *truet, *falset;
12031         MonoInst *cmp_inst = bb->last_ins->inst_left;
12032         MonoInst *condb;
12033         if (!cmp_inst->inst_right->inst_c0 == 0)
12034                 return FALSE;
12035         truet = bb->last_ins->inst_true_bb;
12036         falset = bb->last_ins->inst_false_bb;
12037         if (falset->in_count != 1)
12038                 return FALSE;
12039         condb = falset->last_ins;
12040         /* target bb must have one instruction */
12041         if (!condb || (condb != falset->code))
12042                 return FALSE;
12043         if ((((condb->opcode == CEE_BLE || condb->opcode == CEE_BLT) && (condb->inst_false_bb == truet))
12044                         || ((condb->opcode == CEE_BGE || condb->opcode == CEE_BGT) && (condb->inst_true_bb == truet)))
12045                         && same_trees (cmp_inst->inst_left, condb->inst_left->inst_left)) {
12046                 if (!tree_is_unsigned (condb->inst_left->inst_right))
12047                         return FALSE;
12048                 condb->opcode = get_unsigned_condbranch (condb->opcode);
12049                 /* change the original condbranch to just point to the new unsigned check */
12050                 bb->last_ins->opcode = OP_BR;
12051                 bb->last_ins->inst_target_bb = falset;
12052                 replace_out_block (bb, truet, NULL);
12053                 replace_in_block (truet, bb, NULL);
12054                 return TRUE;
12055         }
12056         return FALSE;
12057 }
12058
12059 /*
12060  * Optimizes the branches on the Control Flow Graph
12061  *
12062  */
12063 void
12064 mono_optimize_branches (MonoCompile *cfg)
12065 {
12066         int i, changed = FALSE;
12067         MonoBasicBlock *bb, *bbn;
12068         guint32 niterations;
12069
12070         /*
12071          * Some crazy loops could cause the code below to go into an infinite
12072          * loop, see bug #53003 for an example. To prevent this, we put an upper
12073          * bound on the number of iterations.
12074          */
12075         if (cfg->num_bblocks > 1000)
12076                 niterations = cfg->num_bblocks * 2;
12077         else
12078                 niterations = 1000;
12079         
12080         do {
12081                 MonoBasicBlock *previous_bb;
12082                 changed = FALSE;
12083                 niterations --;
12084
12085                 /* we skip the entry block (exit is handled specially instead ) */
12086                 for (previous_bb = cfg->bb_entry, bb = cfg->bb_entry->next_bb; bb; previous_bb = bb, bb = bb->next_bb) {
12087                         /* dont touch code inside exception clauses */
12088                         if (bb->region != -1)
12089                                 continue;
12090
12091                         if (!bb->not_useless && remove_block_if_useless (cfg, bb, previous_bb)) {
12092                                 changed = TRUE;
12093                                 continue;
12094                         }
12095
12096                         if ((bbn = bb->next_bb) && bbn->in_count == 0 && bb->region == bbn->region) {
12097                                 if (cfg->verbose_level > 2)
12098                                         g_print ("nullify block triggered %d\n", bbn->block_num);
12099
12100                                 bb->next_bb = bbn->next_bb;
12101
12102                                 for (i = 0; i < bbn->out_count; i++)
12103                                         replace_in_block (bbn->out_bb [i], bbn, NULL);
12104
12105                                 nullify_basic_block (bbn);                      
12106                                 changed = TRUE;
12107                         }
12108
12109                         if (bb->out_count == 1) {
12110                                 bbn = bb->out_bb [0];
12111
12112                                 /* conditional branches where true and false targets are the same can be also replaced with OP_BR */
12113                                 if (bb->last_ins && (bb->last_ins->opcode != OP_BR) && MONO_IS_COND_BRANCH_OP (bb->last_ins)) {
12114                                         if (!cfg->new_ir) {
12115                                                 MonoInst *pop;
12116                                                 MONO_INST_NEW (cfg, pop, CEE_POP);
12117                                                 pop->inst_left = bb->last_ins->inst_left->inst_left;
12118                                                 mono_add_ins_to_end (bb, pop);
12119                                                 MONO_INST_NEW (cfg, pop, CEE_POP);
12120                                                 pop->inst_left = bb->last_ins->inst_left->inst_right;
12121                                                 mono_add_ins_to_end (bb, pop);
12122                                         }
12123                                         bb->last_ins->opcode = OP_BR;
12124                                         bb->last_ins->inst_target_bb = bb->last_ins->inst_true_bb;
12125                                         changed = TRUE;
12126                                         if (cfg->verbose_level > 2)
12127                                                 g_print ("cond branch removal triggered in %d %d\n", bb->block_num, bb->out_count);
12128                                 }
12129
12130                                 if (bb->region == bbn->region && bb->next_bb == bbn) {
12131                                         /* the block are in sequence anyway ... */
12132
12133                                         /* branches to the following block can be removed */
12134                                         if (bb->last_ins && bb->last_ins->opcode == OP_BR) {
12135                                                 bb->last_ins->opcode = OP_NOP;
12136                                                 changed = TRUE;
12137                                                 if (cfg->verbose_level > 2)
12138                                                         g_print ("br removal triggered %d -> %d\n", bb->block_num, bbn->block_num);
12139                                         }
12140
12141                                         if (bbn->in_count == 1 && !bb->extended) {
12142                                                 if (bbn != cfg->bb_exit) {
12143                                                         if (cfg->verbose_level > 2)
12144                                                                 g_print ("block merge triggered %d -> %d\n", bb->block_num, bbn->block_num);
12145                                                         mono_merge_basic_blocks (cfg, bb, bbn);
12146                                                         changed = TRUE;
12147                                                         continue;
12148                                                 }
12149
12150                                                 //mono_print_bb_code (bb);
12151                                         }
12152                                 }
12153                         }
12154
12155                         if ((bbn = bb->next_bb) && bbn->in_count == 0 && bb->region == bbn->region) {
12156                                 if (cfg->verbose_level > 2) {
12157                                         g_print ("nullify block triggered %d\n", bbn->block_num);
12158                                 }
12159                                 bb->next_bb = bbn->next_bb;
12160
12161                                 for (i = 0; i < bbn->out_count; i++)
12162                                         replace_in_block (bbn->out_bb [i], bbn, NULL);
12163
12164                                 nullify_basic_block (bbn);                      
12165                                 changed = TRUE;
12166                                 continue;
12167                         }
12168
12169                         if (bb->out_count == 1) {
12170                                 bbn = bb->out_bb [0];
12171
12172                                 if (bb->last_ins && bb->last_ins->opcode == OP_BR) {
12173                                         bbn = bb->last_ins->inst_target_bb;
12174                                         if (bb->region == bbn->region && bbn->code && bbn->code->opcode == OP_BR &&
12175                                             bbn->code->inst_target_bb->region == bb->region) {
12176                                                 
12177                                                 if (cfg->verbose_level > 2)
12178                                                         g_print ("branch to branch triggered %d -> %d -> %d\n", bb->block_num, bbn->block_num, bbn->code->inst_target_bb->block_num);
12179
12180                                                 replace_in_block (bbn, bb, NULL);
12181                                                 replace_out_block (bb, bbn, bbn->code->inst_target_bb);
12182                                                 link_bblock (cfg, bb, bbn->code->inst_target_bb);
12183                                                 bb->last_ins->inst_target_bb = bbn->code->inst_target_bb;
12184                                                 changed = TRUE;
12185                                                 continue;
12186                                         }
12187                                 }
12188                         } else if (bb->out_count == 2) {
12189                                 if (bb->last_ins && MONO_IS_COND_BRANCH_NOFP (bb->last_ins)) {
12190                                         int branch_result;
12191                                         MonoBasicBlock *taken_branch_target = NULL, *untaken_branch_target = NULL;
12192
12193                                         if (cfg->new_ir) {
12194                                                 if (bb->last_ins->flags & MONO_INST_CFOLD_TAKEN)
12195                                                         branch_result = BRANCH_TAKEN;
12196                                                 else if (bb->last_ins->flags & MONO_INST_CFOLD_NOT_TAKEN)
12197                                                         branch_result = BRANCH_NOT_TAKEN;
12198                                                 else
12199                                                         branch_result = BRANCH_UNDEF;
12200                                         }
12201                                         else
12202                                                 branch_result = mono_eval_cond_branch (bb->last_ins);
12203
12204                                         if (branch_result == BRANCH_TAKEN) {
12205                                                 taken_branch_target = bb->last_ins->inst_true_bb;
12206                                                 untaken_branch_target = bb->last_ins->inst_false_bb;
12207                                         } else if (branch_result == BRANCH_NOT_TAKEN) {
12208                                                 taken_branch_target = bb->last_ins->inst_false_bb;
12209                                                 untaken_branch_target = bb->last_ins->inst_true_bb;
12210                                         }
12211                                         if (taken_branch_target) {
12212                                                 /* if mono_eval_cond_branch () is ever taken to handle 
12213                                                  * non-constant values to compare, issue a pop here.
12214                                                  */
12215                                                 bb->last_ins->opcode = OP_BR;
12216                                                 bb->last_ins->inst_target_bb = taken_branch_target;
12217                                                 if (!bb->extended)
12218                                                         mono_unlink_bblock (cfg, bb, untaken_branch_target);
12219                                                 changed = TRUE;
12220                                                 continue;
12221                                         }
12222                                         bbn = bb->last_ins->inst_true_bb;
12223                                         if (bb->region == bbn->region && bbn->code && bbn->code->opcode == OP_BR &&
12224                                             bbn->code->inst_target_bb->region == bb->region) {
12225                                                 if (cfg->verbose_level > 2)             
12226                                                         g_print ("cbranch1 to branch triggered %d -> (%d) %d (0x%02x)\n", 
12227                                                                  bb->block_num, bbn->block_num, bbn->code->inst_target_bb->block_num, 
12228                                                                  bbn->code->opcode);
12229
12230                                                 /* 
12231                                                  * Unlink, then relink bblocks to avoid various
12232                                                  * tricky situations when the two targets of the branch
12233                                                  * are equal, or will become equal after the change.
12234                                                  */
12235                                                 mono_unlink_bblock (cfg, bb, bb->last_ins->inst_true_bb);
12236                                                 mono_unlink_bblock (cfg, bb, bb->last_ins->inst_false_bb);
12237
12238                                                 bb->last_ins->inst_true_bb = bbn->code->inst_target_bb;
12239
12240                                                 link_bblock (cfg, bb, bb->last_ins->inst_true_bb);
12241                                                 link_bblock (cfg, bb, bb->last_ins->inst_false_bb);
12242
12243                                                 changed = TRUE;
12244                                                 continue;
12245                                         }
12246
12247                                         bbn = bb->last_ins->inst_false_bb;
12248                                         if (bbn && bb->region == bbn->region && bbn->code && bbn->code->opcode == OP_BR &&
12249                                             bbn->code->inst_target_bb->region == bb->region) {
12250                                                 if (cfg->verbose_level > 2)
12251                                                         g_print ("cbranch2 to branch triggered %d -> (%d) %d (0x%02x)\n", 
12252                                                                  bb->block_num, bbn->block_num, bbn->code->inst_target_bb->block_num, 
12253                                                                  bbn->code->opcode);
12254
12255                                                 mono_unlink_bblock (cfg, bb, bb->last_ins->inst_true_bb);
12256                                                 mono_unlink_bblock (cfg, bb, bb->last_ins->inst_false_bb);
12257
12258                                                 bb->last_ins->inst_false_bb = bbn->code->inst_target_bb;
12259
12260                                                 link_bblock (cfg, bb, bb->last_ins->inst_true_bb);
12261                                                 link_bblock (cfg, bb, bb->last_ins->inst_false_bb);
12262
12263                                                 changed = TRUE;
12264                                                 continue;
12265                                         }
12266
12267                                         bbn = bb->last_ins->inst_false_bb;
12268                                         /*
12269                                          * If bb is an extended bb, it could contain an inside branch to bbn.
12270                                          * FIXME: Enable the optimization if that is not true.
12271                                          * If bblocks_linked () is true, then merging bb and bbn
12272                                          * would require addition of an extra branch at the end of bbn 
12273                                          * slowing down loops.
12274                                          */
12275                                         if (cfg->new_ir && bbn && bb->region == bbn->region && bbn->in_count == 1 && cfg->enable_extended_bblocks && bbn != cfg->bb_exit && !bb->extended && !bbn->out_of_line && !mono_bblocks_linked (bbn, bb)) {
12276                                                 g_assert (bbn->in_bb [0] == bb);
12277                                                 if (cfg->verbose_level > 2)
12278                                                         g_print ("merge false branch target triggered BB%d -> BB%d\n", bb->block_num, bbn->block_num);
12279                                                 mono_merge_basic_blocks (cfg, bb, bbn);
12280                                                 changed = TRUE;
12281                                                 continue;
12282                                         }
12283                                 }
12284
12285                                 /* detect and optimize to unsigned compares checks like: if (v < 0 || v > limit */
12286                                 if (bb->last_ins && bb->last_ins->opcode == CEE_BLT && !cfg->new_ir && bb->last_ins->inst_left->inst_right->opcode == OP_ICONST) {
12287                                         if (try_unsigned_compare (cfg, bb)) {
12288                                                 /*g_print ("applied in bb %d (->%d) %s\n", bb->block_num, bb->last_ins->inst_target_bb->block_num, mono_method_full_name (cfg->method, TRUE));*/
12289                                                 changed = TRUE;
12290                                                 continue;
12291                                         }
12292                                 }
12293
12294                                 if (bb->last_ins && MONO_IS_COND_BRANCH_NOFP (bb->last_ins)) {
12295                                         if (bb->last_ins->inst_false_bb && bb->last_ins->inst_false_bb->out_of_line && (bb->region == bb->last_ins->inst_false_bb->region)) {
12296                                                 /* Reverse the branch */
12297                                                 bb->last_ins->opcode = reverse_branch_op (bb->last_ins->opcode);
12298                                                 bbn = bb->last_ins->inst_false_bb;
12299                                                 bb->last_ins->inst_false_bb = bb->last_ins->inst_true_bb;
12300                                                 bb->last_ins->inst_true_bb = bbn;
12301
12302                                                 move_basic_block_to_end (cfg, bb->last_ins->inst_true_bb);
12303                                                 if (cfg->verbose_level > 2)
12304                                                         g_print ("cbranch to throw block triggered %d.\n", 
12305                                                                          bb->block_num);
12306                                         }
12307                                 }
12308                         }
12309                 }
12310         } while (changed && (niterations > 0));
12311 }
12312
12313 static void
12314 mono_compile_create_vars (MonoCompile *cfg)
12315 {
12316         MonoMethodSignature *sig;
12317         MonoMethodHeader *header;
12318         int i;
12319
12320         header = mono_method_get_header (cfg->method);
12321
12322         sig = mono_method_signature (cfg->method);
12323         
12324         if (!MONO_TYPE_IS_VOID (sig->ret)) {
12325                 if (cfg->new_ir) {
12326                         cfg->ret = mono_compile_create_var (cfg, sig->ret, OP_ARG);
12327                         /* Inhibit optimizations */
12328                         cfg->ret->flags |= MONO_INST_VOLATILE;
12329                 } else {
12330                         cfg->ret = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst));
12331                         cfg->ret->opcode = OP_RETARG;
12332                         cfg->ret->inst_vtype = sig->ret;
12333                         cfg->ret->klass = mono_class_from_mono_type (sig->ret);
12334                 }
12335         }
12336         if (cfg->verbose_level > 2)
12337                 g_print ("creating vars\n");
12338
12339         cfg->args = mono_mempool_alloc0 (cfg->mempool, (sig->param_count + sig->hasthis) * sizeof (MonoInst*));
12340
12341         if (sig->hasthis)
12342                 cfg->args [0] = mono_compile_create_var (cfg, &cfg->method->klass->this_arg, OP_ARG);
12343
12344         for (i = 0; i < sig->param_count; ++i) {
12345                 cfg->args [i + sig->hasthis] = mono_compile_create_var (cfg, sig->params [i], OP_ARG);
12346                 if (sig->params [i]->byref) {
12347                         if (!cfg->new_ir) cfg->disable_ssa = TRUE;
12348                 }
12349         }
12350
12351         if (cfg->new_ir && cfg->verbose_level > 2) {
12352                 if (cfg->ret) {
12353                         printf ("\treturn : ");
12354                         mono_print_ins (cfg->ret);
12355                 }
12356
12357                 if (sig->hasthis) {
12358                         printf ("\tthis: ");
12359                         mono_print_ins (cfg->args [0]);
12360                 }
12361
12362                 for (i = 0; i < sig->param_count; ++i) {
12363                         printf ("\targ [%d]: ", i);
12364                         mono_print_ins (cfg->args [i + sig->hasthis]);
12365                 }
12366         }
12367
12368         cfg->locals_start = cfg->num_varinfo;
12369         cfg->locals = mono_mempool_alloc0 (cfg->mempool, header->num_locals * sizeof (MonoInst*));
12370
12371         if (cfg->verbose_level > 2)
12372                 g_print ("creating locals\n");
12373
12374         for (i = 0; i < header->num_locals; ++i)
12375                 cfg->locals [i] = mono_compile_create_var (cfg, header->locals [i], OP_LOCAL);
12376
12377         if (cfg->verbose_level > 2)
12378                 g_print ("locals done\n");
12379
12380         mono_arch_create_vars (cfg);
12381 }
12382
12383 void
12384 mono_print_code (MonoCompile *cfg, const char* msg)
12385 {
12386         MonoBasicBlock *bb;
12387         
12388         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
12389                 MonoInst *tree = bb->code;      
12390
12391                 if (cfg->new_ir) {
12392                         mono_print_bb (bb, msg);
12393                 } else {
12394                         if (!tree)
12395                                 continue;
12396                         
12397                         g_print ("%s CODE BLOCK %d (nesting %d):\n", msg, bb->block_num, bb->nesting);
12398
12399                         MONO_BB_FOR_EACH_INS (bb, tree) {
12400                                 mono_print_tree (tree);
12401                                 g_print ("\n");
12402                         }
12403                 }
12404         }
12405 }
12406
12407 extern const char * const mono_burg_rule_string [];
12408
12409 static void
12410 emit_state (MonoCompile *cfg, MBState *state, int goal)
12411 {
12412         MBState *kids [10];
12413         int ern = mono_burg_rule (state, goal);
12414         const guint16 *nts = mono_burg_nts_data + mono_burg_nts [ern];
12415
12416         //g_print ("rule: %s\n", mono_burg_rule_string [ern]);
12417         switch (goal) {
12418         case MB_NTERM_reg:
12419                 //if (state->reg2)
12420                 //      state->reg1 = state->reg2; /* chain rule */
12421                 //else
12422 #ifdef MONO_ARCH_ENABLE_EMIT_STATE_OPT
12423                 if (!state->reg1)
12424 #endif
12425                         state->reg1 = mono_regstate_next_int (cfg->rs);
12426                 //g_print ("alloc symbolic R%d (reg2: R%d) in block %d\n", state->reg1, state->reg2, cfg->cbb->block_num);
12427                 break;
12428         case MB_NTERM_lreg:
12429                 state->reg1 = mono_regstate_next_int (cfg->rs);
12430                 state->reg2 = mono_regstate_next_int (cfg->rs);
12431                 break;
12432         case MB_NTERM_freg:
12433 #ifdef MONO_ARCH_SOFT_FLOAT
12434                 state->reg1 = mono_regstate_next_int (cfg->rs);
12435                 state->reg2 = mono_regstate_next_int (cfg->rs);
12436 #else
12437                 state->reg1 = mono_regstate_next_float (cfg->rs);
12438 #endif
12439                 break;
12440         default:
12441 #ifdef MONO_ARCH_ENABLE_EMIT_STATE_OPT
12442                 /*
12443                  * Enabling this might cause bugs to surface in the local register
12444                  * allocators on some architectures like x86.
12445                  */
12446                 if ((state->tree->ssa_op == MONO_SSA_STORE) && (state->left->tree->opcode == OP_REGVAR)) {
12447                         /* Do not optimize away reg-reg moves */
12448                         if (! ((state->right->tree->ssa_op == MONO_SSA_LOAD) && (state->right->left->tree->opcode == OP_REGVAR))) {
12449                                 state->right->reg1 = state->left->tree->dreg;
12450                         }
12451                 }
12452 #endif
12453
12454                 /* do nothing */
12455                 break;
12456         }
12457         if (nts [0]) {
12458                 mono_burg_kids (state, ern, kids);
12459
12460                 emit_state (cfg, kids [0], nts [0]);
12461                 if (nts [1]) {
12462                         emit_state (cfg, kids [1], nts [1]);
12463                         if (nts [2]) {
12464                                 emit_state (cfg, kids [2], nts [2]);
12465                                 if (nts [3]) {
12466                                         g_assert (!nts [4]);
12467                                         emit_state (cfg, kids [3], nts [3]);
12468                                 }
12469                         }
12470                 }
12471         }
12472
12473 //      g_print ("emit: %s (%p)\n", mono_burg_rule_string [ern], state);
12474         mono_burg_emit (ern, state, state->tree, cfg);
12475 }
12476
12477 #define DEBUG_SELECTION
12478
12479 static void 
12480 mini_select_instructions (MonoCompile *cfg)
12481 {
12482         MonoBasicBlock *bb;
12483         
12484         cfg->state_pool = mono_mempool_new ();
12485         cfg->rs = mono_regstate_new ();
12486
12487         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
12488                 if (bb->last_ins && MONO_IS_COND_BRANCH_OP (bb->last_ins) &&
12489                     bb->last_ins->inst_false_bb && bb->next_bb != bb->last_ins->inst_false_bb) {
12490
12491                         /* we are careful when inverting, since bugs like #59580
12492                          * could show up when dealing with NaNs.
12493                          */
12494                         if (MONO_IS_COND_BRANCH_NOFP(bb->last_ins) && bb->next_bb == bb->last_ins->inst_true_bb) {
12495                                 MonoBasicBlock *tmp =  bb->last_ins->inst_true_bb;
12496                                 bb->last_ins->inst_true_bb = bb->last_ins->inst_false_bb;
12497                                 bb->last_ins->inst_false_bb = tmp;
12498
12499                                 bb->last_ins->opcode = reverse_branch_op (bb->last_ins->opcode);
12500                         } else {                        
12501                                 MonoInst *ins;
12502
12503                                 MONO_INST_NEW (cfg, ins, OP_BR);
12504                                 ins->inst_target_bb = bb->last_ins->inst_false_bb;
12505                                 MONO_ADD_INS (bb, ins);
12506                         }
12507                 }
12508         }
12509
12510 #ifdef DEBUG_SELECTION
12511         if (cfg->verbose_level >= 4) {
12512                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
12513                         MonoInst *tree;
12514                         g_print ("DUMP BLOCK %d:\n", bb->block_num);
12515                         MONO_BB_FOR_EACH_INS (bb, tree) {
12516                                 mono_print_tree (tree);
12517                                 g_print ("\n");
12518                         }
12519                 }
12520         }
12521 #endif
12522
12523         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
12524                 MonoInst *tree = bb->code, *next;       
12525                 MBState *mbstate;
12526
12527                 if (!tree)
12528                         continue;
12529                 bb->code = NULL;
12530                 bb->last_ins = NULL;
12531                 
12532                 cfg->cbb = bb;
12533                 mono_regstate_reset (cfg->rs);
12534
12535 #ifdef DEBUG_SELECTION
12536                 if (cfg->verbose_level >= 3)
12537                         g_print ("LABEL BLOCK %d:\n", bb->block_num);
12538 #endif
12539                 for (; tree; tree = next) {
12540                         next = tree->next;
12541 #ifdef DEBUG_SELECTION
12542                         if (cfg->verbose_level >= 3) {
12543                                 mono_print_tree (tree);
12544                                 g_print ("\n");
12545                         }
12546 #endif
12547
12548                         cfg->ip = tree->cil_code;
12549                         if (!(mbstate = mono_burg_label (tree, cfg))) {
12550                                 g_warning ("unable to label tree %p", tree);
12551                                 mono_print_tree (tree);
12552                                 g_print ("\n");                         
12553                                 g_assert_not_reached ();
12554                         }
12555                         emit_state (cfg, mbstate, MB_NTERM_stmt);
12556                 }
12557                 bb->max_vreg = cfg->rs->next_vreg;
12558
12559                 if (bb->last_ins)
12560                         bb->last_ins->next = NULL;
12561
12562                 mono_mempool_empty (cfg->state_pool); 
12563         }
12564         mono_mempool_destroy (cfg->state_pool); 
12565
12566         cfg->ip = NULL;
12567 }
12568
12569 /*
12570  * mono_normalize_opcodes:
12571  *
12572  *   Replace CEE_ and OP_ opcodes with the corresponding OP_I or OP_L opcodes.
12573  */
12574
12575 static gint16 *remap_table;
12576
12577 #if SIZEOF_VOID_P == 8
12578 #define REMAP_OPCODE(opcode) OP_L ## opcode
12579 #else
12580 #define REMAP_OPCODE(opcode) OP_I ## opcode
12581 #endif
12582
12583 static G_GNUC_UNUSED void
12584 mono_normalize_opcodes (MonoCompile *cfg, MonoBasicBlock *bb)
12585 {
12586         MonoInst *ins;
12587
12588         if (!remap_table) {
12589                 remap_table = g_new0 (gint16, OP_LAST);
12590
12591 #if SIZEOF_VOID_P == 8
12592                 remap_table [CEE_CONV_U8] = OP_ZEXT_I4;
12593                 remap_table [CEE_CONV_U] = OP_ZEXT_I4;
12594                 remap_table [CEE_CONV_I8] = OP_SEXT_I4;
12595                 remap_table [CEE_CONV_I] = OP_SEXT_I4;
12596                 remap_table [CEE_CONV_OVF_U4] = OP_LCONV_TO_OVF_U4;
12597                 remap_table [CEE_CONV_OVF_I4_UN] = OP_LCONV_TO_OVF_I4_UN;
12598 #else
12599 #endif
12600                 remap_table [CEE_CONV_R4] = OP_ICONV_TO_R4;
12601                 remap_table [CEE_CONV_R8] = OP_ICONV_TO_R8;
12602                 remap_table [CEE_CONV_I4] = OP_MOVE;
12603                 remap_table [CEE_CONV_U4] = OP_MOVE;
12604                 remap_table [CEE_CONV_I1] = REMAP_OPCODE (CONV_TO_I1);
12605                 remap_table [CEE_CONV_I2] = REMAP_OPCODE (CONV_TO_I2);
12606                 remap_table [CEE_CONV_U1] = REMAP_OPCODE (CONV_TO_U1);
12607                 remap_table [CEE_CONV_U2] = REMAP_OPCODE (CONV_TO_U2);
12608                 remap_table [CEE_CONV_R_UN] = REMAP_OPCODE (CONV_TO_R_UN);
12609                 remap_table [CEE_ADD] = REMAP_OPCODE (ADD);
12610                 remap_table [CEE_SUB] = REMAP_OPCODE (SUB);
12611                 remap_table [CEE_MUL] = REMAP_OPCODE (MUL);
12612                 remap_table [CEE_DIV] = REMAP_OPCODE (DIV);
12613                 remap_table [CEE_REM] = REMAP_OPCODE (REM);
12614                 remap_table [CEE_DIV_UN] = REMAP_OPCODE (DIV_UN);
12615                 remap_table [CEE_REM_UN] = REMAP_OPCODE (REM_UN);
12616                 remap_table [CEE_AND] = REMAP_OPCODE (AND);
12617                 remap_table [CEE_OR] = REMAP_OPCODE (OR);
12618                 remap_table [CEE_XOR] = REMAP_OPCODE (XOR);
12619                 remap_table [CEE_SHL] = REMAP_OPCODE (SHL);
12620                 remap_table [CEE_SHR] = REMAP_OPCODE (SHR);
12621                 remap_table [CEE_SHR_UN] = REMAP_OPCODE (SHR_UN);
12622                 remap_table [CEE_NOT] = REMAP_OPCODE (NOT);
12623                 remap_table [CEE_NEG] = REMAP_OPCODE (NEG);
12624                 remap_table [CEE_CALL] = OP_CALL;
12625                 remap_table [CEE_BEQ] = REMAP_OPCODE (BEQ);
12626                 remap_table [CEE_BNE_UN] = REMAP_OPCODE (BNE_UN);
12627                 remap_table [CEE_BLT] = REMAP_OPCODE (BLT);
12628                 remap_table [CEE_BLT_UN] = REMAP_OPCODE (BLT_UN);
12629                 remap_table [CEE_BGT] = REMAP_OPCODE (BGT);
12630                 remap_table [CEE_BGT_UN] = REMAP_OPCODE (BGT_UN);
12631                 remap_table [CEE_BGE] = REMAP_OPCODE (BGE);
12632                 remap_table [CEE_BGE_UN] = REMAP_OPCODE (BGE_UN);
12633                 remap_table [CEE_BLE] = REMAP_OPCODE (BLE);
12634                 remap_table [CEE_BLE_UN] = REMAP_OPCODE (BLE_UN);
12635                 remap_table [CEE_ADD_OVF] = REMAP_OPCODE (ADD_OVF);
12636                 remap_table [CEE_ADD_OVF_UN] = REMAP_OPCODE (ADD_OVF_UN);
12637                 remap_table [CEE_SUB_OVF] = REMAP_OPCODE (SUB_OVF);
12638                 remap_table [CEE_SUB_OVF_UN] = REMAP_OPCODE (SUB_OVF_UN);
12639                 remap_table [CEE_MUL_OVF] = REMAP_OPCODE (MUL_OVF);
12640                 remap_table [CEE_MUL_OVF_UN] = REMAP_OPCODE (MUL_OVF_UN);
12641         }
12642
12643         MONO_BB_FOR_EACH_INS (bb, ins) {
12644                 int remapped = remap_table [ins->opcode];
12645                 if (remapped)
12646                         ins->opcode = remapped;
12647         }
12648 }
12649
12650 void
12651 mono_codegen (MonoCompile *cfg)
12652 {
12653         MonoJumpInfo *patch_info;
12654         MonoBasicBlock *bb;
12655         int i, max_epilog_size;
12656         guint8 *code;
12657
12658         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
12659                 cfg->spill_count = 0;
12660                 /* we reuse dfn here */
12661                 /* bb->dfn = bb_count++; */
12662 #ifdef MONO_ARCH_ENABLE_NORMALIZE_OPCODES
12663                 if (!cfg->new_ir)
12664                         mono_normalize_opcodes (cfg, bb);
12665 #endif
12666
12667                 mono_arch_lowering_pass (cfg, bb);
12668
12669                 if (cfg->opt & MONO_OPT_PEEPHOLE)
12670                         mono_arch_peephole_pass_1 (cfg, bb);
12671
12672                 if (!cfg->globalra)
12673                         mono_local_regalloc (cfg, bb);
12674
12675                 if (cfg->opt & MONO_OPT_PEEPHOLE)
12676                         mono_arch_peephole_pass_2 (cfg, bb);
12677         }
12678
12679         if (cfg->prof_options & MONO_PROFILE_COVERAGE)
12680                 cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, cfg->num_bblocks);
12681
12682         code = mono_arch_emit_prolog (cfg);
12683
12684         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
12685                 code = mono_arch_instrument_prolog (cfg, mono_profiler_method_enter, code, FALSE);
12686
12687         cfg->code_len = code - cfg->native_code;
12688         cfg->prolog_end = cfg->code_len;
12689
12690         mono_debug_open_method (cfg);
12691
12692         /* emit code all basic blocks */
12693         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
12694                 bb->native_offset = cfg->code_len;
12695                 //if ((bb == cfg->bb_entry) || !(bb->region == -1 && !bb->dfn))
12696                         mono_arch_output_basic_block (cfg, bb);
12697
12698                 if (bb == cfg->bb_exit) {
12699                         cfg->epilog_begin = cfg->code_len;
12700
12701                         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE) {
12702                                 code = cfg->native_code + cfg->code_len;
12703                                 code = mono_arch_instrument_epilog (cfg, mono_profiler_method_leave, code, FALSE);
12704                                 cfg->code_len = code - cfg->native_code;
12705                                 g_assert (cfg->code_len < cfg->code_size);
12706                         }
12707
12708                         mono_arch_emit_epilog (cfg);
12709                 }
12710         }
12711
12712         mono_arch_emit_exceptions (cfg);
12713
12714         max_epilog_size = 0;
12715
12716         code = cfg->native_code + cfg->code_len;
12717
12718         /* we always allocate code in cfg->domain->code_mp to increase locality */
12719         cfg->code_size = cfg->code_len + max_epilog_size;
12720         /* fixme: align to MONO_ARCH_CODE_ALIGNMENT */
12721
12722         if (cfg->method->dynamic) {
12723                 guint unwindlen = 0;
12724 #ifdef MONO_ARCH_HAVE_UNWIND_TABLE
12725                 unwindlen = mono_arch_unwindinfo_get_size (cfg->arch.unwindinfo);
12726 #endif
12727                 /* Allocate the code into a separate memory pool so it can be freed */
12728                 cfg->dynamic_info = g_new0 (MonoJitDynamicMethodInfo, 1);
12729                 cfg->dynamic_info->code_mp = mono_code_manager_new_dynamic ();
12730                 mono_domain_lock (cfg->domain);
12731                 mono_dynamic_code_hash_insert (cfg->domain, cfg->method, cfg->dynamic_info);
12732                 mono_domain_unlock (cfg->domain);
12733
12734                 code = mono_code_manager_reserve (cfg->dynamic_info->code_mp, cfg->code_size + unwindlen);
12735         } else {
12736                 guint unwindlen = 0;
12737 #ifdef MONO_ARCH_HAVE_UNWIND_TABLE
12738                 unwindlen = mono_arch_unwindinfo_get_size (cfg->arch.unwindinfo);
12739 #endif
12740                 mono_domain_lock (cfg->domain);
12741                 code = mono_code_manager_reserve (cfg->domain->code_mp, cfg->code_size + unwindlen);
12742                 mono_domain_unlock (cfg->domain);
12743         }
12744
12745         memcpy (code, cfg->native_code, cfg->code_len);
12746         g_free (cfg->native_code);
12747         cfg->native_code = code;
12748         code = cfg->native_code + cfg->code_len;
12749   
12750         /* g_assert (((int)cfg->native_code & (MONO_ARCH_CODE_ALIGNMENT - 1)) == 0); */
12751         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
12752                 switch (patch_info->type) {
12753                 case MONO_PATCH_INFO_ABS: {
12754                         MonoJitICallInfo *info = mono_find_jit_icall_by_addr (patch_info->data.target);
12755                         if (info) {
12756                                 //printf ("TEST %s %p\n", info->name, patch_info->data.target);
12757                                 // FIXME: CLEAN UP THIS MESS.
12758                                 if ((cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) && 
12759                                         strstr (cfg->method->name, info->name)) {
12760                                         /*
12761                                          * This is an icall wrapper, and this is a call to the
12762                                          * wrapped function.
12763                                          */
12764                                         if (cfg->compile_aot) {
12765                                                 patch_info->type = MONO_PATCH_INFO_JIT_ICALL_ADDR;
12766                                                 patch_info->data.name = info->name;
12767                                         }
12768                                 } else {
12769                                         /* for these array methods we currently register the same function pointer
12770                                          * since it's a vararg function. But this means that mono_find_jit_icall_by_addr ()
12771                                          * will return the incorrect one depending on the order they are registered.
12772                                          * See tests/test-arr.cs
12773                                          */
12774                                         if (strstr (info->name, "ves_array_new_va_") == NULL && strstr (info->name, "ves_array_element_address_") == NULL) {
12775                                                 patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
12776                                                 patch_info->data.name = info->name;
12777                                         }
12778                                 }
12779                         }
12780                         else {
12781                                 MonoVTable *vtable = mono_find_class_init_trampoline_by_addr (patch_info->data.target);
12782                                 if (vtable) {
12783                                         patch_info->type = MONO_PATCH_INFO_CLASS_INIT;
12784                                         patch_info->data.klass = vtable->klass;
12785                                 } else {
12786                                         MonoClass *klass = mono_find_delegate_trampoline_by_addr (patch_info->data.target);
12787                                         if (klass) {
12788                                                 patch_info->type = MONO_PATCH_INFO_DELEGATE_TRAMPOLINE;
12789                                                 patch_info->data.klass = klass;
12790                                         }
12791                                 }
12792                         }
12793                         break;
12794                 }
12795                 case MONO_PATCH_INFO_SWITCH: {
12796                         gpointer *table;
12797                         if (cfg->method->dynamic) {
12798                                 table = mono_code_manager_reserve (cfg->dynamic_info->code_mp, sizeof (gpointer) * patch_info->data.table->table_size);
12799                         } else {
12800                                 mono_domain_lock (cfg->domain);
12801                                 table = mono_code_manager_reserve (cfg->domain->code_mp, sizeof (gpointer) * patch_info->data.table->table_size);
12802                                 mono_domain_unlock (cfg->domain);
12803                         }
12804
12805                         if (!cfg->compile_aot && !cfg->new_ir)
12806                                 /* In the aot case, the patch already points to the correct location */
12807                                 patch_info->ip.i = patch_info->ip.label->inst_c0;
12808                         for (i = 0; i < patch_info->data.table->table_size; i++) {
12809                                 /* Might be NULL if the switch is eliminated */
12810                                 if (patch_info->data.table->table [i]) {
12811                                         g_assert (patch_info->data.table->table [i]->native_offset);
12812                                         table [i] = GINT_TO_POINTER (patch_info->data.table->table [i]->native_offset);
12813                                 } else {
12814                                         table [i] = NULL;
12815                                 }
12816                         }
12817                         patch_info->data.table->table = (MonoBasicBlock**)table;
12818                         break;
12819                 }
12820                 default:
12821                         /* do nothing */
12822                         break;
12823                 }
12824         }
12825
12826 #ifdef VALGRIND_JIT_REGISTER_MAP
12827 if (valgrind_register){
12828                 char* nm = mono_method_full_name (cfg->method, TRUE);
12829                 VALGRIND_JIT_REGISTER_MAP (nm, cfg->native_code, cfg->native_code + cfg->code_len);
12830                 g_free (nm);
12831         }
12832 #endif
12833  
12834         if (cfg->verbose_level > 0) {
12835                 char* nm = mono_method_full_name (cfg->method, TRUE);
12836                 g_print ("Method %s emitted at %p to %p (code length %d) [%s]\n", 
12837                                  nm, 
12838                                  cfg->native_code, cfg->native_code + cfg->code_len, cfg->code_len, cfg->domain->friendly_name);
12839                 g_free (nm);
12840         }
12841
12842         {
12843                 gboolean is_generic = FALSE;
12844
12845                 if (cfg->method->is_inflated || mono_method_get_generic_container (cfg->method) ||
12846                                 cfg->method->klass->generic_container || cfg->method->klass->generic_class) {
12847                         is_generic = TRUE;
12848                 }
12849
12850                 if (cfg->generic_sharing_context)
12851                         g_assert (is_generic);
12852         }
12853
12854 #ifdef MONO_ARCH_HAVE_SAVE_UNWIND_INFO
12855         mono_arch_save_unwind_info (cfg);
12856 #endif
12857         
12858         mono_arch_patch_code (cfg->method, cfg->domain, cfg->native_code, cfg->patch_info, cfg->run_cctors);
12859
12860         if (cfg->method->dynamic) {
12861                 mono_code_manager_commit (cfg->dynamic_info->code_mp, cfg->native_code, cfg->code_size, cfg->code_len);
12862         } else {
12863                 mono_domain_lock (cfg->domain);
12864                 mono_code_manager_commit (cfg->domain->code_mp, cfg->native_code, cfg->code_size, cfg->code_len);
12865                 mono_domain_unlock (cfg->domain);
12866         }
12867         
12868         mono_arch_flush_icache (cfg->native_code, cfg->code_len);
12869
12870         mono_debug_close_method (cfg);
12871 #ifdef MONO_ARCH_HAVE_UNWIND_TABLE
12872         mono_arch_unwindinfo_install_unwind_info (&cfg->arch.unwindinfo, cfg->native_code, cfg->code_len);
12873 #endif
12874 }
12875
12876 void
12877 mono_remove_critical_edges (MonoCompile *cfg)
12878 {
12879         MonoBasicBlock *bb;
12880         MonoBasicBlock *previous_bb;
12881         
12882         if (cfg->verbose_level > 3) {
12883                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
12884                         int i;
12885                         printf ("remove_critical_edges, BEFORE BB%d (in:", bb->block_num);
12886                         for (i = 0; i < bb->in_count; i++) {
12887                                 printf (" %d", bb->in_bb [i]->block_num);
12888                         }
12889                         printf (") (out:");
12890                         for (i = 0; i < bb->out_count; i++) {
12891                                 printf (" %d", bb->out_bb [i]->block_num);
12892                         }
12893                         printf (")");
12894                         if (bb->last_ins != NULL) {
12895                                 printf (" ");
12896                                 mono_print_tree (bb->last_ins);
12897                         }
12898                         printf ("\n");
12899                 }
12900         }
12901         
12902         for (previous_bb = cfg->bb_entry, bb = previous_bb->next_bb; bb != NULL; previous_bb = previous_bb->next_bb, bb = bb->next_bb) {
12903                 if (bb->in_count > 1) {
12904                         int in_bb_index;
12905                         for (in_bb_index = 0; in_bb_index < bb->in_count; in_bb_index++) {
12906                                 MonoBasicBlock *in_bb = bb->in_bb [in_bb_index];
12907                                 if (in_bb->out_count > 1) {
12908                                         MonoBasicBlock *new_bb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
12909                                         new_bb->block_num = cfg->num_bblocks++;
12910 //                                      new_bb->real_offset = bb->real_offset;
12911                                         new_bb->region = bb->region;
12912                                         
12913                                         /* Do not alter the CFG while altering the BB list */
12914                                         if (previous_bb->region == bb->region) {
12915                                                 if (previous_bb != cfg->bb_entry) {
12916                                                         /* If previous_bb "followed through" to bb, */
12917                                                         /* keep it linked with a OP_BR */
12918                                                         if ((previous_bb->last_ins == NULL) ||
12919                                                                         ((previous_bb->last_ins->opcode != OP_BR) &&
12920                                                                         (! (MONO_IS_COND_BRANCH_OP (previous_bb->last_ins))) &&
12921                                                                         (previous_bb->last_ins->opcode != OP_SWITCH))) {
12922                                                                 int i;
12923                                                                 /* Make sure previous_bb really falls through bb */
12924                                                                 for (i = 0; i < previous_bb->out_count; i++) {
12925                                                                         if (previous_bb->out_bb [i] == bb) {
12926                                                                                 MonoInst *jump;
12927                                                                                 MONO_INST_NEW (cfg, jump, OP_BR);
12928                                                                                 MONO_ADD_INS (previous_bb, jump);
12929                                                                                 jump->cil_code = previous_bb->cil_code;
12930                                                                                 jump->inst_target_bb = bb;
12931                                                                                 break;
12932                                                                         }
12933                                                                 }
12934                                                         }
12935                                                 } else {
12936                                                         /* We cannot add any inst to the entry BB, so we must */
12937                                                         /* put a new BB in the middle to hold the OP_BR */
12938                                                         MonoInst *jump;
12939                                                         MonoBasicBlock *new_bb_after_entry = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
12940                                                         new_bb_after_entry->block_num = cfg->num_bblocks++;
12941 //                                                      new_bb_after_entry->real_offset = bb->real_offset;
12942                                                         new_bb_after_entry->region = bb->region;
12943                                                         
12944                                                         MONO_INST_NEW (cfg, jump, OP_BR);
12945                                                         MONO_ADD_INS (new_bb_after_entry, jump);
12946                                                         jump->cil_code = bb->cil_code;
12947                                                         jump->inst_target_bb = bb;
12948                                                         
12949                                                         previous_bb->next_bb = new_bb_after_entry;
12950                                                         previous_bb = new_bb_after_entry;
12951                                                         
12952                                                         if (cfg->verbose_level > 2) {
12953                                                                 printf ("remove_critical_edges, added helper BB%d jumping to BB%d\n", new_bb_after_entry->block_num, bb->block_num);
12954                                                         }
12955                                                 }
12956                                         }
12957                                         
12958                                         /* Insert new_bb in the BB list */
12959                                         previous_bb->next_bb = new_bb;
12960                                         new_bb->next_bb = bb;
12961                                         previous_bb = new_bb;
12962                                         
12963                                         /* Setup in_bb and out_bb */
12964                                         new_bb->in_bb = mono_mempool_alloc ((cfg)->mempool, sizeof (MonoBasicBlock*));
12965                                         new_bb->in_bb [0] = in_bb;
12966                                         new_bb->in_count = 1;
12967                                         new_bb->out_bb = mono_mempool_alloc ((cfg)->mempool, sizeof (MonoBasicBlock*));
12968                                         new_bb->out_bb [0] = bb;
12969                                         new_bb->out_count = 1;
12970                                         
12971                                         /* Relink in_bb and bb to (from) new_bb */
12972                                         replace_out_block (in_bb, bb, new_bb);
12973                                         replace_out_block_in_code (in_bb, bb, new_bb);
12974                                         replace_in_block (bb, in_bb, new_bb);
12975                                         
12976                                         if (cfg->verbose_level > 2) {
12977                                                 printf ("remove_critical_edges, removed critical edge from BB%d to BB%d (added BB%d)\n", in_bb->block_num, bb->block_num, new_bb->block_num);
12978                                         }
12979                                 }
12980                         }
12981                 }
12982         }
12983         
12984         if (cfg->verbose_level > 3) {
12985                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
12986                         int i;
12987                         printf ("remove_critical_edges, AFTER BB%d (in:", bb->block_num);
12988                         for (i = 0; i < bb->in_count; i++) {
12989                                 printf (" %d", bb->in_bb [i]->block_num);
12990                         }
12991                         printf (") (out:");
12992                         for (i = 0; i < bb->out_count; i++) {
12993                                 printf (" %d", bb->out_bb [i]->block_num);
12994                         }
12995                         printf (")");
12996                         if (bb->last_ins != NULL) {
12997                                 printf (" ");
12998                                 mono_print_tree (bb->last_ins);
12999                         }
13000                         printf ("\n");
13001                 }
13002         }
13003 }
13004
13005 static MonoGenericInst*
13006 get_object_generic_inst (int type_argc)
13007 {
13008         MonoType **type_argv;
13009         int i;
13010
13011         type_argv = alloca (sizeof (MonoType*) * type_argc);
13012
13013         for (i = 0; i < type_argc; ++i)
13014                 type_argv [i] = &mono_defaults.object_class->byval_arg;
13015
13016         return mono_metadata_get_generic_inst (type_argc, type_argv);
13017 }
13018
13019 /*
13020  * mini_method_compile:
13021  * @method: the method to compile
13022  * @opts: the optimization flags to use
13023  * @domain: the domain where the method will be compiled in
13024  * @run_cctors: whether we should run type ctors if possible
13025  * @compile_aot: whether this is an AOT compilation
13026  * @parts: debug flag
13027  *
13028  * Returns: a MonoCompile* pointer. Caller must check the exception_type
13029  * field in the returned struct to see if compilation succeded.
13030  */
13031 MonoCompile*
13032 mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gboolean run_cctors, gboolean compile_aot, int parts)
13033 {
13034         MonoMethodHeader *header;
13035         guint8 *ip;
13036         MonoCompile *cfg;
13037         MonoJitInfo *jinfo;
13038         int dfn, i, code_size_ratio;
13039         gboolean deadce_has_run = FALSE;
13040         gboolean try_generic_shared;
13041         MonoMethod *method_to_compile, *method_to_register;
13042         int generic_info_size;
13043
13044         mono_jit_stats.methods_compiled++;
13045         if (mono_profiler_get_events () & MONO_PROFILE_JIT_COMPILATION)
13046                 mono_profiler_method_jit (method);
13047         if (MONO_PROBE_METHOD_COMPILE_BEGIN_ENABLED ())
13048                 MONO_PROBE_METHOD_COMPILE_BEGIN (method);
13049  
13050         if (compile_aot)
13051                 /* We are passed the original generic method definition */
13052                 try_generic_shared = mono_class_generic_sharing_enabled (method->klass) &&
13053                         (opts & MONO_OPT_GSHARED) && (method->is_generic || method->klass->generic_container);
13054         else
13055                 try_generic_shared = mono_class_generic_sharing_enabled (method->klass) &&
13056                         (opts & MONO_OPT_GSHARED) && mono_method_is_generic_sharable_impl (method, FALSE);
13057
13058         if (opts & MONO_OPT_GSHARED) {
13059                 if (try_generic_shared)
13060                         mono_stats.generics_sharable_methods++;
13061                 else if (mono_method_is_generic_impl (method))
13062                         mono_stats.generics_unsharable_methods++;
13063         }
13064
13065  restart_compile:
13066         if (try_generic_shared) {
13067                 MonoMethod *declaring_method;
13068                 MonoGenericContext *shared_context;
13069
13070                 if (compile_aot) {
13071                         declaring_method = method;
13072                 } else {
13073                         declaring_method = mono_method_get_declaring_generic_method (method);
13074                         if (method->klass->generic_class)
13075                                 g_assert (method->klass->generic_class->container_class == declaring_method->klass);
13076                         else
13077                                 g_assert (method->klass == declaring_method->klass);
13078                 }
13079
13080                 if (declaring_method->is_generic)
13081                         shared_context = &(mono_method_get_generic_container (declaring_method)->context);
13082                 else
13083                         shared_context = &declaring_method->klass->generic_container->context;
13084
13085                 method_to_compile = mono_class_inflate_generic_method (declaring_method, shared_context);
13086                 g_assert (method_to_compile);
13087         } else {
13088                 method_to_compile = method;
13089         }
13090
13091         cfg = g_new0 (MonoCompile, 1);
13092         cfg->method = method_to_compile;
13093         cfg->mempool = mono_mempool_new ();
13094         cfg->opt = opts;
13095         cfg->prof_options = mono_profiler_get_events ();
13096         cfg->run_cctors = run_cctors;
13097         cfg->domain = domain;
13098         cfg->verbose_level = mini_verbose;
13099         cfg->compile_aot = compile_aot;
13100         cfg->skip_visibility = method->skip_visibility;
13101         if (try_generic_shared)
13102                 cfg->generic_sharing_context = (MonoGenericSharingContext*)&cfg->generic_sharing_context;
13103         cfg->token_info_hash = g_hash_table_new (NULL, NULL);
13104
13105         /* The debugger has no liveness information, so avoid sharing registers/stack slots */
13106         if (mono_debug_using_mono_debugger () || debug_options.mdb_optimizations) {
13107                 cfg->disable_reuse_registers = TRUE;
13108                 cfg->disable_reuse_stack_slots = TRUE;
13109                 /* 
13110                  * This decreases the change the debugger will read registers/stack slots which are
13111                  * not yet initialized.
13112                  */
13113                 cfg->disable_initlocals_opt = TRUE;
13114
13115                 /* Temporarily disable this when running in the debugger until we have support
13116                  * for this in the debugger. */
13117                 cfg->disable_omit_fp = TRUE;
13118
13119                 // cfg->opt |= MONO_OPT_SHARED;
13120                 cfg->opt &= ~MONO_OPT_INLINE;
13121                 cfg->opt &= ~MONO_OPT_COPYPROP;
13122                 cfg->opt &= ~MONO_OPT_CONSPROP;
13123                 cfg->opt &= ~MONO_OPT_GSHARED;
13124         }
13125
13126         header = mono_method_get_header (method_to_compile);
13127         if (!header) {
13128                 cfg->exception_type = MONO_EXCEPTION_INVALID_PROGRAM;
13129                 cfg->exception_message = g_strdup_printf ("Missing or incorrect header for method %s", cfg->method->name);
13130                 if (MONO_PROBE_METHOD_COMPILE_END_ENABLED ())
13131                         MONO_PROBE_METHOD_COMPILE_END (method, FALSE);
13132                 if (cfg->prof_options & MONO_PROFILE_JIT_COMPILATION)
13133                         mono_profiler_method_end_jit (method, NULL, MONO_PROFILE_FAILED);
13134                 return cfg;
13135         }
13136
13137         if (getenv ("MONO_VERBOSE_METHOD")) {
13138                 if (strcmp (cfg->method->name, getenv ("MONO_VERBOSE_METHOD")) == 0)
13139                         cfg->verbose_level = 4;
13140         }
13141
13142         ip = (guint8 *)header->code;
13143
13144         cfg->intvars = mono_mempool_alloc0 (cfg->mempool, sizeof (guint16) * STACK_MAX * header->max_stack);
13145
13146         if (cfg->verbose_level > 2) {
13147                 if (cfg->generic_sharing_context)
13148                         g_print ("converting shared method %s\n", mono_method_full_name (method, TRUE));
13149                 else
13150                         g_print ("converting method %s\n", mono_method_full_name (method, TRUE));
13151         }
13152
13153         if (cfg->opt & (MONO_OPT_ABCREM | MONO_OPT_SSAPRE))
13154                 cfg->opt |= MONO_OPT_SSA;
13155
13156         {
13157                 static int count = 0;
13158
13159                 count ++;
13160
13161                 if (getenv ("MONO_COUNT")) {
13162                         if (count == atoi (getenv ("MONO_COUNT"))) {
13163                                 printf ("LAST: %s\n", mono_method_full_name (method, TRUE));
13164                                 //cfg->verbose_level = 5;
13165                         }
13166                         if (count <= atoi (getenv ("MONO_COUNT")))
13167                                 cfg->new_ir = TRUE;
13168
13169                         /*
13170                          * Passing/returning vtypes in registers in managed methods is an ABI change 
13171                          * from the old JIT.
13172                          */
13173                         disable_vtypes_in_regs = TRUE;
13174                 }
13175                 else
13176                         cfg->new_ir = TRUE;
13177         }
13178
13179         /* 
13180         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")))
13181                 cfg->globalra = TRUE;
13182         */
13183
13184         //cfg->globalra = TRUE;
13185
13186         //if (!strcmp (cfg->method->klass->name, "Tests") && !cfg->method->wrapper_type)
13187         //      cfg->globalra = TRUE;
13188
13189         {
13190                 static int count = 0;
13191                 count ++;
13192
13193                 if (getenv ("COUNT2")) {
13194                         if (count == atoi (getenv ("COUNT2")))
13195                                 printf ("LAST: %s\n", mono_method_full_name (cfg->method, TRUE));
13196                         if (count > atoi (getenv ("COUNT2")))
13197                                 cfg->globalra = FALSE;
13198                 }
13199         }
13200
13201         if (header->clauses)
13202                 cfg->globalra = FALSE;
13203
13204         if (cfg->method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED)
13205                 /* The code in the prolog clobbers caller saved registers */
13206                 cfg->globalra = FALSE;
13207
13208         // FIXME: Disable globalra in case of tracing/profiling
13209
13210         if (cfg->method->save_lmf)
13211                 /* The LMF saving code might clobber caller saved registers */
13212                 cfg->globalra = FALSE;
13213
13214         // FIXME:
13215         if (!strcmp (cfg->method->name, "CompareInternal"))
13216                 cfg->globalra = FALSE;
13217
13218         /*
13219         if (strstr (cfg->method->name, "LoadData"))
13220                 cfg->new_ir = FALSE;
13221         */
13222
13223         if (cfg->new_ir) {
13224                 cfg->rs = mono_regstate_new ();
13225                 cfg->next_vreg = cfg->rs->next_vreg;
13226         }
13227
13228         /* FIXME: Fix SSA to handle branches inside bblocks */
13229         if (cfg->opt & MONO_OPT_SSA)
13230                 cfg->enable_extended_bblocks = FALSE;
13231
13232         /*
13233          * FIXME: This confuses liveness analysis because variables which are assigned after
13234          * a branch inside a bblock become part of the kill set, even though the assignment
13235          * might not get executed. This causes the optimize_initlocals pass to delete some
13236          * assignments which are needed.
13237          * Also, the mono_if_conversion pass needs to be modified to recognize the code
13238          * created by this.
13239          */
13240         //cfg->enable_extended_bblocks = TRUE;
13241
13242         /*
13243          * create MonoInst* which represents arguments and local variables
13244          */
13245         mono_compile_create_vars (cfg);
13246
13247         if (cfg->new_ir) {
13248                 /* SSAPRE is not supported on linear IR */
13249                 cfg->opt &= ~MONO_OPT_SSAPRE;
13250
13251                 i = mono_method_to_ir2 (cfg, method_to_compile, NULL, NULL, NULL, NULL, NULL, 0, FALSE);
13252         }
13253         else {
13254                 i = mono_method_to_ir (cfg, method_to_compile, NULL, NULL, cfg->locals_start, NULL, NULL, NULL, 0, FALSE);
13255         }
13256
13257         if (i < 0) {
13258                 if (try_generic_shared && cfg->exception_type == MONO_EXCEPTION_GENERIC_SHARING_FAILED) {
13259                         if (compile_aot) {
13260                                 if (MONO_PROBE_METHOD_COMPILE_END_ENABLED ())
13261                                         MONO_PROBE_METHOD_COMPILE_END (method, FALSE);
13262                                 return cfg;
13263                         }
13264                         mono_destroy_compile (cfg);
13265                         try_generic_shared = FALSE;
13266                         goto restart_compile;
13267                 }
13268                 g_assert (cfg->exception_type != MONO_EXCEPTION_GENERIC_SHARING_FAILED);
13269
13270                 if (MONO_PROBE_METHOD_COMPILE_END_ENABLED ())
13271                         MONO_PROBE_METHOD_COMPILE_END (method, FALSE);
13272                 if (cfg->prof_options & MONO_PROFILE_JIT_COMPILATION)
13273                         mono_profiler_method_end_jit (method, NULL, MONO_PROFILE_FAILED);
13274                 /* cfg contains the details of the failure, so let the caller cleanup */
13275                 return cfg;
13276         }
13277
13278         mono_jit_stats.basic_blocks += cfg->num_bblocks;
13279         mono_jit_stats.max_basic_blocks = MAX (cfg->num_bblocks, mono_jit_stats.max_basic_blocks);
13280
13281         /*g_print ("numblocks = %d\n", cfg->num_bblocks);*/
13282
13283         if (cfg->new_ir) {
13284                 mono_decompose_long_opts (cfg);
13285
13286                 /* Should be done before branch opts */
13287                 if (cfg->opt & (MONO_OPT_CONSPROP | MONO_OPT_COPYPROP))
13288                         mono_local_cprop2 (cfg);
13289         }
13290
13291         if (cfg->opt & MONO_OPT_BRANCH)
13292                 mono_optimize_branches (cfg);
13293
13294         if (cfg->new_ir) {
13295                 /* This must be done _before_ global reg alloc and _after_ decompose */
13296                 mono_handle_global_vregs (cfg);
13297                 mono_local_deadce (cfg);
13298                 mono_if_conversion (cfg);
13299         }
13300
13301         if ((cfg->opt & MONO_OPT_SSAPRE) || cfg->globalra)
13302                 mono_remove_critical_edges (cfg);
13303
13304         /* Depth-first ordering on basic blocks */
13305         cfg->bblocks = mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * (cfg->num_bblocks + 1));
13306
13307         dfn = 0;
13308         df_visit (cfg->bb_entry, &dfn, cfg->bblocks);
13309         if (cfg->num_bblocks != dfn + 1) {
13310                 MonoBasicBlock *bb;
13311
13312                 cfg->num_bblocks = dfn + 1;
13313
13314                 /* remove unreachable code, because the code in them may be 
13315                  * inconsistent  (access to dead variables for example) */
13316                 for (bb = cfg->bb_entry; bb;) {
13317                         MonoBasicBlock *bbn = bb->next_bb;
13318
13319                         /* 
13320                          * FIXME: Can't use the second case in methods with clauses, since the 
13321                          * bblocks inside the clauses are not processed during dfn computation.
13322                          */
13323                         if ((header->clauses && (bbn && bbn->region == -1 && bbn->in_count == 0)) ||
13324                                 (!header->clauses && (bbn && bbn->region == -1 && !bbn->dfn))) {
13325                                 if (cfg->verbose_level > 1)
13326                                         g_print ("found unreachable code in BB%d\n", bbn->block_num);
13327                                 /* There may exist unreachable branches to this bb */
13328                                 bb->next_bb = bbn->next_bb;
13329                                 nullify_basic_block (bbn);                      
13330                         } else {
13331                                 bb = bb->next_bb;
13332                         }
13333                 }
13334         }
13335
13336         if (((cfg->num_varinfo > 2000) || (cfg->num_bblocks > 1000)) && !cfg->compile_aot) {
13337                 /* 
13338                  * we disable some optimizations if there are too many variables
13339                  * because JIT time may become too expensive. The actual number needs 
13340                  * to be tweaked and eventually the non-linear algorithms should be fixed.
13341                  */
13342                 cfg->opt &= ~ (MONO_OPT_LINEARS | MONO_OPT_COPYPROP | MONO_OPT_CONSPROP);
13343                 cfg->disable_ssa = TRUE;
13344         }
13345
13346         if (cfg->opt & MONO_OPT_LOOP) {
13347                 mono_compile_dominator_info (cfg, MONO_COMP_DOM | MONO_COMP_IDOM);
13348                 mono_compute_natural_loops (cfg);
13349         }
13350
13351         /* after method_to_ir */
13352         if (parts == 1) {
13353                 if (MONO_PROBE_METHOD_COMPILE_END_ENABLED ())
13354                         MONO_PROBE_METHOD_COMPILE_END (method, TRUE);
13355                 return cfg;
13356         }
13357
13358 //#define DEBUGSSA "logic_run"
13359 #define DEBUGSSA_CLASS "Tests"
13360 #ifdef DEBUGSSA
13361
13362         if (!header->num_clauses && !cfg->disable_ssa) {
13363                 mono_local_cprop (cfg);
13364
13365 #ifndef DISABLE_SSA
13366                 if (cfg->new_ir)
13367                         mono_ssa_compute2 (cfg);
13368                 else
13369                         mono_ssa_compute (cfg);
13370 #endif
13371         }
13372 #else 
13373         if (cfg->opt & MONO_OPT_SSA) {
13374                 if (!(cfg->comp_done & MONO_COMP_SSA) && !header->num_clauses && !cfg->disable_ssa) {
13375 #ifndef DISABLE_SSA
13376                         if (!cfg->new_ir)
13377                                 mono_local_cprop (cfg);
13378                         if (cfg->new_ir)
13379                                 mono_ssa_compute2 (cfg);
13380                         else
13381                                 mono_ssa_compute (cfg);
13382 #endif
13383
13384                         if (cfg->verbose_level >= 2) {
13385                                 print_dfn (cfg);
13386                         }
13387                 }
13388         }
13389 #endif
13390
13391         /* after SSA translation */
13392         if (parts == 2) {
13393                 if (MONO_PROBE_METHOD_COMPILE_END_ENABLED ())
13394                         MONO_PROBE_METHOD_COMPILE_END (method, TRUE);
13395                 return cfg;
13396         }
13397
13398         if ((cfg->opt & MONO_OPT_CONSPROP) || (cfg->opt & MONO_OPT_COPYPROP)) {
13399                 if (cfg->comp_done & MONO_COMP_SSA) {
13400 #ifndef DISABLE_SSA
13401                         if (cfg->new_ir)
13402                                 mono_ssa_cprop2 (cfg);
13403                         else
13404                                 mono_ssa_cprop (cfg);
13405 #endif
13406                 } else {
13407                         if (!cfg->new_ir)
13408                                 mono_local_cprop (cfg);
13409                 }
13410         }
13411
13412 #ifndef DISABLE_SSA
13413         if (cfg->comp_done & MONO_COMP_SSA) {                   
13414                 //mono_ssa_strength_reduction (cfg);
13415
13416                 if (cfg->opt & MONO_OPT_SSAPRE) {
13417                         mono_perform_ssapre (cfg);
13418                         //mono_local_cprop (cfg);
13419                 }
13420
13421                 if (cfg->opt & MONO_OPT_DEADCE) {
13422                         if (cfg->new_ir)
13423                                 mono_ssa_deadce2 (cfg);
13424                         else
13425                                 mono_ssa_deadce (cfg);
13426                         deadce_has_run = TRUE;
13427                 }
13428
13429                 if (cfg->new_ir) {
13430                         if ((cfg->flags & (MONO_CFG_HAS_LDELEMA|MONO_CFG_HAS_CHECK_THIS)) && (cfg->opt & MONO_OPT_ABCREM))
13431                                 mono_perform_abc_removal2 (cfg);
13432                 } else {
13433                         if ((cfg->flags & MONO_CFG_HAS_LDELEMA) && (cfg->opt & MONO_OPT_ABCREM))
13434                                 mono_perform_abc_removal (cfg);
13435                 }
13436
13437                 if (cfg->new_ir) {
13438                         mono_ssa_remove2 (cfg);
13439                         mono_local_cprop2 (cfg);
13440                         mono_handle_global_vregs (cfg);
13441                         mono_local_deadce (cfg);
13442                 }
13443                 else
13444                         mono_ssa_remove (cfg);
13445
13446                 if (cfg->opt & MONO_OPT_BRANCH) {
13447                         MonoBasicBlock *bb;
13448
13449                         mono_optimize_branches (cfg);
13450
13451                         /* Have to recompute cfg->bblocks and bb->dfn */
13452                         if (cfg->globalra) {
13453                                 mono_remove_critical_edges (cfg);
13454
13455                                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
13456                                         bb->dfn = 0;
13457
13458                                 /* Depth-first ordering on basic blocks */
13459                                 cfg->bblocks = mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * (cfg->num_bblocks + 1));
13460
13461                                 dfn = 0;
13462                                 df_visit (cfg->bb_entry, &dfn, cfg->bblocks);
13463                                 cfg->num_bblocks = dfn + 1;
13464                         }
13465                 }
13466         }
13467 #endif
13468
13469         /* after SSA removal */
13470         if (parts == 3) {
13471                 if (MONO_PROBE_METHOD_COMPILE_END_ENABLED ())
13472                         MONO_PROBE_METHOD_COMPILE_END (method, TRUE);
13473                 return cfg;
13474         }
13475
13476         if (cfg->new_ir) {
13477 #ifdef MONO_ARCH_SOFT_FLOAT
13478                 mono_handle_soft_float (cfg);
13479 #endif
13480                 mono_decompose_vtype_opts (cfg);
13481                 if (cfg->flags & MONO_CFG_HAS_ARRAY_ACCESS)
13482                         mono_decompose_array_access_opts (cfg);
13483         }
13484
13485         if (!cfg->new_ir) {
13486                 if (cfg->verbose_level > 4)
13487                         mono_print_code (cfg, "BEFORE DECOMPOSE");
13488
13489                 decompose_pass (cfg);
13490         }
13491
13492         if (cfg->got_var) {
13493                 GList *regs;
13494
13495                 g_assert (cfg->got_var_allocated);
13496
13497                 /* 
13498                  * Allways allocate the GOT var to a register, because keeping it
13499                  * in memory will increase the number of live temporaries in some
13500                  * code created by inssel.brg, leading to the well known spills+
13501                  * branches problem. Testcase: mcs crash in 
13502                  * System.MonoCustomAttrs:GetCustomAttributes.
13503                  */
13504                 regs = mono_arch_get_global_int_regs (cfg);
13505                 g_assert (regs);
13506                 cfg->got_var->opcode = OP_REGVAR;
13507                 cfg->got_var->dreg = GPOINTER_TO_INT (regs->data);
13508                 cfg->used_int_regs |= 1LL << cfg->got_var->dreg;
13509                 
13510                 g_list_free (regs);
13511         }
13512
13513         /* todo: remove code when we have verified that the liveness for try/catch blocks
13514          * works perfectly 
13515          */
13516         /* 
13517          * Currently, this can't be commented out since exception blocks are not
13518          * processed during liveness analysis.
13519          */
13520         mono_liveness_handle_exception_clauses (cfg);
13521
13522         if (cfg->globalra) {
13523                 MonoBasicBlock *bb;
13524
13525                 /* Have to do this before regalloc since it can create vregs */
13526                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
13527                         mono_arch_lowering_pass (cfg, bb);
13528
13529                 mono_global_regalloc (cfg);
13530         }
13531
13532         if ((cfg->opt & MONO_OPT_LINEARS) && !cfg->globalra) {
13533                 GList *vars, *regs;
13534                 
13535                 /* For now, compute aliasing info only if needed for deadce... */
13536                 if (!cfg->new_ir && (cfg->opt & MONO_OPT_DEADCE) && (! deadce_has_run) && (header->num_clauses == 0)) {
13537                         cfg->aliasing_info = mono_build_aliasing_information (cfg);
13538                 }
13539
13540                 /* fixme: maybe we can avoid to compute livenesss here if already computed ? */
13541                 cfg->comp_done &= ~MONO_COMP_LIVENESS;
13542                 if (!(cfg->comp_done & MONO_COMP_LIVENESS))
13543                         mono_analyze_liveness (cfg);
13544
13545                 if (cfg->aliasing_info != NULL) {
13546                         mono_aliasing_deadce (cfg->aliasing_info);
13547                         deadce_has_run = TRUE;
13548                 }
13549                 
13550                 if ((vars = mono_arch_get_allocatable_int_vars (cfg))) {
13551                         regs = mono_arch_get_global_int_regs (cfg);
13552                         if (cfg->got_var)
13553                                 regs = g_list_delete_link (regs, regs);
13554                         mono_linear_scan (cfg, vars, regs, &cfg->used_int_regs);
13555                 }
13556                 
13557                 if (cfg->aliasing_info != NULL) {
13558                         mono_destroy_aliasing_information (cfg->aliasing_info);
13559                         cfg->aliasing_info = NULL;
13560                 }
13561         }
13562
13563         //mono_print_code (cfg);
13564
13565     //print_dfn (cfg);
13566         
13567         /* variables are allocated after decompose, since decompose could create temps */
13568         if (!cfg->globalra)
13569                 mono_arch_allocate_vars (cfg);
13570
13571         if (!cfg->new_ir && cfg->opt & MONO_OPT_CFOLD)
13572                 mono_constant_fold (cfg);
13573
13574         if (cfg->new_ir) {
13575                 MonoBasicBlock *bb;
13576                 gboolean need_local_opts;
13577
13578                 if (!cfg->globalra) {
13579                         mono_spill_global_vars (cfg, &need_local_opts);
13580
13581                         if (need_local_opts || cfg->compile_aot) {
13582                                 /* To optimize code created by spill_global_vars */
13583                                 mono_local_cprop2 (cfg);
13584                                 mono_local_deadce (cfg);
13585                         }
13586                 }
13587
13588                 /* Add branches between non-consecutive bblocks */
13589                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
13590                         if (bb->last_ins && MONO_IS_COND_BRANCH_OP (bb->last_ins) &&
13591                                 bb->last_ins->inst_false_bb && bb->next_bb != bb->last_ins->inst_false_bb) {
13592                                 /* we are careful when inverting, since bugs like #59580
13593                                  * could show up when dealing with NaNs.
13594                                  */
13595                                 if (MONO_IS_COND_BRANCH_NOFP(bb->last_ins) && bb->next_bb == bb->last_ins->inst_true_bb) {
13596                                         MonoBasicBlock *tmp =  bb->last_ins->inst_true_bb;
13597                                         bb->last_ins->inst_true_bb = bb->last_ins->inst_false_bb;
13598                                         bb->last_ins->inst_false_bb = tmp;
13599
13600                                         bb->last_ins->opcode = reverse_branch_op (bb->last_ins->opcode);
13601                                 } else {                        
13602                                         MonoInst *inst = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst));
13603                                         inst->opcode = OP_BR;
13604                                         inst->inst_target_bb = bb->last_ins->inst_false_bb;
13605                                         mono_bblock_add_inst (bb, inst);
13606                                 }
13607                         }
13608                 }
13609
13610                 if (cfg->verbose_level >= 4 && !cfg->globalra) {
13611                         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
13612                                 MonoInst *tree = bb->code;      
13613                                 g_print ("DUMP BLOCK %d:\n", bb->block_num);
13614                                 if (!tree)
13615                                         continue;
13616                                 for (; tree; tree = tree->next) {
13617                                         mono_print_ins_index (-1, tree);
13618                                 }
13619                         }
13620                 }
13621
13622                 /* FIXME: */
13623                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
13624                         bb->max_vreg = cfg->next_vreg;
13625                 }
13626         }
13627         else
13628                 mini_select_instructions (cfg);
13629
13630         mono_codegen (cfg);
13631         if (cfg->verbose_level >= 2) {
13632                 char *id =  mono_method_full_name (cfg->method, FALSE);
13633                 mono_disassemble_code (cfg, cfg->native_code, cfg->code_len, id + 3);
13634                 g_free (id);
13635         }
13636
13637         if (cfg->generic_sharing_context)
13638                 generic_info_size = sizeof (MonoGenericJitInfo);
13639         else
13640                 generic_info_size = 0;
13641
13642         if (cfg->method->dynamic) {
13643                 jinfo = g_malloc0 (sizeof (MonoJitInfo) + (header->num_clauses * sizeof (MonoJitExceptionInfo)) +
13644                                 generic_info_size);
13645         } else {
13646                 /* we access cfg->domain->mp */
13647                 mono_domain_lock (cfg->domain);
13648                 jinfo = mono_mempool_alloc0 (cfg->domain->mp, sizeof (MonoJitInfo) +
13649                                 (header->num_clauses * sizeof (MonoJitExceptionInfo)) +
13650                                 generic_info_size);
13651                 mono_domain_unlock (cfg->domain);
13652         }
13653
13654         if (cfg->generic_sharing_context) {
13655                 MonoGenericContext object_context;
13656
13657                 g_assert (!method_to_compile->klass->generic_class);
13658                 if (method_to_compile->klass->generic_container) {
13659                         int type_argc = method_to_compile->klass->generic_container->type_argc;
13660
13661                         object_context.class_inst = get_object_generic_inst (type_argc);
13662                 } else {
13663                         object_context.class_inst = NULL;
13664                 }
13665
13666                 if (mini_method_get_context (method_to_compile)->method_inst) {
13667                         int type_argc = mini_method_get_context (method_to_compile)->method_inst->type_argc;
13668
13669                         object_context.method_inst = get_object_generic_inst (type_argc);
13670                 } else {
13671                         object_context.method_inst = NULL;
13672                 }
13673
13674                 g_assert (object_context.class_inst || object_context.method_inst);
13675
13676                 method_to_register = mono_class_inflate_generic_method (method_to_compile, &object_context);
13677         } else {
13678                 g_assert (method == method_to_compile);
13679                 method_to_register = method;
13680         }
13681
13682         jinfo->method = method_to_register;
13683         jinfo->code_start = cfg->native_code;
13684         jinfo->code_size = cfg->code_len;
13685         jinfo->used_regs = cfg->used_int_regs;
13686         jinfo->domain_neutral = (cfg->opt & MONO_OPT_SHARED) != 0;
13687         jinfo->cas_inited = FALSE; /* initialization delayed at the first stalk walk using this method */
13688         jinfo->num_clauses = header->num_clauses;
13689
13690         if (cfg->generic_sharing_context) {
13691                 MonoInst *inst;
13692                 MonoGenericJitInfo *gi;
13693
13694                 jinfo->has_generic_jit_info = 1;
13695
13696                 gi = mono_jit_info_get_generic_jit_info (jinfo);
13697                 g_assert (gi);
13698
13699                 gi->generic_sharing_context = cfg->generic_sharing_context;
13700
13701                 /*
13702                  * Non-generic static methods only get a "this" info
13703                  * if they use the rgctx variable (which they are
13704                  * forced to if they have any open catch clauses).
13705                  */
13706                 if (cfg->rgctx_var ||
13707                                 (!(method_to_compile->flags & METHOD_ATTRIBUTE_STATIC) &&
13708                                 !mini_method_get_context (method_to_compile)->method_inst)) {
13709                         gi->has_this = 1;
13710
13711                         if ((method_to_compile->flags & METHOD_ATTRIBUTE_STATIC) ||
13712                                         mini_method_get_context (method_to_compile)->method_inst) {
13713                                 inst = cfg->rgctx_var;
13714                                 g_assert (inst->opcode == OP_REGOFFSET);
13715                         } else {
13716                                 inst = cfg->args [0];
13717                         }
13718
13719                         if (inst->opcode == OP_REGVAR) {
13720                                 gi->this_in_reg = 1;
13721                                 gi->this_reg = inst->dreg;
13722
13723                                 //g_print ("this in reg %d\n", inst->dreg);
13724                         } else {
13725                                 g_assert (inst->opcode == OP_REGOFFSET);
13726 #ifdef __i386__
13727                                 g_assert (inst->inst_basereg == X86_EBP);
13728 #elif defined(__x86_64__)
13729                                 g_assert (inst->inst_basereg == X86_EBP || inst->inst_basereg == X86_ESP);
13730 #endif
13731                                 g_assert (inst->inst_offset >= G_MININT32 && inst->inst_offset <= G_MAXINT32);
13732
13733                                 gi->this_in_reg = 0;
13734                                 gi->this_reg = inst->inst_basereg;
13735                                 gi->this_offset = inst->inst_offset;
13736
13737                                 //g_print ("this at offset %d from reg %d\n", gi->this_offset, gi->this_reg);
13738                         }
13739                 } else {
13740                         gi->has_this = 0;
13741                 }
13742         }
13743
13744         if (header->num_clauses) {
13745                 int i;
13746
13747                 for (i = 0; i < header->num_clauses; i++) {
13748                         MonoExceptionClause *ec = &header->clauses [i];
13749                         MonoJitExceptionInfo *ei = &jinfo->clauses [i];
13750                         MonoBasicBlock *tblock;
13751                         MonoInst *exvar;
13752
13753                         ei->flags = ec->flags;
13754
13755                         exvar = mono_find_exvar_for_offset (cfg, ec->handler_offset);
13756                         ei->exvar_offset = exvar ? exvar->inst_offset : 0;
13757
13758                         if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
13759                                 tblock = cfg->cil_offset_to_bb [ec->data.filter_offset];
13760                                 g_assert (tblock);
13761                                 ei->data.filter = cfg->native_code + tblock->native_offset;
13762                         } else {
13763                                 ei->data.catch_class = ec->data.catch_class;
13764                         }
13765
13766                         tblock = cfg->cil_offset_to_bb [ec->try_offset];
13767                         g_assert (tblock);
13768                         ei->try_start = cfg->native_code + tblock->native_offset;
13769                         g_assert (tblock->native_offset);
13770                         tblock = cfg->cil_offset_to_bb [ec->try_offset + ec->try_len];
13771                         g_assert (tblock);
13772                         ei->try_end = cfg->native_code + tblock->native_offset;
13773                         g_assert (tblock->native_offset);
13774                         tblock = cfg->cil_offset_to_bb [ec->handler_offset];
13775                         g_assert (tblock);
13776                         ei->handler_start = cfg->native_code + tblock->native_offset;
13777                 }
13778         }
13779
13780         cfg->jit_info = jinfo;
13781 #if defined(__arm__)
13782         mono_arch_fixup_jinfo (cfg);
13783 #endif
13784
13785         if (!cfg->compile_aot) {
13786                 mono_domain_lock (cfg->domain);
13787                 mono_jit_info_table_add (cfg->domain, jinfo);
13788
13789                 if (cfg->method->dynamic)
13790                         mono_dynamic_code_hash_lookup (cfg->domain, cfg->method)->ji = jinfo;
13791                 mono_domain_unlock (cfg->domain);
13792         }
13793
13794         /* collect statistics */
13795         mono_perfcounters->jit_methods++;
13796         mono_perfcounters->jit_bytes += header->code_size;
13797         mono_jit_stats.allocated_code_size += cfg->code_len;
13798         code_size_ratio = cfg->code_len;
13799         if (code_size_ratio > mono_jit_stats.biggest_method_size && mono_jit_stats.enabled) {
13800                 mono_jit_stats.biggest_method_size = code_size_ratio;
13801                 g_free (mono_jit_stats.biggest_method);
13802                 mono_jit_stats.biggest_method = g_strdup_printf ("%s::%s)", method->klass->name, method->name);
13803         }
13804         code_size_ratio = (code_size_ratio * 100) / mono_method_get_header (method)->code_size;
13805         if (code_size_ratio > mono_jit_stats.max_code_size_ratio && mono_jit_stats.enabled) {
13806                 mono_jit_stats.max_code_size_ratio = code_size_ratio;
13807                 g_free (mono_jit_stats.max_ratio_method);
13808                 mono_jit_stats.max_ratio_method = g_strdup_printf ("%s::%s)", method->klass->name, method->name);
13809         }
13810         mono_jit_stats.native_code_size += cfg->code_len;
13811
13812         if (MONO_PROBE_METHOD_COMPILE_END_ENABLED ())
13813                 MONO_PROBE_METHOD_COMPILE_END (method, TRUE);
13814         if (cfg->prof_options & MONO_PROFILE_JIT_COMPILATION)
13815                 mono_profiler_method_end_jit (method, jinfo, MONO_PROFILE_OK);
13816
13817         return cfg;
13818 }
13819
13820 static MonoJitInfo*
13821 lookup_generic_method (MonoDomain *domain, MonoMethod *method)
13822 {
13823         MonoMethod *open_method;
13824
13825         if (!mono_method_is_generic_sharable_impl (method, FALSE))
13826                 return NULL;
13827
13828         open_method = mono_method_get_declaring_generic_method (method);
13829
13830         return mono_domain_lookup_shared_generic (domain, open_method);
13831 }
13832
13833 /*
13834  * LOCKING: Assumes domain->jit_code_hash_lock is held.
13835  */
13836 static MonoJitInfo*
13837 lookup_method_inner (MonoDomain *domain, MonoMethod *method)
13838 {
13839         MonoJitInfo *ji = mono_internal_hash_table_lookup (&domain->jit_code_hash, method);
13840
13841         if (ji)
13842                 return ji;
13843
13844         return lookup_generic_method (domain, method);
13845 }
13846
13847 static MonoJitInfo*
13848 lookup_method (MonoDomain *domain, MonoMethod *method)
13849 {
13850         MonoJitInfo *info;
13851
13852         mono_domain_jit_code_hash_lock (domain);
13853         info = lookup_method_inner (domain, method);
13854         mono_domain_jit_code_hash_unlock (domain);
13855
13856         return info;
13857 }
13858
13859 static gpointer
13860 mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, int opt)
13861 {
13862         MonoCompile *cfg;
13863         gpointer code = NULL;
13864         MonoJitInfo *info;
13865         MonoVTable *vtable;
13866
13867 #ifdef MONO_USE_AOT_COMPILER
13868         if ((opt & MONO_OPT_AOT) && !(mono_profiler_get_events () & MONO_PROFILE_JIT_COMPILATION)) {
13869                 MonoDomain *domain = mono_domain_get ();
13870
13871                 mono_class_init (method->klass);
13872
13873                 mono_domain_lock (domain);
13874                 if ((code = mono_aot_get_method (domain, method))) {
13875                         mono_domain_unlock (domain);
13876                         vtable = mono_class_vtable (domain, method->klass);
13877                         g_assert (vtable);
13878                         mono_runtime_class_init (vtable);
13879                         return code;
13880                 }
13881
13882                 mono_domain_unlock (domain);
13883         }
13884 #endif
13885
13886         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
13887             (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
13888                 MonoMethod *nm;
13889                 MonoMethodPInvoke* piinfo = (MonoMethodPInvoke *) method;
13890
13891                 if (!piinfo->addr) {
13892                         if (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL)
13893                                 piinfo->addr = mono_lookup_internal_call (method);
13894                         else if (method->iflags & METHOD_IMPL_ATTRIBUTE_NATIVE)
13895 #ifdef PLATFORM_WIN32
13896                                 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);
13897 #else
13898                                 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);
13899 #endif
13900                         else
13901                                 mono_lookup_pinvoke_call (method, NULL, NULL);
13902                 }
13903                 nm = mono_marshal_get_native_wrapper (method, check_for_pending_exc, FALSE);
13904                 return mono_get_addr_from_ftnptr (mono_compile_method (nm));
13905
13906                 //if (mono_debug_format != MONO_DEBUG_FORMAT_NONE) 
13907                 //mono_debug_add_wrapper (method, nm);
13908         } else if ((method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME)) {
13909                 const char *name = method->name;
13910                 MonoMethod *nm;
13911
13912                 if (method->klass->parent == mono_defaults.multicastdelegate_class) {
13913                         if (*name == '.' && (strcmp (name, ".ctor") == 0)) {
13914                                 MonoJitICallInfo *mi = mono_find_jit_icall_by_name ("mono_delegate_ctor");
13915                                 g_assert (mi);
13916                                 return mono_get_addr_from_ftnptr ((gpointer)mono_icall_get_wrapper (mi));
13917                         } else if (*name == 'I' && (strcmp (name, "Invoke") == 0)) {
13918 #ifdef MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE
13919                                 return mono_create_delegate_trampoline (method->klass);
13920 #else
13921                                 nm = mono_marshal_get_delegate_invoke (method, NULL);
13922                                 return mono_get_addr_from_ftnptr (mono_compile_method (nm));
13923 #endif
13924                         } else if (*name == 'B' && (strcmp (name, "BeginInvoke") == 0)) {
13925                                 nm = mono_marshal_get_delegate_begin_invoke (method);
13926                                 return mono_get_addr_from_ftnptr (mono_compile_method (nm));
13927                         } else if (*name == 'E' && (strcmp (name, "EndInvoke") == 0)) {
13928                                 nm = mono_marshal_get_delegate_end_invoke (method);
13929                                 return mono_get_addr_from_ftnptr (mono_compile_method (nm));
13930                         }
13931                 }
13932                 return NULL;
13933         }
13934
13935         if (mono_aot_only)
13936                 g_error ("Attempting to JIT compile method '%s' while running with --aot-only.\n", mono_method_full_name (method, TRUE));
13937
13938         cfg = mini_method_compile (method, opt, target_domain, TRUE, FALSE, 0);
13939
13940         switch (cfg->exception_type) {
13941         case MONO_EXCEPTION_NONE:
13942                 break;
13943         case MONO_EXCEPTION_TYPE_LOAD:
13944         case MONO_EXCEPTION_MISSING_FIELD:
13945         case MONO_EXCEPTION_MISSING_METHOD:
13946         case MONO_EXCEPTION_FILE_NOT_FOUND:
13947         case MONO_EXCEPTION_BAD_IMAGE: {
13948                 /* Throw a type load exception if needed */
13949                 MonoLoaderError *error = mono_loader_get_last_error ();
13950                 MonoException *ex;
13951
13952                 if (error) {
13953                         ex = mono_loader_error_prepare_exception (error);
13954                 } else {
13955                         if (cfg->exception_ptr) {
13956                                 ex = mono_class_get_exception_for_failure (cfg->exception_ptr);
13957                         } else {
13958                                 if (cfg->exception_type == MONO_EXCEPTION_MISSING_FIELD)
13959                                         ex = mono_exception_from_name_msg (mono_defaults.corlib, "System", "MissingFieldException", cfg->exception_message);
13960                                 else if (cfg->exception_type == MONO_EXCEPTION_MISSING_METHOD)
13961                                         ex = mono_exception_from_name_msg (mono_defaults.corlib, "System", "MissingMethodException", cfg->exception_message);
13962                                 else if (cfg->exception_type == MONO_EXCEPTION_TYPE_LOAD)
13963                                         ex = mono_exception_from_name_msg (mono_defaults.corlib, "System", "TypeLoadException", cfg->exception_message);
13964                                 else if (cfg->exception_type == MONO_EXCEPTION_FILE_NOT_FOUND)
13965                                         ex = mono_exception_from_name_msg (mono_defaults.corlib, "System", "FileNotFoundException", cfg->exception_message);
13966                                 else if (cfg->exception_type == MONO_EXCEPTION_BAD_IMAGE)
13967                                         ex = mono_get_exception_bad_image_format (cfg->exception_message);
13968                                 else
13969                                         g_assert_not_reached ();
13970                         }
13971                 }
13972                 mono_destroy_compile (cfg);
13973                 mono_raise_exception (ex);
13974                 break;
13975         }
13976         case MONO_EXCEPTION_INVALID_PROGRAM: {
13977                 MonoException *ex = mono_exception_from_name_msg (mono_defaults.corlib, "System", "InvalidProgramException", cfg->exception_message);
13978                 mono_destroy_compile (cfg);
13979                 mono_raise_exception (ex);
13980                 break;
13981         }
13982         case MONO_EXCEPTION_UNVERIFIABLE_IL: {
13983                 MonoException *ex = mono_exception_from_name_msg (mono_defaults.corlib, "System.Security", "VerificationException", cfg->exception_message);
13984                 mono_destroy_compile (cfg);
13985                 mono_raise_exception (ex);
13986                 break;
13987         }
13988         case MONO_EXCEPTION_METHOD_ACCESS: {
13989                 MonoException *ex = mono_exception_from_name_msg (mono_defaults.corlib, "System", "MethodAccessException", cfg->exception_message);
13990                 mono_destroy_compile (cfg);
13991                 mono_raise_exception (ex);
13992                 break;
13993         }
13994         case MONO_EXCEPTION_FIELD_ACCESS: {
13995                 MonoException *ex = mono_exception_from_name_msg (mono_defaults.corlib, "System", "FieldAccessException", cfg->exception_message);
13996                 mono_destroy_compile (cfg);
13997                 mono_raise_exception (ex);
13998                 break;
13999         }
14000         /* this can only be set if the security manager is active */
14001         case MONO_EXCEPTION_SECURITY_LINKDEMAND: {
14002                 MonoSecurityManager* secman = mono_security_manager_get_methods ();
14003                 MonoObject *exc = NULL;
14004                 gpointer args [2];
14005
14006                 args [0] = &cfg->exception_data;
14007                 args [1] = &method;
14008                 mono_runtime_invoke (secman->linkdemandsecurityexception, NULL, args, &exc);
14009
14010                 mono_destroy_compile (cfg);
14011                 cfg = NULL;
14012
14013                 mono_raise_exception ((MonoException*)exc);
14014         }
14015         case MONO_EXCEPTION_OBJECT_SUPPLIED: {
14016                 MonoException *exp = cfg->exception_ptr;
14017                 MONO_GC_UNREGISTER_ROOT (cfg->exception_ptr);
14018                 mono_destroy_compile (cfg);
14019                 mono_raise_exception (exp);
14020                 break;
14021         }
14022         default:
14023                 g_assert_not_reached ();
14024         }
14025
14026         mono_domain_lock (target_domain);
14027
14028         /* Check if some other thread already did the job. In this case, we can
14029        discard the code this thread generated. */
14030
14031         mono_domain_jit_code_hash_lock (target_domain);
14032
14033         info = lookup_method_inner (target_domain, method);
14034         if (info) {
14035                 /* We can't use a domain specific method in another domain */
14036                 if ((target_domain == mono_domain_get ()) || info->domain_neutral) {
14037                         code = info->code_start;
14038 //                      printf("Discarding code for method %s\n", method->name);
14039                 }
14040         }
14041         
14042         if (code == NULL) {
14043                 mono_internal_hash_table_insert (&target_domain->jit_code_hash, cfg->jit_info->method, cfg->jit_info);
14044                 mono_domain_jit_code_hash_unlock (target_domain);
14045                 code = cfg->native_code;
14046
14047                 if (cfg->generic_sharing_context && mono_method_is_generic_sharable_impl (method, FALSE)) {
14048                         /* g_print ("inserting method %s.%s.%s\n", method->klass->name_space, method->klass->name, method->name); */
14049                         mono_domain_register_shared_generic (target_domain, 
14050                                 mono_method_get_declaring_generic_method (method), cfg->jit_info);
14051                         mono_stats.generics_shared_methods++;
14052                 }
14053         } else {
14054                 mono_domain_jit_code_hash_unlock (target_domain);
14055         }
14056
14057         mono_destroy_compile (cfg);
14058
14059         if (target_domain->jump_target_hash) {
14060                 MonoJumpInfo patch_info;
14061                 GSList *list, *tmp;
14062                 list = g_hash_table_lookup (target_domain->jump_target_hash, method);
14063                 if (list) {
14064                         patch_info.next = NULL;
14065                         patch_info.ip.i = 0;
14066                         patch_info.type = MONO_PATCH_INFO_METHOD_JUMP;
14067                         patch_info.data.method = method;
14068                         g_hash_table_remove (target_domain->jump_target_hash, method);
14069                 }
14070                 for (tmp = list; tmp; tmp = tmp->next)
14071                         mono_arch_patch_code (NULL, target_domain, tmp->data, &patch_info, TRUE);
14072                 g_slist_free (list);
14073         }
14074
14075         mono_domain_unlock (target_domain);
14076
14077         vtable = mono_class_vtable (target_domain, method->klass);
14078         if (!vtable) {
14079                 MonoException *exc;
14080                 exc = mono_class_get_exception_for_failure (method->klass);
14081                 g_assert (exc);
14082                 mono_raise_exception (exc);
14083         }
14084         mono_runtime_class_init (vtable);
14085         return code;
14086 }
14087
14088 static gpointer
14089 mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt)
14090 {
14091         MonoDomain *target_domain, *domain = mono_domain_get ();
14092         MonoJitInfo *info;
14093         gpointer p;
14094         MonoJitICallInfo *callinfo = NULL;
14095
14096         /*
14097          * ICALL wrappers are handled specially, since there is only one copy of them
14098          * shared by all appdomains.
14099          */
14100         if ((method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) && (strstr (method->name, "__icall_wrapper_") == method->name)) {
14101                 const char *icall_name;
14102
14103                 icall_name = method->name + strlen ("__icall_wrapper_");
14104                 g_assert (icall_name);
14105                 callinfo = mono_find_jit_icall_by_name (icall_name);
14106                 g_assert (callinfo);
14107
14108                 /* Must be domain neutral since there is only one copy */
14109                 opt |= MONO_OPT_SHARED;
14110         }
14111
14112         if (opt & MONO_OPT_SHARED)
14113                 target_domain = mono_get_root_domain ();
14114         else 
14115                 target_domain = domain;
14116
14117         info = lookup_method (target_domain, method);
14118         if (info) {
14119                 /* We can't use a domain specific method in another domain */
14120                 if (! ((domain != target_domain) && !info->domain_neutral)) {
14121                         MonoVTable *vtable;
14122
14123                         mono_jit_stats.methods_lookups++;
14124                         vtable = mono_class_vtable (domain, method->klass);
14125                         mono_runtime_class_init (vtable);
14126                         return mono_create_ftnptr (target_domain, info->code_start);
14127                 }
14128         }
14129
14130         p = mono_create_ftnptr (target_domain, mono_jit_compile_method_inner (method, target_domain, opt));
14131
14132         if (callinfo) {
14133                 mono_jit_lock ();
14134                 if (!callinfo->wrapper) {
14135                         callinfo->wrapper = p;
14136                         mono_register_jit_icall_wrapper (callinfo, p);
14137                         mono_debug_add_icall_wrapper (method, callinfo);
14138                 }
14139                 mono_jit_unlock ();
14140         }
14141
14142         return p;
14143 }
14144
14145 static gpointer
14146 mono_jit_compile_method (MonoMethod *method)
14147 {
14148         return mono_jit_compile_method_with_opt (method, default_opt);
14149 }
14150
14151 #ifdef MONO_ARCH_HAVE_INVALIDATE_METHOD
14152 static void
14153 invalidated_delegate_trampoline (char *desc)
14154 {
14155         g_error ("Unmanaged code called delegate of type %s which was already garbage collected.\n"
14156                  "See http://www.go-mono.com/delegate.html for an explanation and ways to fix this.",
14157                  desc);
14158 }
14159 #endif
14160
14161 /*
14162  * mono_jit_free_method:
14163  *
14164  *  Free all memory allocated by the JIT for METHOD.
14165  */
14166 static void
14167 mono_jit_free_method (MonoDomain *domain, MonoMethod *method)
14168 {
14169         MonoJitDynamicMethodInfo *ji;
14170         gboolean destroy = TRUE;
14171
14172         g_assert (method->dynamic);
14173
14174         mono_domain_lock (domain);
14175         ji = mono_dynamic_code_hash_lookup (domain, method);
14176         mono_domain_unlock (domain);
14177
14178         if (!ji)
14179                 return;
14180         mono_domain_lock (domain);
14181         g_hash_table_remove (domain->dynamic_code_hash, method);
14182         mono_internal_hash_table_remove (&domain->jit_code_hash, method);
14183         g_hash_table_remove (domain->jump_trampoline_hash, method);
14184         mono_domain_unlock (domain);
14185
14186 #ifdef MONO_ARCH_HAVE_INVALIDATE_METHOD
14187         if (debug_options.keep_delegates && method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
14188                 /*
14189                  * Instead of freeing the code, change it to call an error routine
14190                  * so people can fix their code.
14191                  */
14192                 char *type = mono_type_full_name (&method->klass->byval_arg);
14193                 char *type_and_method = g_strdup_printf ("%s.%s", type, method->name);
14194
14195                 g_free (type);
14196                 mono_arch_invalidate_method (ji->ji, invalidated_delegate_trampoline, type_and_method);
14197                 destroy = FALSE;
14198         }
14199 #endif
14200
14201         /* 
14202          * This needs to be done before freeing code_mp, since the code address is the
14203          * key in the table, so if we free the code_mp first, another thread can grab the
14204          * same code address and replace our entry in the table.
14205          */
14206         mono_jit_info_table_remove (domain, ji->ji);
14207
14208         if (destroy)
14209                 mono_code_manager_destroy (ji->code_mp);
14210         g_free (ji);
14211 }
14212
14213 gpointer
14214 mono_jit_find_compiled_method (MonoDomain *domain, MonoMethod *method)
14215 {
14216         MonoDomain *target_domain;
14217         MonoJitInfo *info;
14218
14219         if (default_opt & MONO_OPT_SHARED)
14220                 target_domain = mono_get_root_domain ();
14221         else 
14222                 target_domain = domain;
14223
14224         info = lookup_method (target_domain, method);
14225         if (info) {
14226                 /* We can't use a domain specific method in another domain */
14227                 if (! ((domain != target_domain) && !info->domain_neutral)) {
14228                         mono_jit_stats.methods_lookups++;
14229                         return info->code_start;
14230                 }
14231         }
14232
14233         return NULL;
14234 }
14235
14236 /**
14237  * mono_jit_runtime_invoke:
14238  * @method: the method to invoke
14239  * @obj: this pointer
14240  * @params: array of parameter values.
14241  * @exc: used to catch exceptions objects
14242  */
14243 static MonoObject*
14244 mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
14245 {
14246         MonoMethod *to_compile;
14247         MonoMethod *invoke;
14248         MonoObject *(*runtime_invoke) (MonoObject *this, void **params, MonoObject **exc, void* compiled_method);
14249         void* compiled_method;
14250         MonoVTable *vtable;
14251
14252         if (obj == NULL && !(method->flags & METHOD_ATTRIBUTE_STATIC) && !method->string_ctor && (method->wrapper_type == 0)) {
14253                 g_warning ("Ignoring invocation of an instance method on a NULL instance.\n");
14254                 return NULL;
14255         }
14256
14257         if (((method->flags & METHOD_ATTRIBUTE_STATIC) ||
14258                                 (method->is_inflated && mono_method_get_context (method)->method_inst)) &&
14259                         mono_class_generic_sharing_enabled (method->klass) &&
14260                         mono_method_is_generic_sharable_impl (method, FALSE)) {
14261                 to_compile = mono_marshal_get_static_rgctx_invoke (method);
14262         } else {
14263                 to_compile = method;
14264         }
14265
14266         invoke = mono_marshal_get_runtime_invoke (method);
14267         runtime_invoke = mono_jit_compile_method (invoke);
14268         
14269         /* We need this here becuase mono_marshal_get_runtime_invoke can be place 
14270          * the helper method in System.Object and not the target class
14271          */
14272         vtable = mono_class_vtable (mono_domain_get (), method->klass);
14273         g_assert (vtable);
14274         mono_runtime_class_init (vtable);
14275
14276         if (method->klass->rank && (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) &&
14277                 (method->iflags & METHOD_IMPL_ATTRIBUTE_NATIVE)) {
14278                 /* 
14279                  * Array Get/Set/Address methods. The JIT implements them using inline code 
14280                  * inside the runtime invoke wrappers, so no need to compile them.
14281                  */
14282                 compiled_method = NULL;
14283         } else {
14284                 compiled_method = mono_jit_compile_method (to_compile);
14285         }
14286         return runtime_invoke (obj, params, exc, compiled_method);
14287 }
14288
14289 #ifdef MONO_GET_CONTEXT
14290 #define GET_CONTEXT MONO_GET_CONTEXT
14291 #endif
14292
14293 #ifndef GET_CONTEXT
14294 #ifdef PLATFORM_WIN32
14295 #define GET_CONTEXT \
14296         struct sigcontext *ctx = (struct sigcontext*)_dummy;
14297 #else
14298 #ifdef MONO_ARCH_USE_SIGACTION
14299 #define GET_CONTEXT \
14300     void *ctx = context;
14301 #elif defined(__sparc__)
14302 #define GET_CONTEXT \
14303     void *ctx = sigctx;
14304 #else
14305 #define GET_CONTEXT \
14306         void **_p = (void **)&_dummy; \
14307         struct sigcontext *ctx = (struct sigcontext *)++_p;
14308 #endif
14309 #endif
14310 #endif
14311
14312 #ifdef MONO_ARCH_USE_SIGACTION
14313 #define SIG_HANDLER_SIGNATURE(ftn) ftn (int _dummy, siginfo_t *info, void *context)
14314 #elif defined(__sparc__)
14315 #define SIG_HANDLER_SIGNATURE(ftn) ftn (int _dummy, void *sigctx)
14316 #else
14317 #define SIG_HANDLER_SIGNATURE(ftn) ftn (int _dummy)
14318 #endif
14319
14320 static void
14321 SIG_HANDLER_SIGNATURE (sigfpe_signal_handler)
14322 {
14323         MonoException *exc = NULL;
14324 #ifndef MONO_ARCH_USE_SIGACTION
14325         void *info = NULL;
14326 #endif
14327         GET_CONTEXT;
14328
14329 #if defined(MONO_ARCH_HAVE_IS_INT_OVERFLOW)
14330         if (mono_arch_is_int_overflow (ctx, info))
14331                 exc = mono_get_exception_arithmetic ();
14332         else
14333                 exc = mono_get_exception_divide_by_zero ();
14334 #else
14335         exc = mono_get_exception_divide_by_zero ();
14336 #endif
14337         
14338         mono_arch_handle_exception (ctx, exc, FALSE);
14339 }
14340
14341 static void
14342 SIG_HANDLER_SIGNATURE (sigill_signal_handler)
14343 {
14344         MonoException *exc;
14345         GET_CONTEXT;
14346
14347         exc = mono_get_exception_execution_engine ("SIGILL");
14348         
14349         mono_arch_handle_exception (ctx, exc, FALSE);
14350 }
14351
14352 static void
14353 SIG_HANDLER_SIGNATURE (sigsegv_signal_handler)
14354 {
14355 #ifndef MONO_ARCH_SIGSEGV_ON_ALTSTACK
14356         MonoException *exc = NULL;
14357 #endif
14358         MonoJitInfo *ji;
14359         MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
14360
14361         GET_CONTEXT;
14362
14363 #ifdef MONO_ARCH_USE_SIGACTION
14364         if (debug_options.collect_pagefault_stats) {
14365                 if (mono_raw_buffer_is_pagefault (info->si_addr)) {
14366                         mono_raw_buffer_handle_pagefault (info->si_addr);
14367                         return;
14368                 }
14369                 if (mono_aot_is_pagefault (info->si_addr)) {
14370                         mono_aot_handle_pagefault (info->si_addr);
14371                         return;
14372                 }
14373         }
14374 #endif
14375
14376         /* The thread might no be registered with the runtime */
14377         if (!mono_domain_get () || !jit_tls)
14378                 mono_handle_native_sigsegv (SIGSEGV, ctx);
14379
14380         ji = mono_jit_info_table_find (mono_domain_get (), mono_arch_ip_from_context (ctx));
14381
14382 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
14383         /* we got a stack overflow in the soft-guard pages
14384          * There are two cases:
14385          * 1) managed code caused the overflow: we unprotect the soft-guard page
14386          * and let the arch-specific code trigger the exception handling mechanism
14387          * in the thread stack. The soft-guard pages will be protected again as the stack is unwound.
14388          * 2) unmanaged code caused the overflow: we unprotect the soft-guard page
14389          * and hope we can continue with those enabled, at least until the hard-guard page
14390          * is hit. The alternative to continuing here is to just print a message and abort.
14391          * We may add in the future the code to protect the pages again in the codepath
14392          * when we return from unmanaged to managed code.
14393          */
14394         if (jit_tls->stack_ovf_guard_size && (guint8*)info->si_addr >= (guint8*)jit_tls->stack_ovf_guard_base &&
14395                         (guint8*)info->si_addr < (guint8*)jit_tls->stack_ovf_guard_base + jit_tls->stack_ovf_guard_size) {
14396                 mono_mprotect (jit_tls->stack_ovf_guard_base, jit_tls->stack_ovf_guard_size, MONO_MMAP_READ|MONO_MMAP_WRITE|MONO_MMAP_EXEC);
14397                 if (ji) {
14398                         mono_arch_handle_altstack_exception (ctx, info->si_addr, TRUE);
14399                 } else {
14400                         /* We print a message: after this even managed stack overflows
14401                          * may crash the runtime
14402                          */
14403                         fprintf (stderr, "Stack overflow in unmanaged: IP: %p, fault addr: %p\n", mono_arch_ip_from_context (ctx), (gpointer)info->si_addr);
14404                 }
14405                 return;
14406         }
14407         /* The hard-guard page has been hit: there is not much we can do anymore
14408          * Print a hopefully clear message and abort.
14409          */
14410         if (jit_tls->stack_size && 
14411                         ABS ((guint8*)info->si_addr - ((guint8*)jit_tls->end_of_stack - jit_tls->stack_size)) < 32768) {
14412                 const char *method;
14413                 /* we don't do much now, but we can warn the user with a useful message */
14414                 fprintf (stderr, "Stack overflow: IP: %p, fault addr: %p\n", mono_arch_ip_from_context (ctx), (gpointer)info->si_addr);
14415                 if (ji && ji->method)
14416                         method = mono_method_full_name (ji->method, TRUE);
14417                 else
14418                         method = "Unmanaged";
14419                 fprintf (stderr, "At %s\n", method);
14420                 abort ();
14421         } else {
14422                 mono_arch_handle_altstack_exception (ctx, info->si_addr, FALSE);
14423         }
14424 #else
14425
14426         if (!ji) {
14427                 mono_handle_native_sigsegv (SIGSEGV, ctx);
14428         }
14429                         
14430         mono_arch_handle_exception (ctx, exc, FALSE);
14431 #endif
14432 }
14433
14434 #ifndef PLATFORM_WIN32
14435
14436 static void
14437 SIG_HANDLER_SIGNATURE (sigabrt_signal_handler)
14438 {
14439         MonoJitInfo *ji;
14440         GET_CONTEXT;
14441
14442         ji = mono_jit_info_table_find (mono_domain_get (), mono_arch_ip_from_context(ctx));
14443         if (!ji) {
14444                 mono_handle_native_sigsegv (SIGABRT, ctx);
14445         }
14446 }
14447
14448 static void
14449 SIG_HANDLER_SIGNATURE (sigusr1_signal_handler)
14450 {
14451         gboolean running_managed;
14452         MonoException *exc;
14453         MonoThread *thread = mono_thread_current ();
14454         void *ji;
14455         
14456         GET_CONTEXT;
14457
14458         if (thread->thread_dump_requested) {
14459                 thread->thread_dump_requested = FALSE;
14460
14461                 mono_print_thread_dump (ctx);
14462         }
14463
14464         /*
14465          * FIXME:
14466          * This is an async signal, so the code below must not call anything which
14467          * is not async safe. That includes the pthread locking functions. If we
14468          * know that we interrupted managed code, then locking is safe.
14469          */
14470         ji = mono_jit_info_table_find (mono_domain_get (), mono_arch_ip_from_context(ctx));
14471         running_managed = ji != NULL;
14472         
14473         exc = mono_thread_request_interruption (running_managed); 
14474         if (!exc) return;
14475
14476         mono_arch_handle_exception (ctx, exc, FALSE);
14477 }
14478
14479 #if defined(__i386__) || defined(__x86_64__)
14480 #define FULL_STAT_PROFILER_BACKTRACE 1
14481 #define CURRENT_FRAME_GET_BASE_POINTER(f) (* (gpointer*)(f))
14482 #define CURRENT_FRAME_GET_RETURN_ADDRESS(f) (* (((gpointer*)(f)) + 1))
14483 #if MONO_ARCH_STACK_GROWS_UP
14484 #define IS_BEFORE_ON_STACK <
14485 #define IS_AFTER_ON_STACK >
14486 #else
14487 #define IS_BEFORE_ON_STACK >
14488 #define IS_AFTER_ON_STACK <
14489 #endif
14490 #else
14491 #define FULL_STAT_PROFILER_BACKTRACE 0
14492 #endif
14493
14494 #if defined(__ia64__) || defined(__sparc__) || defined(sparc) || defined(__s390__) || defined(s390)
14495
14496 static void
14497 SIG_HANDLER_SIGNATURE (sigprof_signal_handler)
14498 {
14499         NOT_IMPLEMENTED;
14500 }
14501
14502 #else
14503
14504 static void
14505 SIG_HANDLER_SIGNATURE (sigprof_signal_handler)
14506 {
14507         int call_chain_depth = mono_profiler_stat_get_call_chain_depth ();
14508         GET_CONTEXT;
14509         
14510         if (call_chain_depth == 0) {
14511                 mono_profiler_stat_hit (mono_arch_ip_from_context (ctx), ctx);
14512         } else {
14513                 MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
14514                 int current_frame_index = 1;
14515                 MonoContext mono_context;
14516 #if FULL_STAT_PROFILER_BACKTRACE
14517                 guchar *current_frame;
14518                 guchar *stack_bottom;
14519                 guchar *stack_top;
14520 #else
14521                 MonoDomain *domain;
14522 #endif
14523                 guchar *ips [call_chain_depth + 1];
14524
14525                 mono_arch_sigctx_to_monoctx (ctx, &mono_context);
14526                 ips [0] = MONO_CONTEXT_GET_IP (&mono_context);
14527                 
14528                 if (jit_tls != NULL) {
14529 #if FULL_STAT_PROFILER_BACKTRACE
14530                         stack_bottom = jit_tls->end_of_stack;
14531                         stack_top = MONO_CONTEXT_GET_SP (&mono_context);
14532                         current_frame = MONO_CONTEXT_GET_BP (&mono_context);
14533                         
14534                         while ((current_frame_index <= call_chain_depth) &&
14535                                         (stack_bottom IS_BEFORE_ON_STACK (guchar*) current_frame) &&
14536                                         ((guchar*) current_frame IS_BEFORE_ON_STACK stack_top)) {
14537                                 ips [current_frame_index] = CURRENT_FRAME_GET_RETURN_ADDRESS (current_frame);
14538                                 current_frame_index ++;
14539                                 stack_top = current_frame;
14540                                 current_frame = CURRENT_FRAME_GET_BASE_POINTER (current_frame);
14541                         }
14542 #else
14543                         domain = mono_domain_get ();
14544                         if (domain != NULL) {
14545                                 MonoLMF *lmf = NULL;
14546                                 MonoJitInfo *ji;
14547                                 MonoJitInfo res;
14548                                 MonoContext new_mono_context;
14549                                 int native_offset;
14550                                 ji = mono_find_jit_info (domain, jit_tls, &res, NULL, &mono_context,
14551                                                 &new_mono_context, NULL, &lmf, &native_offset, NULL);
14552                                 while ((ji != NULL) && (current_frame_index <= call_chain_depth)) {
14553                                         ips [current_frame_index] = MONO_CONTEXT_GET_IP (&new_mono_context);
14554                                         current_frame_index ++;
14555                                         mono_context = new_mono_context;
14556                                         ji = mono_find_jit_info (domain, jit_tls, &res, NULL, &mono_context,
14557                                                         &new_mono_context, NULL, &lmf, &native_offset, NULL);
14558                                 }
14559                         }
14560 #endif
14561                 }
14562                 
14563                 
14564                 mono_profiler_stat_call_chain (current_frame_index, & ips [0], ctx);
14565         }
14566 }
14567
14568 #endif
14569
14570 static void
14571 SIG_HANDLER_SIGNATURE (sigquit_signal_handler)
14572 {
14573         GET_CONTEXT;
14574
14575         printf ("Full thread dump:\n");
14576
14577         mono_threads_request_thread_dump ();
14578
14579         /*
14580          * print_thread_dump () skips the current thread, since sending a signal
14581          * to it would invoke the signal handler below the sigquit signal handler,
14582          * and signal handlers don't create an lmf, so the stack walk could not
14583          * be performed.
14584          */
14585         mono_print_thread_dump (ctx);
14586 }
14587
14588 static void
14589 SIG_HANDLER_SIGNATURE (sigusr2_signal_handler)
14590 {
14591         gboolean enabled = mono_trace_is_enabled ();
14592
14593         mono_trace_enable (!enabled);
14594 }
14595
14596 #endif
14597
14598 static void
14599 SIG_HANDLER_SIGNATURE (sigint_signal_handler)
14600 {
14601         MonoException *exc;
14602         GET_CONTEXT;
14603
14604         exc = mono_get_exception_execution_engine ("Interrupted (SIGINT).");
14605         
14606         mono_arch_handle_exception (ctx, exc, FALSE);
14607 }
14608
14609 #ifdef PLATFORM_MACOSX
14610
14611 /*
14612  * This code disables the CrashReporter of MacOS X by installing
14613  * a dummy Mach exception handler.
14614  */
14615
14616 /*
14617  * http://darwinsource.opendarwin.org/10.4.3/xnu-792.6.22/osfmk/man/exc_server.html
14618  */
14619 extern
14620 boolean_t
14621 exc_server (mach_msg_header_t *request_msg,
14622             mach_msg_header_t *reply_msg);
14623
14624 /*
14625  * The exception message
14626  */
14627 typedef struct {
14628         mach_msg_base_t msg;  /* common mach message header */
14629         char payload [1024];  /* opaque */
14630 } mach_exception_msg_t;
14631
14632 /* The exception port */
14633 static mach_port_t mach_exception_port = VM_MAP_NULL;
14634
14635 /*
14636  * Implicitly called by exc_server. Must be public.
14637  *
14638  * http://darwinsource.opendarwin.org/10.4.3/xnu-792.6.22/osfmk/man/catch_exception_raise.html
14639  */
14640 kern_return_t
14641 catch_exception_raise (
14642         mach_port_t exception_port,
14643         mach_port_t thread,
14644         mach_port_t task,
14645         exception_type_t exception,
14646         exception_data_t code,
14647         mach_msg_type_number_t code_count)
14648 {
14649         /* consume the exception */
14650         return KERN_FAILURE;
14651 }
14652
14653 /*
14654  * Exception thread handler.
14655  */
14656 static
14657 void *
14658 mach_exception_thread (void *arg)
14659 {
14660         for (;;) {
14661                 mach_exception_msg_t request;
14662                 mach_exception_msg_t reply;
14663                 mach_msg_return_t result;
14664
14665                 /* receive from "mach_exception_port" */
14666                 result = mach_msg (&request.msg.header,
14667                                    MACH_RCV_MSG | MACH_RCV_LARGE,
14668                                    0,
14669                                    sizeof (request),
14670                                    mach_exception_port,
14671                                    MACH_MSG_TIMEOUT_NONE,
14672                                    MACH_PORT_NULL);
14673
14674                 g_assert (result == MACH_MSG_SUCCESS);
14675
14676                 /* dispatch to catch_exception_raise () */
14677                 exc_server (&request.msg.header, &reply.msg.header);
14678
14679                 /* send back to sender */
14680                 result = mach_msg (&reply.msg.header,
14681                                    MACH_SEND_MSG,
14682                                    reply.msg.header.msgh_size,
14683                                    0,
14684                                    MACH_PORT_NULL,
14685                                    MACH_MSG_TIMEOUT_NONE,
14686                                    MACH_PORT_NULL);
14687
14688                 g_assert (result == MACH_MSG_SUCCESS);
14689         }
14690         return NULL;
14691 }
14692
14693 static void
14694 macosx_register_exception_handler ()
14695 {
14696         mach_port_t task;
14697         pthread_attr_t attr;
14698         pthread_t thread;
14699
14700         if (mach_exception_port != VM_MAP_NULL)
14701                 return;
14702
14703         task = mach_task_self ();
14704
14705         /* create the "mach_exception_port" with send & receive rights */
14706         g_assert (mach_port_allocate (task, MACH_PORT_RIGHT_RECEIVE,
14707                                       &mach_exception_port) == KERN_SUCCESS);
14708         g_assert (mach_port_insert_right (task, mach_exception_port, mach_exception_port,
14709                                           MACH_MSG_TYPE_MAKE_SEND) == KERN_SUCCESS);
14710
14711         /* create the exception handler thread */
14712         g_assert (!pthread_attr_init (&attr));
14713         g_assert (!pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED));
14714         g_assert (!pthread_create (&thread, &attr, mach_exception_thread, NULL));
14715         pthread_attr_destroy (&attr);
14716
14717         /*
14718          * register "mach_exception_port" as a receiver for the
14719          * EXC_BAD_ACCESS exception
14720          *
14721          * http://darwinsource.opendarwin.org/10.4.3/xnu-792.6.22/osfmk/man/task_set_exception_ports.html
14722          */
14723         g_assert (task_set_exception_ports (task, EXC_MASK_BAD_ACCESS,
14724                                             mach_exception_port,
14725                                             EXCEPTION_DEFAULT,
14726                                             MACHINE_THREAD_STATE) == KERN_SUCCESS);
14727 }
14728 #endif
14729
14730 #ifndef PLATFORM_WIN32
14731 static void
14732 add_signal_handler (int signo, gpointer handler)
14733 {
14734         struct sigaction sa;
14735
14736 #ifdef MONO_ARCH_USE_SIGACTION
14737         sa.sa_sigaction = handler;
14738         sigemptyset (&sa.sa_mask);
14739         sa.sa_flags = SA_SIGINFO;
14740 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
14741         if (signo == SIGSEGV)
14742                 sa.sa_flags |= SA_ONSTACK;
14743 #endif
14744 #else
14745         sa.sa_handler = handler;
14746         sigemptyset (&sa.sa_mask);
14747         sa.sa_flags = 0;
14748 #endif
14749         g_assert (sigaction (signo, &sa, NULL) != -1);
14750 }
14751
14752 static void
14753 remove_signal_handler (int signo)
14754 {
14755         struct sigaction sa;
14756
14757         sa.sa_handler = SIG_DFL;
14758         sigemptyset (&sa.sa_mask);
14759         sa.sa_flags = 0;
14760
14761         g_assert (sigaction (signo, &sa, NULL) != -1);
14762 }
14763 #endif
14764
14765 static void
14766 mono_runtime_install_handlers (void)
14767 {
14768 #ifdef PLATFORM_WIN32
14769         win32_seh_init();
14770         win32_seh_set_handler(SIGFPE, sigfpe_signal_handler);
14771         win32_seh_set_handler(SIGILL, sigill_signal_handler);
14772         win32_seh_set_handler(SIGSEGV, sigsegv_signal_handler);
14773         if (debug_options.handle_sigint)
14774                 win32_seh_set_handler(SIGINT, sigint_signal_handler);
14775
14776 #else /* !PLATFORM_WIN32 */
14777
14778
14779 #ifdef PLATFORM_MACOSX
14780         macosx_register_exception_handler ();
14781 #endif
14782
14783         if (debug_options.handle_sigint)
14784                 add_signal_handler (SIGINT, sigint_signal_handler);
14785
14786         add_signal_handler (SIGFPE, sigfpe_signal_handler);
14787         add_signal_handler (SIGQUIT, sigquit_signal_handler);
14788         add_signal_handler (SIGILL, sigill_signal_handler);
14789         add_signal_handler (SIGBUS, sigsegv_signal_handler);
14790         if (mono_jit_trace_calls != NULL)
14791                 add_signal_handler (SIGUSR2, sigusr2_signal_handler);
14792
14793         add_signal_handler (mono_thread_get_abort_signal (), sigusr1_signal_handler);
14794         signal (SIGPIPE, SIG_IGN);
14795
14796         add_signal_handler (SIGABRT, sigabrt_signal_handler);
14797
14798         /* catch SIGSEGV */
14799         add_signal_handler (SIGSEGV, sigsegv_signal_handler);
14800 #endif /* PLATFORM_WIN32 */
14801 }
14802
14803 static void
14804 mono_runtime_cleanup_handlers (void)
14805 {
14806 #ifdef PLATFORM_WIN32
14807         win32_seh_cleanup();
14808 #else
14809         if (debug_options.handle_sigint)
14810                 remove_signal_handler (SIGINT);
14811
14812         remove_signal_handler (SIGFPE);
14813         remove_signal_handler (SIGQUIT);
14814         remove_signal_handler (SIGILL);
14815         remove_signal_handler (SIGBUS);
14816         if (mono_jit_trace_calls != NULL)
14817                 remove_signal_handler (SIGUSR2);
14818
14819         remove_signal_handler (mono_thread_get_abort_signal ());
14820
14821         remove_signal_handler (SIGABRT);
14822
14823         remove_signal_handler (SIGSEGV);
14824 #endif /* PLATFORM_WIN32 */
14825 }
14826
14827
14828 #ifdef HAVE_LINUX_RTC_H
14829 #include <linux/rtc.h>
14830 #include <sys/ioctl.h>
14831 #include <fcntl.h>
14832 static int rtc_fd = -1;
14833
14834 static int
14835 enable_rtc_timer (gboolean enable)
14836 {
14837         int flags;
14838         flags = fcntl (rtc_fd, F_GETFL);
14839         if (flags < 0) {
14840                 perror ("getflags");
14841                 return 0;
14842         }
14843         if (enable)
14844                 flags |= FASYNC;
14845         else
14846                 flags &= ~FASYNC;
14847         if (fcntl (rtc_fd, F_SETFL, flags) == -1) {
14848                 perror ("setflags");
14849                 return 0;
14850         }
14851         return 1;
14852 }
14853 #endif
14854
14855 #ifdef PLATFORM_WIN32
14856 static HANDLE win32_main_thread;
14857 static MMRESULT win32_timer;
14858
14859 static void CALLBACK
14860 win32_time_proc (UINT uID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2)
14861 {
14862         CONTEXT context;
14863
14864         context.ContextFlags = CONTEXT_CONTROL;
14865         if (GetThreadContext (win32_main_thread, &context)) {
14866 #ifdef _WIN64
14867                 mono_profiler_stat_hit ((guchar *) context.Rip, &context);
14868 #else
14869                 mono_profiler_stat_hit ((guchar *) context.Eip, &context);
14870 #endif
14871         }
14872 }
14873 #endif
14874
14875 static void
14876 setup_stat_profiler (void)
14877 {
14878 #ifdef ITIMER_PROF
14879         struct itimerval itval;
14880         static int inited = 0;
14881 #ifdef HAVE_LINUX_RTC_H
14882         const char *rtc_freq;
14883         if (!inited && (rtc_freq = g_getenv ("MONO_RTC"))) {
14884                 int freq = 0;
14885                 inited = 1;
14886                 if (*rtc_freq)
14887                         freq = atoi (rtc_freq);
14888                 if (!freq)
14889                         freq = 1024;
14890                 rtc_fd = open ("/dev/rtc", O_RDONLY);
14891                 if (rtc_fd == -1) {
14892                         perror ("open /dev/rtc");
14893                         return;
14894                 }
14895                 add_signal_handler (SIGPROF, sigprof_signal_handler);
14896                 if (ioctl (rtc_fd, RTC_IRQP_SET, freq) == -1) {
14897                         perror ("set rtc freq");
14898                         return;
14899                 }
14900                 if (ioctl (rtc_fd, RTC_PIE_ON, 0) == -1) {
14901                         perror ("start rtc");
14902                         return;
14903                 }
14904                 if (fcntl (rtc_fd, F_SETSIG, SIGPROF) == -1) {
14905                         perror ("setsig");
14906                         return;
14907                 }
14908                 if (fcntl (rtc_fd, F_SETOWN, getpid ()) == -1) {
14909                         perror ("setown");
14910                         return;
14911                 }
14912                 enable_rtc_timer (TRUE);
14913                 return;
14914         }
14915         if (rtc_fd >= 0)
14916                 return;
14917 #endif
14918
14919         itval.it_interval.tv_usec = 999;
14920         itval.it_interval.tv_sec = 0;
14921         itval.it_value = itval.it_interval;
14922         setitimer (ITIMER_PROF, &itval, NULL);
14923         if (inited)
14924                 return;
14925         inited = 1;
14926         add_signal_handler (SIGPROF, sigprof_signal_handler);
14927 #elif defined (PLATFORM_WIN32)
14928         static int inited = 0;
14929         TIMECAPS timecaps;
14930
14931         if (inited)
14932                 return;
14933
14934         inited = 1;
14935         if (timeGetDevCaps (&timecaps, sizeof (timecaps)) != TIMERR_NOERROR)
14936                 return;
14937
14938         if ((win32_main_thread = OpenThread (READ_CONTROL | THREAD_GET_CONTEXT, FALSE, GetCurrentThreadId ())) == NULL)
14939                 return;
14940
14941         if (timeBeginPeriod (1) != TIMERR_NOERROR)
14942                 return;
14943
14944         if ((win32_timer = timeSetEvent (1, 0, win32_time_proc, 0, TIME_PERIODIC)) == 0) {
14945                 timeEndPeriod (1);
14946                 return;
14947         }
14948 #endif
14949 }
14950
14951 /* mono_jit_create_remoting_trampoline:
14952  * @method: pointer to the method info
14953  *
14954  * Creates a trampoline which calls the remoting functions. This
14955  * is used in the vtable of transparent proxies.
14956  * 
14957  * Returns: a pointer to the newly created code 
14958  */
14959 static gpointer
14960 mono_jit_create_remoting_trampoline (MonoMethod *method, MonoRemotingTarget target)
14961 {
14962         MonoMethod *nm;
14963         guint8 *addr = NULL;
14964
14965         if ((method->flags & METHOD_ATTRIBUTE_ABSTRACT) || 
14966             (mono_method_signature (method)->hasthis && (method->klass->marshalbyref || method->klass == mono_defaults.object_class))) {
14967                 nm = mono_marshal_get_remoting_invoke_for_target (method, target);
14968                 addr = mono_compile_method (nm);
14969         } else {
14970                 addr = mono_compile_method (method);
14971         }
14972         return mono_get_addr_from_ftnptr (addr);
14973 }
14974
14975 #ifdef MONO_ARCH_HAVE_IMT
14976 static gpointer
14977 mini_get_imt_trampoline (void)
14978 {
14979         static gpointer tramp = NULL;
14980         if (!tramp)
14981                 tramp = mono_create_specific_trampoline (MONO_FAKE_IMT_METHOD, MONO_TRAMPOLINE_JIT, mono_get_root_domain (), NULL);
14982         return tramp;
14983 }
14984 #endif
14985
14986 #ifdef MONO_ARCH_COMMON_VTABLE_TRAMPOLINE
14987 gpointer
14988 mini_get_vtable_trampoline (void)
14989 {
14990         static gpointer tramp = NULL;
14991         if (!tramp)
14992                 tramp = mono_create_specific_trampoline (MONO_FAKE_VTABLE_METHOD, MONO_TRAMPOLINE_JIT, mono_get_root_domain (), NULL);
14993         return tramp;
14994 }
14995 #endif
14996
14997 static void
14998 mini_parse_debug_options (void)
14999 {
15000         char *options = getenv ("MONO_DEBUG");
15001         gchar **args, **ptr;
15002         
15003         if (!options)
15004                 return;
15005
15006         args = g_strsplit (options, ",", -1);
15007
15008         for (ptr = args; ptr && *ptr; ptr++) {
15009                 const char *arg = *ptr;
15010
15011                 if (!strcmp (arg, "handle-sigint"))
15012                         debug_options.handle_sigint = TRUE;
15013                 else if (!strcmp (arg, "keep-delegates"))
15014                         debug_options.keep_delegates = TRUE;
15015                 else if (!strcmp (arg, "collect-pagefault-stats"))
15016                         debug_options.collect_pagefault_stats = TRUE;
15017                 else if (!strcmp (arg, "break-on-unverified"))
15018                         debug_options.break_on_unverified = TRUE;
15019                 else if (!strcmp (arg, "no-gdb-backtrace"))
15020                         debug_options.no_gdb_backtrace = TRUE;
15021                 else if (!strcmp (arg, "dont-free-domains"))
15022                         mono_dont_free_domains = TRUE;
15023                 else {
15024                         fprintf (stderr, "Invalid option for the MONO_DEBUG env variable: %s\n", arg);
15025                         fprintf (stderr, "Available options: 'handle-sigint', 'keep-delegates', 'collect-pagefault-stats', 'break-on-unverified', 'no-gdb-backtrace', 'dont-free-domains'\n");
15026                         exit (1);
15027                 }
15028         }
15029
15030         g_strfreev (args);
15031 }
15032
15033 MonoDebugOptions *
15034 mini_get_debug_options (void)
15035 {
15036         return &debug_options;
15037 }
15038
15039 MonoDomain *
15040 mini_init (const char *filename, const char *runtime_version)
15041 {
15042         MonoDomain *domain;
15043
15044         MONO_PROBE_VES_INIT_BEGIN ();
15045
15046 #ifdef __linux__
15047         if (access ("/proc/self/maps", F_OK) != 0) {
15048                 g_print ("Mono requires /proc to be mounted.\n");
15049                 exit (1);
15050         }
15051 #endif
15052
15053         /* Happens when using the embedding interface */
15054         if (!default_opt_set)
15055                 default_opt = mono_parse_default_optimizations (NULL);
15056
15057         InitializeCriticalSection (&jit_mutex);
15058
15059         if (!global_codeman)
15060                 global_codeman = mono_code_manager_new ();
15061         jit_icall_name_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
15062
15063         mono_arch_cpu_init ();
15064
15065         mono_arch_init ();
15066
15067         mono_trampolines_init ();
15068
15069         if (!g_thread_supported ())
15070                 g_thread_init (NULL);
15071
15072         if (getenv ("MONO_DEBUG") != NULL)
15073                 mini_parse_debug_options ();
15074
15075         mono_gc_base_init ();
15076
15077         mono_jit_tls_id = TlsAlloc ();
15078         setup_jit_tls_data ((gpointer)-1, mono_thread_abort);
15079
15080         mono_burg_init ();
15081
15082         if (default_opt & MONO_OPT_AOT)
15083                 mono_aot_init ();
15084
15085         mono_runtime_install_handlers ();
15086         mono_threads_install_cleanup (mini_thread_cleanup);
15087
15088 #ifdef MONO_ARCH_HAVE_NOTIFY_PENDING_EXC
15089         // This is experimental code so provide an env var to switch it off
15090         if (getenv ("MONO_DISABLE_PENDING_EXCEPTIONS")) {
15091                 printf ("MONO_DISABLE_PENDING_EXCEPTIONS env var set.\n");
15092         } else {
15093                 check_for_pending_exc = FALSE;
15094                 mono_threads_install_notify_pending_exc (mono_arch_notify_pending_exc);
15095         }
15096 #endif
15097
15098 #define JIT_TRAMPOLINES_WORK
15099 #ifdef JIT_TRAMPOLINES_WORK
15100         mono_install_compile_method (mono_jit_compile_method);
15101         mono_install_free_method (mono_jit_free_method);
15102         mono_install_trampoline (mono_create_jit_trampoline);
15103         mono_install_jump_trampoline (mono_create_jump_trampoline);
15104         mono_install_remoting_trampoline (mono_jit_create_remoting_trampoline);
15105         mono_install_delegate_trampoline (mono_create_delegate_trampoline);
15106 #endif
15107 #define JIT_INVOKE_WORKS
15108 #ifdef JIT_INVOKE_WORKS
15109         mono_install_runtime_invoke (mono_jit_runtime_invoke);
15110 #endif
15111         mono_install_stack_walk (mono_jit_walk_stack);
15112         mono_install_get_cached_class_info (mono_aot_get_cached_class_info);
15113         mono_install_get_class_from_name (mono_aot_get_class_from_name);
15114         mono_install_jit_info_find_in_aot (mono_aot_find_jit_info);
15115
15116         if (debug_options.collect_pagefault_stats) {
15117                 mono_raw_buffer_set_make_unreadable (TRUE);
15118                 mono_aot_set_make_unreadable (TRUE);
15119         }
15120
15121         if (runtime_version)
15122                 domain = mono_init_version (filename, runtime_version);
15123         else
15124                 domain = mono_init_from_assembly (filename, filename);
15125
15126         if (mono_aot_only) {
15127                 /* The IMT tables are very dynamic thus they are hard to AOT */
15128                 mono_use_imt = FALSE;
15129                 /* This helps catch code allocation requests */
15130                 mono_code_manager_set_read_only (domain->code_mp);
15131         }
15132
15133 #ifdef MONO_ARCH_HAVE_IMT
15134         if (mono_use_imt) {
15135                 mono_install_imt_thunk_builder (mono_arch_build_imt_thunk);
15136                 mono_install_imt_trampoline (mini_get_imt_trampoline ());
15137 #if MONO_ARCH_COMMON_VTABLE_TRAMPOLINE
15138                 mono_install_vtable_trampoline (mini_get_vtable_trampoline ());
15139 #endif
15140         }
15141 #endif
15142
15143         /* This must come after mono_init () in the aot-only case */
15144         mono_exceptions_init ();
15145         mono_install_handler (mono_get_throw_exception ());
15146
15147         mono_icall_init ();
15148
15149         mono_add_internal_call ("System.Diagnostics.StackFrame::get_frame_info", 
15150                                 ves_icall_get_frame_info);
15151         mono_add_internal_call ("System.Diagnostics.StackTrace::get_trace", 
15152                                 ves_icall_get_trace);
15153         mono_add_internal_call ("System.Exception::get_trace", 
15154                                 ves_icall_System_Exception_get_trace);
15155         mono_add_internal_call ("System.Security.SecurityFrame::_GetSecurityFrame",
15156                                 ves_icall_System_Security_SecurityFrame_GetSecurityFrame);
15157         mono_add_internal_call ("System.Security.SecurityFrame::_GetSecurityStack",
15158                                 ves_icall_System_Security_SecurityFrame_GetSecurityStack);
15159         mono_add_internal_call ("Mono.Runtime::mono_runtime_install_handlers", 
15160                                 mono_runtime_install_handlers);
15161
15162
15163         create_helper_signature ();
15164
15165 #define JIT_CALLS_WORK
15166 #ifdef JIT_CALLS_WORK
15167         /* Needs to be called here since register_jit_icall depends on it */
15168         mono_marshal_init ();
15169
15170         mono_arch_register_lowlevel_calls ();
15171         register_icall (mono_profiler_method_enter, "mono_profiler_method_enter", NULL, TRUE);
15172         register_icall (mono_profiler_method_leave, "mono_profiler_method_leave", NULL, TRUE);
15173         register_icall (mono_trace_enter_method, "mono_trace_enter_method", NULL, TRUE);
15174         register_icall (mono_trace_leave_method, "mono_trace_leave_method", NULL, TRUE);
15175         register_icall (mono_get_lmf_addr, "mono_get_lmf_addr", "ptr", TRUE);
15176         register_icall (mono_jit_thread_attach, "mono_jit_thread_attach", "void", TRUE);
15177         register_icall (mono_domain_get, "mono_domain_get", "ptr", TRUE);
15178
15179         register_icall (mono_get_throw_exception (), "mono_arch_throw_exception", "void object", TRUE);
15180         register_icall (mono_get_rethrow_exception (), "mono_arch_rethrow_exception", "void object", TRUE);
15181         register_icall (mono_get_throw_exception_by_name (), "mono_arch_throw_exception_by_name", "void ptr", TRUE); 
15182 #if MONO_ARCH_HAVE_THROW_CORLIB_EXCEPTION
15183         register_icall (mono_get_throw_corlib_exception (), "mono_arch_throw_corlib_exception", 
15184                                  "void ptr", TRUE);
15185 #endif
15186         register_icall (mono_thread_get_undeniable_exception, "mono_thread_get_undeniable_exception", "object", FALSE);
15187         register_icall (mono_thread_interruption_checkpoint, "mono_thread_interruption_checkpoint", "void", FALSE);
15188         register_icall (mono_thread_force_interruption_checkpoint, "mono_thread_force_interruption_checkpoint", "void", FALSE);
15189         register_icall (mono_load_remote_field_new, "mono_load_remote_field_new", "object object ptr ptr", FALSE);
15190         register_icall (mono_store_remote_field_new, "mono_store_remote_field_new", "void object ptr ptr object", FALSE);
15191
15192         /* 
15193          * NOTE, NOTE, NOTE, NOTE:
15194          * when adding emulation for some opcodes, remember to also add a dummy
15195          * rule to the burg files, because we need the arity information to be correct.
15196          */
15197 #ifndef MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS
15198         mono_register_opcode_emulation (OP_LMUL, "__emul_lmul", "long long long", mono_llmult, TRUE);
15199         mono_register_opcode_emulation (OP_LDIV, "__emul_ldiv", "long long long", mono_lldiv, FALSE);
15200         mono_register_opcode_emulation (OP_LDIV_UN, "__emul_ldiv_un", "long long long", mono_lldiv_un, FALSE);
15201         mono_register_opcode_emulation (OP_LREM, "__emul_lrem", "long long long", mono_llrem, FALSE);
15202         mono_register_opcode_emulation (OP_LREM_UN, "__emul_lrem_un", "long long long", mono_llrem_un, FALSE);
15203         mono_register_opcode_emulation (OP_LMUL_OVF_UN, "__emul_lmul_ovf_un", "long long long", mono_llmult_ovf_un, FALSE);
15204         mono_register_opcode_emulation (OP_LMUL_OVF, "__emul_lmul_ovf", "long long long", mono_llmult_ovf, FALSE);
15205 #endif
15206
15207 #ifndef MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
15208         mono_register_opcode_emulation (OP_LSHL, "__emul_lshl", "long long int32", mono_lshl, TRUE);
15209         mono_register_opcode_emulation (OP_LSHR, "__emul_lshr", "long long int32", mono_lshr, TRUE);
15210         mono_register_opcode_emulation (OP_LSHR_UN, "__emul_lshr_un", "long long int32", mono_lshr_un, TRUE);
15211 #endif
15212
15213 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
15214         mono_register_opcode_emulation (CEE_DIV, "__emul_idiv", "int32 int32 int32", mono_idiv, FALSE);
15215         mono_register_opcode_emulation (CEE_DIV_UN, "__emul_idiv_un", "int32 int32 int32", mono_idiv_un, FALSE);
15216         mono_register_opcode_emulation (CEE_REM, "__emul_irem", "int32 int32 int32", mono_irem, FALSE);
15217         mono_register_opcode_emulation (CEE_REM_UN, "__emul_irem_un", "int32 int32 int32", mono_irem_un, FALSE);
15218         mono_register_opcode_emulation (OP_IDIV, "__emul_op_idiv", "int32 int32 int32", mono_idiv, FALSE);
15219         mono_register_opcode_emulation (OP_IDIV_UN, "__emul_op_idiv_un", "int32 int32 int32", mono_idiv_un, FALSE);
15220         mono_register_opcode_emulation (OP_IREM, "__emul_op_irem", "int32 int32 int32", mono_irem, FALSE);
15221         mono_register_opcode_emulation (OP_IREM_UN, "__emul_op_irem_un", "int32 int32 int32", mono_irem_un, FALSE);
15222 #endif
15223
15224 #ifdef MONO_ARCH_EMULATE_MUL_DIV
15225         mono_register_opcode_emulation (CEE_MUL_OVF, "__emul_imul_ovf", "int32 int32 int32", mono_imul_ovf, FALSE);
15226         mono_register_opcode_emulation (CEE_MUL_OVF_UN, "__emul_imul_ovf_un", "int32 int32 int32", mono_imul_ovf_un, FALSE);
15227         mono_register_opcode_emulation (CEE_MUL, "__emul_imul", "int32 int32 int32", mono_imul, TRUE);
15228         mono_register_opcode_emulation (OP_IMUL, "__emul_op_imul", "int32 int32 int32", mono_imul, TRUE);
15229         mono_register_opcode_emulation (OP_IMUL_OVF, "__emul_op_imul_ovf", "int32 int32 int32", mono_imul_ovf, FALSE);
15230         mono_register_opcode_emulation (OP_IMUL_OVF_UN, "__emul_op_imul_ovf_un", "int32 int32 int32", mono_imul_ovf_un, FALSE);
15231 #endif
15232 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_SOFT_FLOAT)
15233         mono_register_opcode_emulation (OP_FDIV, "__emul_fdiv", "double double double", mono_fdiv, FALSE);
15234 #endif
15235
15236         mono_register_opcode_emulation (OP_FCONV_TO_U8, "__emul_fconv_to_u8", "ulong double", mono_fconv_u8, FALSE);
15237         mono_register_opcode_emulation (OP_FCONV_TO_U4, "__emul_fconv_to_u4", "uint32 double", mono_fconv_u4, FALSE);
15238         mono_register_opcode_emulation (OP_FCONV_TO_OVF_I8, "__emul_fconv_to_ovf_i8", "long double", mono_fconv_ovf_i8, FALSE);
15239         mono_register_opcode_emulation (OP_FCONV_TO_OVF_U8, "__emul_fconv_to_ovf_u8", "ulong double", mono_fconv_ovf_u8, FALSE);
15240
15241 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
15242         mono_register_opcode_emulation (OP_FCONV_TO_I8, "__emul_fconv_to_i8", "long double", mono_fconv_i8, FALSE);
15243 #endif
15244 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
15245         mono_register_opcode_emulation (CEE_CONV_R_UN, "__emul_conv_r_un", "double int32", mono_conv_to_r8_un, FALSE);
15246         mono_register_opcode_emulation (OP_ICONV_TO_R_UN, "__emul_iconv_to_r_un", "double int32", mono_conv_to_r8_un, FALSE);
15247 #endif
15248 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
15249         mono_register_opcode_emulation (OP_LCONV_TO_R8, "__emul_lconv_to_r8", "double long", mono_lconv_to_r8, FALSE);
15250 #endif
15251 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
15252         mono_register_opcode_emulation (OP_LCONV_TO_R4, "__emul_lconv_to_r4", "float long", mono_lconv_to_r4, FALSE);
15253 #endif
15254 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
15255         mono_register_opcode_emulation (OP_LCONV_TO_R_UN, "__emul_lconv_to_r8_un", "double long", mono_lconv_to_r8_un, FALSE);
15256 #endif
15257 #ifdef MONO_ARCH_EMULATE_FREM
15258         mono_register_opcode_emulation (OP_FREM, "__emul_frem", "double double double", fmod, FALSE);
15259 #endif
15260
15261 #ifdef MONO_ARCH_SOFT_FLOAT
15262         mono_register_opcode_emulation (OP_FSUB, "__emul_fsub", "double double double", mono_fsub, FALSE);
15263         mono_register_opcode_emulation (OP_FADD, "__emul_fadd", "double double double", mono_fadd, FALSE);
15264         mono_register_opcode_emulation (OP_FMUL, "__emul_fmul", "double double double", mono_fmul, FALSE);
15265         mono_register_opcode_emulation (OP_FNEG, "__emul_fneg", "double double", mono_fneg, FALSE);
15266         mono_register_opcode_emulation (CEE_CONV_R8, "__emul_conv_r8", "double int32", mono_conv_to_r8, FALSE);
15267         mono_register_opcode_emulation (OP_ICONV_TO_R8, "__emul_iconv_to_r8", "double int32", mono_conv_to_r8, FALSE);
15268         mono_register_opcode_emulation (CEE_CONV_R4, "__emul_conv_r4", "double int32", mono_conv_to_r4, FALSE);
15269         mono_register_opcode_emulation (OP_ICONV_TO_R4, "__emul_iconv_to_r4", "double int32", mono_conv_to_r4, FALSE);
15270         mono_register_opcode_emulation (OP_FCONV_TO_R4, "__emul_fconv_to_r4", "double double", mono_fconv_r4, FALSE);
15271         mono_register_opcode_emulation (OP_FCONV_TO_I1, "__emul_fconv_to_i1", "int8 double", mono_fconv_i1, FALSE);
15272         mono_register_opcode_emulation (OP_FCONV_TO_I2, "__emul_fconv_to_i2", "int16 double", mono_fconv_i2, FALSE);
15273         mono_register_opcode_emulation (OP_FCONV_TO_I4, "__emul_fconv_to_i4", "int32 double", mono_fconv_i4, FALSE);
15274         mono_register_opcode_emulation (OP_FCONV_TO_U1, "__emul_fconv_to_u1", "uint8 double", mono_fconv_u1, FALSE);
15275         mono_register_opcode_emulation (OP_FCONV_TO_U2, "__emul_fconv_to_u2", "uint16 double", mono_fconv_u2, FALSE);
15276
15277         mono_register_opcode_emulation (OP_FBEQ, "__emul_fcmp_eq", "uint32 double double", mono_fcmp_eq, FALSE);
15278         mono_register_opcode_emulation (OP_FBLT, "__emul_fcmp_lt", "uint32 double double", mono_fcmp_lt, FALSE);
15279         mono_register_opcode_emulation (OP_FBGT, "__emul_fcmp_gt", "uint32 double double", mono_fcmp_gt, FALSE);
15280         mono_register_opcode_emulation (OP_FBLE, "__emul_fcmp_le", "uint32 double double", mono_fcmp_le, FALSE);
15281         mono_register_opcode_emulation (OP_FBGE, "__emul_fcmp_ge", "uint32 double double", mono_fcmp_ge, FALSE);
15282         mono_register_opcode_emulation (OP_FBNE_UN, "__emul_fcmp_ne_un", "uint32 double double", mono_fcmp_ne_un, FALSE);
15283         mono_register_opcode_emulation (OP_FBLT_UN, "__emul_fcmp_lt_un", "uint32 double double", mono_fcmp_lt_un, FALSE);
15284         mono_register_opcode_emulation (OP_FBGT_UN, "__emul_fcmp_gt_un", "uint32 double double", mono_fcmp_gt_un, FALSE);
15285         mono_register_opcode_emulation (OP_FBLE_UN, "__emul_fcmp_le_un", "uint32 double double", mono_fcmp_le_un, FALSE);
15286         mono_register_opcode_emulation (OP_FBGE_UN, "__emul_fcmp_ge_un", "uint32 double double", mono_fcmp_ge_un, FALSE);
15287
15288         mono_register_opcode_emulation (OP_FCEQ, "__emul_fcmp_ceq", "uint32 double double", mono_fceq, FALSE);
15289         mono_register_opcode_emulation (OP_FCGT, "__emul_fcmp_cgt", "uint32 double double", mono_fcgt, FALSE);
15290         mono_register_opcode_emulation (OP_FCGT_UN, "__emul_fcmp_cgt_un", "uint32 double double", mono_fcgt_un, FALSE);
15291         mono_register_opcode_emulation (OP_FCLT, "__emul_fcmp_clt", "uint32 double double", mono_fclt, FALSE);
15292         mono_register_opcode_emulation (OP_FCLT_UN, "__emul_fcmp_clt_un", "uint32 double double", mono_fclt_un, FALSE);
15293
15294         register_icall (mono_fload_r4, "mono_fload_r4", "double ptr", FALSE);
15295         register_icall (mono_fstore_r4, "mono_fstore_r4", "void double ptr", FALSE);
15296         register_icall (mono_fload_r4_arg, "mono_fload_r4_arg", "uint32 double", FALSE);
15297 #endif
15298
15299 #if SIZEOF_VOID_P == 4
15300         mono_register_opcode_emulation (OP_FCONV_TO_U, "__emul_fconv_to_u", "uint32 double", mono_fconv_u4, TRUE);
15301 #endif
15302
15303         /* other jit icalls */
15304         register_icall (mono_delegate_ctor, "mono_delegate_ctor", "void object object ptr", FALSE);
15305         register_icall (mono_class_static_field_address , "mono_class_static_field_address", 
15306                                  "ptr ptr ptr", FALSE);
15307         register_icall (mono_ldtoken_wrapper, "mono_ldtoken_wrapper", "ptr ptr ptr ptr", FALSE);
15308         register_icall (mono_ldtoken_wrapper_generic_shared, "mono_ldtoken_wrapper_generic_shared",
15309                 "ptr ptr ptr ptr", FALSE);
15310         register_icall (mono_get_special_static_data, "mono_get_special_static_data", "ptr int", FALSE);
15311         register_icall (mono_ldstr, "mono_ldstr", "object ptr ptr int32", FALSE);
15312         register_icall (mono_helper_stelem_ref_check, "helper_stelem_ref_check", "void object object", FALSE);
15313         register_icall (mono_object_new, "mono_object_new", "object ptr ptr", FALSE);
15314         register_icall (mono_object_new_specific, "mono_object_new_specific", "object ptr", FALSE);
15315         register_icall (mono_array_new, "mono_array_new", "object ptr ptr int32", FALSE);
15316         register_icall (mono_array_new_specific, "mono_array_new_specific", "object ptr int32", FALSE);
15317         register_icall (mono_runtime_class_init, "mono_runtime_class_init", "void ptr", FALSE);
15318         register_icall (mono_ldftn, "mono_ldftn", "ptr ptr", FALSE);
15319         register_icall (mono_ldftn_nosync, "mono_ldftn_nosync", "ptr ptr", FALSE);
15320         register_icall (mono_ldvirtfn, "mono_ldvirtfn", "ptr object ptr", FALSE);
15321         register_icall (mono_ldvirtfn_gshared, "mono_ldvirtfn_gshared", "ptr object ptr", FALSE);
15322         register_icall (mono_helper_compile_generic_method, "compile_generic_method", "ptr object ptr ptr ptr", FALSE);
15323         register_icall (mono_helper_compile_generic_method_wo_context, "compile_generic_method_wo_context",
15324                 "ptr object ptr ptr", FALSE);
15325         register_icall (mono_helper_ldstr, "helper_ldstr", "object ptr int", FALSE);
15326         register_icall (mono_helper_ldstr_mscorlib, "helper_ldstr_mscorlib", "object int", FALSE);
15327         register_icall (mono_helper_newobj_mscorlib, "helper_newobj_mscorlib", "object int", FALSE);
15328         register_icall (mono_value_copy, "mono_value_copy", "void ptr ptr ptr", FALSE);
15329         register_icall (mono_object_castclass, "mono_object_castclass", "object object ptr", FALSE);
15330         register_icall (mono_break, "mono_break", NULL, TRUE);
15331         register_icall (mono_create_corlib_exception_0, "mono_create_corlib_exception_0", "object int", TRUE);
15332         register_icall (mono_create_corlib_exception_1, "mono_create_corlib_exception_1", "object int object", TRUE);
15333         register_icall (mono_create_corlib_exception_2, "mono_create_corlib_exception_2", "object int object object", TRUE);
15334         register_icall (mono_array_new_2, "mono_array_new_2", "object ptr int int", FALSE);
15335 #endif
15336
15337 #define JIT_RUNTIME_WORKS
15338 #ifdef JIT_RUNTIME_WORKS
15339         mono_install_runtime_cleanup ((MonoDomainFunc)mini_cleanup);
15340         mono_runtime_init (domain, mono_thread_start_cb, mono_thread_attach_cb);
15341 #endif
15342
15343         mono_generic_sharing_init ();
15344
15345         mono_thread_attach (domain);
15346         
15347         mono_profiler_runtime_initialized ();
15348         
15349         MONO_PROBE_VES_INIT_END ();
15350         
15351         return domain;
15352 }
15353
15354 MonoJitStats mono_jit_stats = {0};
15355
15356 static void 
15357 print_jit_stats (void)
15358 {
15359         if (mono_jit_stats.enabled) {
15360                 g_print ("Mono Jit statistics\n");
15361                 g_print ("Compiled methods:       %ld\n", mono_jit_stats.methods_compiled);
15362                 g_print ("Methods from AOT:       %ld\n", mono_jit_stats.methods_aot);
15363                 g_print ("Methods cache lookup:   %ld\n", mono_jit_stats.methods_lookups);
15364                 g_print ("Method trampolines:     %ld\n", mono_jit_stats.method_trampolines);
15365                 g_print ("Basic blocks:           %ld\n", mono_jit_stats.basic_blocks);
15366                 g_print ("Max basic blocks:       %ld\n", mono_jit_stats.max_basic_blocks);
15367                 g_print ("Allocated vars:         %ld\n", mono_jit_stats.allocate_var);
15368                 g_print ("Analyze stack repeat:   %ld\n", mono_jit_stats.analyze_stack_repeat);
15369                 g_print ("Compiled CIL code size: %ld\n", mono_jit_stats.cil_code_size);
15370                 g_print ("Native code size:       %ld\n", mono_jit_stats.native_code_size);
15371                 g_print ("Max code size ratio:    %.2f (%s)\n", mono_jit_stats.max_code_size_ratio/100.0,
15372                                  mono_jit_stats.max_ratio_method);
15373                 g_print ("Biggest method:         %ld (%s)\n", mono_jit_stats.biggest_method_size,
15374                                  mono_jit_stats.biggest_method);
15375                 g_print ("Code reallocs:          %ld\n", mono_jit_stats.code_reallocs);
15376                 g_print ("Allocated code size:    %ld\n", mono_jit_stats.allocated_code_size);
15377                 g_print ("Inlineable methods:     %ld\n", mono_jit_stats.inlineable_methods);
15378                 g_print ("Inlined methods:        %ld\n", mono_jit_stats.inlined_methods);
15379                 g_print ("Regvars:                %ld\n", mono_jit_stats.regvars);
15380                 g_print ("Locals stack size:      %ld\n", mono_jit_stats.locals_stack_size);
15381
15382                 g_print ("\nCreated object count:   %ld\n", mono_stats.new_object_count);
15383                 g_print ("Delegates created:      %ld\n", mono_stats.delegate_creations);
15384                 g_print ("Initialized classes:    %ld\n", mono_stats.initialized_class_count);
15385                 g_print ("Used classes:           %ld\n", mono_stats.used_class_count);
15386                 g_print ("Generic vtables:        %ld\n", mono_stats.generic_vtable_count);
15387                 g_print ("Methods:                %ld\n", mono_stats.method_count);
15388                 g_print ("Static data size:       %ld\n", mono_stats.class_static_data_size);
15389                 g_print ("VTable data size:       %ld\n", mono_stats.class_vtable_size);
15390                 g_print ("Mscorlib mempool size:  %d\n", mono_mempool_get_allocated (mono_defaults.corlib->mempool));
15391
15392                 g_print ("\nGeneric instances:      %ld\n", mono_stats.generic_instance_count);
15393                 g_print ("Initialized classes:    %ld\n", mono_stats.generic_class_count);
15394                 g_print ("Inflated methods:       %ld / %ld\n", mono_stats.inflated_method_count_2,
15395                          mono_stats.inflated_method_count);
15396                 g_print ("Inflated types:         %ld\n", mono_stats.inflated_type_count);
15397                 g_print ("Generics metadata size: %ld\n", mono_stats.generics_metadata_size);
15398                 g_print ("Generics virtual invokes: %ld\n", mono_jit_stats.generic_virtual_invocations);
15399
15400                 g_print ("Sharable generic methods: %ld\n", mono_stats.generics_sharable_methods);
15401                 g_print ("Unsharable generic methods: %ld\n", mono_stats.generics_unsharable_methods);
15402                 g_print ("Shared generic methods: %ld\n", mono_stats.generics_shared_methods);
15403
15404                 g_print ("Dynamic code allocs:    %ld\n", mono_stats.dynamic_code_alloc_count);
15405                 g_print ("Dynamic code bytes:     %ld\n", mono_stats.dynamic_code_bytes_count);
15406                 g_print ("Dynamic code frees:     %ld\n", mono_stats.dynamic_code_frees_count);
15407
15408                 g_print ("IMT tables size:        %ld\n", mono_stats.imt_tables_size);
15409                 g_print ("IMT number of tables:   %ld\n", mono_stats.imt_number_of_tables);
15410                 g_print ("IMT number of methods:  %ld\n", mono_stats.imt_number_of_methods);
15411                 g_print ("IMT used slots:         %ld\n", mono_stats.imt_used_slots);
15412                 g_print ("IMT colliding slots:    %ld\n", mono_stats.imt_slots_with_collisions);
15413                 g_print ("IMT max collisions:     %ld\n", mono_stats.imt_max_collisions_in_slot);
15414                 g_print ("IMT methods at max col: %ld\n", mono_stats.imt_method_count_when_max_collisions);
15415                 g_print ("IMT thunks size:        %ld\n", mono_stats.imt_thunks_size);
15416
15417                 g_print ("JIT info table inserts: %ld\n", mono_stats.jit_info_table_insert_count);
15418                 g_print ("JIT info table removes: %ld\n", mono_stats.jit_info_table_remove_count);
15419                 g_print ("JIT info table lookups: %ld\n", mono_stats.jit_info_table_lookup_count);
15420
15421                 g_print ("Hazardous pointers:     %ld\n", mono_stats.hazardous_pointer_count);
15422 #ifdef HAVE_SGEN_GC
15423                 g_print ("Minor GC collections:   %ld\n", mono_stats.minor_gc_count);
15424                 g_print ("Major GC collections:   %ld\n", mono_stats.major_gc_count);
15425                 g_print ("Minor GC time in msecs: %lf\n", (double)mono_stats.minor_gc_time_usecs / 1000.0);
15426                 g_print ("Major GC time in msecs: %lf\n", (double)mono_stats.major_gc_time_usecs / 1000.0);
15427 #endif
15428                 if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS) {
15429                         g_print ("\nDecl security check   : %ld\n", mono_jit_stats.cas_declsec_check);
15430                         g_print ("LinkDemand (user)     : %ld\n", mono_jit_stats.cas_linkdemand);
15431                         g_print ("LinkDemand (icall)    : %ld\n", mono_jit_stats.cas_linkdemand_icall);
15432                         g_print ("LinkDemand (pinvoke)  : %ld\n", mono_jit_stats.cas_linkdemand_pinvoke);
15433                         g_print ("LinkDemand (aptc)     : %ld\n", mono_jit_stats.cas_linkdemand_aptc);
15434                         g_print ("Demand (code gen)     : %ld\n", mono_jit_stats.cas_demand_generation);
15435                 }
15436                 if (debug_options.collect_pagefault_stats) {
15437                         g_print ("Metadata pagefaults   : %d\n", mono_raw_buffer_get_n_pagefaults ());
15438                         g_print ("AOT pagefaults        : %d\n", mono_aot_get_n_pagefaults ());
15439                 }
15440
15441                 g_free (mono_jit_stats.max_ratio_method);
15442                 mono_jit_stats.max_ratio_method = NULL;
15443                 g_free (mono_jit_stats.biggest_method);
15444                 mono_jit_stats.biggest_method = NULL;
15445         }
15446 }
15447
15448 void
15449 mini_cleanup (MonoDomain *domain)
15450 {
15451 #ifdef HAVE_LINUX_RTC_H
15452         if (rtc_fd >= 0)
15453                 enable_rtc_timer (FALSE);
15454 #endif
15455
15456         /* 
15457          * mono_runtime_cleanup() and mono_domain_finalize () need to
15458          * be called early since they need the execution engine still
15459          * fully working (mono_domain_finalize may invoke managed finalizers
15460          * and mono_runtime_cleanup will wait for other threads to finish).
15461          */
15462         mono_domain_finalize (domain, 2000);
15463
15464         /* This accesses metadata so needs to be called before runtime shutdown */
15465         print_jit_stats ();
15466
15467         mono_runtime_cleanup (domain);
15468
15469         mono_profiler_shutdown ();
15470
15471         mono_icall_cleanup ();
15472
15473         mono_runtime_cleanup_handlers ();
15474
15475         mono_domain_free (domain, TRUE);
15476
15477         mono_debugger_cleanup ();
15478
15479         mono_trampolines_cleanup ();
15480
15481         mono_code_manager_destroy (global_codeman);
15482         g_hash_table_destroy (jit_icall_name_hash);
15483         g_free (emul_opcode_map);
15484
15485         mono_arch_cleanup ();
15486
15487         mono_cleanup ();
15488
15489         mono_trace_cleanup ();
15490
15491         mono_counters_dump (-1, stdout);
15492
15493         if (mono_inject_async_exc_method)
15494                 mono_method_desc_free (mono_inject_async_exc_method);
15495
15496         TlsFree(mono_jit_tls_id);
15497
15498         DeleteCriticalSection (&jit_mutex);
15499
15500         DeleteCriticalSection (&mono_delegate_section);
15501 }
15502
15503 void
15504 mono_set_defaults (int verbose_level, guint32 opts)
15505 {
15506         mini_verbose = verbose_level;
15507         default_opt = opts;
15508         default_opt_set = TRUE;
15509 }
15510
15511 static void
15512 mono_precompile_assembly (MonoAssembly *ass, void *user_data)
15513 {
15514         GHashTable *assemblies = (GHashTable*)user_data;
15515         MonoImage *image = mono_assembly_get_image (ass);
15516         MonoMethod *method, *invoke;
15517         int i, count = 0;
15518
15519         if (g_hash_table_lookup (assemblies, ass))
15520                 return;
15521
15522         g_hash_table_insert (assemblies, ass, ass);
15523
15524         if (mini_verbose > 0)
15525                 printf ("PRECOMPILE: %s.\n", mono_image_get_filename (image));
15526
15527         for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_METHOD); ++i) {
15528                 method = mono_get_method (image, MONO_TOKEN_METHOD_DEF | (i + 1), NULL);
15529                 if (method->flags & METHOD_ATTRIBUTE_ABSTRACT)
15530                         continue;
15531
15532                 count++;
15533                 if (mini_verbose > 1) {
15534                         char * desc = mono_method_full_name (method, TRUE);
15535                         g_print ("Compiling %d %s\n", count, desc);
15536                         g_free (desc);
15537                 }
15538                 mono_compile_method (method);
15539                 if (strcmp (method->name, "Finalize") == 0) {
15540                         invoke = mono_marshal_get_runtime_invoke (method);
15541                         mono_compile_method (invoke);
15542                 }
15543                 if (method->klass->marshalbyref && mono_method_signature (method)->hasthis) {
15544                         invoke = mono_marshal_get_remoting_invoke_with_check (method);
15545                         mono_compile_method (invoke);
15546                 }
15547         }
15548
15549         /* Load and precompile referenced assemblies as well */
15550         for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_ASSEMBLYREF); ++i) {
15551                 mono_assembly_load_reference (image, i);
15552                 if (image->references [i])
15553                         mono_precompile_assembly (image->references [i], assemblies);
15554         }
15555 }
15556
15557 void mono_precompile_assemblies ()
15558 {
15559         GHashTable *assemblies = g_hash_table_new (NULL, NULL);
15560
15561         mono_assembly_foreach ((GFunc)mono_precompile_assembly, assemblies);
15562
15563         g_hash_table_destroy (assemblies);
15564 }