2008-02-21 Mark Probst <mark.probst@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 PLATFORM_WIN32
30 #define _WIN32_WINNT 0x0500
31 #endif
32
33 #ifdef HAVE_VALGRIND_MEMCHECK_H
34 #include <valgrind/memcheck.h>
35 #endif
36
37 #include <mono/metadata/assembly.h>
38 #include <mono/metadata/loader.h>
39 #include <mono/metadata/tabledefs.h>
40 #include <mono/metadata/class.h>
41 #include <mono/metadata/object.h>
42 #include <mono/metadata/exception.h>
43 #include <mono/metadata/opcodes.h>
44 #include <mono/metadata/mono-endian.h>
45 #include <mono/metadata/tokentype.h>
46 #include <mono/metadata/tabledefs.h>
47 #include <mono/metadata/threads.h>
48 #include <mono/metadata/marshal.h>
49 #include <mono/metadata/socket-io.h>
50 #include <mono/metadata/appdomain.h>
51 #include <mono/metadata/debug-helpers.h>
52 #include <mono/io-layer/io-layer.h>
53 #include "mono/metadata/profiler.h"
54 #include <mono/metadata/profiler-private.h>
55 #include <mono/metadata/mono-config.h>
56 #include <mono/metadata/environment.h>
57 #include <mono/metadata/mono-debug.h>
58 #include <mono/metadata/monitor.h>
59 #include <mono/metadata/gc-internal.h>
60 #include <mono/metadata/security-manager.h>
61 #include <mono/metadata/threads-types.h>
62 #include <mono/metadata/rawbuffer.h>
63 #include <mono/metadata/security-core-clr.h>
64 #include <mono/utils/mono-math.h>
65 #include <mono/utils/mono-compiler.h>
66 #include <mono/utils/mono-counters.h>
67 #include <mono/utils/mono-logger.h>
68 #include <mono/utils/mono-mmap.h>
69
70 #include "mini.h"
71 #include <string.h>
72 #include <ctype.h>
73 #include "inssel.h"
74 #include "trace.h"
75
76 #include "jit-icalls.h"
77
78 #include "aliasing.h"
79
80 #include "debug-mini.h"
81
82 #define BRANCH_COST 100
83 #define INLINE_LENGTH_LIMIT 20
84 #define INLINE_FAILURE do {\
85                 if ((cfg->method != method) && (method->wrapper_type == MONO_WRAPPER_NONE))\
86                         goto inline_failure;\
87         } while (0)
88 #define CHECK_CFG_EXCEPTION do {\
89                 if (cfg->exception_type != MONO_EXCEPTION_NONE)\
90                         goto exception_exit;\
91         } while (0)
92 #define METHOD_ACCESS_FAILURE do {      \
93                 char *method_fname = mono_method_full_name (method, TRUE);      \
94                 char *cil_method_fname = mono_method_full_name (cil_method, TRUE);      \
95                 cfg->exception_type = MONO_EXCEPTION_METHOD_ACCESS;     \
96                 cfg->exception_message = g_strdup_printf ("Method `%s' is inaccessible from method `%s'\n", cil_method_fname, method_fname);    \
97                 g_free (method_fname);  \
98                 g_free (cil_method_fname);      \
99                 goto exception_exit;    \
100         } while (0)
101 #define FIELD_ACCESS_FAILURE do {       \
102                 char *method_fname = mono_method_full_name (method, TRUE);      \
103                 char *field_fname = mono_field_full_name (field);       \
104                 cfg->exception_type = MONO_EXCEPTION_FIELD_ACCESS;      \
105                 cfg->exception_message = g_strdup_printf ("Field `%s' is inaccessible from method `%s'\n", field_fname, method_fname);  \
106                 g_free (method_fname);  \
107                 g_free (field_fname);   \
108                 goto exception_exit;    \
109         } while (0)
110 #define GENERIC_SHARING_FAILURE(opcode) do {            \
111                 if (cfg->generic_sharing_context) {     \
112                         if (!(method->flags & METHOD_ATTRIBUTE_STATIC)) \
113                                 /*g_print ("sharing failed for method %s.%s.%s/%d opcode %s line %d\n", method->klass->name_space, method->klass->name, method->name, method->signature->param_count, mono_opcode_name ((opcode)), __LINE__)*/; \
114                         cfg->exception_type = MONO_EXCEPTION_GENERIC_SHARING_FAILED;    \
115                         goto exception_exit;    \
116                 }                       \
117         } while (0)
118
119 #define MONO_CHECK_THIS(ins) (mono_method_signature (cfg->method)->hasthis && (ins)->ssa_op == MONO_SSA_LOAD && (ins)->inst_left->inst_c0 == 0)
120
121 static void setup_stat_profiler (void);
122 gboolean  mono_arch_print_tree(MonoInst *tree, int arity);
123 static gpointer mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt);
124 static gpointer mono_jit_compile_method (MonoMethod *method);
125 static gpointer mono_jit_find_compiled_method (MonoDomain *domain, MonoMethod *method);
126 static gpointer mono_create_jit_trampoline_in_domain (MonoDomain *domain, MonoMethod *method);
127 inline static int mono_emit_jit_icall (MonoCompile *cfg, MonoBasicBlock *bblock, gconstpointer func, MonoInst **args, const guint8 *ip);
128
129 static void handle_stobj (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *dest, MonoInst *src, 
130                           const unsigned char *ip, MonoClass *klass, gboolean to_end, gboolean native, gboolean write_barrier);
131
132 static void dec_foreach (MonoInst *tree, MonoCompile *cfg);
133
134 static int mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock, 
135                    int locals_offset, MonoInst *return_var, GList *dont_inline, MonoInst **inline_args, 
136                    guint inline_offset, gboolean is_virtual_call);
137
138 #ifdef MONO_ARCH_SOFT_FLOAT
139 static void
140 handle_store_float (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *ptr, MonoInst *val, const unsigned char *ip);
141 #endif
142
143 /* helper methods signature */
144 static MonoMethodSignature *helper_sig_class_init_trampoline = NULL;
145 static MonoMethodSignature *helper_sig_generic_class_init_trampoline = NULL;
146 static MonoMethodSignature *helper_sig_domain_get = NULL;
147
148 static guint32 default_opt = 0;
149 static gboolean default_opt_set = FALSE;
150
151 guint32 mono_jit_tls_id = -1;
152 MonoTraceSpec *mono_jit_trace_calls = NULL;
153 gboolean mono_break_on_exc = FALSE;
154 #ifndef DISABLE_AOT
155 gboolean mono_compile_aot = FALSE;
156 #endif
157 MonoMethodDesc *mono_inject_async_exc_method = NULL;
158 int mono_inject_async_exc_pos;
159 MonoMethodDesc *mono_break_at_bb_method = NULL;
160 int mono_break_at_bb_bb_num;
161
162 static int mini_verbose = 0;
163
164 #define mono_jit_lock() EnterCriticalSection (&jit_mutex)
165 #define mono_jit_unlock() LeaveCriticalSection (&jit_mutex)
166 static CRITICAL_SECTION jit_mutex;
167
168 static GHashTable *class_init_hash_addr = NULL;
169 static GHashTable *delegate_trampoline_hash_addr = NULL;
170
171 static MonoCodeManager *global_codeman = NULL;
172
173 static GHashTable *jit_icall_name_hash = NULL;
174
175 static MonoDebugOptions debug_options;
176
177 #ifdef VALGRIND_JIT_REGISTER_MAP
178 static int valgrind_register = 0;
179 #endif
180
181 /*
182  * Address of the trampoline code.  This is used by the debugger to check
183  * whether a method is a trampoline.
184  */
185 guint8* mono_trampoline_code [MONO_TRAMPOLINE_NUM];
186
187 /*
188  * Table written to by the debugger with a 1-based index into the
189  * mono_breakpoint_info table, which contains changes made to
190  * the JIT instructions by the debugger.
191  */
192 gssize
193 mono_breakpoint_info_index [MONO_BREAKPOINT_ARRAY_SIZE];
194
195 /* Whenever to check for pending exceptions in managed-to-native wrappers */
196 gboolean check_for_pending_exc = TRUE;
197
198 gboolean
199 mono_running_on_valgrind (void)
200 {
201 #ifdef HAVE_VALGRIND_MEMCHECK_H
202                 if (RUNNING_ON_VALGRIND){
203 #ifdef VALGRIND_JIT_REGISTER_MAP
204                         valgrind_register = TRUE;
205 #endif
206                         return TRUE;
207                 } else
208                         return FALSE;
209 #else
210                 return FALSE;
211 #endif
212 }
213
214 typedef struct {
215         void *ip;
216         MonoMethod *method;
217 } FindTrampUserData;
218
219 static void
220 find_tramp (gpointer key, gpointer value, gpointer user_data)
221 {
222         FindTrampUserData *ud = (FindTrampUserData*)user_data;
223
224         if (value == ud->ip)
225                 ud->method = (MonoMethod*)key;
226 }
227
228 /* debug function */
229 G_GNUC_UNUSED static char*
230 get_method_from_ip (void *ip)
231 {
232         MonoJitInfo *ji;
233         char *method;
234         char *res;
235         MonoDomain *domain = mono_domain_get ();
236         MonoDebugSourceLocation *location;
237         FindTrampUserData user_data;
238         
239         ji = mono_jit_info_table_find (domain, ip);
240         if (!ji) {
241                 user_data.ip = ip;
242                 user_data.method = NULL;
243                 mono_domain_lock (domain);
244                 g_hash_table_foreach (domain->jit_trampoline_hash, find_tramp, &user_data);
245                 mono_domain_unlock (domain);
246                 if (user_data.method) {
247                         char *mname = mono_method_full_name (user_data.method, TRUE);
248                         res = g_strdup_printf ("<%p - JIT trampoline for %s>", ip, mname);
249                         g_free (mname);
250                         return res;
251                 }
252                 else
253                         return NULL;
254         }
255         method = mono_method_full_name (ji->method, TRUE);
256         /* FIXME: unused ? */
257         location = mono_debug_lookup_source_location (ji->method, (guint32)((guint8*)ip - (guint8*)ji->code_start), domain);
258
259         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);
260
261         mono_debug_free_source_location (location);
262         g_free (method);
263
264         return res;
265 }
266
267 /** 
268  * mono_pmip:
269  * @ip: an instruction pointer address
270  *
271  * This method is used from a debugger to get the name of the
272  * method at address @ip.   This routine is typically invoked from
273  * a debugger like this:
274  *
275  * (gdb) print mono_pmip ($pc)
276  *
277  * Returns: the name of the method at address @ip.
278  */
279 G_GNUC_UNUSED char *
280 mono_pmip (void *ip)
281 {
282         return get_method_from_ip (ip);
283 }
284
285 /** 
286  * mono_print_method_from_ip
287  * @ip: an instruction pointer address
288  *
289  * This method is used from a debugger to get the name of the
290  * method at address @ip.
291  *
292  * This prints the name of the method at address @ip in the standard
293  * output.  Unlike mono_pmip which returns a string, this routine
294  * prints the value on the standard output. 
295  */
296 void
297 mono_print_method_from_ip (void *ip)
298 {
299         MonoJitInfo *ji;
300         char *method;
301         MonoDebugSourceLocation *source;
302         MonoDomain *domain = mono_domain_get ();
303         FindTrampUserData user_data;
304         
305         ji = mono_jit_info_table_find (domain, ip);
306         if (!ji) {
307                 user_data.ip = ip;
308                 user_data.method = NULL;
309                 mono_domain_lock (domain);
310                 g_hash_table_foreach (domain->jit_trampoline_hash, find_tramp, &user_data);
311                 mono_domain_unlock (domain);
312                 if (user_data.method) {
313                         char *mname = mono_method_full_name (user_data.method, TRUE);
314                         printf ("IP %p is a JIT trampoline for %s\n", ip, mname);
315                         g_free (mname);
316                 }
317                 else
318                         g_print ("No method at %p\n", ip);
319                 return;
320         }
321         method = mono_method_full_name (ji->method, TRUE);
322         source = mono_debug_lookup_source_location (ji->method, (guint32)((guint8*)ip - (guint8*)ji->code_start), domain);
323
324         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);
325
326         if (source)
327                 g_print ("%s:%d\n", source->source_file, source->row);
328
329         mono_debug_free_source_location (source);
330         g_free (method);
331 }
332         
333 /* 
334  * mono_method_same_domain:
335  *
336  * Determine whenever two compiled methods are in the same domain, thus
337  * the address of the callee can be embedded in the caller.
338  */
339 gboolean mono_method_same_domain (MonoJitInfo *caller, MonoJitInfo *callee)
340 {
341         if (!caller || !callee)
342                 return FALSE;
343
344         /*
345          * If the call was made from domain-neutral to domain-specific 
346          * code, we can't patch the call site.
347          */
348         if (caller->domain_neutral && !callee->domain_neutral)
349                 return FALSE;
350
351         if ((caller->method->klass == mono_defaults.appdomain_class) &&
352                 (strstr (caller->method->name, "InvokeInDomain"))) {
353                  /* The InvokeInDomain methods change the current appdomain */
354                 return FALSE;
355         }
356
357         return TRUE;
358 }
359
360 /*
361  * mono_global_codeman_reserve:
362  *
363  *  Allocate code memory from the global code manager.
364  */
365 void *mono_global_codeman_reserve (int size)
366 {
367         void *ptr;
368
369         if (!global_codeman) {
370                 /* This can happen during startup */
371                 global_codeman = mono_code_manager_new ();
372                 return mono_code_manager_reserve (global_codeman, size);
373         }
374         else {
375                 mono_jit_lock ();
376                 ptr = mono_code_manager_reserve (global_codeman, size);
377                 mono_jit_unlock ();
378                 return ptr;
379         }
380 }
381
382 MonoJumpInfoToken *
383 mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
384 {
385         MonoJumpInfoToken *res = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoToken));
386         res->image = image;
387         res->token = token;
388
389         return res;
390 }
391
392 #define MONO_INIT_VARINFO(vi,id) do { \
393         (vi)->range.first_use.pos.bid = 0xffff; \
394         (vi)->reg = -1; \
395         (vi)->idx = (id); \
396 } while (0)
397
398 //#define UNVERIFIED do { G_BREAKPOINT (); goto unverified; } while (0)
399 #define UNVERIFIED do { if (debug_options.break_on_unverified) G_BREAKPOINT (); else goto unverified; } while (0)
400
401 /*
402  * Basic blocks have two numeric identifiers:
403  * dfn: Depth First Number
404  * block_num: unique ID assigned at bblock creation
405  */
406 #define NEW_BBLOCK(cfg,new_bb) do {     \
407                 new_bb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock)); \
408                 MONO_INST_LIST_INIT (&new_bb->ins_list); \
409         } while (0)
410
411 #define ADD_BBLOCK(cfg,b) do {  \
412                 cfg->cil_offset_to_bb [(b)->cil_code - cfg->cil_start] = (b);   \
413                 (b)->block_num = cfg->num_bblocks++;    \
414                 (b)->real_offset = real_offset; \
415         } while (0)
416
417 #define GET_BBLOCK(cfg,tblock,ip) do {  \
418                 (tblock) = cfg->cil_offset_to_bb [(ip) - cfg->cil_start]; \
419                 if (!(tblock)) {        \
420                         if ((ip) >= end || (ip) < header->code) UNVERIFIED; \
421                         NEW_BBLOCK (cfg, (tblock));     \
422                         (tblock)->cil_code = (ip);      \
423                         ADD_BBLOCK (cfg, (tblock));     \
424                 } \
425         } while (0)
426
427 #define CHECK_BBLOCK(target,ip,tblock) do {     \
428                 if ((target) < (ip) && \
429                                 MONO_INST_LIST_EMPTY (&(tblock)->ins_list)) { \
430                         bb_recheck = g_list_prepend (bb_recheck, (tblock)); \
431                         if (cfg->verbose_level > 2) \
432                                 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)); \
433                 } \
434         } while (0)
435
436 #define NEW_ICONST(cfg,dest,val) do {   \
437                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
438                 (dest)->opcode = OP_ICONST;     \
439                 (dest)->inst_c0 = (val);        \
440                 (dest)->type = STACK_I4;        \
441         } while (0)
442
443 #define NEW_PCONST(cfg,dest,val) do {   \
444                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
445                 (dest)->opcode = OP_PCONST;     \
446                 (dest)->inst_p0 = (val);        \
447                 (dest)->type = STACK_PTR;       \
448         } while (0)
449
450
451 #ifdef MONO_ARCH_NEED_GOT_VAR
452
453 #define NEW_PATCH_INFO(cfg,dest,el1,el2) do {   \
454                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
455                 (dest)->opcode = OP_PATCH_INFO; \
456                 (dest)->inst_left = (gpointer)(el1);    \
457                 (dest)->inst_right = (gpointer)(el2);   \
458         } while (0)
459
460 #define NEW_AOTCONST(cfg,dest,patch_type,cons) do {                     \
461                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
462                 (dest)->opcode = cfg->compile_aot ? OP_GOT_ENTRY : OP_PCONST; \
463                 if (cfg->compile_aot) {                                 \
464                         MonoInst *group, *got_var, *got_loc;            \
465                         got_loc = mono_get_got_var (cfg);               \
466                         NEW_TEMPLOAD ((cfg), got_var, got_loc->inst_c0); \
467                         NEW_PATCH_INFO ((cfg), group, cons, patch_type); \
468                         (dest)->inst_p0 = got_var;                      \
469                         (dest)->inst_p1 = group;                        \
470                 } else {                                                \
471                         (dest)->inst_p0 = (cons);                       \
472                         (dest)->inst_i1 = (gpointer)(patch_type);       \
473                 }                                                       \
474                 (dest)->type = STACK_PTR;                               \
475         } while (0)
476
477 #define NEW_AOTCONST_TOKEN(cfg,dest,patch_type,image,token,stack_type,stack_class) do { \
478                 MonoInst *group, *got_var, *got_loc;                    \
479                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
480                 (dest)->opcode = OP_GOT_ENTRY;                          \
481                 got_loc = mono_get_got_var (cfg);                       \
482                 NEW_TEMPLOAD ((cfg), got_var, got_loc->inst_c0);        \
483                 NEW_PATCH_INFO ((cfg), group, NULL, patch_type);        \
484                 group->inst_p0 = mono_jump_info_token_new ((cfg)->mempool, (image), (token)); \
485                 (dest)->inst_p0 = got_var;                              \
486                 (dest)->inst_p1 = group;                                \
487                 (dest)->type = (stack_type);                    \
488         (dest)->klass = (stack_class);          \
489         } while (0)
490
491 #else
492
493 #define NEW_AOTCONST(cfg,dest,patch_type,cons) do {    \
494                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
495                 (dest)->opcode = cfg->compile_aot ? OP_AOTCONST : OP_PCONST;    \
496                 (dest)->inst_p0 = (cons);       \
497                 (dest)->inst_i1 = (gpointer)(patch_type); \
498                 (dest)->type = STACK_PTR;       \
499     } while (0)
500
501 #define NEW_AOTCONST_TOKEN(cfg,dest,patch_type,image,token,stack_type,stack_class) do { \
502                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
503                 (dest)->opcode = OP_AOTCONST;   \
504                 (dest)->inst_p0 = mono_jump_info_token_new ((cfg)->mempool, (image), (token));  \
505                 (dest)->inst_p1 = (gpointer)(patch_type); \
506                 (dest)->type = (stack_type);    \
507         (dest)->klass = (stack_class);          \
508     } while (0)
509
510 #endif
511
512 #define NEW_CLASSCONST(cfg,dest,val) NEW_AOTCONST ((cfg), (dest), MONO_PATCH_INFO_CLASS, (val))
513
514 #define NEW_IMAGECONST(cfg,dest,val) NEW_AOTCONST ((cfg), (dest), MONO_PATCH_INFO_IMAGE, (val))
515
516 #define NEW_FIELDCONST(cfg,dest,val) NEW_AOTCONST ((cfg), (dest), MONO_PATCH_INFO_FIELD, (val))
517
518 #define NEW_METHODCONST(cfg,dest,val) NEW_AOTCONST ((cfg), (dest), MONO_PATCH_INFO_METHODCONST, (val))
519
520 #define NEW_VTABLECONST(cfg,dest,vtable) NEW_AOTCONST ((cfg), (dest), MONO_PATCH_INFO_VTABLE, cfg->compile_aot ? (gpointer)((vtable)->klass) : (vtable))
521
522 #define NEW_SFLDACONST(cfg,dest,val) NEW_AOTCONST ((cfg), (dest), MONO_PATCH_INFO_SFLDA, (val))
523
524 #define NEW_LDSTRCONST(cfg,dest,image,token) NEW_AOTCONST_TOKEN ((cfg), (dest), MONO_PATCH_INFO_LDSTR, (image), (token), STACK_OBJ, mono_defaults.string_class)
525
526 #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)
527
528 #define NEW_LDTOKENCONST(cfg,dest,image,token) NEW_AOTCONST_TOKEN ((cfg), (dest), MONO_PATCH_INFO_LDTOKEN, (image), (token), STACK_PTR, NULL)
529
530 #define NEW_DECLSECCONST(cfg,dest,image,entry) do { \
531                 if (cfg->compile_aot) { \
532                         NEW_AOTCONST_TOKEN (cfg, dest, MONO_PATCH_INFO_DECLSEC, image, (entry).index, STACK_OBJ, NULL); \
533                 } else { \
534                         NEW_PCONST (cfg, args [0], (entry).blob); \
535                 } \
536         } while (0)
537
538 #define NEW_DOMAINCONST(cfg,dest) do { \
539                 if (cfg->opt & MONO_OPT_SHARED) { \
540                         /* avoid depending on undefined C behavior in sequence points */ \
541                         MonoInst* __domain_var = mono_get_domainvar (cfg); \
542                         NEW_TEMPLOAD (cfg, dest, __domain_var->inst_c0); \
543                 } else { \
544                         NEW_PCONST (cfg, dest, (cfg)->domain); \
545                 } \
546         } while (0)
547
548 #define GET_VARINFO_INST(cfg,num) ((cfg)->varinfo [(num)]->inst)
549
550 #define NEW_ARGLOAD(cfg,dest,num) do {  \
551                 if (arg_array [(num)]->opcode == OP_ICONST) (dest) = arg_array [(num)]; else { \
552                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
553                 (dest)->ssa_op = MONO_SSA_LOAD; \
554                 (dest)->inst_i0 = arg_array [(num)];    \
555                 (dest)->opcode = mini_type_to_ldind ((cfg), (dest)->inst_i0->inst_vtype); \
556                 type_to_eval_stack_type ((cfg), param_types [(num)], (dest));   \
557                 (dest)->klass = (dest)->inst_i0->klass; \
558         }} while (0)
559
560 #define NEW_LOCLOAD(cfg,dest,num) do {  \
561                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
562                 (dest)->ssa_op = MONO_SSA_LOAD; \
563                 (dest)->inst_i0 = (cfg)->varinfo [locals_offset + (num)];       \
564                 (dest)->opcode = mini_type_to_ldind ((cfg), (dest)->inst_i0->inst_vtype); \
565                 type_to_eval_stack_type ((cfg), header->locals [(num)], (dest));        \
566                 (dest)->klass = (dest)->inst_i0->klass; \
567         } while (0)
568
569 #define NEW_LOCLOADA(cfg,dest,num) do { \
570                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
571                 (dest)->ssa_op = MONO_SSA_ADDRESS_TAKEN;        \
572                 (dest)->inst_i0 = (cfg)->varinfo [locals_offset + (num)];       \
573                 (dest)->inst_i0->flags |= MONO_INST_INDIRECT;   \
574                 (dest)->opcode = OP_LDADDR;     \
575                 (dest)->type = STACK_MP;        \
576                 (dest)->klass = (dest)->inst_i0->klass; \
577         if (!MONO_TYPE_ISSTRUCT (header->locals [(num)])) \
578            (cfg)->disable_ssa = TRUE; \
579         } while (0)
580
581 #define NEW_RETLOADA(cfg,dest) do {     \
582         if (cfg->vret_addr) { \
583                     (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));   \
584                     (dest)->ssa_op = MONO_SSA_LOAD;     \
585                     (dest)->inst_i0 = cfg->vret_addr; \
586                     (dest)->opcode = mini_type_to_ldind ((cfg), (dest)->inst_i0->inst_vtype); \
587             (dest)->type = STACK_MP; \
588                     (dest)->klass = (dest)->inst_i0->klass;     \
589         } else { \
590                         (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
591                     (dest)->ssa_op = MONO_SSA_ADDRESS_TAKEN;    \
592                     (dest)->inst_i0 = (cfg)->ret;       \
593                     (dest)->inst_i0->flags |= MONO_INST_INDIRECT;       \
594                     (dest)->opcode = cfg->ret_var_is_local ? OP_LDADDR : CEE_LDIND_I;   \
595                     (dest)->type = STACK_MP;    \
596                     (dest)->klass = (dest)->inst_i0->klass;     \
597             (cfg)->disable_ssa = TRUE; \
598         } \
599         } while (0)
600
601 #define NEW_ARGLOADA(cfg,dest,num) do { \
602                 if (arg_array [(num)]->opcode == OP_ICONST) goto inline_failure; \
603                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
604                 (dest)->ssa_op = MONO_SSA_ADDRESS_TAKEN;        \
605                 (dest)->inst_i0 = arg_array [(num)];    \
606                 (dest)->inst_i0->flags |= MONO_INST_INDIRECT;   \
607                 (dest)->opcode = OP_LDADDR;     \
608                 (dest)->type = STACK_MP;        \
609                 (dest)->klass = (dest)->inst_i0->klass; \
610                 (cfg)->disable_ssa = TRUE; \
611         } while (0)
612
613 #define NEW_TEMPLOAD(cfg,dest,num) do { \
614                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
615                 (dest)->ssa_op = MONO_SSA_LOAD; \
616                 (dest)->inst_i0 = (cfg)->varinfo [(num)];       \
617                 (dest)->opcode = mini_type_to_ldind ((cfg), (dest)->inst_i0->inst_vtype); \
618                 type_to_eval_stack_type ((cfg), (dest)->inst_i0->inst_vtype, (dest));   \
619                 (dest)->klass = (dest)->inst_i0->klass; \
620         } while (0)
621
622 #define NEW_TEMPLOADA(cfg,dest,num) do {        \
623                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
624                 (dest)->ssa_op = MONO_SSA_ADDRESS_TAKEN;        \
625                 (dest)->inst_i0 = (cfg)->varinfo [(num)];       \
626                 (dest)->inst_i0->flags |= MONO_INST_INDIRECT;   \
627                 (dest)->opcode = OP_LDADDR;     \
628                 (dest)->type = STACK_MP;        \
629                 (dest)->klass = (dest)->inst_i0->klass; \
630         if (!MONO_TYPE_ISSTRUCT (cfg->varinfo [(num)]->inst_vtype)) \
631            (cfg)->disable_ssa = TRUE; \
632         } while (0)
633
634
635 #define NEW_INDLOAD(cfg,dest,addr,vtype) do {   \
636                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
637                 (dest)->inst_left = addr;       \
638                 (dest)->opcode = mini_type_to_ldind ((cfg), vtype);     \
639                 type_to_eval_stack_type ((cfg), vtype, (dest)); \
640                 /* FIXME: (dest)->klass = (dest)->inst_i0->klass;*/     \
641         } while (0)
642
643 #define NEW_INDSTORE(cfg,dest,addr,value,vtype) do {    \
644                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
645                 (dest)->inst_i0 = addr; \
646                 (dest)->opcode = mini_type_to_stind ((cfg), vtype);     \
647                 (dest)->inst_i1 = (value);      \
648                 /* FIXME: (dest)->klass = (dest)->inst_i0->klass;*/     \
649         } while (0)
650
651 #define NEW_TEMPSTORE(cfg,dest,num,inst) do {   \
652                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
653                 (dest)->ssa_op = MONO_SSA_STORE;        \
654                 (dest)->inst_i0 = (cfg)->varinfo [(num)];       \
655                 (dest)->opcode = mini_type_to_stind ((cfg), (dest)->inst_i0->inst_vtype); \
656                 (dest)->inst_i1 = (inst);       \
657                 (dest)->klass = (dest)->inst_i0->klass; \
658         } while (0)
659
660 #define NEW_LOCSTORE(cfg,dest,num,inst) do {    \
661                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
662                 (dest)->opcode = mini_type_to_stind ((cfg), header->locals [(num)]); \
663                 (dest)->ssa_op = MONO_SSA_STORE;        \
664                 (dest)->inst_i0 = (cfg)->varinfo [locals_offset + (num)];       \
665                 (dest)->inst_i1 = (inst);       \
666                 (dest)->klass = (dest)->inst_i0->klass; \
667         } while (0)
668
669 #define NEW_ARGSTORE(cfg,dest,num,inst) do {    \
670                 if (arg_array [(num)]->opcode == OP_ICONST) goto inline_failure; \
671                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
672                 (dest)->opcode = mini_type_to_stind ((cfg), param_types [(num)]); \
673                 (dest)->ssa_op = MONO_SSA_STORE;        \
674                 (dest)->inst_i0 = arg_array [(num)];    \
675                 (dest)->inst_i1 = (inst);       \
676                 (dest)->klass = (dest)->inst_i0->klass; \
677         } while (0)
678
679 #define NEW_MEMCPY(cfg,dest,dst,src,memcpy_size,memcpy_align) do { \
680                 MONO_INST_NEW (cfg, dest, OP_MEMCPY); \
681         (dest)->inst_left = (dst); \
682                 (dest)->inst_right = (src); \
683                 (dest)->cil_code = ip; \
684         (dest)->backend.memcpy_args = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoMemcpyArgs)); \
685                 (dest)->backend.memcpy_args->size = (memcpy_size); \
686                 (dest)->backend.memcpy_args->align = (memcpy_align); \
687     } while (0)
688
689 #define NEW_MEMSET(cfg,dest,dst,imm,memcpy_size,memcpy_align) do { \
690                 MONO_INST_NEW (cfg, dest, OP_MEMSET); \
691         (dest)->inst_left = (dst); \
692                 (dest)->inst_imm = (imm); \
693                 (dest)->cil_code = ip; \
694         (dest)->backend.memcpy_args = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoMemcpyArgs)); \
695                 (dest)->backend.memcpy_args->size = (memcpy_size); \
696                 (dest)->backend.memcpy_args->align = (memcpy_align); \
697     } while (0)
698
699 #define NEW_DUMMY_USE(cfg,dest,load) do { \
700                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
701                 (dest)->opcode = OP_DUMMY_USE; \
702                 (dest)->inst_left = (load); \
703     } while (0)
704
705 #define NEW_DUMMY_STORE(cfg,dest,num) do { \
706                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
707                 (dest)->inst_i0 = (cfg)->varinfo [(num)];       \
708                 (dest)->opcode = OP_DUMMY_STORE; \
709                 (dest)->klass = (dest)->inst_i0->klass; \
710         } while (0)
711
712 #define ADD_BINOP(op) do {      \
713                 MONO_INST_NEW (cfg, ins, (op)); \
714                 ins->cil_code = ip;     \
715                 sp -= 2;        \
716                 ins->inst_i0 = sp [0];  \
717                 ins->inst_i1 = sp [1];  \
718                 *sp++ = ins;    \
719                 type_from_op (ins);     \
720                 CHECK_TYPE (ins);       \
721         } while (0)
722
723 #define ADD_UNOP(op) do {       \
724                 MONO_INST_NEW (cfg, ins, (op)); \
725                 ins->cil_code = ip;     \
726                 sp--;   \
727                 ins->inst_i0 = sp [0];  \
728                 *sp++ = ins;    \
729                 type_from_op (ins);     \
730                 CHECK_TYPE (ins);       \
731         } while (0)
732
733 #define ADD_BINCOND(next_block) do {    \
734                 MonoInst *cmp;  \
735                 sp -= 2;                \
736                 MONO_INST_NEW(cfg, cmp, OP_COMPARE);    \
737                 cmp->inst_i0 = sp [0];  \
738                 cmp->inst_i1 = sp [1];  \
739                 cmp->cil_code = ins->cil_code;  \
740                 type_from_op (cmp);     \
741                 CHECK_TYPE (cmp);       \
742                 ins->inst_i0 = cmp;     \
743                 MONO_ADD_INS (bblock, ins);     \
744                 ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);      \
745                 GET_BBLOCK (cfg, tblock, target);               \
746                 link_bblock (cfg, bblock, tblock);      \
747                 ins->inst_true_bb = tblock;     \
748                 CHECK_BBLOCK (target, ip, tblock);      \
749                 if ((next_block)) {     \
750                         link_bblock (cfg, bblock, (next_block));        \
751                         ins->inst_false_bb = (next_block);      \
752                         start_new_bblock = 1;   \
753                 } else {        \
754                         GET_BBLOCK (cfg, tblock, ip);           \
755                         link_bblock (cfg, bblock, tblock);      \
756                         ins->inst_false_bb = tblock;    \
757                         start_new_bblock = 2;   \
758                 }       \
759         } while (0)
760
761 /* FIXME: handle float, long ... */
762 #define ADD_UNCOND(istrue) do { \
763                 MonoInst *cmp;  \
764                 sp--;           \
765                 MONO_INST_NEW(cfg, cmp, OP_COMPARE);    \
766                 cmp->inst_i0 = sp [0];  \
767                 switch (cmp->inst_i0->type) { \
768                 case STACK_I8: \
769                         cmp->inst_i1 = zero_int64; break; \
770                 case STACK_R8: \
771                         cmp->inst_i1 = zero_r8; break; \
772                 case STACK_PTR: \
773                 case STACK_MP: \
774                         cmp->inst_i1 = zero_ptr; break; \
775                 case STACK_OBJ: \
776                         cmp->inst_i1 = zero_obj; break; \
777                 default: \
778                         cmp->inst_i1 = zero_int32;  \
779                 }  \
780                 cmp->cil_code = ins->cil_code;  \
781                 type_from_op (cmp);     \
782                 CHECK_TYPE (cmp);       \
783                 ins->inst_i0 = cmp;     \
784                 ins->opcode = (istrue)? CEE_BNE_UN: CEE_BEQ;    \
785                 MONO_ADD_INS (bblock, ins);     \
786                 ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);      \
787                 GET_BBLOCK (cfg, tblock, target);               \
788                 link_bblock (cfg, bblock, tblock);      \
789                 ins->inst_true_bb = tblock;     \
790                 CHECK_BBLOCK (target, ip, tblock);      \
791                 GET_BBLOCK (cfg, tblock, ip);           \
792                 link_bblock (cfg, bblock, tblock);      \
793                 ins->inst_false_bb = tblock;    \
794                 start_new_bblock = 2;   \
795         } while (0)
796
797 #define NEW_LDELEMA(cfg,dest,sp,k) do { \
798                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
799                 (dest)->opcode = CEE_LDELEMA;   \
800                 (dest)->inst_left = (sp) [0];   \
801                 (dest)->inst_right = (sp) [1];  \
802                 (dest)->type = STACK_MP;        \
803                 (dest)->klass = (k);    \
804                 (cfg)->flags |= MONO_CFG_HAS_LDELEMA; \
805         } while (0)
806
807 #define NEW_GROUP(cfg,dest,el1,el2) do {        \
808                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
809                 (dest)->opcode = OP_GROUP;      \
810                 (dest)->inst_left = (el1);      \
811                 (dest)->inst_right = (el2);     \
812         } while (0)
813
814 #if 0
815 static gint
816 compare_bblock (gconstpointer a, gconstpointer b)
817 {
818         const MonoBasicBlock *b1 = a;
819         const MonoBasicBlock *b2 = b;
820
821         return b2->cil_code - b1->cil_code;
822 }
823 #endif
824
825 /* *
826  * link_bblock: Links two basic blocks
827  *
828  * links two basic blocks in the control flow graph, the 'from'
829  * argument is the starting block and the 'to' argument is the block
830  * the control flow ends to after 'from'.
831  */
832 static void
833 link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
834 {
835         MonoBasicBlock **newa;
836         int i, found;
837
838 #if 0
839         if (from->cil_code) {
840                 if (to->cil_code)
841                         g_print ("edge from IL%04x to IL_%04x\n", from->cil_code - cfg->cil_code, to->cil_code - cfg->cil_code);
842                 else
843                         g_print ("edge from IL%04x to exit\n", from->cil_code - cfg->cil_code);
844         } else {
845                 if (to->cil_code)
846                         g_print ("edge from entry to IL_%04x\n", to->cil_code - cfg->cil_code);
847                 else
848                         g_print ("edge from entry to exit\n");
849         }
850 #endif
851         found = FALSE;
852         for (i = 0; i < from->out_count; ++i) {
853                 if (to == from->out_bb [i]) {
854                         found = TRUE;
855                         break;
856                 }
857         }
858         if (!found) {
859                 newa = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (from->out_count + 1));
860                 for (i = 0; i < from->out_count; ++i) {
861                         newa [i] = from->out_bb [i];
862                 }
863                 newa [i] = to;
864                 from->out_count++;
865                 from->out_bb = newa;
866         }
867
868         found = FALSE;
869         for (i = 0; i < to->in_count; ++i) {
870                 if (from == to->in_bb [i]) {
871                         found = TRUE;
872                         break;
873                 }
874         }
875         if (!found) {
876                 newa = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (to->in_count + 1));
877                 for (i = 0; i < to->in_count; ++i) {
878                         newa [i] = to->in_bb [i];
879                 }
880                 newa [i] = from;
881                 to->in_count++;
882                 to->in_bb = newa;
883         }
884 }
885
886 /**
887  * mono_unlink_bblock:
888  *
889  *   Unlink two basic blocks.
890  */
891 static void
892 mono_unlink_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
893 {
894         int i, pos;
895         gboolean found;
896
897         found = FALSE;
898         for (i = 0; i < from->out_count; ++i) {
899                 if (to == from->out_bb [i]) {
900                         found = TRUE;
901                         break;
902                 }
903         }
904         if (found) {
905                 pos = 0;
906                 for (i = 0; i < from->out_count; ++i) {
907                         if (from->out_bb [i] != to)
908                                 from->out_bb [pos ++] = from->out_bb [i];
909                 }
910                 g_assert (pos == from->out_count - 1);
911                 from->out_count--;
912         }
913
914         found = FALSE;
915         for (i = 0; i < to->in_count; ++i) {
916                 if (from == to->in_bb [i]) {
917                         found = TRUE;
918                         break;
919                 }
920         }
921         if (found) {
922                 pos = 0;
923                 for (i = 0; i < to->in_count; ++i) {
924                         if (to->in_bb [i] != from)
925                                 to->in_bb [pos ++] = to->in_bb [i];
926                 }
927                 g_assert (pos == to->in_count - 1);
928                 to->in_count--;
929         }
930 }
931
932 /**
933  * mono_find_block_region:
934  *
935  *   We mark each basic block with a region ID. We use that to avoid BB
936  *   optimizations when blocks are in different regions.
937  *
938  * Returns:
939  *   A region token that encodes where this region is, and information
940  *   about the clause owner for this block.
941  *
942  *   The region encodes the try/catch/filter clause that owns this block
943  *   as well as the type.  -1 is a special value that represents a block
944  *   that is in none of try/catch/filter.
945  */
946 static int
947 mono_find_block_region (MonoCompile *cfg, int offset)
948 {
949         MonoMethod *method = cfg->method;
950         MonoMethodHeader *header = mono_method_get_header (method);
951         MonoExceptionClause *clause;
952         int i;
953
954         /* first search for handlers and filters */
955         for (i = 0; i < header->num_clauses; ++i) {
956                 clause = &header->clauses [i];
957                 if ((clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) && (offset >= clause->data.filter_offset) &&
958                     (offset < (clause->handler_offset)))
959                         return ((i + 1) << 8) | MONO_REGION_FILTER | clause->flags;
960                            
961                 if (MONO_OFFSET_IN_HANDLER (clause, offset)) {
962                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY)
963                                 return ((i + 1) << 8) | MONO_REGION_FINALLY | clause->flags;
964                         else if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
965                                 return ((i + 1) << 8) | MONO_REGION_FAULT | clause->flags;
966                         else if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE)
967                                 return ((i + 1) << 8) | MONO_REGION_CATCH | clause->flags;
968                 }
969         }
970
971         /* search the try blocks */
972         for (i = 0; i < header->num_clauses; ++i) {
973                 clause = &header->clauses [i];
974                 if (MONO_OFFSET_IN_CLAUSE (clause, offset))
975                         return ((i + 1) << 8) | clause->flags;
976         }
977
978         return -1;
979 }
980
981 static GList*
982 mono_find_final_block (MonoCompile *cfg, unsigned char *ip, unsigned char *target, int type)
983 {
984         MonoMethod *method = cfg->method;
985         MonoMethodHeader *header = mono_method_get_header (method);
986         MonoExceptionClause *clause;
987         MonoBasicBlock *handler;
988         int i;
989         GList *res = NULL;
990
991         for (i = 0; i < header->num_clauses; ++i) {
992                 clause = &header->clauses [i];
993                 if (MONO_OFFSET_IN_CLAUSE (clause, (ip - header->code)) && 
994                     (!MONO_OFFSET_IN_CLAUSE (clause, (target - header->code)))) {
995                         if (clause->flags == type) {
996                                 handler = cfg->cil_offset_to_bb [clause->handler_offset];
997                                 g_assert (handler);
998                                 res = g_list_append (res, handler);
999                         }
1000                 }
1001         }
1002         return res;
1003 }
1004
1005 MonoInst *
1006 mono_find_spvar_for_region (MonoCompile *cfg, int region)
1007 {
1008         return g_hash_table_lookup (cfg->spvars, GINT_TO_POINTER (region));
1009 }
1010
1011 static void
1012 mono_create_spvar_for_region (MonoCompile *cfg, int region)
1013 {
1014         MonoInst *var;
1015
1016         var = g_hash_table_lookup (cfg->spvars, GINT_TO_POINTER (region));
1017         if (var)
1018                 return;
1019
1020         var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1021         /* prevent it from being register allocated */
1022         var->flags |= MONO_INST_INDIRECT;
1023
1024         g_hash_table_insert (cfg->spvars, GINT_TO_POINTER (region), var);
1025 }
1026
1027 static MonoInst *
1028 mono_find_exvar_for_offset (MonoCompile *cfg, int offset)
1029 {
1030         return g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
1031 }
1032
1033 static MonoInst*
1034 mono_create_exvar_for_offset (MonoCompile *cfg, int offset)
1035 {
1036         MonoInst *var;
1037
1038         var = g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
1039         if (var)
1040                 return var;
1041
1042         var = mono_compile_create_var (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL);
1043         /* prevent it from being register allocated */
1044         var->flags |= MONO_INST_INDIRECT;
1045
1046         g_hash_table_insert (cfg->exvars, GINT_TO_POINTER (offset), var);
1047
1048         return var;
1049 }
1050
1051 static void
1052 df_visit (MonoBasicBlock *start, int *dfn, MonoBasicBlock **array)
1053 {
1054         int i;
1055
1056         array [*dfn] = start;
1057         /*g_print ("visit %d at %p (BB%ld)\n", *dfn, start->cil_code, start->block_num);*/
1058         for (i = 0; i < start->out_count; ++i) {
1059                 if (start->out_bb [i]->dfn)
1060                         continue;
1061                 (*dfn)++;
1062                 start->out_bb [i]->dfn = *dfn;
1063                 start->out_bb [i]->df_parent = start;
1064                 array [*dfn] = start->out_bb [i];
1065                 df_visit (start->out_bb [i], dfn, array);
1066         }
1067 }
1068
1069 static MonoBasicBlock*
1070 find_previous (MonoBasicBlock **bblocks, guint32 n_bblocks, MonoBasicBlock *start, const guchar *code)
1071 {
1072         MonoBasicBlock *best = start;
1073         int i;
1074
1075         for (i = 0; i < n_bblocks; ++i) {
1076                 if (bblocks [i]) {
1077                         MonoBasicBlock *bb = bblocks [i];
1078
1079                         if (bb->cil_code && bb->cil_code < code && bb->cil_code > best->cil_code)
1080                                 best = bb;
1081                 }
1082         }
1083
1084         return best;
1085 }
1086
1087 static void
1088 split_bblock (MonoCompile *cfg, MonoBasicBlock *first, MonoBasicBlock *second) {
1089         int i, j;
1090         MonoInst *inst;
1091         MonoBasicBlock *bb;
1092
1093         if (!MONO_INST_LIST_EMPTY (&second->ins_list))
1094                 return;
1095         
1096         /* 
1097          * FIXME: take into account all the details:
1098          * second may have been the target of more than one bblock
1099          */
1100         second->out_count = first->out_count;
1101         second->out_bb = first->out_bb;
1102
1103         for (i = 0; i < first->out_count; ++i) {
1104                 bb = first->out_bb [i];
1105                 for (j = 0; j < bb->in_count; ++j) {
1106                         if (bb->in_bb [j] == first)
1107                                 bb->in_bb [j] = second;
1108                 }
1109         }
1110
1111         first->out_count = 0;
1112         first->out_bb = NULL;
1113         link_bblock (cfg, first, second);
1114
1115         /*g_print ("start search at %p for %p\n", first->cil_code, second->cil_code);*/
1116         MONO_BB_FOR_EACH_INS (first, inst) {
1117                 MonoInst *inst_next;
1118
1119                 /*char *code = mono_disasm_code_one (NULL, cfg->method, inst->next->cil_code, NULL);
1120                 g_print ("found %p: %s", inst->next->cil_code, code);
1121                 g_free (code);*/
1122                 if (inst->cil_code >= second->cil_code)
1123                         continue;
1124
1125                 inst_next = mono_inst_list_next (&inst->node, &first->ins_list);
1126                 if (!inst_next)
1127                         break;
1128
1129                 if (inst_next->cil_code < second->cil_code)
1130                         continue;
1131                         
1132                 second->ins_list.next = inst->node.next;
1133                 second->ins_list.prev = first->ins_list.prev;
1134                 inst->node.next = &first->ins_list;
1135                 first->ins_list.prev = &inst->node;
1136
1137                 second->next_bb = first->next_bb;
1138                 first->next_bb = second;
1139                 return;
1140         }
1141         if (MONO_INST_LIST_EMPTY (&second->ins_list)) {
1142                 g_warning ("bblock split failed in %s::%s\n", cfg->method->klass->name, cfg->method->name);
1143                 //G_BREAKPOINT ();
1144         }
1145 }
1146
1147 static guint32
1148 reverse_branch_op (guint32 opcode)
1149 {
1150         static const int reverse_map [] = {
1151                 CEE_BNE_UN, CEE_BLT, CEE_BLE, CEE_BGT, CEE_BGE,
1152                 CEE_BEQ, CEE_BLT_UN, CEE_BLE_UN, CEE_BGT_UN, CEE_BGE_UN
1153         };
1154         static const int reverse_fmap [] = {
1155                 OP_FBNE_UN, OP_FBLT, OP_FBLE, OP_FBGT, OP_FBGE,
1156                 OP_FBEQ, OP_FBLT_UN, OP_FBLE_UN, OP_FBGT_UN, OP_FBGE_UN
1157         };
1158         static const int reverse_lmap [] = {
1159                 OP_LBNE_UN, OP_LBLT, OP_LBLE, OP_LBGT, OP_LBGE,
1160                 OP_LBEQ, OP_LBLT_UN, OP_LBLE_UN, OP_LBGT_UN, OP_LBGE_UN
1161         };
1162         static const int reverse_imap [] = {
1163                 OP_IBNE_UN, OP_IBLT, OP_IBLE, OP_IBGT, OP_IBGE,
1164                 OP_IBEQ, OP_IBLT_UN, OP_IBLE_UN, OP_IBGT_UN, OP_IBGE_UN
1165         };
1166                                 
1167         if (opcode >= CEE_BEQ && opcode <= CEE_BLT_UN) {
1168                 opcode = reverse_map [opcode - CEE_BEQ];
1169         } else if (opcode >= OP_FBEQ && opcode <= OP_FBLT_UN) {
1170                 opcode = reverse_fmap [opcode - OP_FBEQ];
1171         } else if (opcode >= OP_LBEQ && opcode <= OP_LBLT_UN) {
1172                 opcode = reverse_lmap [opcode - OP_LBEQ];
1173         } else if (opcode >= OP_IBEQ && opcode <= OP_IBLT_UN) {
1174                 opcode = reverse_imap [opcode - OP_IBEQ];
1175         } else
1176                 g_assert_not_reached ();
1177
1178         return opcode;
1179 }
1180
1181 #ifdef MONO_ARCH_SOFT_FLOAT
1182 static int
1183 condbr_to_fp_br (int opcode)
1184 {
1185         switch (opcode) {
1186         case CEE_BEQ: return OP_FBEQ;
1187         case CEE_BGE: return OP_FBGE;
1188         case CEE_BGT: return OP_FBGT;
1189         case CEE_BLE: return OP_FBLE;
1190         case CEE_BLT: return OP_FBLT;
1191         case CEE_BNE_UN: return OP_FBNE_UN;
1192         case CEE_BGE_UN: return OP_FBGE_UN;
1193         case CEE_BGT_UN: return OP_FBGT_UN;
1194         case CEE_BLE_UN: return OP_FBLE_UN;
1195         case CEE_BLT_UN: return OP_FBLT_UN;
1196         }
1197         g_assert_not_reached ();
1198         return 0;
1199 }
1200 #endif
1201
1202 /*
1203  * Returns the type used in the eval stack when @type is loaded.
1204  * FIXME: return a MonoType/MonoClass for the byref and VALUETYPE cases.
1205  */
1206 static void
1207 type_to_eval_stack_type (MonoCompile *cfg, MonoType *type, MonoInst *inst)
1208 {
1209         MonoClass *klass;
1210
1211         inst->klass = klass = mono_class_from_mono_type (type);
1212         if (type->byref) {
1213                 inst->type = STACK_MP;
1214                 return;
1215         }
1216
1217 handle_enum:
1218         switch (type->type) {
1219         case MONO_TYPE_VOID:
1220                 inst->type = STACK_INV;
1221                 return;
1222         case MONO_TYPE_I1:
1223         case MONO_TYPE_U1:
1224         case MONO_TYPE_BOOLEAN:
1225         case MONO_TYPE_I2:
1226         case MONO_TYPE_U2:
1227         case MONO_TYPE_CHAR:
1228         case MONO_TYPE_I4:
1229         case MONO_TYPE_U4:
1230                 inst->type = STACK_I4;
1231                 return;
1232         case MONO_TYPE_I:
1233         case MONO_TYPE_U:
1234         case MONO_TYPE_PTR:
1235         case MONO_TYPE_FNPTR:
1236                 inst->type = STACK_PTR;
1237                 return;
1238         case MONO_TYPE_CLASS:
1239         case MONO_TYPE_STRING:
1240         case MONO_TYPE_OBJECT:
1241         case MONO_TYPE_SZARRAY:
1242         case MONO_TYPE_ARRAY:    
1243                 inst->type = STACK_OBJ;
1244                 return;
1245         case MONO_TYPE_I8:
1246         case MONO_TYPE_U8:
1247                 inst->type = STACK_I8;
1248                 return;
1249         case MONO_TYPE_R4:
1250         case MONO_TYPE_R8:
1251                 inst->type = STACK_R8;
1252                 return;
1253         case MONO_TYPE_VALUETYPE:
1254                 if (type->data.klass->enumtype) {
1255                         type = type->data.klass->enum_basetype;
1256                         goto handle_enum;
1257                 } else {
1258                         inst->klass = klass;
1259                         inst->type = STACK_VTYPE;
1260                         return;
1261                 }
1262         case MONO_TYPE_TYPEDBYREF:
1263                 inst->klass = mono_defaults.typed_reference_class;
1264                 inst->type = STACK_VTYPE;
1265                 return;
1266         case MONO_TYPE_GENERICINST:
1267                 type = &type->data.generic_class->container_class->byval_arg;
1268                 goto handle_enum;
1269         case MONO_TYPE_VAR :
1270         case MONO_TYPE_MVAR :
1271                 /* FIXME: all the arguments must be references for now,
1272                  * later look inside cfg and see if the arg num is
1273                  * really a reference
1274                  */
1275                 g_assert (cfg->generic_sharing_context);
1276                 inst->type = STACK_OBJ;
1277                 return;
1278         default:
1279                 g_error ("unknown type 0x%02x in eval stack type", type->type);
1280         }
1281 }
1282
1283 /*
1284  * The following tables are used to quickly validate the IL code in type_from_op ().
1285  */
1286 static const char
1287 bin_num_table [STACK_MAX] [STACK_MAX] = {
1288         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1289         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
1290         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1291         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
1292         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_R8,  STACK_INV, STACK_INV, STACK_INV},
1293         {STACK_INV, STACK_MP,  STACK_INV, STACK_MP,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV},
1294         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1295         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
1296 };
1297
1298 static const char 
1299 neg_table [] = {
1300         STACK_INV, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_INV, STACK_INV, STACK_INV
1301 };
1302
1303 /* reduce the size of this table */
1304 static const char
1305 bin_int_table [STACK_MAX] [STACK_MAX] = {
1306         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1307         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1308         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1309         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1310         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1311         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1312         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1313         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
1314 };
1315
1316 static const char
1317 bin_comp_table [STACK_MAX] [STACK_MAX] = {
1318 /*      Inv i  L  p  F  &  O  vt */
1319         {0},
1320         {0, 1, 0, 1, 0, 0, 0, 0}, /* i, int32 */
1321         {0, 0, 1, 0, 0, 0, 0, 0}, /* L, int64 */
1322         {0, 1, 0, 1, 0, 2, 4, 0}, /* p, ptr */
1323         {0, 0, 0, 0, 1, 0, 0, 0}, /* F, R8 */
1324         {0, 0, 0, 2, 0, 1, 0, 0}, /* &, managed pointer */
1325         {0, 0, 0, 4, 0, 0, 3, 0}, /* O, reference */
1326         {0, 0, 0, 0, 0, 0, 0, 0}, /* vt value type */
1327 };
1328
1329 /* reduce the size of this table */
1330 static const char
1331 shift_table [STACK_MAX] [STACK_MAX] = {
1332         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1333         {STACK_INV, STACK_I4,  STACK_INV, STACK_I4,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1334         {STACK_INV, STACK_I8,  STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1335         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1336         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1337         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1338         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1339         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
1340 };
1341
1342 /*
1343  * Tables to map from the non-specific opcode to the matching
1344  * type-specific opcode.
1345  */
1346 /* handles from CEE_ADD to CEE_SHR_UN (CEE_REM_UN for floats) */
1347 static const guint16
1348 binops_op_map [STACK_MAX] = {
1349         0, 0, OP_LADD-CEE_ADD, OP_PADD-CEE_ADD, OP_FADD-CEE_ADD, OP_PADD-CEE_ADD
1350 };
1351
1352 /* handles from CEE_NEG to CEE_CONV_U8 */
1353 static const guint16
1354 unops_op_map [STACK_MAX] = {
1355         0, 0, OP_LNEG-CEE_NEG, OP_PNEG-CEE_NEG, OP_FNEG-CEE_NEG, OP_PNEG-CEE_NEG
1356 };
1357
1358 /* handles from CEE_CONV_U2 to CEE_SUB_OVF_UN */
1359 static const guint16
1360 ovfops_op_map [STACK_MAX] = {
1361         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
1362 };
1363
1364 /* handles from CEE_CONV_OVF_I1_UN to CEE_CONV_OVF_U_UN */
1365 static const guint16
1366 ovf2ops_op_map [STACK_MAX] = {
1367         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
1368 };
1369
1370 /* handles from CEE_CONV_OVF_I1 to CEE_CONV_OVF_U8 */
1371 static const guint16
1372 ovf3ops_op_map [STACK_MAX] = {
1373         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
1374 };
1375
1376 /* handles from CEE_CEQ to CEE_CLT_UN */
1377 static const guint16
1378 ceqops_op_map [STACK_MAX] = {
1379         0, 0, OP_LCEQ-OP_CEQ, OP_PCEQ-OP_CEQ, OP_FCEQ-OP_CEQ, OP_LCEQ-OP_CEQ
1380 };
1381
1382 /*
1383  * Sets ins->type (the type on the eval stack) according to the
1384  * type of the opcode and the arguments to it.
1385  * Invalid IL code is marked by setting ins->type to the invalid value STACK_INV.
1386  *
1387  * FIXME: this function sets ins->type unconditionally in some cases, but
1388  * it should set it to invalid for some types (a conv.x on an object)
1389  */
1390 static void
1391 type_from_op (MonoInst *ins) {
1392         switch (ins->opcode) {
1393         /* binops */
1394         case CEE_ADD:
1395         case CEE_SUB:
1396         case CEE_MUL:
1397         case CEE_DIV:
1398         case CEE_REM:
1399                 /* FIXME: check unverifiable args for STACK_MP */
1400                 ins->type = bin_num_table [ins->inst_i0->type] [ins->inst_i1->type];
1401                 ins->opcode += binops_op_map [ins->type];
1402                 return;
1403         case CEE_DIV_UN:
1404         case CEE_REM_UN:
1405         case CEE_AND:
1406         case CEE_OR:
1407         case CEE_XOR:
1408                 ins->type = bin_int_table [ins->inst_i0->type] [ins->inst_i1->type];
1409                 ins->opcode += binops_op_map [ins->type];
1410                 return;
1411         case CEE_SHL:
1412         case CEE_SHR:
1413         case CEE_SHR_UN:
1414                 ins->type = shift_table [ins->inst_i0->type] [ins->inst_i1->type];
1415                 ins->opcode += binops_op_map [ins->type];
1416                 return;
1417         case OP_COMPARE:
1418         case OP_LCOMPARE:
1419                 /* FIXME: handle some specifics with ins->next->type */
1420                 ins->type = bin_comp_table [ins->inst_i0->type] [ins->inst_i1->type] ? STACK_I4: STACK_INV;
1421                 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))))
1422                         ins->opcode = OP_LCOMPARE;
1423                 return;
1424         case OP_CEQ:
1425                 ins->type = bin_comp_table [ins->inst_i0->type] [ins->inst_i1->type] ? STACK_I4: STACK_INV;
1426                 ins->opcode += ceqops_op_map [ins->inst_i0->type];
1427                 return;
1428                 
1429         case OP_CGT:
1430         case OP_CGT_UN:
1431         case OP_CLT:
1432         case OP_CLT_UN:
1433                 ins->type = (bin_comp_table [ins->inst_i0->type] [ins->inst_i1->type] & 1) ? STACK_I4: STACK_INV;
1434                 ins->opcode += ceqops_op_map [ins->inst_i0->type];
1435                 return;
1436         /* unops */
1437         case CEE_NEG:
1438                 ins->type = neg_table [ins->inst_i0->type];
1439                 ins->opcode += unops_op_map [ins->type];
1440                 return;
1441         case CEE_NOT:
1442                 if (ins->inst_i0->type >= STACK_I4 && ins->inst_i0->type <= STACK_PTR)
1443                         ins->type = ins->inst_i0->type;
1444                 else
1445                         ins->type = STACK_INV;
1446                 ins->opcode += unops_op_map [ins->type];
1447                 return;
1448         case CEE_CONV_I1:
1449         case CEE_CONV_I2:
1450         case CEE_CONV_I4:
1451         case CEE_CONV_U4:
1452                 ins->type = STACK_I4;
1453                 ins->opcode += unops_op_map [ins->inst_i0->type];
1454                 return;
1455         case CEE_CONV_R_UN:
1456                 ins->type = STACK_R8;
1457                 switch (ins->inst_i0->type) {
1458                 case STACK_I4:
1459                 case STACK_PTR:
1460                         break;
1461                 case STACK_I8:
1462                         ins->opcode = OP_LCONV_TO_R_UN; 
1463                         break;
1464                 }
1465                 return;
1466         case CEE_CONV_OVF_I1:
1467         case CEE_CONV_OVF_U1:
1468         case CEE_CONV_OVF_I2:
1469         case CEE_CONV_OVF_U2:
1470         case CEE_CONV_OVF_I4:
1471         case CEE_CONV_OVF_U4:
1472                 ins->type = STACK_I4;
1473                 ins->opcode += ovf3ops_op_map [ins->inst_i0->type];
1474                 return;
1475         case CEE_CONV_OVF_I_UN:
1476         case CEE_CONV_OVF_U_UN:
1477                 ins->type = STACK_PTR;
1478                 ins->opcode += ovf2ops_op_map [ins->inst_i0->type];
1479                 return;
1480         case CEE_CONV_OVF_I1_UN:
1481         case CEE_CONV_OVF_I2_UN:
1482         case CEE_CONV_OVF_I4_UN:
1483         case CEE_CONV_OVF_U1_UN:
1484         case CEE_CONV_OVF_U2_UN:
1485         case CEE_CONV_OVF_U4_UN:
1486                 ins->type = STACK_I4;
1487                 ins->opcode += ovf2ops_op_map [ins->inst_i0->type];
1488                 return;
1489         case CEE_CONV_U:
1490                 ins->type = STACK_PTR;
1491                 switch (ins->inst_i0->type) {
1492                 case STACK_I4:
1493                         break;
1494                 case STACK_PTR:
1495                 case STACK_MP:
1496 #if SIZEOF_VOID_P == 8
1497                         ins->opcode = OP_LCONV_TO_U;
1498 #endif
1499                         break;
1500                 case STACK_I8:
1501                         ins->opcode = OP_LCONV_TO_U;
1502                         break;
1503                 case STACK_R8:
1504                         ins->opcode = OP_FCONV_TO_U;
1505                         break;
1506                 }
1507                 return;
1508         case CEE_CONV_I8:
1509         case CEE_CONV_U8:
1510                 ins->type = STACK_I8;
1511                 ins->opcode += unops_op_map [ins->inst_i0->type];
1512                 return;
1513         case CEE_CONV_OVF_I8:
1514         case CEE_CONV_OVF_U8:
1515                 ins->type = STACK_I8;
1516                 ins->opcode += ovf3ops_op_map [ins->inst_i0->type];
1517                 return;
1518         case CEE_CONV_OVF_U8_UN:
1519         case CEE_CONV_OVF_I8_UN:
1520                 ins->type = STACK_I8;
1521                 ins->opcode += ovf2ops_op_map [ins->inst_i0->type];
1522                 return;
1523         case CEE_CONV_R4:
1524         case CEE_CONV_R8:
1525                 ins->type = STACK_R8;
1526                 ins->opcode += unops_op_map [ins->inst_i0->type];
1527                 return;
1528         case OP_CKFINITE:
1529                 ins->type = STACK_R8;           
1530                 return;
1531         case CEE_CONV_U2:
1532         case CEE_CONV_U1:
1533                 ins->type = STACK_I4;
1534                 ins->opcode += ovfops_op_map [ins->inst_i0->type];
1535                 break;
1536         case CEE_CONV_I:
1537         case CEE_CONV_OVF_I:
1538         case CEE_CONV_OVF_U:
1539                 ins->type = STACK_PTR;
1540                 ins->opcode += ovfops_op_map [ins->inst_i0->type];
1541                 return;
1542         case CEE_ADD_OVF:
1543         case CEE_ADD_OVF_UN:
1544         case CEE_MUL_OVF:
1545         case CEE_MUL_OVF_UN:
1546         case CEE_SUB_OVF:
1547         case CEE_SUB_OVF_UN:
1548                 ins->type = bin_num_table [ins->inst_i0->type] [ins->inst_i1->type];
1549                 ins->opcode += ovfops_op_map [ins->inst_i0->type];
1550                 if (ins->type == STACK_R8)
1551                         ins->type = STACK_INV;
1552                 return;
1553         default:
1554                 g_error ("opcode 0x%04x not handled in type from op", ins->opcode);
1555                 break;
1556         }
1557 }
1558
1559 static const char 
1560 ldind_type [] = {
1561         STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_R8, STACK_OBJ
1562 };
1563
1564 /* map ldelem.x to the matching ldind.x opcode */
1565 static const guchar
1566 ldelem_to_ldind [] = {
1567         CEE_LDIND_I1,
1568         CEE_LDIND_U1,
1569         CEE_LDIND_I2,
1570         CEE_LDIND_U2,
1571         CEE_LDIND_I4,
1572         CEE_LDIND_U4,
1573         CEE_LDIND_I8,
1574         CEE_LDIND_I,
1575         CEE_LDIND_R4,
1576         CEE_LDIND_R8,
1577         CEE_LDIND_REF
1578 };
1579
1580 /* map stelem.x to the matching stind.x opcode */
1581 static const guchar
1582 stelem_to_stind [] = {
1583         CEE_STIND_I,
1584         CEE_STIND_I1,
1585         CEE_STIND_I2,
1586         CEE_STIND_I4,
1587         CEE_STIND_I8,
1588         CEE_STIND_R4,
1589         CEE_STIND_R8,
1590         CEE_STIND_REF
1591 };
1592
1593 #if 0
1594
1595 static const char
1596 param_table [STACK_MAX] [STACK_MAX] = {
1597         {0},
1598 };
1599
1600 static int
1601 check_values_to_signature (MonoInst *args, MonoType *this, MonoMethodSignature *sig) {
1602         int i;
1603
1604         if (sig->hasthis) {
1605                 switch (args->type) {
1606                 case STACK_I4:
1607                 case STACK_I8:
1608                 case STACK_R8:
1609                 case STACK_VTYPE:
1610                 case STACK_INV:
1611                         return 0;
1612                 }
1613                 args++;
1614         }
1615         for (i = 0; i < sig->param_count; ++i) {
1616                 switch (args [i].type) {
1617                 case STACK_INV:
1618                         return 0;
1619                 case STACK_MP:
1620                         if (!sig->params [i]->byref)
1621                                 return 0;
1622                         continue;
1623                 case STACK_OBJ:
1624                         if (sig->params [i]->byref)
1625                                 return 0;
1626                         switch (sig->params [i]->type) {
1627                         case MONO_TYPE_CLASS:
1628                         case MONO_TYPE_STRING:
1629                         case MONO_TYPE_OBJECT:
1630                         case MONO_TYPE_SZARRAY:
1631                         case MONO_TYPE_ARRAY:
1632                                 break;
1633                         default:
1634                                 return 0;
1635                         }
1636                         continue;
1637                 case STACK_R8:
1638                         if (sig->params [i]->byref)
1639                                 return 0;
1640                         if (sig->params [i]->type != MONO_TYPE_R4 && sig->params [i]->type != MONO_TYPE_R8)
1641                                 return 0;
1642                         continue;
1643                 case STACK_PTR:
1644                 case STACK_I4:
1645                 case STACK_I8:
1646                 case STACK_VTYPE:
1647                         break;
1648                 }
1649                 /*if (!param_table [args [i].type] [sig->params [i]->type])
1650                         return 0;*/
1651         }
1652         return 1;
1653 }
1654 #endif
1655
1656 static guint
1657 mini_type_to_ldind (MonoCompile* cfg, MonoType *type)
1658 {
1659         if (cfg->generic_sharing_context && !type->byref) {
1660                 /* FIXME: all the arguments must be references for now,
1661                  * later look inside cfg and see if the arg num is
1662                  * really a reference
1663                  */
1664                 if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)
1665                         return CEE_LDIND_REF;
1666         }
1667         return mono_type_to_ldind (type);
1668 }
1669
1670 static guint
1671 mini_type_to_stind (MonoCompile* cfg, MonoType *type)
1672 {
1673         if (cfg->generic_sharing_context && !type->byref) {
1674                 /* FIXME: all the arguments must be references for now,
1675                  * later look inside cfg and see if the arg num is
1676                  * really a reference
1677                  */
1678                 if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)
1679                         return CEE_STIND_REF;
1680         }
1681         return mono_type_to_stind (type);
1682 }
1683
1684 int
1685 mono_op_imm_to_op (int opcode)
1686 {
1687         switch (opcode) {
1688         case OP_ADD_IMM:
1689                 return OP_PADD;
1690         case OP_IADD_IMM:
1691                 return OP_IADD;
1692         case OP_LADD_IMM:
1693                 return OP_LADD;
1694         case OP_ISUB_IMM:
1695                 return OP_ISUB;
1696         case OP_LSUB_IMM:
1697                 return OP_LSUB;
1698         case OP_AND_IMM:
1699 #if SIZEOF_VOID_P == 4
1700                 return OP_IAND;
1701 #else
1702                 return OP_LAND;
1703 #endif
1704         case OP_IAND_IMM:
1705                 return OP_IAND;
1706         case OP_LAND_IMM:
1707                 return OP_LAND;
1708         case OP_IOR_IMM:
1709                 return OP_IOR;
1710         case OP_LOR_IMM:
1711                 return OP_LOR;
1712         case OP_IXOR_IMM:
1713                 return OP_IXOR;
1714         case OP_LXOR_IMM:
1715                 return OP_LXOR;
1716         case OP_ISHL_IMM:
1717                 return OP_ISHL;
1718         case OP_LSHL_IMM:
1719                 return OP_LSHL;
1720         case OP_ISHR_IMM:
1721                 return OP_ISHR;
1722         case OP_LSHR_IMM:
1723                 return OP_LSHR;
1724         case OP_ISHR_UN_IMM:
1725                 return OP_ISHR_UN;
1726         case OP_LSHR_UN_IMM:
1727                 return OP_LSHR_UN;
1728         case OP_IDIV_IMM:
1729                 return OP_IDIV;
1730         case OP_IDIV_UN_IMM:
1731                 return OP_IDIV_UN;
1732         case OP_IREM_UN_IMM:
1733                 return OP_IREM_UN;
1734         case OP_IREM_IMM:
1735                 return OP_IREM;
1736         case OP_DIV_IMM:
1737 #if SIZEOF_VOID_P == 4
1738                 return OP_IDIV;
1739 #else
1740                 return OP_LDIV;
1741 #endif
1742         case OP_REM_IMM:
1743 #if SIZEOF_VOID_P == 4
1744                 return OP_IREM;
1745 #else
1746                 return OP_LREM;
1747 #endif
1748         case OP_ADDCC_IMM:
1749                 return OP_ADDCC;
1750         case OP_ADC_IMM:
1751                 return OP_ADC;
1752         case OP_SUBCC_IMM:
1753                 return OP_SUBCC;
1754         case OP_SBB_IMM:
1755                 return OP_SBB;
1756         case OP_IADC_IMM:
1757                 return OP_IADC;
1758         case OP_ISBB_IMM:
1759                 return OP_ISBB;
1760         case OP_COMPARE_IMM:
1761                 return OP_COMPARE;
1762         case OP_ICOMPARE_IMM:
1763                 return OP_ICOMPARE;
1764         default:
1765                 printf ("%s\n", mono_inst_name (opcode));
1766                 g_assert_not_reached ();
1767         }
1768 }
1769
1770 /*
1771  * When we need a pointer to the current domain many times in a method, we
1772  * call mono_domain_get() once and we store the result in a local variable.
1773  * This function returns the variable that represents the MonoDomain*.
1774  */
1775 inline static MonoInst *
1776 mono_get_domainvar (MonoCompile *cfg)
1777 {
1778         if (!cfg->domainvar)
1779                 cfg->domainvar = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1780         return cfg->domainvar;
1781 }
1782
1783 /*
1784  * The got_var contains the address of the Global Offset Table when AOT 
1785  * compiling.
1786  */
1787 inline static MonoInst *
1788 mono_get_got_var (MonoCompile *cfg)
1789 {
1790 #ifdef MONO_ARCH_NEED_GOT_VAR
1791         if (!cfg->compile_aot)
1792                 return NULL;
1793         if (!cfg->got_var) {
1794                 cfg->got_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1795         }
1796         return cfg->got_var;
1797 #else
1798         return NULL;
1799 #endif
1800 }
1801
1802 MonoInst*
1803 mono_compile_create_var (MonoCompile *cfg, MonoType *type, int opcode)
1804 {
1805         MonoInst *inst;
1806         int num = cfg->num_varinfo;
1807
1808         if ((num + 1) >= cfg->varinfo_count) {
1809                 int orig_count = cfg->varinfo_count;
1810                 cfg->varinfo_count = (cfg->varinfo_count + 2) * 2;
1811                 cfg->varinfo = (MonoInst **)g_realloc (cfg->varinfo, sizeof (MonoInst*) * cfg->varinfo_count);
1812                 cfg->vars = (MonoMethodVar *)g_realloc (cfg->vars, sizeof (MonoMethodVar) * cfg->varinfo_count);
1813                 memset (&cfg->vars [orig_count], 0, (cfg->varinfo_count - orig_count) * sizeof (MonoMethodVar));
1814         }
1815
1816         /*g_print ("created temp %d of type 0x%x\n", num, type->type);*/
1817         mono_jit_stats.allocate_var++;
1818
1819         MONO_INST_NEW (cfg, inst, opcode);
1820         inst->inst_c0 = num;
1821         inst->inst_vtype = type;
1822         inst->klass = mono_class_from_mono_type (type);
1823         /* if set to 1 the variable is native */
1824         inst->backend.is_pinvoke = 0;
1825
1826         cfg->varinfo [num] = inst;
1827
1828         MONO_INIT_VARINFO (&cfg->vars [num], num);
1829
1830         cfg->num_varinfo++;
1831         if (cfg->verbose_level > 2)
1832                 g_print ("created temp %d of type %s\n", num, mono_type_get_name (type));
1833         return inst;
1834 }
1835
1836 /*
1837  * Transform a MonoInst into a load from the variable of index var_index.
1838  */
1839 void
1840 mono_compile_make_var_load (MonoCompile *cfg, MonoInst *dest, gssize var_index) {
1841         memset (dest, 0, sizeof (MonoInst));
1842         dest->ssa_op = MONO_SSA_LOAD;
1843         dest->inst_i0 = cfg->varinfo [var_index];
1844         dest->opcode = mini_type_to_ldind (cfg, dest->inst_i0->inst_vtype);
1845         type_to_eval_stack_type (cfg, dest->inst_i0->inst_vtype, dest);
1846         dest->klass = dest->inst_i0->klass;
1847 }
1848
1849 /*
1850  * Create a MonoInst that is a load from the variable of index var_index.
1851  */
1852 MonoInst*
1853 mono_compile_create_var_load (MonoCompile *cfg, gssize var_index) {
1854         MonoInst *dest;
1855         NEW_TEMPLOAD (cfg,dest,var_index);
1856         return dest;
1857 }
1858
1859 /*
1860  * Create a MonoInst that is a store of the given value into the variable of index var_index.
1861  */
1862 MonoInst*
1863 mono_compile_create_var_store (MonoCompile *cfg, gssize var_index, MonoInst *value) {
1864         MonoInst *dest;
1865         NEW_TEMPSTORE (cfg, dest, var_index, value);
1866         return dest;
1867 }
1868
1869 static MonoType*
1870 type_from_stack_type (MonoInst *ins) {
1871         switch (ins->type) {
1872         case STACK_I4: return &mono_defaults.int32_class->byval_arg;
1873         case STACK_I8: return &mono_defaults.int64_class->byval_arg;
1874         case STACK_PTR: return &mono_defaults.int_class->byval_arg;
1875         case STACK_R8: return &mono_defaults.double_class->byval_arg;
1876         case STACK_MP:
1877                 /* 
1878                  * this if used to be commented without any specific reason, but
1879                  * it breaks #80235 when commented
1880                  */
1881                 if (ins->klass)
1882                         return &ins->klass->this_arg;
1883                 else
1884                         return &mono_defaults.object_class->this_arg;
1885         case STACK_OBJ:
1886                 /* ins->klass may not be set for ldnull.
1887                  * Also, if we have a boxed valuetype, we want an object lass,
1888                  * not the valuetype class
1889                  */
1890                 if (ins->klass && !ins->klass->valuetype)
1891                         return &ins->klass->byval_arg;
1892                 return &mono_defaults.object_class->byval_arg;
1893         case STACK_VTYPE: return &ins->klass->byval_arg;
1894         default:
1895                 g_error ("stack type %d to montype not handled\n", ins->type);
1896         }
1897         return NULL;
1898 }
1899
1900 MonoType*
1901 mono_type_from_stack_type (MonoInst *ins) {
1902         return type_from_stack_type (ins);
1903 }
1904
1905 static MonoClass*
1906 array_access_to_klass (int opcode, MonoInst *array_obj)
1907 {
1908         switch (opcode) {
1909         case CEE_LDELEM_U1:
1910                 return mono_defaults.byte_class;
1911         case CEE_LDELEM_U2:
1912                 return mono_defaults.uint16_class;
1913         case CEE_LDELEM_I:
1914         case CEE_STELEM_I:
1915                 return mono_defaults.int_class;
1916         case CEE_LDELEM_I1:
1917         case CEE_STELEM_I1:
1918                 return mono_defaults.sbyte_class;
1919         case CEE_LDELEM_I2:
1920         case CEE_STELEM_I2:
1921                 return mono_defaults.int16_class;
1922         case CEE_LDELEM_I4:
1923         case CEE_STELEM_I4:
1924                 return mono_defaults.int32_class;
1925         case CEE_LDELEM_U4:
1926                 return mono_defaults.uint32_class;
1927         case CEE_LDELEM_I8:
1928         case CEE_STELEM_I8:
1929                 return mono_defaults.int64_class;
1930         case CEE_LDELEM_R4:
1931         case CEE_STELEM_R4:
1932                 return mono_defaults.single_class;
1933         case CEE_LDELEM_R8:
1934         case CEE_STELEM_R8:
1935                 return mono_defaults.double_class;
1936         case CEE_LDELEM_REF:
1937         case CEE_STELEM_REF: {
1938                 MonoClass *klass = array_obj->klass;
1939                 /* FIXME: add assert */
1940                 if (klass && klass->rank)
1941                         return klass->element_class;
1942                 return mono_defaults.object_class;
1943         }
1944         default:
1945                 g_assert_not_reached ();
1946         }
1947         return NULL;
1948 }
1949
1950 void
1951 mono_add_ins_to_end (MonoBasicBlock *bb, MonoInst *inst)
1952 {
1953         MonoInst *last = mono_inst_list_last (&bb->ins_list);
1954
1955         if (last && ((last->opcode >= CEE_BEQ &&
1956                         last->opcode <= CEE_BLT_UN) ||
1957                         last->opcode == OP_BR ||
1958                         last->opcode == OP_SWITCH)) {
1959                 MONO_INST_LIST_ADD_TAIL (&inst->node, &last->node);
1960         } else {
1961                 MONO_ADD_INS (bb, inst);
1962         }
1963 }
1964
1965 void
1966 mono_add_varcopy_to_end (MonoCompile *cfg, MonoBasicBlock *bb, int src, int dest)
1967 {
1968         MonoInst *inst, *load;
1969
1970         NEW_TEMPLOAD (cfg, load, src);
1971
1972         NEW_TEMPSTORE (cfg, inst, dest, load);
1973         /* FIXME: handle CEE_STIND_R4 */
1974         if (inst->opcode == CEE_STOBJ) {
1975                 NEW_TEMPLOADA (cfg, inst, dest);
1976                 handle_stobj (cfg, bb, inst, load, NULL, inst->klass, TRUE, FALSE, FALSE);
1977         } else {
1978                 inst->cil_code = NULL;
1979                 mono_add_ins_to_end (bb, inst);
1980         }
1981 }
1982
1983 /*
1984  * merge_stacks:
1985  *
1986  * Merge stack state between two basic blocks according to Ecma 335, Partition III,
1987  * section 1.8.1.1. Store the resulting stack state into stack_2.
1988  * Returns: TRUE, if verification succeeds, FALSE otherwise.
1989  * FIXME: We should store the stack state in a dedicated structure instead of in
1990  * MonoInst's.
1991  */
1992 static gboolean
1993 merge_stacks (MonoCompile *cfg, MonoStackSlot *state_1, MonoStackSlot *state_2, guint32 size)
1994 {
1995         int i;
1996
1997         if (cfg->dont_verify_stack_merge)
1998                 return TRUE;
1999
2000         /* FIXME: Implement all checks from the spec */
2001
2002         for (i = 0; i < size; ++i) {
2003                 MonoStackSlot *slot1 = &state_1 [i];
2004                 MonoStackSlot *slot2 = &state_2 [i];
2005
2006                 if (slot1->type != slot2->type)
2007                         return FALSE;
2008
2009                 switch (slot1->type) {
2010                 case STACK_PTR:
2011                         /* FIXME: Perform merge ? */
2012                         /* klass == NULL means a native int */
2013                         if (slot1->klass && slot2->klass) {
2014                                 if (slot1->klass != slot2->klass)
2015                                         return FALSE;
2016                         }
2017                         break;
2018                 case STACK_MP:
2019                         /* FIXME: Change this to an assert and fix the JIT to allways fill this */
2020                         if (slot1->klass && slot2->klass) {
2021                                 if (slot1->klass != slot2->klass)
2022                                         return FALSE;
2023                         }
2024                         break;
2025                 case STACK_OBJ: {
2026                         MonoClass *klass1 = slot1->klass;
2027                         MonoClass *klass2 = slot2->klass;
2028
2029                         if (!klass1) {
2030                                 /* slot1 is ldnull */
2031                         } else if (!klass2) {
2032                                 /* slot2 is ldnull */
2033                                 slot2->klass = slot1->klass;
2034                         }
2035                         break;
2036                 }
2037                 }
2038         }
2039
2040         return TRUE;
2041 }
2042
2043 /*
2044  * This function is called to handle items that are left on the evaluation stack
2045  * at basic block boundaries. What happens is that we save the values to local variables
2046  * and we reload them later when first entering the target basic block (with the
2047  * handle_loaded_temps () function).
2048  * It is also used to handle items on the stack in store opcodes, since it is
2049  * possible that the variable to be stored into is already on the stack, in
2050  * which case its old value should be used.
2051  * A single joint point will use the same variables (stored in the array bb->out_stack or
2052  * bb->in_stack, if the basic block is before or after the joint point).
2053  * If the stack merge fails at a join point, cfg->unverifiable is set.
2054  */
2055 static int
2056 handle_stack_args (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst **sp, int count) {
2057         int i, bindex;
2058         MonoBasicBlock *outb;
2059         MonoInst *inst, **locals;
2060         MonoStackSlot *stack_state;
2061         gboolean found;
2062
2063         if (!count)
2064                 return 0;
2065         if (cfg->verbose_level > 3)
2066                 g_print ("%d item(s) on exit from B%d\n", count, bb->block_num);
2067
2068         stack_state = mono_mempool_alloc (cfg->mempool, sizeof (MonoStackSlot) * count);
2069         for (i = 0; i < count; ++i) {
2070                 stack_state [i].type = sp [i]->type;
2071                 stack_state [i].klass = sp [i]->klass;
2072
2073                 /* Check that instructions other than ldnull have ins->klass set */
2074                 if (!cfg->dont_verify_stack_merge && (sp [i]->type == STACK_OBJ) && !((sp [i]->opcode == OP_PCONST) && sp [i]->inst_c0 == 0))
2075                         g_assert (sp [i]->klass);
2076         }
2077
2078         /* Perform verification and stack state merge */
2079         for (i = 0; i < bb->out_count; ++i) {
2080                 outb = bb->out_bb [i];
2081
2082                 /* exception handlers are linked, but they should not be considered for stack args */
2083                 if (outb->flags & BB_EXCEPTION_HANDLER)
2084                         continue;
2085                 if (outb->stack_state) {
2086                         gboolean verified;
2087
2088                         if (count != outb->in_scount) {
2089                                 cfg->unverifiable = TRUE;
2090                                 return 0;
2091                         }
2092                         verified = merge_stacks (cfg, stack_state, outb->stack_state, count);
2093                         if (!verified) {
2094                                 cfg->unverifiable = TRUE;
2095                                 return 0;
2096                         }
2097
2098                         if (cfg->verbose_level > 3) {
2099                                 int j;
2100
2101                                 for (j = 0; j < count; ++j)
2102                                         printf ("\tStack state of BB%d, slot %d=%d\n", outb->block_num, j, outb->stack_state [j].type);
2103                         }
2104                 } else {
2105                         /* Make a copy of the stack state */
2106                         outb->stack_state = mono_mempool_alloc (cfg->mempool, sizeof (MonoStackSlot) * count);
2107                         memcpy (outb->stack_state, stack_state, sizeof (MonoStackSlot) * count);
2108                 }
2109         }
2110
2111         if (!bb->out_scount) {
2112                 bb->out_scount = count;
2113                 //g_print ("bblock %d has out:", bb->block_num);
2114                 found = FALSE;
2115                 for (i = 0; i < bb->out_count; ++i) {
2116                         outb = bb->out_bb [i];
2117                         /* exception handlers are linked, but they should not be considered for stack args */
2118                         if (outb->flags & BB_EXCEPTION_HANDLER)
2119                                 continue;
2120                         //g_print (" %d", outb->block_num);
2121                         if (outb->in_stack) {
2122                                 found = TRUE;
2123                                 bb->out_stack = outb->in_stack;
2124                                 break;
2125                         }
2126                 }
2127                 //g_print ("\n");
2128                 if (!found) {
2129                         bb->out_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * count);
2130                         for (i = 0; i < count; ++i) {
2131                                 /* 
2132                                  * try to reuse temps already allocated for this purpouse, if they occupy the same
2133                                  * stack slot and if they are of the same type.
2134                                  * This won't cause conflicts since if 'local' is used to 
2135                                  * store one of the values in the in_stack of a bblock, then
2136                                  * the same variable will be used for the same outgoing stack 
2137                                  * slot as well. 
2138                                  * This doesn't work when inlining methods, since the bblocks
2139                                  * in the inlined methods do not inherit their in_stack from
2140                                  * the bblock they are inlined to. See bug #58863 for an
2141                                  * example.
2142                                  * This hack is disabled since it also prevents proper tracking of types.
2143                                  */
2144 #if 1
2145                                 bb->out_stack [i] = mono_compile_create_var (cfg, type_from_stack_type (sp [i]), OP_LOCAL);
2146 #else
2147                                 if (cfg->inlined_method)
2148                                         bb->out_stack [i] = mono_compile_create_var (cfg, type_from_stack_type (sp [i]), OP_LOCAL);
2149                                 else
2150                                         bb->out_stack [i] = mono_compile_get_interface_var (cfg, i, sp [i]);
2151 #endif
2152                         }
2153                 }
2154         }
2155
2156         for (i = 0; i < bb->out_count; ++i) {
2157                 outb = bb->out_bb [i];
2158                 /* exception handlers are linked, but they should not be considered for stack args */
2159                 if (outb->flags & BB_EXCEPTION_HANDLER)
2160                         continue;
2161                 if (outb->in_scount) {
2162                         if (outb->in_scount != bb->out_scount)
2163                                 G_BREAKPOINT ();
2164                         continue; /* check they are the same locals */
2165                 }
2166                 outb->in_scount = count;
2167                 outb->in_stack = bb->out_stack;
2168         }
2169
2170         locals = bb->out_stack;
2171         for (i = 0; i < count; ++i) {
2172                 /* add store ops at the end of the bb, before the branch */
2173                 NEW_TEMPSTORE (cfg, inst, locals [i]->inst_c0, sp [i]);
2174                 if (inst->opcode == CEE_STOBJ) {
2175                         NEW_TEMPLOADA (cfg, inst, locals [i]->inst_c0);
2176                         handle_stobj (cfg, bb, inst, sp [i], sp [i]->cil_code, inst->klass, TRUE, FALSE, FALSE);
2177                 } else {
2178                         inst->cil_code = sp [i]->cil_code;
2179                         mono_add_ins_to_end (bb, inst);
2180                 }
2181                 if (cfg->verbose_level > 3)
2182                         g_print ("storing %d to temp %d\n", i, (int)locals [i]->inst_c0);
2183         }
2184
2185         /*
2186          * It is possible that the out bblocks already have in_stack assigned, and
2187          * the in_stacks differ. In this case, we will store to all the different 
2188          * in_stacks.
2189          */
2190
2191         found = TRUE;
2192         bindex = 0;
2193         while (found) {
2194                 /* Find a bblock which has a different in_stack */
2195                 found = FALSE;
2196                 while (bindex < bb->out_count) {
2197                         outb = bb->out_bb [bindex];
2198                         /* exception handlers are linked, but they should not be considered for stack args */
2199                         if (outb->flags & BB_EXCEPTION_HANDLER) {
2200                                 bindex++;
2201                                 continue;
2202                         }
2203                         if (outb->in_stack != locals) {
2204                                 /* 
2205                                  * Instead of storing sp [i] to locals [i], we need to store
2206                                  * locals [i] to <new locals>[i], since the sp [i] tree can't
2207                                  * be shared between trees.
2208                                  */
2209                                 for (i = 0; i < count; ++i)
2210                                         mono_add_varcopy_to_end (cfg, bb, locals [i]->inst_c0, outb->in_stack [i]->inst_c0);
2211                                 locals = outb->in_stack;
2212                                 found = TRUE;
2213                                 break;
2214                         }
2215                         bindex ++;
2216                 }
2217         }
2218         
2219         return 0;
2220 }
2221
2222 static int
2223 ret_type_to_call_opcode (MonoType *type, int calli, int virt, MonoGenericSharingContext *gsctx)
2224 {
2225         if (type->byref)
2226                 return calli? OP_CALL_REG: virt? OP_CALLVIRT: OP_CALL;
2227
2228 handle_enum:
2229         type = mini_get_basic_type_from_generic (gsctx, type);
2230         switch (type->type) {
2231         case MONO_TYPE_VOID:
2232                 return calli? OP_VOIDCALL_REG: virt? OP_VOIDCALLVIRT: OP_VOIDCALL;
2233         case MONO_TYPE_I1:
2234         case MONO_TYPE_U1:
2235         case MONO_TYPE_BOOLEAN:
2236         case MONO_TYPE_I2:
2237         case MONO_TYPE_U2:
2238         case MONO_TYPE_CHAR:
2239         case MONO_TYPE_I4:
2240         case MONO_TYPE_U4:
2241                 return calli? OP_CALL_REG: virt? OP_CALLVIRT: OP_CALL;
2242         case MONO_TYPE_I:
2243         case MONO_TYPE_U:
2244         case MONO_TYPE_PTR:
2245         case MONO_TYPE_FNPTR:
2246                 return calli? OP_CALL_REG: virt? OP_CALLVIRT: OP_CALL;
2247         case MONO_TYPE_CLASS:
2248         case MONO_TYPE_STRING:
2249         case MONO_TYPE_OBJECT:
2250         case MONO_TYPE_SZARRAY:
2251         case MONO_TYPE_ARRAY:    
2252                 return calli? OP_CALL_REG: virt? OP_CALLVIRT: OP_CALL;
2253         case MONO_TYPE_I8:
2254         case MONO_TYPE_U8:
2255                 return calli? OP_LCALL_REG: virt? OP_LCALLVIRT: OP_LCALL;
2256         case MONO_TYPE_R4:
2257         case MONO_TYPE_R8:
2258                 return calli? OP_FCALL_REG: virt? OP_FCALLVIRT: OP_FCALL;
2259         case MONO_TYPE_VALUETYPE:
2260                 if (type->data.klass->enumtype) {
2261                         type = type->data.klass->enum_basetype;
2262                         goto handle_enum;
2263                 } else
2264                         return calli? OP_VCALL_REG: virt? OP_VCALLVIRT: OP_VCALL;
2265         case MONO_TYPE_TYPEDBYREF:
2266                 return calli? OP_VCALL_REG: virt? OP_VCALLVIRT: OP_VCALL;
2267         case MONO_TYPE_GENERICINST:
2268                 type = &type->data.generic_class->container_class->byval_arg;
2269                 goto handle_enum;
2270         default:
2271                 g_error ("unknown type 0x%02x in ret_type_to_call_opcode", type->type);
2272         }
2273         return -1;
2274 }
2275
2276 void
2277 mono_create_jump_table (MonoCompile *cfg, MonoInst *label, MonoBasicBlock **bbs, int num_blocks)
2278 {
2279         MonoJumpInfo *ji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo));
2280         MonoJumpInfoBBTable *table;
2281
2282         table = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfoBBTable));
2283         table->table = bbs;
2284         table->table_size = num_blocks;
2285         
2286         ji->ip.label = label;
2287         ji->type = MONO_PATCH_INFO_SWITCH;
2288         ji->data.table = table;
2289         ji->next = cfg->patch_info;
2290         cfg->patch_info = ji;
2291 }
2292
2293 static void
2294 mono_save_token_info (MonoCompile *cfg, MonoImage *image, guint32 token, gpointer key)
2295 {
2296         if (cfg->compile_aot) {
2297                 MonoJumpInfoToken *jump_info_token = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoToken));
2298                 jump_info_token->image = image;
2299                 jump_info_token->token = token;
2300                 g_hash_table_insert (cfg->token_info_hash, key, jump_info_token);
2301         }
2302 }
2303
2304 /*
2305  * When we add a tree of instructions, we need to ensure the instructions currently
2306  * on the stack are executed before (like, if we load a value from a local).
2307  * We ensure this by saving the currently loaded values to temps and rewriting the
2308  * instructions to load the values.
2309  * This is not done for opcodes that terminate a basic block (because it's handled already
2310  * by handle_stack_args ()) and for opcodes that can't change values, like POP.
2311  */
2312 static void
2313 handle_loaded_temps (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst **stack, MonoInst **sp)
2314 {
2315         MonoInst *load, *store, *temp, *ins;
2316
2317         while (stack < sp) {
2318                 ins = *stack;
2319                 /* handle also other constants */
2320                 if ((ins->opcode != OP_ICONST) &&
2321                     /* temps never get written to again, so we can safely avoid duplicating them */
2322                     !(ins->ssa_op == MONO_SSA_LOAD && ins->inst_i0->opcode == OP_LOCAL && ins->inst_i0->flags & MONO_INST_IS_TEMP)) {
2323                         temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
2324                         temp->flags |= MONO_INST_IS_TEMP;
2325                         NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
2326                         store->cil_code = ins->cil_code;
2327                         if (store->opcode == CEE_STOBJ) {
2328                                 NEW_TEMPLOADA (cfg, store, temp->inst_c0);
2329                                 handle_stobj (cfg, bblock, store, ins, ins->cil_code, temp->klass, FALSE, FALSE, FALSE);
2330                         } else
2331                                 MONO_ADD_INS (bblock, store);
2332                         NEW_TEMPLOAD (cfg, load, temp->inst_c0);
2333                         load->cil_code = ins->cil_code;
2334                         *stack = load;
2335                 }
2336                 stack++;
2337         }
2338 }
2339
2340 /*
2341  * target_type_is_incompatible:
2342  * @cfg: MonoCompile context
2343  *
2344  * Check that the item @arg on the evaluation stack can be stored
2345  * in the target type (can be a local, or field, etc).
2346  * The cfg arg can be used to check if we need verification or just
2347  * validity checks.
2348  *
2349  * Returns: non-0 value if arg can't be stored on a target.
2350  */
2351 static int
2352 target_type_is_incompatible (MonoCompile *cfg, MonoType *target, MonoInst *arg)
2353 {
2354         MonoType *simple_type;
2355         MonoClass *klass;
2356
2357         if (target->byref) {
2358                 /* FIXME: check that the pointed to types match */
2359                 if (arg->type == STACK_MP)
2360                         return arg->klass != mono_class_from_mono_type (target);
2361                 if (arg->type == STACK_PTR)
2362                         return 0;
2363                 return 1;
2364         }
2365         simple_type = mono_type_get_underlying_type (target);
2366         switch (simple_type->type) {
2367         case MONO_TYPE_VOID:
2368                 return 1;
2369         case MONO_TYPE_I1:
2370         case MONO_TYPE_U1:
2371         case MONO_TYPE_BOOLEAN:
2372         case MONO_TYPE_I2:
2373         case MONO_TYPE_U2:
2374         case MONO_TYPE_CHAR:
2375         case MONO_TYPE_I4:
2376         case MONO_TYPE_U4:
2377                 if (arg->type != STACK_I4 && arg->type != STACK_PTR)
2378                         return 1;
2379                 return 0;
2380         case MONO_TYPE_PTR:
2381                 /* STACK_MP is needed when setting pinned locals */
2382                 if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
2383                         return 1;
2384                 return 0;
2385         case MONO_TYPE_I:
2386         case MONO_TYPE_U:
2387         case MONO_TYPE_FNPTR:
2388                 if (arg->type != STACK_I4 && arg->type != STACK_PTR)
2389                         return 1;
2390                 return 0;
2391         case MONO_TYPE_OBJECT:
2392                 if (arg->type != STACK_OBJ)
2393                         return 1;
2394                 return 0;
2395         case MONO_TYPE_STRING:
2396                 if (arg->type != STACK_OBJ)
2397                         return 1;
2398                 /* ldnull has arg->klass unset */
2399                 /*if (arg->klass && arg->klass != mono_defaults.string_class) {
2400                         G_BREAKPOINT ();
2401                         return 1;
2402                 }*/
2403                 return 0;
2404         case MONO_TYPE_CLASS:
2405         case MONO_TYPE_SZARRAY:
2406         case MONO_TYPE_ARRAY:    
2407                 if (arg->type != STACK_OBJ)
2408                         return 1;
2409                 /* FIXME: check type compatibility */
2410                 return 0;
2411         case MONO_TYPE_I8:
2412         case MONO_TYPE_U8:
2413                 if (arg->type != STACK_I8)
2414                         return 1;
2415                 return 0;
2416         case MONO_TYPE_R4:
2417         case MONO_TYPE_R8:
2418                 if (arg->type != STACK_R8)
2419                         return 1;
2420                 return 0;
2421         case MONO_TYPE_VALUETYPE:
2422                 if (arg->type != STACK_VTYPE)
2423                         return 1;
2424                 klass = mono_class_from_mono_type (simple_type);
2425                 if (klass != arg->klass)
2426                         return 1;
2427                 return 0;
2428         case MONO_TYPE_TYPEDBYREF:
2429                 if (arg->type != STACK_VTYPE)
2430                         return 1;
2431                 klass = mono_class_from_mono_type (simple_type);
2432                 if (klass != arg->klass)
2433                         return 1;
2434                 return 0;
2435         case MONO_TYPE_GENERICINST:
2436                 if (mono_type_generic_inst_is_valuetype (simple_type)) {
2437                         klass = mono_class_from_mono_type (simple_type);
2438                         if (klass->enumtype)
2439                                 return target_type_is_incompatible (cfg, klass->enum_basetype, arg);
2440                         if (arg->type != STACK_VTYPE)
2441                                 return 1;
2442                         if (klass != arg->klass)
2443                                 return 1;
2444                         return 0;
2445                 } else {
2446                         if (arg->type != STACK_OBJ)
2447                                 return 1;
2448                         /* FIXME: check type compatibility */
2449                         return 0;
2450                 }
2451         case MONO_TYPE_VAR:
2452         case MONO_TYPE_MVAR:
2453                 /* FIXME: all the arguments must be references for now,
2454                  * later look inside cfg and see if the arg num is
2455                  * really a reference
2456                  */
2457                 g_assert (cfg->generic_sharing_context);
2458                 if (arg->type != STACK_OBJ)
2459                         return 1;
2460                 return 0;
2461         default:
2462                 g_error ("unknown type 0x%02x in target_type_is_incompatible", simple_type->type);
2463         }
2464         return 1;
2465 }
2466
2467 /*
2468  * Prepare arguments for passing to a function call.
2469  * Return a non-zero value if the arguments can't be passed to the given
2470  * signature.
2471  * The type checks are not yet complete and some conversions may need
2472  * casts on 32 or 64 bit architectures.
2473  *
2474  * FIXME: implement this using target_type_is_incompatible ()
2475  */
2476 static int
2477 check_call_signature (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args)
2478 {
2479         MonoType *simple_type;
2480         int i;
2481
2482         if (sig->hasthis) {
2483                 if (args [0]->type != STACK_OBJ && args [0]->type != STACK_MP && args [0]->type != STACK_PTR)
2484                         return 1;
2485                 args++;
2486         }
2487         for (i = 0; i < sig->param_count; ++i) {
2488                 if (sig->params [i]->byref) {
2489                         if (args [i]->type != STACK_MP && args [i]->type != STACK_PTR)
2490                                 return 1;
2491                         continue;
2492                 }
2493                 simple_type = sig->params [i];
2494                 simple_type = mini_get_basic_type_from_generic (cfg->generic_sharing_context, simple_type);
2495 handle_enum:
2496                 switch (simple_type->type) {
2497                 case MONO_TYPE_VOID:
2498                         return 1;
2499                         continue;
2500                 case MONO_TYPE_I1:
2501                 case MONO_TYPE_U1:
2502                 case MONO_TYPE_BOOLEAN:
2503                 case MONO_TYPE_I2:
2504                 case MONO_TYPE_U2:
2505                 case MONO_TYPE_CHAR:
2506                 case MONO_TYPE_I4:
2507                 case MONO_TYPE_U4:
2508                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR)
2509                                 return 1;
2510                         continue;
2511                 case MONO_TYPE_I:
2512                 case MONO_TYPE_U:
2513                 case MONO_TYPE_PTR:
2514                 case MONO_TYPE_FNPTR:
2515                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR && args [i]->type != STACK_MP && args [i]->type != STACK_OBJ)
2516                                 return 1;
2517                         continue;
2518                 case MONO_TYPE_CLASS:
2519                 case MONO_TYPE_STRING:
2520                 case MONO_TYPE_OBJECT:
2521                 case MONO_TYPE_SZARRAY:
2522                 case MONO_TYPE_ARRAY:    
2523                         if (args [i]->type != STACK_OBJ)
2524                                 return 1;
2525                         continue;
2526                 case MONO_TYPE_I8:
2527                 case MONO_TYPE_U8:
2528                         if (args [i]->type != STACK_I8)
2529                                 return 1;
2530                         continue;
2531                 case MONO_TYPE_R4:
2532                 case MONO_TYPE_R8:
2533                         if (args [i]->type != STACK_R8)
2534                                 return 1;
2535                         continue;
2536                 case MONO_TYPE_VALUETYPE:
2537                         if (simple_type->data.klass->enumtype) {
2538                                 simple_type = simple_type->data.klass->enum_basetype;
2539                                 goto handle_enum;
2540                         }
2541                         if (args [i]->type != STACK_VTYPE)
2542                                 return 1;
2543                         continue;
2544                 case MONO_TYPE_TYPEDBYREF:
2545                         if (args [i]->type != STACK_VTYPE)
2546                                 return 1;
2547                         continue;
2548                 case MONO_TYPE_GENERICINST:
2549                         simple_type = &simple_type->data.generic_class->container_class->byval_arg;
2550                         goto handle_enum;
2551
2552                 default:
2553                         g_error ("unknown type 0x%02x in check_call_signature",
2554                                  simple_type->type);
2555                 }
2556         }
2557         return 0;
2558 }
2559
2560 inline static int
2561 mono_spill_call (MonoCompile *cfg, MonoBasicBlock *bblock, MonoCallInst *call, MonoMethodSignature *sig, gboolean ret_object, 
2562                  const guint8 *ip, gboolean to_end)
2563 {
2564         MonoInst *temp, *store, *ins = (MonoInst*)call;
2565         MonoType *ret = sig->ret;
2566
2567         if (!MONO_TYPE_IS_VOID (ret) || ret_object) {
2568                 if (ret_object) {
2569                         call->inst.type = STACK_OBJ;
2570                         call->inst.opcode = OP_CALL;
2571                         temp = mono_compile_create_var (cfg, &mono_defaults.string_class->byval_arg, OP_LOCAL);
2572                 } else {
2573                         type_to_eval_stack_type (cfg, ret, ins);
2574                         temp = mono_compile_create_var (cfg, ret, OP_LOCAL);
2575                 }
2576                 
2577                 temp->flags |= MONO_INST_IS_TEMP;
2578
2579                 if (MONO_TYPE_ISSTRUCT (ret)) {
2580                         MonoInst *loada, *dummy_store;
2581
2582                         /* 
2583                          * Emit a dummy store to the local holding the result so the
2584                          * liveness info remains correct.
2585                          */
2586                         NEW_DUMMY_STORE (cfg, dummy_store, temp->inst_c0);
2587                         if (to_end)
2588                                 mono_add_ins_to_end (bblock, dummy_store);
2589                         else
2590                                 MONO_ADD_INS (bblock, dummy_store);
2591
2592                         /* we use this to allocate native sized structs */
2593                         temp->backend.is_pinvoke = sig->pinvoke;
2594
2595                         NEW_TEMPLOADA (cfg, loada, temp->inst_c0);
2596                         if (call->inst.opcode == OP_VCALL)
2597                                 ins->inst_left = loada;
2598                         else
2599                                 ins->inst_right = loada; /* a virtual or indirect call */
2600
2601                         if (to_end)
2602                                 mono_add_ins_to_end (bblock, ins);
2603                         else
2604                                 MONO_ADD_INS (bblock, ins);
2605                 } else {
2606                         NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
2607                         store->cil_code = ip;
2608                         
2609 #ifdef MONO_ARCH_SOFT_FLOAT
2610                         if (store->opcode == CEE_STIND_R4) {
2611                                 /*FIXME implement proper support for to_end*/
2612                                 g_assert (!to_end);
2613                                 NEW_TEMPLOADA (cfg, store, temp->inst_c0);
2614                                 handle_store_float (cfg, bblock, store, ins, ip);
2615                         } else
2616 #endif
2617                         if (to_end)
2618                                 mono_add_ins_to_end (bblock, store);
2619                         else
2620                                 MONO_ADD_INS (bblock, store);
2621                 }
2622                 return temp->inst_c0;
2623         } else {
2624                 if (to_end)
2625                         mono_add_ins_to_end (bblock, ins);
2626                 else
2627                         MONO_ADD_INS (bblock, ins);
2628                 return -1;
2629         }
2630 }
2631
2632 inline static MonoCallInst *
2633 mono_emit_call_args (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethodSignature *sig, 
2634                      MonoInst **args, int calli, int virtual, const guint8 *ip, gboolean to_end)
2635 {
2636         MonoCallInst *call;
2637         MonoInst *arg, *n;
2638
2639         MONO_INST_NEW_CALL (cfg, call, ret_type_to_call_opcode (sig->ret, calli, virtual, cfg->generic_sharing_context));
2640
2641 #ifdef MONO_ARCH_SOFT_FLOAT
2642         /* we need to convert the r4 value to an int value */
2643         {
2644                 int i;
2645                 for (i = 0; i < sig->param_count; ++i) {
2646                         if (!sig->params [i]->byref && sig->params [i]->type == MONO_TYPE_R4) {
2647                                 MonoInst *iargs [1];
2648                                 int temp;
2649                                 iargs [0] = args [i + sig->hasthis];
2650
2651                                 temp = mono_emit_jit_icall (cfg, bblock, mono_fload_r4_arg, iargs, ip);
2652                                 NEW_TEMPLOAD (cfg, arg, temp);
2653                                 args [i + sig->hasthis] = arg;
2654                         }
2655                 }
2656         }
2657 #endif
2658
2659         call->inst.cil_code = ip;
2660         call->args = args;
2661         call->signature = sig;
2662         call = mono_arch_call_opcode (cfg, bblock, call, virtual);
2663         type_to_eval_stack_type (cfg, sig->ret, &call->inst);
2664
2665         MONO_INST_LIST_FOR_EACH_ENTRY_SAFE (arg, n, &call->out_args, node) {
2666                 if (!arg->cil_code)
2667                         arg->cil_code = ip;
2668                 if (to_end)
2669                         mono_add_ins_to_end (bblock, arg);
2670                 else
2671                         MONO_ADD_INS (bblock, arg);
2672         }
2673         return call;
2674 }
2675
2676 inline static MonoCallInst*
2677 mono_emit_calli (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethodSignature *sig, 
2678                  MonoInst **args, MonoInst *addr, const guint8 *ip)
2679 {
2680         MonoCallInst *call = mono_emit_call_args (cfg, bblock, sig, args, TRUE, FALSE, ip, FALSE);
2681
2682         call->inst.inst_i0 = addr;
2683
2684         return call;
2685 }
2686
2687 inline static int
2688 mono_emit_calli_spilled (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethodSignature *sig, 
2689                                                  MonoInst **args, MonoInst *addr, const guint8 *ip)
2690 {
2691         MonoCallInst *call = mono_emit_calli (cfg, bblock, sig, args, addr, ip);
2692
2693         return mono_spill_call (cfg, bblock, call, sig, FALSE, ip, FALSE);
2694 }
2695
2696 static MonoCallInst*
2697 mono_emit_method_call_full (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *method, MonoMethodSignature *sig,
2698                        MonoInst **args, const guint8 *ip, MonoInst *this, gboolean to_end)
2699 {
2700         gboolean virtual = this != NULL;
2701         MonoCallInst *call;
2702
2703         call = mono_emit_call_args (cfg, bblock, sig, args, FALSE, virtual, ip, to_end);
2704
2705         if (this && sig->hasthis && 
2706             (method->klass->marshalbyref || method->klass == mono_defaults.object_class) && 
2707             !(method->flags & METHOD_ATTRIBUTE_VIRTUAL) && !MONO_CHECK_THIS (this)) {
2708                 call->method = mono_marshal_get_remoting_invoke_with_check (method);
2709         } else {
2710                 call->method = method;
2711         }
2712         call->inst.flags |= MONO_INST_HAS_METHOD;
2713         call->inst.inst_left = this;
2714
2715         if (call->method->klass->flags & TYPE_ATTRIBUTE_INTERFACE)
2716                 /* Needed by the code generated in inssel.brg */
2717                 mono_get_got_var (cfg);
2718
2719         return call;
2720 }
2721
2722 static MonoCallInst*
2723 mono_emit_method_call (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *method, MonoMethodSignature *sig,
2724                        MonoInst **args, const guint8 *ip, MonoInst *this)
2725 {
2726         return mono_emit_method_call_full (cfg, bblock, method, sig, args, ip, this, FALSE);
2727 }
2728
2729 inline static int
2730 mono_emit_method_call_spilled (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *method,  
2731                        MonoMethodSignature *signature, MonoInst **args, const guint8 *ip, MonoInst *this)
2732 {
2733         MonoCallInst *call = mono_emit_method_call (cfg, bblock, method, signature, args, ip, this);
2734
2735         return mono_spill_call (cfg, bblock, call, signature, method->string_ctor, ip, FALSE);
2736 }
2737
2738 inline static int
2739 mono_emit_method_call_spilled_full (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *method,  
2740                        MonoMethodSignature *signature, MonoInst **args, const guint8 *ip, MonoInst *this,
2741                        gboolean ret_object, gboolean to_end)
2742 {
2743         MonoCallInst *call = mono_emit_method_call_full (cfg, bblock, method, signature, args, ip, this, to_end);
2744
2745         return mono_spill_call (cfg, bblock, call, signature, ret_object, ip, to_end);
2746 }
2747
2748 inline static int
2749 mono_emit_native_call (MonoCompile *cfg, MonoBasicBlock *bblock, gconstpointer func, MonoMethodSignature *sig,
2750                        MonoInst **args, const guint8 *ip, gboolean ret_object, gboolean to_end)
2751 {
2752         MonoCallInst *call;
2753
2754         g_assert (sig);
2755
2756         call = mono_emit_call_args (cfg, bblock, sig, args, FALSE, FALSE, ip, to_end);
2757         call->fptr = func;
2758
2759         return mono_spill_call (cfg, bblock, call, sig, ret_object, ip, to_end);
2760 }
2761
2762 inline static int
2763 mono_emit_jit_icall (MonoCompile *cfg, MonoBasicBlock *bblock, gconstpointer func, MonoInst **args, const guint8 *ip)
2764 {
2765         MonoJitICallInfo *info = mono_find_jit_icall_by_addr (func);
2766         
2767         if (!info) {
2768                 g_warning ("unregistered JIT ICall");
2769                 g_assert_not_reached ();
2770         }
2771
2772         return mono_emit_native_call (cfg, bblock, mono_icall_get_wrapper (info), info->sig, args, ip, FALSE, FALSE);
2773 }
2774
2775 static void
2776 mono_emulate_opcode (MonoCompile *cfg, MonoInst *tree, MonoInst **iargs, MonoJitICallInfo *info)
2777 {
2778         MonoInst *ins, *temp = NULL, *store, *load;
2779         MonoInstList *head, *list;
2780         int nargs;
2781         MonoCallInst *call;
2782
2783         //g_print ("emulating: ");
2784         //mono_print_tree_nl (tree);
2785         MONO_INST_NEW_CALL (cfg, call, ret_type_to_call_opcode (info->sig->ret, FALSE, FALSE, cfg->generic_sharing_context));
2786         ins = (MonoInst*)call;
2787         MONO_INST_LIST_INIT (&ins->node);
2788         
2789         call->inst.cil_code = tree->cil_code;
2790         call->args = iargs;
2791         call->signature = info->sig;
2792
2793         call = mono_arch_call_opcode (cfg, cfg->cbb, call, FALSE);
2794
2795         if (!MONO_TYPE_IS_VOID (info->sig->ret)) {
2796                 temp = mono_compile_create_var (cfg, info->sig->ret, OP_LOCAL);
2797                 temp->flags |= MONO_INST_IS_TEMP;
2798                 NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
2799                 MONO_INST_LIST_INIT (&store->node);
2800                 /* FIXME: handle CEE_STIND_R4 */
2801                 store->cil_code = tree->cil_code;
2802         } else {
2803                 store = ins;
2804         }
2805
2806         nargs = info->sig->param_count + info->sig->hasthis;
2807
2808         if (nargs) {
2809                 MONO_INST_LIST_ADD_TAIL (&store->node,
2810                                         &call->out_args);
2811                 list = &call->out_args;
2812         } else {
2813                 list = &store->node;
2814         }
2815
2816         if (cfg->prev_ins) {
2817                 /* 
2818                  * This assumes that that in a tree, emulate_opcode is called for a
2819                  * node before it is called for its children. dec_foreach needs to
2820                  * take this into account.
2821                  */
2822                 head = &cfg->prev_ins->node;
2823         } else {
2824                 head = &cfg->cbb->ins_list;
2825         }
2826
2827         MONO_INST_LIST_SPLICE_INIT (list, head);
2828
2829         call->fptr = mono_icall_get_wrapper (info);
2830
2831         if (!MONO_TYPE_IS_VOID (info->sig->ret)) {
2832                 NEW_TEMPLOAD (cfg, load, temp->inst_c0);
2833                 *tree = *load;
2834         }
2835 }
2836
2837 /*
2838  * This entry point could be used later for arbitrary method
2839  * redirection.
2840  */
2841 inline static int
2842 mini_redirect_call (int *temp, MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *method,  
2843                        MonoMethodSignature *signature, MonoInst **args, const guint8 *ip, MonoInst *this)
2844 {
2845
2846         if (method->klass == mono_defaults.string_class) {
2847                 /* managed string allocation support */
2848                 if (strcmp (method->name, "InternalAllocateStr") == 0) {
2849                         MonoInst *iargs [2];
2850                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
2851                         MonoMethod *managed_alloc = mono_gc_get_managed_allocator (vtable, FALSE);
2852                         if (!managed_alloc)
2853                                 return FALSE;
2854                         NEW_VTABLECONST (cfg, iargs [0], vtable);
2855                         iargs [1] = args [0];
2856                         *temp = mono_emit_method_call_spilled (cfg, bblock, managed_alloc, mono_method_signature (managed_alloc), iargs, ip, this);
2857                         return TRUE;
2858                 }
2859         }
2860         return FALSE;
2861 }
2862
2863 static MonoMethodSignature *
2864 mono_get_array_new_va_signature (int arity)
2865 {
2866         static GHashTable *sighash = NULL;
2867         MonoMethodSignature *res;
2868         int i;
2869
2870         mono_jit_lock ();
2871         if (!sighash) {
2872                 sighash = g_hash_table_new (NULL, NULL);
2873         }
2874         else if ((res = g_hash_table_lookup (sighash, GINT_TO_POINTER (arity)))) {
2875                 mono_jit_unlock ();
2876                 return res;
2877         }
2878
2879         res = mono_metadata_signature_alloc (mono_defaults.corlib, arity + 1);
2880
2881         res->pinvoke = 1;
2882 #ifdef MONO_ARCH_VARARG_ICALLS
2883         /* Only set this only some archs since not all backends can handle varargs+pinvoke */
2884         res->call_convention = MONO_CALL_VARARG;
2885 #endif
2886
2887 #ifdef PLATFORM_WIN32
2888         res->call_convention = MONO_CALL_C;
2889 #endif
2890
2891         res->params [0] = &mono_defaults.int_class->byval_arg;  
2892         for (i = 0; i < arity; i++)
2893                 res->params [i + 1] = &mono_defaults.int_class->byval_arg;
2894
2895         res->ret = &mono_defaults.int_class->byval_arg;
2896
2897         g_hash_table_insert (sighash, GINT_TO_POINTER (arity), res);
2898         mono_jit_unlock ();
2899
2900         return res;
2901 }
2902
2903 #ifdef MONO_ARCH_SOFT_FLOAT
2904 static void
2905 handle_store_float (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *ptr, MonoInst *val, const unsigned char *ip)
2906 {
2907         MonoInst *iargs [2];
2908         iargs [0] = val;
2909         iargs [1] = ptr;
2910
2911         mono_emit_jit_icall (cfg, bblock, mono_fstore_r4, iargs, ip);
2912 }
2913
2914 static int
2915 handle_load_float (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *ptr, const unsigned char *ip)
2916 {
2917         MonoInst *iargs [1];
2918         iargs [0] = ptr;
2919
2920         return mono_emit_jit_icall (cfg, bblock, mono_fload_r4, iargs, ip);
2921 }
2922
2923 #define LDLOC_SOFT_FLOAT(cfg,ins,idx,ip) do {\
2924                 if (header->locals [(idx)]->type == MONO_TYPE_R4 && !header->locals [(idx)]->byref) {   \
2925                         int temp;       \
2926                         NEW_LOCLOADA (cfg, (ins), (idx));       \
2927                         temp = handle_load_float (cfg, bblock, (ins), (ip));    \
2928                         NEW_TEMPLOAD (cfg, (ins), temp);        \
2929                 }       \
2930         } while (0)
2931 #define STLOC_SOFT_FLOAT(cfg,ins,idx,ip) do {\
2932                 if (header->locals [(idx)]->type == MONO_TYPE_R4 && !header->locals [(idx)]->byref) {   \
2933                         int temp;       \
2934                         NEW_LOCLOADA (cfg, (ins), (idx));       \
2935                         handle_store_float (cfg, bblock, (ins), *sp, (ip));     \
2936                         MONO_INST_NEW (cfg, (ins), OP_NOP);     \
2937                 }       \
2938         } while (0)
2939 #define LDARG_SOFT_FLOAT(cfg,ins,idx,ip) do {\
2940                 if (param_types [(idx)]->type == MONO_TYPE_R4 && !param_types [(idx)]->byref) { \
2941                         int temp;       \
2942                         NEW_ARGLOADA (cfg, (ins), (idx));       \
2943                         temp = handle_load_float (cfg, bblock, (ins), (ip));    \
2944                         NEW_TEMPLOAD (cfg, (ins), temp);        \
2945                 }       \
2946         } while (0)
2947 #define STARG_SOFT_FLOAT(cfg,ins,idx,ip) do {\
2948                 if (param_types [(idx)]->type == MONO_TYPE_R4 && !param_types [(idx)]->byref) { \
2949                         int temp;       \
2950                         NEW_ARGLOADA (cfg, (ins), (idx));       \
2951                         handle_store_float (cfg, bblock, (ins), *sp, (ip));     \
2952                         MONO_INST_NEW (cfg, (ins), OP_NOP);     \
2953                 }       \
2954         } while (0)
2955 #else
2956 #define LDLOC_SOFT_FLOAT(cfg,ins,idx,ip)
2957 #define STLOC_SOFT_FLOAT(cfg,ins,idx,ip)
2958 #define LDARG_SOFT_FLOAT(cfg,ins,idx,ip)
2959 #define STARG_SOFT_FLOAT(cfg,ins,idx,ip)
2960 #endif
2961
2962 static MonoMethod*
2963 get_memcpy_method (void)
2964 {
2965         static MonoMethod *memcpy_method = NULL;
2966         if (!memcpy_method) {
2967                 memcpy_method = mono_class_get_method_from_name (mono_defaults.string_class, "memcpy", 3);
2968                 if (!memcpy_method)
2969                         g_error ("Old corlib found. Install a new one");
2970         }
2971         return memcpy_method;
2972 }
2973
2974 static void
2975 handle_stobj (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *dest, MonoInst *src, const unsigned char *ip, MonoClass *klass, gboolean to_end, gboolean native, gboolean write_barrier) {
2976         MonoInst *iargs [3];
2977         int n;
2978         guint32 align = 0;
2979         MonoMethod *memcpy_method;
2980
2981         g_assert (klass);
2982         /*
2983          * This check breaks with spilled vars... need to handle it during verification anyway.
2984          * g_assert (klass && klass == src->klass && klass == dest->klass);
2985          */
2986
2987         if (native)
2988                 n = mono_class_native_size (klass, &align);
2989         else
2990                 n = mono_class_value_size (klass, &align);
2991
2992 #if HAVE_WRITE_BARRIERS
2993         /* if native is true there should be no references in the struct */
2994         if (write_barrier && klass->has_references && !native) {
2995                 iargs [0] = dest;
2996                 iargs [1] = src;
2997                 NEW_PCONST (cfg, iargs [2], klass);
2998
2999                 mono_emit_jit_icall (cfg, bblock, mono_value_copy, iargs, ip);
3000                 return;
3001         }
3002 #endif
3003
3004         /* FIXME: add write barrier handling */
3005         if ((cfg->opt & MONO_OPT_INTRINS) && !to_end && n <= sizeof (gpointer) * 5) {
3006                 MonoInst *inst;
3007                 if (dest->opcode == OP_LDADDR) {
3008                         /* Keep liveness info correct */
3009                         NEW_DUMMY_STORE (cfg, inst, dest->inst_i0->inst_c0);
3010                         MONO_ADD_INS (bblock, inst);
3011                 }
3012                 NEW_MEMCPY (cfg, inst, dest, src, n, align);
3013                 MONO_ADD_INS (bblock, inst);
3014                 return;
3015         }
3016         iargs [0] = dest;
3017         iargs [1] = src;
3018         NEW_ICONST (cfg, iargs [2], n);
3019
3020         memcpy_method = get_memcpy_method ();
3021         mono_emit_method_call_spilled_full (cfg, bblock, memcpy_method, memcpy_method->signature, iargs, ip, NULL, FALSE, to_end);
3022 }
3023
3024 static MonoMethod*
3025 get_memset_method (void)
3026 {
3027         static MonoMethod *memset_method = NULL;
3028         if (!memset_method) {
3029                 memset_method = mono_class_get_method_from_name (mono_defaults.string_class, "memset", 3);
3030                 if (!memset_method)
3031                         g_error ("Old corlib found. Install a new one");
3032         }
3033         return memset_method;
3034 }
3035
3036 static void
3037 handle_initobj (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *dest, const guchar *ip, MonoClass *klass, MonoInst **stack_start, MonoInst **sp)
3038 {
3039         MonoInst *iargs [3];
3040         MonoInst *ins, *zero_int32;
3041         int n;
3042         guint32 align;
3043         MonoMethod *memset_method;
3044
3045         NEW_ICONST (cfg, zero_int32, 0);
3046
3047         mono_class_init (klass);
3048         n = mono_class_value_size (klass, &align);
3049         MONO_INST_NEW (cfg, ins, 0);
3050         ins->cil_code = ip;
3051         ins->inst_left = dest;
3052         ins->inst_right = zero_int32;
3053         if (n == 1) {
3054                 ins->opcode = CEE_STIND_I1;
3055                 MONO_ADD_INS (bblock, ins);
3056         } else if ((n == 2) && (align >= 2)) {
3057                 ins->opcode = CEE_STIND_I2;
3058                 MONO_ADD_INS (bblock, ins);
3059         } else if ((n == 2) && (align >= 4)) {
3060                 ins->opcode = CEE_STIND_I4;
3061                 MONO_ADD_INS (bblock, ins);
3062         } else if (n <= sizeof (gpointer) * 5) {
3063                 NEW_MEMSET (cfg, ins, dest, 0, n, align);
3064                 MONO_ADD_INS (bblock, ins);
3065         } else {
3066                 memset_method = get_memset_method ();
3067                 handle_loaded_temps (cfg, bblock, stack_start, sp);
3068                 iargs [0] = dest;
3069                 NEW_ICONST (cfg, iargs [1], 0);
3070                 NEW_ICONST (cfg, iargs [2], n);
3071                 mono_emit_method_call_spilled (cfg, bblock, memset_method, memset_method->signature, iargs, ip, NULL);
3072         }
3073 }
3074
3075 static int
3076 handle_alloc (MonoCompile *cfg, MonoBasicBlock *bblock, MonoClass *klass, gboolean for_box, const guchar *ip)
3077 {
3078         MonoInst *iargs [2];
3079         void *alloc_ftn;
3080
3081         if (cfg->opt & MONO_OPT_SHARED) {
3082                 NEW_DOMAINCONST (cfg, iargs [0]);
3083                 NEW_CLASSCONST (cfg, iargs [1], klass);
3084
3085                 alloc_ftn = mono_object_new;
3086         } else if (cfg->compile_aot && bblock->out_of_line && klass->type_token && klass->image == mono_defaults.corlib) {
3087                 /* This happens often in argument checking code, eg. throw new FooException... */
3088                 /* Avoid relocations by calling a helper function specialized to mscorlib */
3089                 NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (klass->type_token));
3090                 return mono_emit_jit_icall (cfg, bblock, mono_helper_newobj_mscorlib, iargs, ip);
3091         } else {
3092                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
3093                 MonoMethod *managed_alloc = mono_gc_get_managed_allocator (vtable, for_box);
3094                 gboolean pass_lw;
3095
3096                 if (managed_alloc) {
3097                         NEW_VTABLECONST (cfg, iargs [0], vtable);
3098                         return mono_emit_method_call_spilled (cfg, bblock, managed_alloc, mono_method_signature (managed_alloc), iargs, ip, NULL);
3099                 }
3100                 alloc_ftn = mono_class_get_allocation_ftn (vtable, for_box, &pass_lw);
3101                 if (pass_lw) {
3102                         guint32 lw = vtable->klass->instance_size;
3103                         lw = ((lw + (sizeof (gpointer) - 1)) & ~(sizeof (gpointer) - 1)) / sizeof (gpointer);
3104                         NEW_ICONST (cfg, iargs [0], lw);
3105                         NEW_VTABLECONST (cfg, iargs [1], vtable);
3106                 }
3107                 else
3108                         NEW_VTABLECONST (cfg, iargs [0], vtable);
3109         }
3110
3111         return mono_emit_jit_icall (cfg, bblock, alloc_ftn, iargs, ip);
3112 }
3113
3114 /**
3115  * Handles unbox of a Nullable<T>, returning a temp variable
3116  * where the result is stored
3117  */
3118 static int
3119 handle_unbox_nullable (MonoCompile* cfg, MonoBasicBlock* bblock, MonoInst* val, const guchar *ip, MonoClass* klass)
3120 {
3121        MonoMethod* method = mono_class_get_method_from_name (klass, "Unbox", 1);
3122        return mono_emit_method_call_spilled (cfg, bblock, method, mono_method_signature (method), &val, ip, NULL);
3123         
3124 }
3125
3126
3127
3128 static MonoInst *
3129 handle_box (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *val, const guchar *ip, MonoClass *klass)
3130 {
3131         MonoInst *dest, *vtoffset, *add, *vstore;
3132         int temp;
3133
3134        if (mono_class_is_nullable (klass)) {
3135                MonoMethod* method = mono_class_get_method_from_name (klass, "Box", 1);
3136                temp = mono_emit_method_call_spilled (cfg, bblock, method, mono_method_signature (method), &val, ip, NULL);
3137                NEW_TEMPLOAD (cfg, dest, temp);
3138                return dest;
3139        }
3140
3141
3142         temp = handle_alloc (cfg, bblock, klass, TRUE, ip);
3143         NEW_TEMPLOAD (cfg, dest, temp);
3144         NEW_ICONST (cfg, vtoffset, sizeof (MonoObject));
3145         MONO_INST_NEW (cfg, add, OP_PADD);
3146         add->inst_left = dest;
3147         add->inst_right = vtoffset;
3148         add->cil_code = ip;
3149         add->klass = klass;
3150         MONO_INST_NEW (cfg, vstore, CEE_STIND_I);
3151         vstore->opcode = mini_type_to_stind (cfg, &klass->byval_arg);
3152         vstore->cil_code = ip;
3153         vstore->inst_left = add;
3154         vstore->inst_right = val;
3155
3156 #ifdef MONO_ARCH_SOFT_FLOAT
3157         if (vstore->opcode == CEE_STIND_R4) {
3158                 handle_store_float (cfg, bblock, add, val, ip);
3159         } else
3160 #endif
3161         if (vstore->opcode == CEE_STOBJ) {
3162                 handle_stobj (cfg, bblock, add, val, ip, klass, FALSE, FALSE, TRUE);
3163         } else
3164                 MONO_ADD_INS (bblock, vstore);
3165
3166         NEW_TEMPLOAD (cfg, dest, temp);
3167         return dest;
3168 }
3169
3170 static MonoInst*
3171 handle_delegate_ctor (MonoCompile *cfg, MonoBasicBlock *bblock, MonoClass *klass, MonoInst *target, MonoMethod *method, unsigned char *ip)
3172 {
3173         gpointer *trampoline;
3174         MonoInst *obj, *ins, *store, *offset_ins, *method_ins, *tramp_ins;
3175         int temp;
3176
3177         temp = handle_alloc (cfg, bblock, klass, FALSE, ip);
3178
3179         /* Inline the contents of mono_delegate_ctor */
3180
3181         /* Set target field */
3182         /* Optimize away setting of NULL target */
3183         if (!(target->opcode == OP_PCONST && target->inst_p0 == 0)) {
3184                 NEW_TEMPLOAD (cfg, obj, temp);
3185                 NEW_ICONST (cfg, offset_ins, G_STRUCT_OFFSET (MonoDelegate, target));
3186                 MONO_INST_NEW (cfg, ins, OP_PADD);
3187                 ins->cil_code = ip;
3188                 ins->inst_left = obj;
3189                 ins->inst_right = offset_ins;
3190
3191                 MONO_INST_NEW (cfg, store, CEE_STIND_REF);
3192                 store->cil_code = ip;
3193                 store->inst_left = ins;
3194                 store->inst_right = target;
3195                 mono_bblock_add_inst (bblock, store);
3196         }
3197
3198         /* Set method field */
3199         NEW_TEMPLOAD (cfg, obj, temp);
3200         NEW_ICONST (cfg, offset_ins, G_STRUCT_OFFSET (MonoDelegate, method));
3201         MONO_INST_NEW (cfg, ins, OP_PADD);
3202         ins->cil_code = ip;
3203         ins->inst_left = obj;
3204         ins->inst_right = offset_ins;
3205
3206         NEW_METHODCONST (cfg, method_ins, method);
3207
3208         MONO_INST_NEW (cfg, store, CEE_STIND_I);
3209         store->cil_code = ip;
3210         store->inst_left = ins;
3211         store->inst_right = method_ins;
3212         mono_bblock_add_inst (bblock, store);
3213
3214         /* Set invoke_impl field */
3215         NEW_TEMPLOAD (cfg, obj, temp);
3216         NEW_ICONST (cfg, offset_ins, G_STRUCT_OFFSET (MonoDelegate, invoke_impl));
3217         MONO_INST_NEW (cfg, ins, OP_PADD);
3218         ins->cil_code = ip;
3219         ins->inst_left = obj;
3220         ins->inst_right = offset_ins;
3221
3222         trampoline = mono_create_delegate_trampoline (klass);
3223         NEW_AOTCONST (cfg, tramp_ins, MONO_PATCH_INFO_ABS, trampoline);
3224
3225         MONO_INST_NEW (cfg, store, CEE_STIND_I);
3226         store->cil_code = ip;
3227         store->inst_left = ins;
3228         store->inst_right = tramp_ins;
3229         mono_bblock_add_inst (bblock, store);
3230
3231         /* All the checks which are in mono_delegate_ctor () are done by the delegate trampoline */
3232
3233         NEW_TEMPLOAD (cfg, obj, temp);
3234
3235         return obj;
3236 }
3237
3238 static int
3239 handle_array_new (MonoCompile *cfg, MonoBasicBlock *bblock, int rank, MonoInst **sp, unsigned char *ip)
3240 {
3241         MonoMethodSignature *esig;
3242         char icall_name [256];
3243         char *name;
3244         MonoJitICallInfo *info;
3245
3246         /* Need to register the icall so it gets an icall wrapper */
3247         sprintf (icall_name, "ves_array_new_va_%d", rank);
3248
3249         mono_jit_lock ();
3250         info = mono_find_jit_icall_by_name (icall_name);
3251         if (info == NULL) {
3252                 esig = mono_get_array_new_va_signature (rank);
3253                 name = g_strdup (icall_name);
3254                 info = mono_register_jit_icall (mono_array_new_va, name, esig, FALSE);
3255
3256                 g_hash_table_insert (jit_icall_name_hash, name, name);
3257         }
3258         mono_jit_unlock ();
3259
3260         cfg->flags |= MONO_CFG_HAS_VARARGS;
3261
3262         /* FIXME: This uses info->sig, but it should use the signature of the wrapper */
3263         return mono_emit_native_call (cfg, bblock, mono_icall_get_wrapper (info), info->sig, sp, ip, TRUE, FALSE);
3264 }
3265
3266 static void
3267 mono_emit_load_got_addr (MonoCompile *cfg)
3268 {
3269         MonoInst *load, *store, *dummy_use;
3270         MonoInst *get_got;
3271
3272         if (!cfg->got_var || cfg->got_var_allocated)
3273                 return;
3274
3275         MONO_INST_NEW (cfg, get_got, OP_LOAD_GOTADDR);
3276         NEW_TEMPSTORE (cfg, store, cfg->got_var->inst_c0, get_got);
3277
3278         /* Add it to the start of the first bblock */
3279         MONO_INST_LIST_ADD (&store->node, &cfg->bb_entry->ins_list);
3280
3281         cfg->got_var_allocated = TRUE;
3282
3283         /* 
3284          * Add a dummy use to keep the got_var alive, since real uses might
3285          * only be generated in the decompose or instruction selection phases.
3286          * Add it to end_bblock, so the variable's lifetime covers the whole
3287          * method.
3288          */
3289         NEW_TEMPLOAD (cfg, load, cfg->got_var->inst_c0);
3290         NEW_DUMMY_USE (cfg, dummy_use, load);
3291         MONO_ADD_INS (cfg->bb_exit, dummy_use);
3292 }
3293
3294 #define CODE_IS_STLOC(ip) (((ip) [0] >= CEE_STLOC_0 && (ip) [0] <= CEE_STLOC_3) || ((ip) [0] == CEE_STLOC_S))
3295
3296 static gboolean
3297 mini_class_is_system_array (MonoClass *klass)
3298 {
3299         if (klass->parent == mono_defaults.array_class)
3300                 return TRUE;
3301         else
3302                 return FALSE;
3303 }
3304
3305 static gboolean
3306 mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method)
3307 {
3308         MonoMethodHeader *header = mono_method_get_header (method);
3309         MonoMethodSignature *signature = mono_method_signature (method);
3310         MonoVTable *vtable;
3311         int i;
3312
3313         if (cfg->generic_sharing_context)
3314                 return FALSE;
3315
3316 #ifdef MONO_ARCH_HAVE_LMF_OPS
3317         if (((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
3318                  (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) &&
3319             !MONO_TYPE_ISSTRUCT (signature->ret) && !mini_class_is_system_array (method->klass))
3320                 return TRUE;
3321 #endif
3322
3323         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
3324             (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
3325             (method->iflags & METHOD_IMPL_ATTRIBUTE_NOINLINING) ||
3326             (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) ||
3327             (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
3328             (method->klass->marshalbyref) ||
3329             !header || header->num_clauses ||
3330             /* fixme: why cant we inline valuetype returns? */
3331             MONO_TYPE_ISSTRUCT (signature->ret))
3332                 return FALSE;
3333
3334 #ifdef MONO_ARCH_SOFT_FLOAT
3335         /* this complicates things, fix later */
3336         if (signature->ret->type == MONO_TYPE_R4)
3337                 return FALSE;
3338 #endif
3339         /* its not worth to inline methods with valuetype arguments?? */
3340         for (i = 0; i < signature->param_count; i++) {
3341                 if (MONO_TYPE_ISSTRUCT (signature->params [i])) {
3342                         return FALSE;
3343                 }
3344 #ifdef MONO_ARCH_SOFT_FLOAT
3345                 /* this complicates things, fix later */
3346                 if (!signature->params [i]->byref && signature->params [i]->type == MONO_TYPE_R4)
3347                         return FALSE;
3348 #endif
3349         }
3350
3351         /*
3352          * if we can initialize the class of the method right away, we do,
3353          * otherwise we don't allow inlining if the class needs initialization,
3354          * since it would mean inserting a call to mono_runtime_class_init()
3355          * inside the inlined code
3356          */
3357         if (!(cfg->opt & MONO_OPT_SHARED)) {
3358                 vtable = mono_class_vtable (cfg->domain, method->klass);
3359                 if (method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) {
3360                         if (cfg->run_cctors) {
3361                                 /* This makes so that inline cannot trigger */
3362                                 /* .cctors: too many apps depend on them */
3363                                 /* running with a specific order... */
3364                                 if (! vtable->initialized)
3365                                         return FALSE;
3366                                 mono_runtime_class_init (vtable);
3367                         }
3368                 }
3369                 else if (!vtable->initialized && mono_class_needs_cctor_run (method->klass, NULL))
3370                         return FALSE;
3371         } else {
3372                 /* 
3373                  * If we're compiling for shared code
3374                  * the cctor will need to be run at aot method load time, for example,
3375                  * or at the end of the compilation of the inlining method.
3376                  */
3377                 if (mono_class_needs_cctor_run (method->klass, NULL) && !((method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT)))
3378                         return FALSE;
3379         }
3380         //if (!MONO_TYPE_IS_VOID (signature->ret)) return FALSE;
3381
3382         /*
3383          * CAS - do not inline methods with declarative security
3384          * Note: this has to be before any possible return TRUE;
3385          */
3386         if (mono_method_has_declsec (method))
3387                 return FALSE;
3388
3389         /* also consider num_locals? */
3390         if (getenv ("MONO_INLINELIMIT")) {
3391                 if (header->code_size < atoi (getenv ("MONO_INLINELIMIT"))) {
3392                         return TRUE;
3393                 }
3394         } else if (header->code_size < INLINE_LENGTH_LIMIT)
3395                 return TRUE;
3396
3397         return FALSE;
3398 }
3399
3400 static gboolean
3401 mini_field_access_needs_cctor_run (MonoCompile *cfg, MonoMethod *method, MonoVTable *vtable)
3402 {
3403         if (vtable->initialized && !cfg->compile_aot)
3404                 return FALSE;
3405
3406         if (vtable->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT)
3407                 return FALSE;
3408
3409         if (!mono_class_needs_cctor_run (vtable->klass, method))
3410                 return FALSE;
3411
3412         if (! (method->flags & METHOD_ATTRIBUTE_STATIC) && (vtable->klass == method->klass))
3413                 /* The initialization is already done before the method is called */
3414                 return FALSE;
3415
3416         return TRUE;
3417 }
3418
3419 static MonoInst*
3420 mini_get_ldelema_ins (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *cmethod, MonoInst **sp, unsigned char *ip, gboolean is_set)
3421 {
3422         int temp, rank;
3423         MonoInst *addr;
3424         MonoMethod *addr_method;
3425         int element_size;
3426
3427         rank = mono_method_signature (cmethod)->param_count - (is_set? 1: 0);
3428
3429         if (rank == 1) {
3430                 MONO_INST_NEW (cfg, addr, CEE_LDELEMA);
3431                 addr->inst_left = sp [0];
3432                 addr->inst_right = sp [1];
3433                 addr->cil_code = ip;
3434                 addr->type = STACK_MP;
3435                 addr->klass = cmethod->klass->element_class;
3436                 return addr;
3437         }
3438
3439         if (rank == 2 && (cfg->opt & MONO_OPT_INTRINS)) {
3440 #if defined(MONO_ARCH_EMULATE_MUL_DIV) && !defined(MONO_ARCH_NO_EMULATE_MUL)
3441                 /* OP_LDELEMA2D depends on OP_LMUL */
3442 #else
3443                 MonoInst *indexes;
3444                 NEW_GROUP (cfg, indexes, sp [1], sp [2]);
3445                 MONO_INST_NEW (cfg, addr, OP_LDELEMA2D);
3446                 addr->inst_left = sp [0];
3447                 addr->inst_right = indexes;
3448                 addr->cil_code = ip;
3449                 addr->type = STACK_MP;
3450                 addr->klass = cmethod->klass->element_class;
3451                 return addr;
3452 #endif
3453         }
3454
3455         element_size = mono_class_array_element_size (cmethod->klass->element_class);
3456         addr_method = mono_marshal_get_array_address (rank, element_size);
3457         temp = mono_emit_method_call_spilled (cfg, bblock, addr_method, addr_method->signature, sp, ip, NULL);
3458         NEW_TEMPLOAD (cfg, addr, temp);
3459         return addr;
3460
3461 }
3462
3463 static MonoJitICallInfo **emul_opcode_map = NULL;
3464
3465 MonoJitICallInfo *
3466 mono_find_jit_opcode_emulation (int opcode)
3467 {
3468         g_assert (opcode >= 0 && opcode <= OP_LAST);
3469         if  (emul_opcode_map)
3470                 return emul_opcode_map [opcode];
3471         else
3472                 return NULL;
3473 }
3474
3475 static int
3476 is_unsigned_regsize_type (MonoType *type)
3477 {
3478         switch (type->type) {
3479         case MONO_TYPE_U1:
3480         case MONO_TYPE_U2:
3481         case MONO_TYPE_U4:
3482 #if SIZEOF_VOID_P == 8
3483         /*case MONO_TYPE_U8: this requires different opcodes in inssel.brg */
3484 #endif
3485                 return TRUE;
3486         default:
3487                 return FALSE;
3488         }
3489 }
3490
3491 static MonoInst*
3492 mini_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
3493 {
3494         MonoInst *ins = NULL;
3495         
3496         static MonoClass *runtime_helpers_class = NULL;
3497         if (! runtime_helpers_class)
3498                 runtime_helpers_class = mono_class_from_name (mono_defaults.corlib,
3499                         "System.Runtime.CompilerServices", "RuntimeHelpers");
3500
3501         if (cmethod->klass == mono_defaults.string_class) {
3502                 if (strcmp (cmethod->name, "get_Chars") == 0) {
3503                         MONO_INST_NEW (cfg, ins, OP_GETCHR);
3504                         ins->inst_i0 = args [0];
3505                         ins->inst_i1 = args [1];
3506                         return ins;
3507                 } else if (strcmp (cmethod->name, "get_Length") == 0) {
3508                         MONO_INST_NEW (cfg, ins, OP_STRLEN);
3509                         ins->inst_i0 = args [0];
3510                         return ins;
3511                 } else if (strcmp (cmethod->name, "InternalSetChar") == 0) {
3512                         MonoInst *get_addr;
3513                         MONO_INST_NEW (cfg, get_addr, OP_STR_CHAR_ADDR);
3514                         get_addr->inst_i0 = args [0];
3515                         get_addr->inst_i1 = args [1];
3516                         MONO_INST_NEW (cfg, ins, CEE_STIND_I2);
3517                         ins->inst_i0 = get_addr;
3518                         ins->inst_i1 = args [2];
3519                         return ins;
3520                 } else 
3521                         return NULL;
3522         } else if (cmethod->klass == mono_defaults.object_class) {
3523                 if (strcmp (cmethod->name, "GetType") == 0) {
3524                         MONO_INST_NEW (cfg, ins, OP_GETTYPE);
3525                         ins->inst_i0 = args [0];
3526                         return ins;
3527                 /* The OP_GETHASHCODE rule depends on OP_MUL */
3528 #if !defined(MONO_ARCH_EMULATE_MUL_DIV) && !defined(HAVE_MOVING_COLLECTOR)
3529                 } else if (strcmp (cmethod->name, "InternalGetHashCode") == 0) {
3530                         MONO_INST_NEW (cfg, ins, OP_GETHASHCODE);
3531                         ins->inst_i0 = args [0];
3532                         return ins;
3533 #endif
3534                 } else if (strcmp (cmethod->name, ".ctor") == 0) {
3535                         MONO_INST_NEW (cfg, ins, OP_NOP);
3536                         return ins;
3537                 } else
3538                         return NULL;
3539         } else if (cmethod->klass == mono_defaults.array_class) {
3540                 if (cmethod->name [0] != 'g')
3541                         return NULL;
3542
3543                 if (strcmp (cmethod->name, "get_Rank") == 0) {
3544                         MONO_INST_NEW (cfg, ins, OP_ARRAY_RANK);
3545                         ins->inst_i0 = args [0];
3546                         return ins;
3547                 } else if (strcmp (cmethod->name, "get_Length") == 0) {
3548                         MONO_INST_NEW (cfg, ins, CEE_LDLEN);
3549                         ins->inst_i0 = args [0];
3550                         return ins;
3551                 } else
3552                         return NULL;
3553         } else if (cmethod->klass == runtime_helpers_class) {
3554                 if (strcmp (cmethod->name, "get_OffsetToStringData") == 0) {
3555                         NEW_ICONST (cfg, ins, G_STRUCT_OFFSET (MonoString, chars));
3556                         return ins;
3557                 } else
3558                         return NULL;
3559         } else if (cmethod->klass == mono_defaults.thread_class) {
3560                 if (strcmp (cmethod->name, "get_CurrentThread") == 0 && (ins = mono_arch_get_thread_intrinsic (cfg)))
3561                         return ins;
3562                 if (strcmp (cmethod->name, "MemoryBarrier") == 0) {
3563                         MONO_INST_NEW (cfg, ins, OP_MEMORY_BARRIER);
3564                         return ins;
3565                 }
3566         } else if (mini_class_is_system_array (cmethod->klass) &&
3567                         strcmp (cmethod->name, "GetGenericValueImpl") == 0) {
3568                 MonoInst *sp [2];
3569                 MonoInst *ldelem, *store, *load;
3570                 MonoClass *eklass = mono_class_from_mono_type (fsig->params [1]);
3571                 int n;
3572                 n = mini_type_to_stind (cfg, &eklass->byval_arg);
3573                 if (n == CEE_STOBJ)
3574                         return NULL;
3575                 sp [0] = args [0];
3576                 sp [1] = args [1];
3577                 NEW_LDELEMA (cfg, ldelem, sp, eklass);
3578                 ldelem->flags |= MONO_INST_NORANGECHECK;
3579                 MONO_INST_NEW (cfg, store, n);
3580                 MONO_INST_NEW (cfg, load, mini_type_to_ldind (cfg, &eklass->byval_arg));
3581                 type_to_eval_stack_type (cfg, &eklass->byval_arg, load);
3582                 load->inst_left = ldelem;
3583                 store->inst_left = args [2];
3584                 store->inst_right = load;
3585                 return store;
3586         } else if (cmethod->klass == mono_defaults.math_class) {
3587                 if (strcmp (cmethod->name, "Min") == 0) {
3588                         if (is_unsigned_regsize_type (fsig->params [0])) {
3589                                 MONO_INST_NEW (cfg, ins, OP_MIN);
3590                                 ins->inst_i0 = args [0];
3591                                 ins->inst_i1 = args [1];
3592                                 return ins;
3593                         }
3594                 } else if (strcmp (cmethod->name, "Max") == 0) {
3595                         if (is_unsigned_regsize_type (fsig->params [0])) {
3596                                 MONO_INST_NEW (cfg, ins, OP_MAX);
3597                                 ins->inst_i0 = args [0];
3598                                 ins->inst_i1 = args [1];
3599                                 return ins;
3600                         }
3601                 }
3602         } else if (cmethod->klass->image == mono_defaults.corlib &&
3603                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
3604                            (strcmp (cmethod->klass->name, "Interlocked") == 0)) {
3605                 ins = NULL;
3606
3607 #if SIZEOF_VOID_P == 8
3608                 if (strcmp (cmethod->name, "Read") == 0 && (fsig->params [0]->type == MONO_TYPE_I8)) {
3609                         /* 64 bit reads are already atomic */
3610                         MONO_INST_NEW (cfg, ins, CEE_LDIND_I8);
3611                         ins->inst_i0 = args [0];
3612                 }
3613 #endif
3614
3615 #ifdef MONO_ARCH_HAVE_ATOMIC_ADD
3616                 if (strcmp (cmethod->name, "Increment") == 0) {
3617                         MonoInst *ins_iconst;
3618                         guint32 opcode;
3619
3620                         if (fsig->params [0]->type == MONO_TYPE_I4)
3621                                 opcode = OP_ATOMIC_ADD_NEW_I4;
3622                         else if (fsig->params [0]->type == MONO_TYPE_I8)
3623                                 opcode = OP_ATOMIC_ADD_NEW_I8;
3624                         else
3625                                 g_assert_not_reached ();
3626
3627 #if SIZEOF_VOID_P == 4
3628                         if (opcode == OP_ATOMIC_ADD_NEW_I8)
3629                                 return NULL;
3630 #endif
3631
3632                         MONO_INST_NEW (cfg, ins, opcode);
3633                         MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
3634                         ins_iconst->inst_c0 = 1;
3635
3636                         ins->inst_i0 = args [0];
3637                         ins->inst_i1 = ins_iconst;
3638                 } else if (strcmp (cmethod->name, "Decrement") == 0) {
3639                         MonoInst *ins_iconst;
3640                         guint32 opcode;
3641
3642                         if (fsig->params [0]->type == MONO_TYPE_I4)
3643                                 opcode = OP_ATOMIC_ADD_NEW_I4;
3644                         else if (fsig->params [0]->type == MONO_TYPE_I8)
3645                                 opcode = OP_ATOMIC_ADD_NEW_I8;
3646                         else
3647                                 g_assert_not_reached ();
3648
3649 #if SIZEOF_VOID_P == 4
3650                         if (opcode == OP_ATOMIC_ADD_NEW_I8)
3651                                 return NULL;
3652 #endif
3653
3654                         MONO_INST_NEW (cfg, ins, opcode);
3655                         MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
3656                         ins_iconst->inst_c0 = -1;
3657
3658                         ins->inst_i0 = args [0];
3659                         ins->inst_i1 = ins_iconst;
3660                 } else if (strcmp (cmethod->name, "Add") == 0) {
3661                         guint32 opcode;
3662
3663                         if (fsig->params [0]->type == MONO_TYPE_I4)
3664                                 opcode = OP_ATOMIC_ADD_NEW_I4;
3665                         else if (fsig->params [0]->type == MONO_TYPE_I8)
3666                                 opcode = OP_ATOMIC_ADD_NEW_I8;
3667                         else
3668                                 g_assert_not_reached ();
3669
3670 #if SIZEOF_VOID_P == 4
3671                         if (opcode == OP_ATOMIC_ADD_NEW_I8)
3672                                 return NULL;
3673 #endif
3674                         
3675                         MONO_INST_NEW (cfg, ins, opcode);
3676
3677                         ins->inst_i0 = args [0];
3678                         ins->inst_i1 = args [1];
3679                 }
3680 #endif /* MONO_ARCH_HAVE_ATOMIC_ADD */
3681
3682 #ifdef MONO_ARCH_HAVE_ATOMIC_EXCHANGE
3683                 if (strcmp (cmethod->name, "Exchange") == 0) {
3684                         guint32 opcode;
3685
3686                         if (fsig->params [0]->type == MONO_TYPE_I4)
3687                                 opcode = OP_ATOMIC_EXCHANGE_I4;
3688 #if SIZEOF_VOID_P == 8
3689                         else if ((fsig->params [0]->type == MONO_TYPE_I8) ||
3690                                          (fsig->params [0]->type == MONO_TYPE_I) ||
3691                                          (fsig->params [0]->type == MONO_TYPE_OBJECT))
3692                                 opcode = OP_ATOMIC_EXCHANGE_I8;
3693 #else
3694                         else if ((fsig->params [0]->type == MONO_TYPE_I) ||
3695                                          (fsig->params [0]->type == MONO_TYPE_OBJECT))
3696                                 opcode = OP_ATOMIC_EXCHANGE_I4;
3697 #endif
3698                         else
3699                                 return NULL;
3700
3701 #if SIZEOF_VOID_P == 4
3702                         if (opcode == OP_ATOMIC_EXCHANGE_I8)
3703                                 return NULL;
3704 #endif
3705
3706                         MONO_INST_NEW (cfg, ins, opcode);
3707
3708                         ins->inst_i0 = args [0];
3709                         ins->inst_i1 = args [1];
3710                 }
3711 #endif /* MONO_ARCH_HAVE_ATOMIC_EXCHANGE */
3712
3713                 if (ins)
3714                         return ins;
3715         } else if (cmethod->klass->image == mono_defaults.corlib) {
3716                 if (cmethod->name [0] == 'B' && strcmp (cmethod->name, "Break") == 0
3717                                 && strcmp (cmethod->klass->name, "Debugger") == 0) {
3718                         MONO_INST_NEW (cfg, ins, OP_BREAK);
3719                         return ins;
3720                 }
3721                 if (cmethod->name [0] == 'g' && strcmp (cmethod->name, "get_IsRunningOnWindows") == 0
3722                                 && strcmp (cmethod->klass->name, "Environment") == 0) {
3723 #ifdef PLATFORM_WIN32
3724                         NEW_ICONST (cfg, ins, 1);
3725 #else
3726                         NEW_ICONST (cfg, ins, 0);
3727 #endif
3728                         return ins;
3729                 }
3730         }
3731
3732         return mono_arch_get_inst_for_method (cfg, cmethod, fsig, args);
3733 }
3734
3735 static void
3736 mono_save_args (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethodSignature *sig, MonoInst **sp, MonoInst **args)
3737 {
3738         MonoInst *store, *temp;
3739         int i;
3740
3741         g_assert (!MONO_TYPE_ISSTRUCT (sig->ret));
3742
3743         if (!sig->hasthis && sig->param_count == 0) 
3744                 return;
3745
3746         if (sig->hasthis) {
3747                 if (sp [0]->opcode == OP_ICONST) {
3748                         *args++ = sp [0];
3749                 } else {
3750                         temp = mono_compile_create_var (cfg, type_from_stack_type (*sp), OP_LOCAL);
3751                         *args++ = temp;
3752                         NEW_TEMPSTORE (cfg, store, temp->inst_c0, *sp);
3753                         /* FIXME: handle CEE_STIND_R4 */
3754                         store->cil_code = sp [0]->cil_code;
3755                         MONO_ADD_INS (bblock, store);
3756                 }
3757                 sp++;
3758         }
3759
3760         for (i = 0; i < sig->param_count; ++i) {
3761                 if (sp [0]->opcode == OP_ICONST) {
3762                         *args++ = sp [0];
3763                 } else {
3764                         temp = mono_compile_create_var (cfg, sig->params [i], OP_LOCAL);
3765                         *args++ = temp;
3766                         NEW_TEMPSTORE (cfg, store, temp->inst_c0, *sp);
3767                         store->cil_code = sp [0]->cil_code;
3768                         /* FIXME: handle CEE_STIND_R4 */
3769                         if (store->opcode == CEE_STOBJ) {
3770                                 NEW_TEMPLOADA (cfg, store, temp->inst_c0);
3771                                 handle_stobj (cfg, bblock, store, *sp, sp [0]->cil_code, temp->klass, FALSE, FALSE, FALSE);
3772 #ifdef MONO_ARCH_SOFT_FLOAT
3773                         } else if (store->opcode == CEE_STIND_R4) {
3774                                 NEW_TEMPLOADA (cfg, store, temp->inst_c0);
3775                                 handle_store_float (cfg, bblock, store, *sp, sp [0]->cil_code);
3776 #endif
3777                         } else {
3778                                 MONO_ADD_INS (bblock, store);
3779                         } 
3780                 }
3781                 sp++;
3782         }
3783 }
3784 #define MONO_INLINE_CALLED_LIMITED_METHODS 0
3785 #define MONO_INLINE_CALLER_LIMITED_METHODS 0
3786
3787 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
3788 static char*
3789 mono_inline_called_method_name_limit = NULL;
3790 static gboolean check_inline_called_method_name_limit (MonoMethod *called_method) {
3791         char *called_method_name = mono_method_full_name (called_method, TRUE);
3792         int strncmp_result;
3793         
3794         if (mono_inline_called_method_name_limit == NULL) {
3795                 char *limit_string = getenv ("MONO_INLINE_CALLED_METHOD_NAME_LIMIT");
3796                 if (limit_string != NULL) {
3797                         mono_inline_called_method_name_limit = limit_string;
3798                 } else {
3799                         mono_inline_called_method_name_limit = (char *) "";
3800                 }
3801         }
3802         
3803         strncmp_result = strncmp (called_method_name, mono_inline_called_method_name_limit, strlen (mono_inline_called_method_name_limit));
3804         g_free (called_method_name);
3805         
3806         //return (strncmp_result <= 0);
3807         return (strncmp_result == 0);
3808 }
3809 #endif
3810
3811 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
3812 static char*
3813 mono_inline_caller_method_name_limit = NULL;
3814 static gboolean check_inline_caller_method_name_limit (MonoMethod *caller_method) {
3815         char *caller_method_name = mono_method_full_name (caller_method, TRUE);
3816         int strncmp_result;
3817         
3818         if (mono_inline_caller_method_name_limit == NULL) {
3819                 char *limit_string = getenv ("MONO_INLINE_CALLER_METHOD_NAME_LIMIT");
3820                 if (limit_string != NULL) {
3821                         mono_inline_caller_method_name_limit = limit_string;
3822                 } else {
3823                         mono_inline_caller_method_name_limit = (char *) "";
3824                 }
3825         }
3826         
3827         strncmp_result = strncmp (caller_method_name, mono_inline_caller_method_name_limit, strlen (mono_inline_caller_method_name_limit));
3828         g_free (caller_method_name);
3829         
3830         //return (strncmp_result <= 0);
3831         return (strncmp_result == 0);
3832 }
3833 #endif
3834
3835 static int
3836 inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoBasicBlock *bblock, MonoInst **sp,
3837                 guchar *ip, guint real_offset, GList *dont_inline, MonoBasicBlock **last_b, gboolean inline_allways)
3838 {
3839         MonoInst *ins, *rvar = NULL;
3840         MonoMethodHeader *cheader;
3841         MonoBasicBlock *ebblock, *sbblock;
3842         int i, costs, new_locals_offset;
3843         MonoMethod *prev_inlined_method;
3844         MonoBasicBlock **prev_cil_offset_to_bb;
3845         unsigned char* prev_cil_start;
3846         guint32 prev_cil_offset_to_bb_len;
3847
3848         g_assert (cfg->exception_type == MONO_EXCEPTION_NONE);
3849
3850 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
3851         if ((! inline_allways) && ! check_inline_called_method_name_limit (cmethod))
3852                 return 0;
3853 #endif
3854 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
3855         if ((! inline_allways) && ! check_inline_caller_method_name_limit (cfg->method))
3856                 return 0;
3857 #endif
3858
3859         if (bblock->out_of_line && !inline_allways)
3860                 return 0;
3861
3862         if (cfg->verbose_level > 2)
3863                 g_print ("INLINE START %p %s -> %s\n", cmethod,  mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
3864
3865         if (!cmethod->inline_info) {
3866                 mono_jit_stats.inlineable_methods++;
3867                 cmethod->inline_info = 1;
3868         }
3869         /* allocate space to store the return value */
3870         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
3871                 rvar =  mono_compile_create_var (cfg, fsig->ret, OP_LOCAL);
3872         }
3873
3874         /* allocate local variables */
3875         cheader = mono_method_get_header (cmethod);
3876         new_locals_offset = cfg->num_varinfo;
3877         for (i = 0; i < cheader->num_locals; ++i)
3878                 mono_compile_create_var (cfg, cheader->locals [i], OP_LOCAL);
3879
3880         /* allocate starte and end blocks */
3881         NEW_BBLOCK (cfg, sbblock);
3882         sbblock->block_num = cfg->num_bblocks++;
3883         sbblock->real_offset = real_offset;
3884
3885         NEW_BBLOCK (cfg, ebblock);
3886         ebblock->block_num = cfg->num_bblocks++;
3887         ebblock->real_offset = real_offset;
3888
3889         prev_inlined_method = cfg->inlined_method;
3890         cfg->inlined_method = cmethod;
3891         prev_cil_offset_to_bb = cfg->cil_offset_to_bb;
3892         prev_cil_offset_to_bb_len = cfg->cil_offset_to_bb_len;
3893         prev_cil_start = cfg->cil_start;
3894
3895         costs = mono_method_to_ir (cfg, cmethod, sbblock, ebblock, new_locals_offset, rvar, dont_inline, sp, real_offset, *ip == CEE_CALLVIRT);
3896
3897         cfg->inlined_method = prev_inlined_method;
3898         cfg->cil_offset_to_bb = prev_cil_offset_to_bb;
3899         cfg->cil_offset_to_bb_len = prev_cil_offset_to_bb_len;
3900         cfg->cil_start = prev_cil_start;
3901
3902         if ((costs >= 0 && costs < 60) || inline_allways) {
3903                 if (cfg->verbose_level > 2)
3904                         g_print ("INLINE END %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
3905                 
3906                 mono_jit_stats.inlined_methods++;
3907
3908                 /* always add some code to avoid block split failures */
3909                 MONO_INST_NEW (cfg, ins, OP_NOP);
3910                 MONO_ADD_INS (bblock, ins);
3911                 ins->cil_code = ip;
3912
3913                 bblock->next_bb = sbblock;
3914                 link_bblock (cfg, bblock, sbblock);
3915
3916                 if (rvar) {
3917                         NEW_TEMPLOAD (cfg, ins, rvar->inst_c0);
3918 #ifdef MONO_ARCH_SOFT_FLOAT
3919                         if (ins->opcode == CEE_LDIND_R4) {
3920                                 int temp;
3921                                 NEW_TEMPLOADA (cfg, ins, rvar->inst_c0);
3922                                 temp = handle_load_float (cfg, bblock, ins, ip);
3923                                 NEW_TEMPLOAD (cfg, ins, temp);
3924                         }
3925 #endif
3926                         *sp++ = ins;
3927                 }
3928                 *last_b = ebblock;
3929                 return costs + 1;
3930         } else {
3931                 if (cfg->verbose_level > 2)
3932                         g_print ("INLINE ABORTED %s\n", mono_method_full_name (cmethod, TRUE));
3933                 cfg->exception_type = MONO_EXCEPTION_NONE;
3934                 mono_loader_clear_error ();
3935         }
3936         return 0;
3937 }
3938
3939 /*
3940  * Some of these comments may well be out-of-date.
3941  * Design decisions: we do a single pass over the IL code (and we do bblock 
3942  * splitting/merging in the few cases when it's required: a back jump to an IL
3943  * address that was not already seen as bblock starting point).
3944  * Code is validated as we go (full verification is still better left to metadata/verify.c).
3945  * Complex operations are decomposed in simpler ones right away. We need to let the 
3946  * arch-specific code peek and poke inside this process somehow (except when the 
3947  * optimizations can take advantage of the full semantic info of coarse opcodes).
3948  * All the opcodes of the form opcode.s are 'normalized' to opcode.
3949  * MonoInst->opcode initially is the IL opcode or some simplification of that 
3950  * (OP_LOAD, OP_STORE). The arch-specific code may rearrange it to an arch-specific 
3951  * opcode with value bigger than OP_LAST.
3952  * At this point the IR can be handed over to an interpreter, a dumb code generator
3953  * or to the optimizing code generator that will translate it to SSA form.
3954  *
3955  * Profiling directed optimizations.
3956  * We may compile by default with few or no optimizations and instrument the code
3957  * or the user may indicate what methods to optimize the most either in a config file
3958  * or through repeated runs where the compiler applies offline the optimizations to 
3959  * each method and then decides if it was worth it.
3960  *
3961  */
3962
3963 #define CHECK_TYPE(ins) if (!(ins)->type) UNVERIFIED
3964 #define CHECK_STACK(num) if ((sp - stack_start) < (num)) UNVERIFIED
3965 #define CHECK_STACK_OVF(num) if (((sp - stack_start) + (num)) > header->max_stack) UNVERIFIED
3966 #define CHECK_ARG(num) if ((unsigned)(num) >= (unsigned)num_args) UNVERIFIED
3967 #define CHECK_LOCAL(num) if ((unsigned)(num) >= (unsigned)header->num_locals) UNVERIFIED
3968 #define CHECK_OPSIZE(size) if (ip + size > end) UNVERIFIED
3969 #define CHECK_UNVERIFIABLE(cfg) if (cfg->unverifiable) UNVERIFIED
3970 #define CHECK_TYPELOAD(klass) if (!(klass) || (klass)->exception_type) {cfg->exception_ptr = klass; goto load_error;}
3971
3972 /* offset from br.s -> br like opcodes */
3973 #define BIG_BRANCH_OFFSET 13
3974
3975 static inline gboolean
3976 ip_in_bb (MonoCompile *cfg, MonoBasicBlock *bb, const guint8* ip)
3977 {
3978         MonoBasicBlock *b = cfg->cil_offset_to_bb [ip - cfg->cil_start];
3979         
3980         return b == NULL || b == bb;
3981 }
3982
3983 static int
3984 get_basic_blocks (MonoCompile *cfg, MonoMethodHeader* header, guint real_offset, unsigned char *start, unsigned char *end, unsigned char **pos)
3985 {
3986         unsigned char *ip = start;
3987         unsigned char *target;
3988         int i;
3989         guint cli_addr;
3990         MonoBasicBlock *bblock;
3991         const MonoOpcode *opcode;
3992
3993         while (ip < end) {
3994                 cli_addr = ip - start;
3995                 i = mono_opcode_value ((const guint8 **)&ip, end);
3996                 if (i < 0)
3997                         UNVERIFIED;
3998                 opcode = &mono_opcodes [i];
3999                 switch (opcode->argument) {
4000                 case MonoInlineNone:
4001                         ip++; 
4002                         break;
4003                 case MonoInlineString:
4004                 case MonoInlineType:
4005                 case MonoInlineField:
4006                 case MonoInlineMethod:
4007                 case MonoInlineTok:
4008                 case MonoInlineSig:
4009                 case MonoShortInlineR:
4010                 case MonoInlineI:
4011                         ip += 5;
4012                         break;
4013                 case MonoInlineVar:
4014                         ip += 3;
4015                         break;
4016                 case MonoShortInlineVar:
4017                 case MonoShortInlineI:
4018                         ip += 2;
4019                         break;
4020                 case MonoShortInlineBrTarget:
4021                         target = start + cli_addr + 2 + (signed char)ip [1];
4022                         GET_BBLOCK (cfg, bblock, target);
4023                         ip += 2;
4024                         if (ip < end)
4025                                 GET_BBLOCK (cfg, bblock, ip);
4026                         break;
4027                 case MonoInlineBrTarget:
4028                         target = start + cli_addr + 5 + (gint32)read32 (ip + 1);
4029                         GET_BBLOCK (cfg, bblock, target);
4030                         ip += 5;
4031                         if (ip < end)
4032                                 GET_BBLOCK (cfg, bblock, ip);
4033                         break;
4034                 case MonoInlineSwitch: {
4035                         guint32 n = read32 (ip + 1);
4036                         guint32 j;
4037                         ip += 5;
4038                         cli_addr += 5 + 4 * n;
4039                         target = start + cli_addr;
4040                         GET_BBLOCK (cfg, bblock, target);
4041                         
4042                         for (j = 0; j < n; ++j) {
4043                                 target = start + cli_addr + (gint32)read32 (ip);
4044                                 GET_BBLOCK (cfg, bblock, target);
4045                                 ip += 4;
4046                         }
4047                         break;
4048                 }
4049                 case MonoInlineR:
4050                 case MonoInlineI8:
4051                         ip += 9;
4052                         break;
4053                 default:
4054                         g_assert_not_reached ();
4055                 }
4056
4057                 if (i == CEE_THROW) {
4058                         unsigned char *bb_start = ip - 1;
4059                         
4060                         /* Find the start of the bblock containing the throw */
4061                         bblock = NULL;
4062                         while ((bb_start >= start) && !bblock) {
4063                                 bblock = cfg->cil_offset_to_bb [(bb_start) - start];
4064                                 bb_start --;
4065                         }
4066                         if (bblock)
4067                                 bblock->out_of_line = 1;
4068                 }
4069         }
4070         return 0;
4071 unverified:
4072         *pos = ip;
4073         return 1;
4074 }
4075
4076 static MonoInst*
4077 emit_tree (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *ins, const guint8* ip_next)
4078 {
4079         MonoInst *store, *temp, *load;
4080         
4081         if (ip_in_bb (cfg, bblock, ip_next) &&
4082                 (CODE_IS_STLOC (ip_next) || *ip_next == CEE_RET))
4083                         return ins;
4084         
4085         temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
4086         temp->flags |= MONO_INST_IS_TEMP;
4087         NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
4088         /* FIXME: handle CEE_STIND_R4 */
4089         store->cil_code = ins->cil_code;
4090         MONO_ADD_INS (bblock, store);
4091         NEW_TEMPLOAD (cfg, load, temp->inst_c0);
4092         load->cil_code = ins->cil_code;
4093         return load;
4094 }
4095
4096 static inline MonoMethod *
4097 mini_get_method (MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
4098 {
4099         MonoMethod *method;
4100
4101         if (m->wrapper_type != MONO_WRAPPER_NONE)
4102                 return mono_method_get_wrapper_data (m, token);
4103
4104         method = mono_get_method_full (m->klass->image, token, klass, context);
4105
4106         return method;
4107 }
4108
4109 static inline MonoClass*
4110 mini_get_class (MonoMethod *method, guint32 token, MonoGenericContext *context)
4111 {
4112         MonoClass *klass;
4113
4114         if (method->wrapper_type != MONO_WRAPPER_NONE)
4115                 klass = mono_method_get_wrapper_data (method, token);
4116         else
4117                 klass = mono_class_get_full (method->klass->image, token, context);
4118         if (klass)
4119                 mono_class_init (klass);
4120         return klass;
4121 }
4122
4123 /*
4124  * Returns TRUE if the JIT should abort inlining because "callee"
4125  * is influenced by security attributes.
4126  */
4127 static
4128 gboolean check_linkdemand (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee, MonoBasicBlock *bblock, unsigned char *ip)
4129 {
4130         guint32 result;
4131         
4132         if ((cfg->method != caller) && mono_method_has_declsec (callee)) {
4133                 return TRUE;
4134         }
4135         
4136         result = mono_declsec_linkdemand (cfg->domain, caller, callee);
4137         if (result == MONO_JIT_SECURITY_OK)
4138                 return FALSE;
4139
4140         if (result == MONO_JIT_LINKDEMAND_ECMA) {
4141                 /* Generate code to throw a SecurityException before the actual call/link */
4142                 MonoSecurityManager *secman = mono_security_manager_get_methods ();
4143                 MonoInst *args [2];
4144
4145                 NEW_ICONST (cfg, args [0], 4);
4146                 NEW_METHODCONST (cfg, args [1], caller);
4147                 mono_emit_method_call_spilled (cfg, bblock, secman->linkdemandsecurityexception, mono_method_signature (secman->linkdemandsecurityexception), args, ip, NULL);
4148         } else if (cfg->exception_type == MONO_EXCEPTION_NONE) {
4149                  /* don't hide previous results */
4150                 cfg->exception_type = MONO_EXCEPTION_SECURITY_LINKDEMAND;
4151                 cfg->exception_data = result;
4152                 return TRUE;
4153         }
4154         
4155         return FALSE;
4156 }
4157
4158 static MonoMethod*
4159 method_access_exception (void)
4160 {
4161         static MonoMethod *method = NULL;
4162
4163         if (!method) {
4164                 MonoSecurityManager *secman = mono_security_manager_get_methods ();
4165                 method = mono_class_get_method_from_name (secman->securitymanager,
4166                                                           "MethodAccessException", 2);
4167         }
4168         g_assert (method);
4169         return method;
4170 }
4171
4172 static void
4173 emit_throw_method_access_exception (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee,
4174                                     MonoBasicBlock *bblock, unsigned char *ip)
4175 {
4176         MonoMethod *thrower = method_access_exception ();
4177         MonoInst *args [2];
4178
4179         NEW_METHODCONST (cfg, args [0], caller);
4180         NEW_METHODCONST (cfg, args [1], callee);
4181         mono_emit_method_call_spilled (cfg, bblock, thrower,
4182                 mono_method_signature (thrower), args, ip, NULL);
4183 }
4184
4185 static MonoMethod*
4186 verification_exception (void)
4187 {
4188         static MonoMethod *method = NULL;
4189
4190         if (!method) {
4191                 MonoSecurityManager *secman = mono_security_manager_get_methods ();
4192                 method = mono_class_get_method_from_name (secman->securitymanager,
4193                                                           "VerificationException", 0);
4194         }
4195         g_assert (method);
4196         return method;
4197 }
4198
4199 static void
4200 emit_throw_verification_exception (MonoCompile *cfg, MonoBasicBlock *bblock, unsigned char *ip)
4201 {
4202         MonoMethod *thrower = verification_exception ();
4203
4204         mono_emit_method_call_spilled (cfg, bblock, thrower,
4205                 mono_method_signature (thrower),
4206                 NULL, ip, NULL);
4207 }
4208
4209 static void
4210 ensure_method_is_allowed_to_call_method (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee,
4211                                          MonoBasicBlock *bblock, unsigned char *ip)
4212 {
4213         MonoSecurityCoreCLRLevel caller_level = mono_security_core_clr_method_level (caller, TRUE);
4214         MonoSecurityCoreCLRLevel callee_level = mono_security_core_clr_method_level (callee, TRUE);
4215         gboolean is_safe = TRUE;
4216
4217         if (!(caller_level >= callee_level ||
4218                         caller_level == MONO_SECURITY_CORE_CLR_SAFE_CRITICAL ||
4219                         callee_level == MONO_SECURITY_CORE_CLR_SAFE_CRITICAL)) {
4220                 is_safe = FALSE;
4221         }
4222
4223         if (!is_safe)
4224                 emit_throw_method_access_exception (cfg, caller, callee, bblock, ip);
4225 }
4226
4227 static gboolean
4228 method_is_safe (MonoMethod *method)
4229 {
4230         /*
4231         if (strcmp (method->name, "unsafeMethod") == 0)
4232                 return FALSE;
4233         */
4234         return TRUE;
4235 }
4236
4237 /*
4238  * Check that the IL instructions at ip are the array initialization
4239  * sequence and return the pointer to the data and the size.
4240  */
4241 static const char*
4242 initialize_array_data (MonoMethod *method, gboolean aot, unsigned char *ip, MonoInst *newarr, int *out_size)
4243 {
4244         /*
4245          * newarr[System.Int32]
4246          * dup
4247          * ldtoken field valuetype ...
4248          * call void class [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype [mscorlib]System.RuntimeFieldHandle)
4249          */
4250         if (ip [0] == CEE_DUP && ip [1] == CEE_LDTOKEN && ip [5] == 0x4 && ip [6] == CEE_CALL) {
4251                 MonoClass *klass = newarr->inst_newa_class;
4252                 guint32 field_token = read32 (ip + 2);
4253                 guint32 field_index = field_token & 0xffffff;
4254                 guint32 token = read32 (ip + 7);
4255                 guint32 rva;
4256                 const char *data_ptr;
4257                 int size = 0;
4258                 MonoMethod *cmethod;
4259                 MonoClass *dummy_class;
4260                 MonoClassField *field = mono_field_from_token (method->klass->image, field_token, &dummy_class, NULL);
4261                 int dummy_align;
4262
4263                 if (!field)
4264                         return NULL;
4265
4266                 if (newarr->inst_newa_len->opcode != OP_ICONST)
4267                         return NULL;
4268                 cmethod = mini_get_method (method, token, NULL, NULL);
4269                 if (!cmethod)
4270                         return NULL;
4271                 if (strcmp (cmethod->name, "InitializeArray") || strcmp (cmethod->klass->name, "RuntimeHelpers") || cmethod->klass->image != mono_defaults.corlib)
4272                         return NULL;
4273                 switch (mono_type_get_underlying_type (&klass->byval_arg)->type) {
4274                 case MONO_TYPE_BOOLEAN:
4275                 case MONO_TYPE_I1:
4276                 case MONO_TYPE_U1:
4277                         size = 1; break;
4278                 /* we need to swap on big endian, so punt. Should we handle R4 and R8 as well? */
4279 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
4280                 case MONO_TYPE_CHAR:
4281                 case MONO_TYPE_I2:
4282                 case MONO_TYPE_U2:
4283                         size = 2; break;
4284                 case MONO_TYPE_I4:
4285                 case MONO_TYPE_U4:
4286                 case MONO_TYPE_R4:
4287                         size = 4; break;
4288                 case MONO_TYPE_R8:
4289 #ifdef ARM_FPU_FPA
4290                         return NULL; /* stupid ARM FP swapped format */
4291 #endif
4292                 case MONO_TYPE_I8:
4293                 case MONO_TYPE_U8:
4294                         size = 8; break;
4295 #endif
4296                 default:
4297                         return NULL;
4298                 }
4299                 size *= newarr->inst_newa_len->inst_c0;
4300                 if (size > mono_type_size (field->type, &dummy_align))
4301                     return NULL;
4302                 *out_size = size;
4303                 /*g_print ("optimized in %s: size: %d, numelems: %d\n", method->name, size, newarr->inst_newa_len->inst_c0);*/
4304                 field_index = read32 (ip + 2) & 0xffffff;
4305                 mono_metadata_field_info (method->klass->image, field_index - 1, NULL, &rva, NULL);
4306                 data_ptr = mono_image_rva_map (method->klass->image, rva);
4307                 /*g_print ("field: 0x%08x, rva: %d, rva_ptr: %p\n", read32 (ip + 2), rva, data_ptr);*/
4308                 /* for aot code we do the lookup on load */
4309                 if (aot && data_ptr)
4310                         return GUINT_TO_POINTER (rva);
4311                 return data_ptr;
4312         }
4313         return NULL;
4314 }
4315
4316 static void
4317 set_exception_type_from_invalid_il (MonoCompile *cfg, MonoMethod *method, unsigned char *ip)
4318 {
4319         char *method_fname = mono_method_full_name (method, TRUE);
4320         char *method_code = mono_disasm_code_one (NULL, method, ip, NULL);
4321         cfg->exception_type = MONO_EXCEPTION_INVALID_PROGRAM;
4322         cfg->exception_message = g_strdup_printf ("Invalid IL code in %s: %s\n", method_fname, method_code);
4323         g_free (method_fname);
4324         g_free (method_code);
4325 }
4326
4327 /*
4328  * Generates this->vtable->runtime_generic_context
4329  */
4330 static MonoInst*
4331 get_runtime_generic_context_from_this (MonoCompile *cfg, MonoInst *this, unsigned char *ip)
4332 {
4333         MonoInst *vtable, *rgc_ptr_addr, *rgc_ptr_offset, *rgc_ptr;
4334
4335         MONO_INST_NEW (cfg, vtable, CEE_LDIND_I);
4336         vtable->cil_code = ip;
4337         vtable->inst_left = this;
4338         vtable->type = STACK_PTR;
4339
4340         NEW_ICONST (cfg, rgc_ptr_offset, G_STRUCT_OFFSET (MonoVTable, runtime_generic_context));
4341
4342         MONO_INST_NEW (cfg, rgc_ptr_addr, OP_PADD);
4343         rgc_ptr_addr->cil_code = ip;
4344         rgc_ptr_addr->inst_left = vtable;
4345         rgc_ptr_addr->inst_right = rgc_ptr_offset;
4346         rgc_ptr_addr->type = STACK_PTR;
4347
4348         MONO_INST_NEW (cfg, rgc_ptr, CEE_LDIND_I);
4349         rgc_ptr->cil_code = ip;
4350         rgc_ptr->inst_left = rgc_ptr_addr;
4351         rgc_ptr->type = STACK_PTR;
4352
4353         return rgc_ptr;
4354 }
4355
4356 static MonoInst*
4357 get_runtime_generic_context_field_from_offset (MonoCompile *cfg, MonoInst *rgc_ptr, int offset, unsigned char *ip)
4358 {
4359         MonoInst *field_offset, *field_addr, *field;
4360
4361         if (offset == 0) {
4362                 field_addr = rgc_ptr;
4363         } else {
4364                 NEW_ICONST (cfg, field_offset, offset);
4365
4366                 MONO_INST_NEW (cfg, field_addr, OP_PADD);
4367                 field_addr->cil_code = ip;
4368                 field_addr->inst_left = rgc_ptr;
4369                 field_addr->inst_right = field_offset;
4370                 field_addr->type = STACK_PTR;
4371         }
4372
4373         MONO_INST_NEW (cfg, field, CEE_LDIND_I);
4374         field->cil_code = ip;
4375         field->inst_left = field_addr;
4376         field->type = STACK_PTR;
4377
4378         return field;
4379 }
4380
4381 /*
4382  * Generates ((MonoRuntimeGenericSuperInfo*)rgc)[-depth].XXX where XXX
4383  * is specified by rgctx_type.
4384  */
4385 static MonoInst*
4386 get_runtime_generic_context_super_ptr (MonoCompile *cfg, MonoInst *rgc_ptr, int depth, int rgctx_type, unsigned char *ip)
4387 {
4388         int field_offset_const;
4389
4390         g_assert (depth >= 1);
4391
4392         switch (rgctx_type) {
4393         case MONO_RGCTX_INFO_STATIC_DATA :
4394                 field_offset_const = G_STRUCT_OFFSET (MonoRuntimeGenericSuperInfo, static_data);
4395                 break;
4396         case MONO_RGCTX_INFO_KLASS :
4397                 field_offset_const = G_STRUCT_OFFSET (MonoRuntimeGenericSuperInfo, klass);
4398                 break;
4399         case MONO_RGCTX_INFO_VTABLE:
4400                 field_offset_const = G_STRUCT_OFFSET (MonoRuntimeGenericSuperInfo, vtable);
4401                 break;
4402         default :
4403                 g_assert_not_reached ();
4404         }
4405
4406         return get_runtime_generic_context_field_from_offset (cfg, rgc_ptr,
4407                 -depth * sizeof (MonoRuntimeGenericSuperInfo) + field_offset_const, ip);
4408 }
4409
4410 static int
4411 get_rgctx_arg_info_field_offset (int rgctx_type)
4412 {
4413         switch (rgctx_type) {
4414         case MONO_RGCTX_INFO_STATIC_DATA :
4415                 return G_STRUCT_OFFSET (MonoRuntimeGenericArgInfo, static_data);
4416         case MONO_RGCTX_INFO_KLASS:
4417                 return G_STRUCT_OFFSET (MonoRuntimeGenericArgInfo, klass);
4418         case MONO_RGCTX_INFO_VTABLE :
4419                 return G_STRUCT_OFFSET (MonoRuntimeGenericArgInfo, vtable);
4420         default:
4421                 g_assert_not_reached ();
4422         }
4423 }
4424
4425 /*
4426  * Generates rgc->arg_infos [arg_num].XXX where XXX is specified by
4427  * rgctx_type;
4428  */
4429 static MonoInst*
4430 get_runtime_generic_context_arg_ptr (MonoCompile *cfg, MonoInst *rgc_ptr, int arg_num, int rgctx_type, unsigned char *ip)
4431 {
4432         int arg_info_offset, arg_info_field_offset;
4433
4434         g_assert (arg_num >= 0);
4435
4436         arg_info_offset = G_STRUCT_OFFSET (MonoRuntimeGenericContext, arg_infos) +
4437                 arg_num * sizeof (MonoRuntimeGenericArgInfo);
4438
4439         arg_info_field_offset = get_rgctx_arg_info_field_offset (rgctx_type);
4440
4441         return get_runtime_generic_context_field_from_offset (cfg, rgc_ptr, arg_info_offset + arg_info_field_offset, ip);
4442 }
4443
4444 /*
4445  * Generates rgc->other_infos [index].XXX if index is non-negative, or
4446  * rgc->extra_other_infos [-index + 1] if index is negative.  XXX is
4447  * specified by rgctx_type;
4448  */
4449 static MonoInst*
4450 get_runtime_generic_context_other_table_ptr (MonoCompile *cfg, MonoInst *rgc_ptr, int index, unsigned char *ip)
4451 {
4452         if (index < MONO_RGCTX_MAX_OTHER_INFOS) {
4453                 int other_type_offset;
4454
4455                 other_type_offset = G_STRUCT_OFFSET (MonoRuntimeGenericContext, other_infos) +
4456                         index * sizeof (gpointer);
4457
4458                 return get_runtime_generic_context_field_from_offset (cfg, rgc_ptr, other_type_offset, ip);
4459         } else {
4460                 int table_ptr_offset, slot_offset;
4461                 MonoInst *table_ptr;
4462
4463                 table_ptr_offset = G_STRUCT_OFFSET (MonoRuntimeGenericContext, extra_other_infos);
4464                 table_ptr = get_runtime_generic_context_field_from_offset (cfg, rgc_ptr, table_ptr_offset, ip);
4465
4466                 slot_offset = (index - MONO_RGCTX_MAX_OTHER_INFOS) * sizeof (gpointer);
4467
4468                 return get_runtime_generic_context_field_from_offset (cfg, table_ptr, slot_offset, ip);
4469         }
4470 }
4471
4472 static MonoInst*
4473 get_runtime_generic_context_other_ptr (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *bblock,
4474         MonoInst *rgc_ptr, guint32 token, int token_source, int rgctx_type, unsigned char *ip, int index)
4475 {
4476         MonoInst *args [6];
4477         int temp;
4478         MonoInst *result;
4479
4480         g_assert (method->wrapper_type == MONO_WRAPPER_NONE);
4481
4482         NEW_CLASSCONST (cfg, args [0], method->klass);
4483         args [1] = rgc_ptr;
4484         NEW_ICONST (cfg, args [2], token);
4485         NEW_ICONST (cfg, args [3], token_source);
4486         NEW_ICONST (cfg, args [4], rgctx_type);
4487         NEW_ICONST (cfg, args [5], index);
4488
4489         temp = mono_emit_jit_icall (cfg, bblock, mono_helper_get_rgctx_other_ptr, args, ip);
4490         NEW_TEMPLOAD (cfg, result, temp);
4491
4492         return result;
4493 }
4494
4495 static MonoInst*
4496 get_runtime_generic_context_ptr (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *bblock,
4497         MonoClass *klass, guint32 type_token, int token_source, MonoGenericContext *generic_context, MonoInst *rgctx,
4498         int rgctx_type, unsigned char *ip)
4499 {
4500         int arg_num = -1;
4501         int relation = mono_class_generic_class_relation (klass, rgctx_type, method->klass, generic_context, &arg_num);
4502
4503         switch (relation) {
4504         case MINI_GENERIC_CLASS_RELATION_SELF: {
4505                 int depth = klass->idepth;
4506                 return get_runtime_generic_context_super_ptr (cfg, rgctx, depth, rgctx_type, ip);
4507         }
4508         case MINI_GENERIC_CLASS_RELATION_ARGUMENT:
4509                 return get_runtime_generic_context_arg_ptr (cfg, rgctx, arg_num, rgctx_type, ip);
4510         case MINI_GENERIC_CLASS_RELATION_OTHER_TABLE:
4511                 return get_runtime_generic_context_other_table_ptr (cfg, rgctx, arg_num, ip);
4512         case MINI_GENERIC_CLASS_RELATION_OTHER:
4513                 return get_runtime_generic_context_other_ptr (cfg, method, bblock, rgctx,
4514                         type_token, token_source, rgctx_type, ip, arg_num);
4515         default:
4516                 g_assert_not_reached ();
4517                 return NULL;
4518         }
4519 }
4520
4521 /*
4522  * mono_method_to_ir: translates IL into basic blocks containing trees
4523  */
4524 static int
4525 mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock, 
4526                    int locals_offset, MonoInst *return_var, GList *dont_inline, MonoInst **inline_args, 
4527                    guint inline_offset, gboolean is_virtual_call)
4528 {
4529         MonoInst *zero_int32, *zero_int64, *zero_ptr, *zero_obj, *zero_r8;
4530         MonoInst *ins, **sp, **stack_start;
4531         MonoBasicBlock *bblock, *tblock = NULL, *init_localsbb = NULL;
4532         MonoMethod *cmethod;
4533         MonoInst **arg_array;
4534         MonoMethodHeader *header;
4535         MonoImage *image;
4536         guint32 token, ins_flag;
4537         MonoClass *klass;
4538         MonoClass *constrained_call = NULL;
4539         unsigned char *ip, *end, *target, *err_pos;
4540         static double r8_0 = 0.0;
4541         MonoMethodSignature *sig;
4542         MonoGenericContext *generic_context = NULL;
4543         MonoGenericContainer *generic_container = NULL;
4544         MonoType **param_types;
4545         GList *bb_recheck = NULL, *tmp;
4546         int i, n, start_new_bblock, ialign;
4547         int num_calls = 0, inline_costs = 0;
4548         int breakpoint_id = 0;
4549         guint32 align;
4550         guint real_offset, num_args;
4551         MonoBoolean security, pinvoke;
4552         MonoSecurityManager* secman = NULL;
4553         MonoDeclSecurityActions actions;
4554         GSList *class_inits = NULL;
4555         gboolean dont_verify, dont_verify_stloc;
4556
4557         /* serialization and xdomain stuff may need access to private fields and methods */
4558         dont_verify = method->klass->image->assembly->corlib_internal? TRUE: FALSE;
4559         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE;
4560         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH;
4561         dont_verify |= method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE; /* bug #77896 */
4562         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP;
4563         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP_INVOKE;
4564
4565         /* turn off visibility checks for smcs */
4566         dont_verify |= mono_security_get_mode () == MONO_SECURITY_MODE_SMCS_HACK;
4567
4568         /* still some type unsafety issues in marshal wrappers... (unknown is PtrToStructure) */
4569         dont_verify_stloc = method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE;
4570         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_UNKNOWN;
4571         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED;
4572
4573         /* Not turned on yet */
4574         cfg->dont_verify_stack_merge = TRUE;
4575
4576         image = method->klass->image;
4577         header = mono_method_get_header (method);
4578         generic_container = method->generic_container;
4579         sig = mono_method_signature (method);
4580         num_args = sig->hasthis + sig->param_count;
4581         ip = (unsigned char*)header->code;
4582         cfg->cil_start = ip;
4583         end = ip + header->code_size;
4584         mono_jit_stats.cil_code_size += header->code_size;
4585
4586         if (sig->is_inflated)
4587                 generic_context = mono_method_get_context (method);
4588         else if (generic_container)
4589                 generic_context = &generic_container->context;
4590
4591         if (!cfg->generic_sharing_context)
4592                 g_assert (!sig->has_type_parameters);
4593
4594         if (cfg->method == method)
4595                 real_offset = 0;
4596         else
4597                 real_offset = inline_offset;
4598
4599         cfg->cil_offset_to_bb = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoBasicBlock*) * header->code_size);
4600         cfg->cil_offset_to_bb_len = header->code_size;
4601
4602         if (cfg->verbose_level > 2)
4603                 g_print ("method to IR %s\n", mono_method_full_name (method, TRUE));
4604
4605         dont_inline = g_list_prepend (dont_inline, method);
4606         if (cfg->method == method) {
4607
4608                 if (cfg->prof_options & MONO_PROFILE_INS_COVERAGE)
4609                         cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, header->code_size);
4610
4611                 /* ENTRY BLOCK */
4612                 NEW_BBLOCK (cfg, start_bblock);
4613                 cfg->bb_entry = start_bblock;
4614                 start_bblock->cil_code = NULL;
4615                 start_bblock->cil_length = 0;
4616                 start_bblock->block_num = cfg->num_bblocks++;
4617
4618                 /* EXIT BLOCK */
4619                 NEW_BBLOCK (cfg, end_bblock);
4620                 cfg->bb_exit = end_bblock;
4621                 end_bblock->cil_code = NULL;
4622                 end_bblock->cil_length = 0;
4623                 end_bblock->block_num = cfg->num_bblocks++;
4624                 g_assert (cfg->num_bblocks == 2);
4625
4626                 arg_array = alloca (sizeof (MonoInst *) * num_args);
4627                 for (i = num_args - 1; i >= 0; i--)
4628                         arg_array [i] = cfg->varinfo [i];
4629
4630                 if (header->num_clauses) {
4631                         cfg->spvars = g_hash_table_new (NULL, NULL);
4632                         cfg->exvars = g_hash_table_new (NULL, NULL);
4633                 }
4634                 /* handle exception clauses */
4635                 for (i = 0; i < header->num_clauses; ++i) {
4636                         MonoBasicBlock *try_bb;
4637                         MonoExceptionClause *clause = &header->clauses [i];
4638                         GET_BBLOCK (cfg, try_bb, ip + clause->try_offset);
4639                         try_bb->real_offset = clause->try_offset;
4640                         GET_BBLOCK (cfg, tblock, ip + clause->handler_offset);
4641                         tblock->real_offset = clause->handler_offset;
4642                         tblock->flags |= BB_EXCEPTION_HANDLER;
4643
4644                         link_bblock (cfg, try_bb, tblock);
4645
4646                         if (*(ip + clause->handler_offset) == CEE_POP)
4647                                 tblock->flags |= BB_EXCEPTION_DEAD_OBJ;
4648
4649                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY ||
4650                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER ||
4651                             clause->flags == MONO_EXCEPTION_CLAUSE_FAULT) {
4652                                 MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
4653                                 MONO_ADD_INS (tblock, ins);
4654
4655                                 /* todo: is a fault block unsafe to optimize? */
4656                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
4657                                         tblock->flags |= BB_EXCEPTION_UNSAFE;
4658                         }
4659
4660
4661                         /*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);
4662                           while (p < end) {
4663                           g_print ("%s", mono_disasm_code_one (NULL, method, p, &p));
4664                           }*/
4665                         /* catch and filter blocks get the exception object on the stack */
4666                         if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE ||
4667                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
4668                                 MonoInst *load, *dummy_use;
4669
4670                                 /* mostly like handle_stack_args (), but just sets the input args */
4671                                 /* g_print ("handling clause at IL_%04x\n", clause->handler_offset); */
4672                                 tblock->in_scount = 1;
4673                                 tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
4674                                 tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
4675                                 tblock->stack_state = mono_mempool_alloc (cfg->mempool, sizeof (MonoStackSlot));
4676                                 tblock->stack_state [0].type = STACK_OBJ;
4677                                 /* FIXME? */
4678                                 tblock->stack_state [0].klass = mono_defaults.object_class;
4679
4680                                 /* 
4681                                  * Add a dummy use for the exvar so its liveness info will be
4682                                  * correct.
4683                                  */
4684                                 NEW_TEMPLOAD (cfg, load, tblock->in_stack [0]->inst_c0);
4685                                 NEW_DUMMY_USE (cfg, dummy_use, load);
4686                                 MONO_ADD_INS (tblock, dummy_use);
4687                                 
4688                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
4689                                         GET_BBLOCK (cfg, tblock, ip + clause->data.filter_offset);
4690                                         tblock->real_offset = clause->data.filter_offset;
4691                                         tblock->in_scount = 1;
4692                                         tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
4693                                         tblock->stack_state = mono_mempool_alloc (cfg->mempool, sizeof (MonoStackSlot));
4694                                         tblock->stack_state [0].type = STACK_OBJ;
4695                                         /* FIXME? */
4696                                         tblock->stack_state [0].klass = mono_defaults.object_class;
4697
4698                                         /* The filter block shares the exvar with the handler block */
4699                                         tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
4700                                         MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
4701                                         MONO_ADD_INS (tblock, ins);
4702                                 }
4703                         }
4704                 }
4705         } else {
4706                 arg_array = alloca (sizeof (MonoInst *) * num_args);
4707                 mono_save_args (cfg, start_bblock, sig, inline_args, arg_array);
4708         }
4709
4710         /* FIRST CODE BLOCK */
4711         NEW_BBLOCK (cfg, bblock);
4712         bblock->cil_code = ip;
4713
4714         ADD_BBLOCK (cfg, bblock);
4715
4716         if (cfg->method == method) {
4717                 breakpoint_id = mono_debugger_method_has_breakpoint (method);
4718                 if (breakpoint_id && (mono_debug_format != MONO_DEBUG_FORMAT_DEBUGGER)) {
4719                         MONO_INST_NEW (cfg, ins, OP_BREAK);
4720                         MONO_ADD_INS (bblock, ins);
4721                 }
4722         }
4723
4724         if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS)
4725                 secman = mono_security_manager_get_methods ();
4726
4727         security = (secman && mono_method_has_declsec (method));
4728         /* at this point having security doesn't mean we have any code to generate */
4729         if (security && (cfg->method == method)) {
4730                 /* Only Demand, NonCasDemand and DemandChoice requires code generation.
4731                  * And we do not want to enter the next section (with allocation) if we
4732                  * have nothing to generate */
4733                 security = mono_declsec_get_demands (method, &actions);
4734         }
4735
4736         /* we must Demand SecurityPermission.Unmanaged before P/Invoking */
4737         pinvoke = (secman && (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE));
4738         if (pinvoke) {
4739                 MonoMethod *wrapped = mono_marshal_method_from_wrapper (method);
4740                 if (wrapped && (wrapped->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
4741                         MonoCustomAttrInfo* custom = mono_custom_attrs_from_method (wrapped);
4742
4743                         /* unless the method or it's class has the [SuppressUnmanagedCodeSecurity] attribute */
4744                         if (custom && mono_custom_attrs_has_attr (custom, secman->suppressunmanagedcodesecurity)) {
4745                                 pinvoke = FALSE;
4746                         }
4747                         if (custom)
4748                                 mono_custom_attrs_free (custom);
4749
4750                         if (pinvoke) {
4751                                 custom = mono_custom_attrs_from_class (wrapped->klass);
4752                                 if (custom && mono_custom_attrs_has_attr (custom, secman->suppressunmanagedcodesecurity)) {
4753                                         pinvoke = FALSE;
4754                                 }
4755                                 if (custom)
4756                                         mono_custom_attrs_free (custom);
4757                         }
4758                 } else {
4759                         /* not a P/Invoke after all */
4760                         pinvoke = FALSE;
4761                 }
4762         }
4763         
4764         if ((header->init_locals || (cfg->method == method && (cfg->opt & MONO_OPT_SHARED))) || cfg->compile_aot || security || pinvoke) {
4765                 /* we use a separate basic block for the initialization code */
4766                 NEW_BBLOCK (cfg, init_localsbb);
4767                 cfg->bb_init = init_localsbb;
4768                 init_localsbb->real_offset = real_offset;
4769                 start_bblock->next_bb = init_localsbb;
4770                 init_localsbb->next_bb = bblock;
4771                 link_bblock (cfg, start_bblock, init_localsbb);
4772                 link_bblock (cfg, init_localsbb, bblock);
4773                 init_localsbb->block_num = cfg->num_bblocks++;
4774         } else {
4775                 start_bblock->next_bb = bblock;
4776                 link_bblock (cfg, start_bblock, bblock);
4777         }
4778
4779         /* at this point we know, if security is TRUE, that some code needs to be generated */
4780         if (security && (cfg->method == method)) {
4781                 MonoInst *args [2];
4782
4783                 mono_jit_stats.cas_demand_generation++;
4784
4785                 if (actions.demand.blob) {
4786                         /* Add code for SecurityAction.Demand */
4787                         NEW_DECLSECCONST (cfg, args[0], image, actions.demand);
4788                         NEW_ICONST (cfg, args [1], actions.demand.size);
4789                         /* Calls static void SecurityManager.InternalDemand (byte* permissions, int size); */
4790                         mono_emit_method_call_spilled (cfg, init_localsbb, secman->demand, mono_method_signature (secman->demand), args, ip, NULL);
4791                 }
4792                 if (actions.noncasdemand.blob) {
4793                         /* CLR 1.x uses a .noncasdemand (but 2.x doesn't) */
4794                         /* For Mono we re-route non-CAS Demand to Demand (as the managed code must deal with it anyway) */
4795                         NEW_DECLSECCONST (cfg, args[0], image, actions.noncasdemand);
4796                         NEW_ICONST (cfg, args [1], actions.noncasdemand.size);
4797                         /* Calls static void SecurityManager.InternalDemand (byte* permissions, int size); */
4798                         mono_emit_method_call_spilled (cfg, init_localsbb, secman->demand, mono_method_signature (secman->demand), args, ip, NULL);
4799                 }
4800                 if (actions.demandchoice.blob) {
4801                         /* New in 2.0, Demand must succeed for one of the permissions (i.e. not all) */
4802                         NEW_DECLSECCONST (cfg, args[0], image, actions.demandchoice);
4803                         NEW_ICONST (cfg, args [1], actions.demandchoice.size);
4804                         /* Calls static void SecurityManager.InternalDemandChoice (byte* permissions, int size); */
4805                         mono_emit_method_call_spilled (cfg, init_localsbb, secman->demandchoice, mono_method_signature (secman->demandchoice), args, ip, NULL);
4806                 }
4807         }
4808
4809         /* we must Demand SecurityPermission.Unmanaged before p/invoking */
4810         if (pinvoke) {
4811                 mono_emit_method_call_spilled (cfg, init_localsbb, secman->demandunmanaged, mono_method_signature (secman->demandunmanaged), NULL, ip, NULL);
4812         }
4813
4814         if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR) {
4815                 if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
4816                         MonoMethod *wrapped = mono_marshal_method_from_wrapper (method);
4817                         if (wrapped && (wrapped->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
4818                                 if (!(method->klass && method->klass->image &&
4819                                                 mono_security_core_clr_is_platform_image (method->klass->image))) {
4820                                         emit_throw_method_access_exception (cfg, method, wrapped, bblock, ip);
4821                                 }
4822                         }
4823                 }
4824                 if (!method_is_safe (method))
4825                         emit_throw_verification_exception (cfg, bblock, ip);
4826         }
4827
4828         if (get_basic_blocks (cfg, header, real_offset, ip, end, &err_pos)) {
4829                 ip = err_pos;
4830                 UNVERIFIED;
4831         }
4832
4833         if (cfg->method == method)
4834                 mono_debug_init_method (cfg, bblock, breakpoint_id);
4835
4836         param_types = mono_mempool_alloc (cfg->mempool, sizeof (MonoType*) * num_args);
4837         if (sig->hasthis)
4838                 param_types [0] = method->klass->valuetype?&method->klass->this_arg:&method->klass->byval_arg;
4839         for (n = 0; n < sig->param_count; ++n)
4840                 param_types [n + sig->hasthis] = sig->params [n];
4841         for (n = 0; n < header->num_locals; ++n) {
4842                 if (header->locals [n]->type == MONO_TYPE_VOID && !header->locals [n]->byref)
4843                         UNVERIFIED;
4844         }
4845         class_inits = NULL;
4846
4847         /* do this somewhere outside - not here */
4848         NEW_ICONST (cfg, zero_int32, 0);
4849         NEW_ICONST (cfg, zero_int64, 0);
4850         zero_int64->type = STACK_I8;
4851         NEW_PCONST (cfg, zero_ptr, 0);
4852         NEW_PCONST (cfg, zero_obj, 0);
4853         zero_obj->type = STACK_OBJ;
4854
4855         MONO_INST_NEW (cfg, zero_r8, OP_R8CONST);
4856         zero_r8->type = STACK_R8;
4857         zero_r8->inst_p0 = &r8_0;
4858
4859         /* add a check for this != NULL to inlined methods */
4860         if (is_virtual_call) {
4861                 MONO_INST_NEW (cfg, ins, OP_CHECK_THIS);
4862                 NEW_ARGLOAD (cfg, ins->inst_left, 0);
4863                 ins->cil_code = ip;
4864                 MONO_ADD_INS (bblock, ins);
4865         }
4866
4867         /* we use a spare stack slot in SWITCH and NEWOBJ and others */
4868         stack_start = sp = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (header->max_stack + 1));
4869
4870         ins_flag = 0;
4871         start_new_bblock = 0;
4872         while (ip < end) {
4873
4874                 if (cfg->method == method)
4875                         real_offset = ip - header->code;
4876                 else
4877                         real_offset = inline_offset;
4878
4879                 if (start_new_bblock) {
4880                         bblock->cil_length = ip - bblock->cil_code;
4881                         if (start_new_bblock == 2) {
4882                                 g_assert (ip == tblock->cil_code);
4883                         } else {
4884                                 GET_BBLOCK (cfg, tblock, ip);
4885                         }
4886                         bblock->next_bb = tblock;
4887                         bblock = tblock;
4888                         start_new_bblock = 0;
4889                         for (i = 0; i < bblock->in_scount; ++i) {
4890                                 if (cfg->verbose_level > 3)
4891                                         g_print ("loading %d from temp %d\n", i, (int)bblock->in_stack [i]->inst_c0);                                           
4892                                 NEW_TEMPLOAD (cfg, ins, bblock->in_stack [i]->inst_c0);
4893                                 *sp++ = ins;
4894                         }
4895                         g_slist_free (class_inits);
4896                         class_inits = NULL;
4897                 } else {
4898                         if ((tblock = cfg->cil_offset_to_bb [ip - cfg->cil_start]) && (tblock != bblock)) {
4899                                 link_bblock (cfg, bblock, tblock);
4900                                 if (sp != stack_start) {
4901                                         handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
4902                                         sp = stack_start;
4903                                         CHECK_UNVERIFIABLE (cfg);
4904                                 }
4905                                 bblock->next_bb = tblock;
4906                                 bblock = tblock;
4907                                 for (i = 0; i < bblock->in_scount; ++i) {
4908                                         if (cfg->verbose_level > 3)
4909                                                 g_print ("loading %d from temp %d\n", i, (int)bblock->in_stack [i]->inst_c0);                                           
4910                                         NEW_TEMPLOAD (cfg, ins, bblock->in_stack [i]->inst_c0);
4911                                         *sp++ = ins;
4912                                 }
4913                                 g_slist_free (class_inits);
4914                                 class_inits = NULL;
4915                         }
4916                 }
4917
4918                 bblock->real_offset = real_offset;
4919
4920                 if ((cfg->method == method) && cfg->coverage_info) {
4921                         MonoInst *store, *one;
4922                         guint32 cil_offset = ip - header->code;
4923                         cfg->coverage_info->data [cil_offset].cil_code = ip;
4924
4925                         /* TODO: Use an increment here */
4926                         NEW_ICONST (cfg, one, 1);
4927                         one->cil_code = ip;
4928
4929                         NEW_PCONST (cfg, ins, &(cfg->coverage_info->data [cil_offset].count));
4930                         ins->cil_code = ip;
4931
4932                         MONO_INST_NEW (cfg, store, CEE_STIND_I);
4933                         store->cil_code = ip;
4934                         store->inst_left = ins;
4935                         store->inst_right = one;
4936
4937                         MONO_ADD_INS (bblock, store);
4938                 }
4939
4940                 if (cfg->verbose_level > 3)
4941                         g_print ("converting (in B%d: stack: %d) %s", bblock->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
4942
4943                 switch (*ip) {
4944                 case CEE_NOP:
4945                         MONO_INST_NEW (cfg, ins, OP_NOP);
4946                         ins->cil_code = ip++;
4947                         MONO_ADD_INS (bblock, ins);
4948                         break;
4949                 case CEE_BREAK:
4950                         MONO_INST_NEW (cfg, ins, OP_BREAK);
4951                         ins->cil_code = ip++;
4952                         MONO_ADD_INS (bblock, ins);
4953                         break;
4954                 case CEE_LDARG_0:
4955                 case CEE_LDARG_1:
4956                 case CEE_LDARG_2:
4957                 case CEE_LDARG_3:
4958                         CHECK_STACK_OVF (1);
4959                         n = (*ip)-CEE_LDARG_0;
4960                         CHECK_ARG (n);
4961                         NEW_ARGLOAD (cfg, ins, n);
4962                         LDARG_SOFT_FLOAT (cfg, ins, n, ip);
4963                         ins->cil_code = ip++;
4964                         *sp++ = ins;
4965                         break;
4966                 case CEE_LDLOC_0:
4967                 case CEE_LDLOC_1:
4968                 case CEE_LDLOC_2:
4969                 case CEE_LDLOC_3:
4970                         CHECK_STACK_OVF (1);
4971                         n = (*ip)-CEE_LDLOC_0;
4972                         CHECK_LOCAL (n);
4973                         NEW_LOCLOAD (cfg, ins, n);
4974                         LDLOC_SOFT_FLOAT (cfg, ins, n, ip);
4975                         ins->cil_code = ip++;
4976                         *sp++ = ins;
4977                         break;
4978                 case CEE_STLOC_0:
4979                 case CEE_STLOC_1:
4980                 case CEE_STLOC_2:
4981                 case CEE_STLOC_3:
4982                         CHECK_STACK (1);
4983                         n = (*ip)-CEE_STLOC_0;
4984                         CHECK_LOCAL (n);
4985                         --sp;
4986                         handle_loaded_temps (cfg, bblock, stack_start, sp);
4987                         NEW_LOCSTORE (cfg, ins, n, *sp);
4988                         ins->cil_code = ip;
4989                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
4990                                 UNVERIFIED;
4991                         STLOC_SOFT_FLOAT (cfg, ins, n, ip);
4992                         if (ins->opcode == CEE_STOBJ) {
4993                                 NEW_LOCLOADA (cfg, ins, n);
4994                                 handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE, FALSE);
4995                         } else
4996                                 MONO_ADD_INS (bblock, ins);
4997                         ++ip;
4998                         inline_costs += 1;
4999                         break;
5000                 case CEE_LDARG_S:
5001                         CHECK_OPSIZE (2);
5002                         CHECK_STACK_OVF (1);
5003                         CHECK_ARG (ip [1]);
5004                         NEW_ARGLOAD (cfg, ins, ip [1]);
5005                         LDARG_SOFT_FLOAT (cfg, ins, ip [1], ip);
5006                         ins->cil_code = ip;
5007                         *sp++ = ins;
5008                         ip += 2;
5009                         break;
5010                 case CEE_LDARGA_S:
5011                         CHECK_OPSIZE (2);
5012                         CHECK_STACK_OVF (1);
5013                         CHECK_ARG (ip [1]);
5014                         NEW_ARGLOADA (cfg, ins, ip [1]);
5015                         ins->cil_code = ip;
5016                         *sp++ = ins;
5017                         ip += 2;
5018                         break;
5019                 case CEE_STARG_S:
5020                         CHECK_OPSIZE (2);
5021                         CHECK_STACK (1);
5022                         --sp;
5023                         CHECK_ARG (ip [1]);
5024                         NEW_ARGSTORE (cfg, ins, ip [1], *sp);
5025                         handle_loaded_temps (cfg, bblock, stack_start, sp);
5026                         ins->cil_code = ip;
5027                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [ip [1]], *sp))
5028                                 UNVERIFIED;
5029                         STARG_SOFT_FLOAT (cfg, ins, ip [1], ip);
5030                         if (ins->opcode == CEE_STOBJ) {
5031                                 NEW_ARGLOADA (cfg, ins, ip [1]);
5032                                 handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE, FALSE);
5033                         } else
5034                                 MONO_ADD_INS (bblock, ins);
5035                         ip += 2;
5036                         break;
5037                 case CEE_LDLOC_S:
5038                         CHECK_OPSIZE (2);
5039                         CHECK_STACK_OVF (1);
5040                         CHECK_LOCAL (ip [1]);
5041                         NEW_LOCLOAD (cfg, ins, ip [1]);
5042                         LDLOC_SOFT_FLOAT (cfg, ins, ip [1], ip);
5043                         ins->cil_code = ip;
5044                         *sp++ = ins;
5045                         ip += 2;
5046                         break;
5047                 case CEE_LDLOCA_S:
5048                         CHECK_OPSIZE (2);
5049                         CHECK_STACK_OVF (1);
5050                         CHECK_LOCAL (ip [1]);
5051                         NEW_LOCLOADA (cfg, ins, ip [1]);
5052                         ins->cil_code = ip;
5053                         *sp++ = ins;
5054                         ip += 2;
5055                         break;
5056                 case CEE_STLOC_S:
5057                         CHECK_OPSIZE (2);
5058                         CHECK_STACK (1);
5059                         --sp;
5060                         handle_loaded_temps (cfg, bblock, stack_start, sp);
5061                         CHECK_LOCAL (ip [1]);
5062                         NEW_LOCSTORE (cfg, ins, ip [1], *sp);
5063                         ins->cil_code = ip;
5064                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [ip [1]], *sp))
5065                                 UNVERIFIED;
5066                         STLOC_SOFT_FLOAT (cfg, ins, ip [1], ip);
5067                         if (ins->opcode == CEE_STOBJ) {
5068                                 NEW_LOCLOADA (cfg, ins, ip [1]);
5069                                 handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE, FALSE);
5070                         } else
5071                                 MONO_ADD_INS (bblock, ins);
5072                         ip += 2;
5073                         inline_costs += 1;
5074                         break;
5075                 case CEE_LDNULL:
5076                         CHECK_STACK_OVF (1);
5077                         NEW_PCONST (cfg, ins, NULL);
5078                         ins->cil_code = ip;
5079                         ins->type = STACK_OBJ;
5080                         ++ip;
5081                         *sp++ = ins;
5082                         break;
5083                 case CEE_LDC_I4_M1:
5084                         CHECK_STACK_OVF (1);
5085                         NEW_ICONST (cfg, ins, -1);
5086                         ins->cil_code = ip;
5087                         ++ip;
5088                         *sp++ = ins;
5089                         break;
5090                 case CEE_LDC_I4_0:
5091                 case CEE_LDC_I4_1:
5092                 case CEE_LDC_I4_2:
5093                 case CEE_LDC_I4_3:
5094                 case CEE_LDC_I4_4:
5095                 case CEE_LDC_I4_5:
5096                 case CEE_LDC_I4_6:
5097                 case CEE_LDC_I4_7:
5098                 case CEE_LDC_I4_8:
5099                         CHECK_STACK_OVF (1);
5100                         NEW_ICONST (cfg, ins, (*ip) - CEE_LDC_I4_0);
5101                         ins->cil_code = ip;
5102                         ++ip;
5103                         *sp++ = ins;
5104                         break;
5105                 case CEE_LDC_I4_S:
5106                         CHECK_OPSIZE (2);
5107                         CHECK_STACK_OVF (1);
5108                         ++ip;
5109                         NEW_ICONST (cfg, ins, *((signed char*)ip));
5110                         ins->cil_code = ip;
5111                         ++ip;
5112                         *sp++ = ins;
5113                         break;
5114                 case CEE_LDC_I4:
5115                         CHECK_OPSIZE (5);
5116                         CHECK_STACK_OVF (1);
5117                         NEW_ICONST (cfg, ins, (gint32)read32 (ip + 1));
5118                         ins->cil_code = ip;
5119                         ip += 5;
5120                         *sp++ = ins;
5121                         break;
5122                 case CEE_LDC_I8:
5123                         CHECK_OPSIZE (9);
5124                         CHECK_STACK_OVF (1);
5125                         MONO_INST_NEW (cfg, ins, OP_I8CONST);
5126                         ins->cil_code = ip;
5127                         ins->type = STACK_I8;
5128                         ++ip;
5129                         ins->inst_l = (gint64)read64 (ip);
5130                         ip += 8;
5131                         *sp++ = ins;
5132                         break;
5133                 case CEE_LDC_R4: {
5134                         float *f;
5135                         /* we should really allocate this only late in the compilation process */
5136                         mono_domain_lock (cfg->domain);
5137                         f = mono_mempool_alloc (cfg->domain->mp, sizeof (float));
5138                         mono_domain_unlock (cfg->domain);
5139                         CHECK_OPSIZE (5);
5140                         CHECK_STACK_OVF (1);
5141                         MONO_INST_NEW (cfg, ins, OP_R4CONST);
5142                         ins->type = STACK_R8;
5143                         ++ip;
5144                         readr4 (ip, f);
5145                         ins->inst_p0 = f;
5146
5147                         ip += 4;
5148                         *sp++ = ins;                    
5149                         break;
5150                 }
5151                 case CEE_LDC_R8: {
5152                         double *d;
5153                         mono_domain_lock (cfg->domain);
5154                         d = mono_mempool_alloc (cfg->domain->mp, sizeof (double));
5155                         mono_domain_unlock (cfg->domain);
5156                         CHECK_OPSIZE (9);
5157                         CHECK_STACK_OVF (1);
5158                         MONO_INST_NEW (cfg, ins, OP_R8CONST);
5159                         ins->type = STACK_R8;
5160                         ++ip;
5161                         readr8 (ip, d);
5162                         ins->inst_p0 = d;
5163
5164                         ip += 8;
5165                         *sp++ = ins;                    
5166                         break;
5167                 }
5168                 case CEE_DUP: {
5169                         MonoInst *temp, *store;
5170                         CHECK_STACK (1);
5171                         CHECK_STACK_OVF (1);
5172                         sp--;
5173                         ins = *sp;
5174                 
5175                         /* 
5176                          * small optimization: if the loaded value was from a local already,
5177                          * just load it twice.
5178                          */
5179                         if (ins->ssa_op == MONO_SSA_LOAD && 
5180                             (ins->inst_i0->opcode == OP_LOCAL || ins->inst_i0->opcode == OP_ARG)) {
5181                                 sp++;
5182                                 MONO_INST_NEW (cfg, temp, 0);
5183                                 *temp = *ins;
5184                                 temp->cil_code = ip;
5185                                 *sp++ = temp;
5186                         } else {
5187                                 temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
5188                                 temp->flags |= MONO_INST_IS_TEMP;
5189                                 temp->cil_code = ip;
5190                                 NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
5191                                 store->cil_code = ip;
5192                                 /* FIXME: handle CEE_STIND_R4 */
5193                                 if (store->opcode == CEE_STOBJ) {
5194                                         NEW_TEMPLOADA (cfg, store, temp->inst_c0);
5195                                         handle_stobj (cfg, bblock, store, sp [0], sp [0]->cil_code, store->klass, TRUE, FALSE, FALSE);
5196                                 } else {
5197                                         MONO_ADD_INS (bblock, store);
5198                                 }
5199                                 NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
5200                                 *sp++ = ins;
5201                                 ins->cil_code = ip;
5202                                 NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
5203                                 *sp++ = ins;
5204                                 ins->cil_code = ip;
5205                         }
5206                         ++ip;
5207                         inline_costs += 2;
5208                         break;
5209                 }
5210                 case CEE_POP:
5211                         CHECK_STACK (1);
5212                         MONO_INST_NEW (cfg, ins, CEE_POP);
5213                         MONO_ADD_INS (bblock, ins);
5214                         ins->cil_code = ip++;
5215                         --sp;
5216                         ins->inst_i0 = *sp;
5217                         break;
5218                 case CEE_JMP:
5219                         CHECK_OPSIZE (5);
5220                         if (stack_start != sp)
5221                                 UNVERIFIED;
5222                         MONO_INST_NEW (cfg, ins, OP_JMP);
5223                         token = read32 (ip + 1);
5224                         /* FIXME: check the signature matches */
5225                         cmethod = mini_get_method (method, token, NULL, generic_context);
5226
5227                         if (!cmethod)
5228                                 goto load_error;
5229
5230                         if (cfg->generic_sharing_context && mono_method_check_context_used (cmethod))
5231                                 GENERIC_SHARING_FAILURE (CEE_JMP);
5232
5233                         if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS) {
5234                                 if (check_linkdemand (cfg, method, cmethod, bblock, ip))
5235                                         INLINE_FAILURE;
5236                                 CHECK_CFG_EXCEPTION;
5237                         }
5238
5239                         ins->inst_p0 = cmethod;
5240                         MONO_ADD_INS (bblock, ins);
5241                         ip += 5;
5242                         start_new_bblock = 1;
5243                         break;
5244                 case CEE_CALLI:
5245                 case CEE_CALL:
5246                 case CEE_CALLVIRT: {
5247                         MonoInst *addr = NULL;
5248                         MonoMethodSignature *fsig = NULL;
5249                         int temp, array_rank = 0;
5250                         int virtual = *ip == CEE_CALLVIRT;
5251                         gboolean no_spill;
5252
5253                         CHECK_OPSIZE (5);
5254                         token = read32 (ip + 1);
5255
5256                         if (*ip == CEE_CALLI) {
5257                                 cmethod = NULL;
5258                                 CHECK_STACK (1);
5259                                 --sp;
5260                                 addr = *sp;
5261                                 if (method->wrapper_type != MONO_WRAPPER_NONE)
5262                                         fsig = (MonoMethodSignature *)mono_method_get_wrapper_data (method, token);
5263                                 else
5264                                         fsig = mono_metadata_parse_signature (image, token);
5265
5266                                 n = fsig->param_count + fsig->hasthis;
5267                         } else {
5268                                 MonoMethod *cil_method;
5269                                 
5270                                 if (method->wrapper_type != MONO_WRAPPER_NONE) {
5271                                         cmethod =  (MonoMethod *)mono_method_get_wrapper_data (method, token);
5272                                         cil_method = cmethod;
5273                                 } else if (constrained_call) {
5274                                         cmethod = mono_get_method_constrained (image, token, constrained_call, generic_context, &cil_method);
5275                                         cil_method = cmethod;
5276                                 } else {
5277                                         cmethod = mini_get_method (method, token, NULL, generic_context);
5278                                         cil_method = cmethod;
5279                                 }
5280
5281                                 if (!cmethod)
5282                                         goto load_error;
5283                                 if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_method (method, cil_method))
5284                                         METHOD_ACCESS_FAILURE;
5285
5286                                 if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR)
5287                                         ensure_method_is_allowed_to_call_method (cfg, method, cil_method, bblock, ip);
5288
5289                                 if (!virtual && (cmethod->flags & METHOD_ATTRIBUTE_ABSTRACT))
5290                                         /* MS.NET seems to silently convert this to a callvirt */
5291                                         virtual = 1;
5292
5293                                 if (!cmethod->klass->inited){
5294                                         if (!mono_class_init (cmethod->klass))
5295                                                 goto load_error;
5296                                 }
5297
5298                                 if (mono_method_signature (cmethod)->pinvoke) {
5299                                         MonoMethod *wrapper = mono_marshal_get_native_wrapper (cmethod, check_for_pending_exc);
5300                                         fsig = mono_method_signature (wrapper);
5301                                 } else if (constrained_call) {
5302                                         fsig = mono_method_signature (cmethod);
5303                                 } else {
5304                                         fsig = mono_method_get_signature_full (cmethod, image, token, generic_context);
5305                                 }
5306
5307                                 mono_save_token_info (cfg, image, token, cmethod);
5308
5309                                 n = fsig->param_count + fsig->hasthis;
5310
5311                                 if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS) {
5312                                         if (check_linkdemand (cfg, method, cmethod, bblock, ip))
5313                                                 INLINE_FAILURE;
5314                                         CHECK_CFG_EXCEPTION;
5315                                 }
5316
5317                                 if (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL &&
5318                                     mini_class_is_system_array (cmethod->klass)) {
5319                                         array_rank = cmethod->klass->rank;
5320                                 }
5321
5322                                 if (cmethod->string_ctor)
5323                                         g_assert_not_reached ();
5324
5325                         }
5326
5327                         if (!cfg->generic_sharing_context && cmethod && cmethod->klass->generic_container)
5328                                 UNVERIFIED;
5329
5330                         if (cfg->generic_sharing_context && cmethod && mono_method_check_context_used (cmethod))
5331                                 GENERIC_SHARING_FAILURE (*ip);
5332
5333                         CHECK_STACK (n);
5334
5335                         //g_assert (!virtual || fsig->hasthis);
5336
5337                         sp -= n;
5338
5339                         if (constrained_call) {
5340                                 /*
5341                                  * We have the `constrained.' prefix opcode.
5342                                  */
5343                                 if (constrained_call->valuetype && !cmethod->klass->valuetype) {
5344                                         MonoInst *load;
5345                                         /*
5346                                          * The type parameter is instantiated as a valuetype,
5347                                          * but that type doesn't override the method we're
5348                                          * calling, so we need to box `this'.
5349                                          * sp [0] is a pointer to the data: we need the value
5350                                          * in handle_box (), so load it here.
5351                                          */
5352                                         MONO_INST_NEW (cfg, load, mini_type_to_ldind (cfg, &constrained_call->byval_arg));
5353                                         type_to_eval_stack_type (cfg, &constrained_call->byval_arg, load);
5354                                         load->cil_code = ip;
5355                                         load->inst_left = sp [0];
5356                                         sp [0] = handle_box (cfg, bblock, load, ip, constrained_call);
5357                                 } else if (!constrained_call->valuetype) {
5358                                         MonoInst *ins;
5359
5360                                         /*
5361                                          * The type parameter is instantiated as a reference
5362                                          * type.  We have a managed pointer on the stack, so
5363                                          * we need to dereference it here.
5364                                          */
5365
5366                                         MONO_INST_NEW (cfg, ins, CEE_LDIND_REF);
5367                                         ins->cil_code = ip;
5368                                         ins->inst_i0 = sp [0];
5369                                         ins->type = STACK_OBJ;
5370                                         ins->klass = mono_class_from_mono_type (&constrained_call->byval_arg);
5371                                         sp [0] = ins;
5372                                 } else if (cmethod->klass->valuetype)
5373                                         virtual = 0;
5374                                 constrained_call = NULL;
5375                         }
5376
5377                         if (*ip != CEE_CALLI && check_call_signature (cfg, fsig, sp))
5378                                 UNVERIFIED;
5379
5380                         if (cmethod && virtual && 
5381                             (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) && 
5382                             !((cmethod->flags & METHOD_ATTRIBUTE_FINAL) && 
5383                               cmethod->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK) &&
5384                             mono_method_signature (cmethod)->generic_param_count) {
5385                                 MonoInst *this_temp, *this_arg_temp, *store;
5386                                 MonoInst *iargs [4];
5387
5388                                 g_assert (mono_method_signature (cmethod)->is_inflated);
5389                                 /* Prevent inlining of methods that contain indirect calls */
5390                                 INLINE_FAILURE;
5391
5392                                 this_temp = mono_compile_create_var (cfg, type_from_stack_type (sp [0]), OP_LOCAL);
5393                                 this_temp->cil_code = ip;
5394                                 NEW_TEMPSTORE (cfg, store, this_temp->inst_c0, sp [0]);
5395
5396                                 store->cil_code = ip;
5397                                 MONO_ADD_INS (bblock, store);
5398
5399                                 /* FIXME: This should be a managed pointer */
5400                                 this_arg_temp = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
5401                                 this_arg_temp->cil_code = ip;
5402
5403                                 /* Because of the PCONST below */
5404                                 cfg->disable_aot = TRUE;
5405                                 NEW_TEMPLOAD (cfg, iargs [0], this_temp->inst_c0);
5406                                 NEW_METHODCONST (cfg, iargs [1], cmethod);
5407                                 NEW_PCONST (cfg, iargs [2], mono_method_get_context (cmethod));
5408                                 NEW_TEMPLOADA (cfg, iargs [3], this_arg_temp->inst_c0);
5409                                 temp = mono_emit_jit_icall (cfg, bblock, mono_helper_compile_generic_method, iargs, ip);
5410
5411                                 NEW_TEMPLOAD (cfg, addr, temp);
5412                                 NEW_TEMPLOAD (cfg, sp [0], this_arg_temp->inst_c0);
5413
5414                                 if ((temp = mono_emit_calli_spilled (cfg, bblock, fsig, sp, addr, ip)) != -1) {
5415                                         NEW_TEMPLOAD (cfg, *sp, temp);
5416                                         sp++;
5417                                 }
5418
5419                                 ip += 5;
5420                                 ins_flag = 0;
5421                                 break;
5422                         }
5423
5424                         if ((ins_flag & MONO_INST_TAILCALL) && cmethod && (*ip == CEE_CALL) &&
5425                                  (mono_metadata_signature_equal (mono_method_signature (method), mono_method_signature (cmethod)))) {
5426                                 int i;
5427
5428                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
5429                                 INLINE_FAILURE;
5430                                 /* FIXME: This assumes the two methods has the same number and type of arguments */
5431                                 /*
5432                                  * We implement tail calls by storing the actual arguments into the 
5433                                  * argument variables, then emitting a OP_JMP. Since the actual arguments
5434                                  * can refer to the arg variables, we have to spill them.
5435                                  */
5436                                 handle_loaded_temps (cfg, bblock, sp, sp + n);
5437                                 for (i = 0; i < n; ++i) {
5438                                         /* Prevent argument from being register allocated */
5439                                         arg_array [i]->flags |= MONO_INST_VOLATILE;
5440
5441                                         /* Check if argument is the same */
5442                                         /* 
5443                                          * FIXME: This loses liveness info, so it can only be done if the
5444                                          * argument is not register allocated.
5445                                          */
5446                                         NEW_ARGLOAD (cfg, ins, i);
5447                                         if ((ins->opcode == sp [i]->opcode) && (ins->inst_i0 == sp [i]->inst_i0))
5448                                                 continue;
5449
5450                                         NEW_ARGSTORE (cfg, ins, i, sp [i]);
5451                                         ins->cil_code = ip;
5452                                         /* FIXME: handle CEE_STIND_R4 */
5453                                         if (ins->opcode == CEE_STOBJ) {
5454                                                 NEW_ARGLOADA (cfg, ins, i);
5455                                                 handle_stobj (cfg, bblock, ins, sp [i], sp [i]->cil_code, ins->klass, FALSE, FALSE, FALSE);
5456                                         }
5457                                         else
5458                                                 MONO_ADD_INS (bblock, ins);
5459                                 }
5460                                 MONO_INST_NEW (cfg, ins, OP_JMP);
5461                                 ins->cil_code = ip;
5462                                 ins->inst_p0 = cmethod;
5463                                 ins->inst_p1 = arg_array [0];
5464                                 MONO_ADD_INS (bblock, ins);
5465                                 link_bblock (cfg, bblock, end_bblock);                  
5466                                 start_new_bblock = 1;
5467                                 /* skip CEE_RET as well */
5468                                 ip += 6;
5469                                 ins_flag = 0;
5470                                 break;
5471                         }
5472                         if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_get_inst_for_method (cfg, cmethod, fsig, sp))) {
5473                                 ins->cil_code = ip;
5474
5475                                 if (MONO_TYPE_IS_VOID (fsig->ret)) {
5476                                         MONO_ADD_INS (bblock, ins);
5477                                 } else {
5478                                         type_to_eval_stack_type (cfg, fsig->ret, ins);
5479                                         *sp = ins;
5480                                         sp++;
5481                                 }
5482
5483                                 ip += 5;
5484                                 ins_flag = 0;
5485                                 break;
5486                         }
5487
5488                         handle_loaded_temps (cfg, bblock, stack_start, sp);
5489
5490                         if ((cfg->opt & MONO_OPT_INLINE) && cmethod &&
5491                             (!virtual || !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) || (cmethod->flags & METHOD_ATTRIBUTE_FINAL)) && 
5492                             mono_method_check_inlining (cfg, cmethod) &&
5493                                  !g_list_find (dont_inline, cmethod)) {
5494                                 int costs;
5495                                 MonoBasicBlock *ebblock;
5496                                 gboolean allways = FALSE;
5497
5498                                 if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
5499                                         (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
5500                                         /* Prevent inlining of methods that call wrappers */
5501                                         INLINE_FAILURE;
5502                                         cmethod = mono_marshal_get_native_wrapper (cmethod, check_for_pending_exc);
5503                                         allways = TRUE;
5504                                 }
5505
5506                                 if ((costs = inline_method (cfg, cmethod, fsig, bblock, sp, ip, real_offset, dont_inline, &ebblock, allways))) {
5507                                         ip += 5;
5508                                         real_offset += 5;
5509
5510                                         GET_BBLOCK (cfg, bblock, ip);
5511                                         ebblock->next_bb = bblock;
5512                                         link_bblock (cfg, ebblock, bblock);
5513
5514                                         if (!MONO_TYPE_IS_VOID (fsig->ret))
5515                                                 sp++;
5516
5517                                         /* indicates start of a new block, and triggers a load of all 
5518                                            stack arguments at bb boundarie */
5519                                         bblock = ebblock;
5520
5521                                         inline_costs += costs;
5522                                         ins_flag = 0;
5523                                         break;
5524                                 }
5525                         }
5526                         
5527                         inline_costs += 10 * num_calls++;
5528
5529                         /* tail recursion elimination */
5530                         if ((cfg->opt & MONO_OPT_TAILC) && *ip == CEE_CALL && cmethod == method && ip [5] == CEE_RET) {
5531                                 gboolean has_vtargs = FALSE;
5532                                 int i;
5533                                 
5534                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
5535                                 INLINE_FAILURE;
5536                                 /* keep it simple */
5537                                 for (i =  fsig->param_count - 1; i >= 0; i--) {
5538                                         if (MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->params [i])) 
5539                                                 has_vtargs = TRUE;
5540                                 }
5541
5542                                 if (!has_vtargs) {
5543                                         for (i = 0; i < n; ++i) {
5544                                                 /* FIXME: handle CEE_STIND_R4 */
5545                                                 NEW_ARGSTORE (cfg, ins, i, sp [i]);
5546                                                 ins->cil_code = ip;
5547                                                 MONO_ADD_INS (bblock, ins);
5548                                         }
5549                                         MONO_INST_NEW (cfg, ins, OP_BR);
5550                                         ins->cil_code = ip;
5551                                         MONO_ADD_INS (bblock, ins);
5552                                         tblock = start_bblock->out_bb [0];
5553                                         link_bblock (cfg, bblock, tblock);
5554                                         ins->inst_target_bb = tblock;
5555                                         start_new_bblock = 1;
5556
5557                                         /* skip the CEE_RET, too */
5558                                         if (ip_in_bb (cfg, bblock, ip + 5))
5559                                                 ip += 6;
5560                                         else
5561                                                 ip += 5;
5562                                         ins_flag = 0;
5563                                         break;
5564                                 }
5565                         }
5566
5567                         if (ip_in_bb (cfg, bblock, ip + 5) 
5568                                 && (!MONO_TYPE_ISSTRUCT (fsig->ret))
5569                                 && (!MONO_TYPE_IS_VOID (fsig->ret) || (cmethod && cmethod->string_ctor))
5570                                 && (CODE_IS_STLOC (ip + 5) || ip [5] == CEE_POP || ip [5] == CEE_RET))
5571                                 /* No need to spill */
5572                                 no_spill = TRUE;
5573                         else
5574                                 no_spill = FALSE;
5575
5576                         if (*ip == CEE_CALLI) {
5577                                 /* Prevent inlining of methods with indirect calls */
5578                                 INLINE_FAILURE;
5579                                 if (no_spill) {
5580                                         ins = (MonoInst*)mono_emit_calli (cfg, bblock, fsig, sp, addr, ip);
5581                                         *sp++ = ins;                                    
5582                                 } else {
5583                                         if ((temp = mono_emit_calli_spilled (cfg, bblock, fsig, sp, addr, ip)) != -1) {
5584                                                 NEW_TEMPLOAD (cfg, *sp, temp);
5585                                                 sp++;
5586                                         }
5587                                 }                       
5588                         } else if (array_rank) {
5589                                 MonoInst *addr;
5590
5591                                 if (strcmp (cmethod->name, "Set") == 0) { /* array Set */ 
5592                                         if (sp [fsig->param_count]->type == STACK_OBJ) {
5593                                                 MonoInst *iargs [2];
5594                                                 MonoInst *array, *to_store, *store;
5595
5596                                                 handle_loaded_temps (cfg, bblock, stack_start, sp);
5597                                                 
5598                                                 array = mono_compile_create_var (cfg, type_from_stack_type (sp [0]), OP_LOCAL);
5599                                                 NEW_TEMPSTORE (cfg, store, array->inst_c0, sp [0]);
5600                                                 store->cil_code = ip;
5601                                                 MONO_ADD_INS (bblock, store);
5602                                                 NEW_TEMPLOAD (cfg, iargs [0], array->inst_c0);
5603
5604                                                 to_store = mono_compile_create_var (cfg, type_from_stack_type (sp [fsig->param_count]), OP_LOCAL);
5605                                                 NEW_TEMPSTORE (cfg, store, to_store->inst_c0, sp [fsig->param_count]);
5606                                                 /* FIXME: handle CEE_STIND_R4 */
5607                                                 store->cil_code = ip;
5608                                                 MONO_ADD_INS (bblock, store);
5609                                                 NEW_TEMPLOAD (cfg, iargs [1], to_store->inst_c0);
5610
5611                                                 /*
5612                                                  * We first save the args for the call so that the args are copied to the stack
5613                                                  * and a new instruction tree for them is created. If we don't do this,
5614                                                  * the same MonoInst is added to two different trees and this is not 
5615                                                  * allowed by burg.
5616                                                  */
5617                                                 mono_emit_jit_icall (cfg, bblock, mono_helper_stelem_ref_check, iargs, ip);
5618
5619                                                 NEW_TEMPLOAD (cfg, sp [0], array->inst_c0);
5620                                                 NEW_TEMPLOAD (cfg, sp [fsig->param_count], to_store->inst_c0);
5621                                         }
5622
5623                                         addr = mini_get_ldelema_ins (cfg, bblock, cmethod, sp, ip, TRUE);
5624                                         NEW_INDSTORE (cfg, ins, addr, sp [fsig->param_count], fsig->params [fsig->param_count - 1]);
5625                                         ins->cil_code = ip;
5626                                         /* FIXME: handle CEE_STIND_R4 */
5627                                         if (ins->opcode == CEE_STOBJ) {
5628                                                 handle_stobj (cfg, bblock, addr, sp [fsig->param_count], ip, mono_class_from_mono_type (fsig->params [fsig->param_count-1]), FALSE, FALSE, TRUE);
5629                                         } else {
5630                                                 MONO_ADD_INS (bblock, ins);
5631                                         }
5632
5633                                 } else if (strcmp (cmethod->name, "Get") == 0) { /* array Get */
5634                                         addr = mini_get_ldelema_ins (cfg, bblock, cmethod, sp, ip, FALSE);
5635                                         NEW_INDLOAD (cfg, ins, addr, fsig->ret);
5636                                         ins->cil_code = ip;
5637
5638                                         *sp++ = ins;
5639                                 } else if (strcmp (cmethod->name, "Address") == 0) { /* array Address */
5640                                         addr = mini_get_ldelema_ins (cfg, bblock, cmethod, sp, ip, FALSE);
5641                                         *sp++ = addr;
5642                                 } else {
5643                                         g_assert_not_reached ();
5644                                 }
5645
5646                         } else {
5647                                 /* Prevent inlining of methods which call other methods */
5648                                 INLINE_FAILURE;
5649                                 if (mini_redirect_call (&temp, cfg, bblock, cmethod, fsig, sp, ip, virtual ? sp [0] : NULL)) {
5650                                         if (temp != -1) {
5651                                                 NEW_TEMPLOAD (cfg, *sp, temp);
5652                                                 sp++;
5653                                         }
5654                                 } else if (no_spill) {
5655                                         ins = (MonoInst*)mono_emit_method_call (cfg, bblock, cmethod, fsig, sp, ip, virtual ? sp [0] : NULL);
5656                                         *sp++ = ins;
5657                                 } else {
5658                                         if ((temp = mono_emit_method_call_spilled (cfg, bblock, cmethod, fsig, sp, ip, virtual ? sp [0] : NULL)) != -1) {
5659                                                 MonoInst *load;
5660                                                 NEW_TEMPLOAD (cfg, load, temp);
5661
5662 #ifdef MONO_ARCH_SOFT_FLOAT
5663                                                 if (load->opcode == CEE_LDIND_R4) {
5664                                                         NEW_TEMPLOADA (cfg, load, temp);
5665                                                         temp = handle_load_float (cfg, bblock, load, ip);
5666                                                         NEW_TEMPLOAD (cfg, load, temp);
5667                                                 }
5668 #endif
5669                                                 *sp++ = load;
5670                                         }
5671                                 }
5672                         }
5673
5674                         ip += 5;
5675                         ins_flag = 0;
5676                         break;
5677                 }
5678                 case CEE_RET:
5679                         if (cfg->method != method) {
5680                                 /* return from inlined method */
5681                                 if (return_var) {
5682                                         MonoInst *store;
5683                                         CHECK_STACK (1);
5684                                         --sp;
5685                                         //g_assert (returnvar != -1);
5686                                         NEW_TEMPSTORE (cfg, store, return_var->inst_c0, *sp);
5687                                         store->cil_code = sp [0]->cil_code;
5688                                         /* FIXME: handle CEE_STIND_R4 */
5689                                         if (store->opcode == CEE_STOBJ) {
5690                                                 g_assert_not_reached ();
5691                                                 NEW_TEMPLOADA (cfg, store, return_var->inst_c0);
5692                                                 /* FIXME: it is possible some optimization will pass the a heap pointer for the struct address, so we'll need the write barrier */
5693                                                 handle_stobj (cfg, bblock, store, *sp, sp [0]->cil_code, return_var->klass, FALSE, FALSE, FALSE);
5694 #ifdef MONO_ARCH_SOFT_FLOAT
5695                                         } else if (store->opcode == CEE_STIND_R4) {
5696                                                 NEW_TEMPLOADA (cfg, store, return_var->inst_c0);
5697                                                 handle_store_float (cfg, bblock, store, *sp, sp [0]->cil_code);
5698 #endif
5699                                         } else
5700                                                 MONO_ADD_INS (bblock, store);
5701                                 } 
5702                         } else {
5703                                 if (cfg->ret) {
5704                                         g_assert (!return_var);
5705                                         CHECK_STACK (1);
5706                                         --sp;
5707                                         MONO_INST_NEW (cfg, ins, OP_NOP);
5708                                         ins->opcode = mini_type_to_stind (cfg, mono_method_signature (method)->ret);
5709                                         if (ins->opcode == CEE_STOBJ) {
5710                                                 NEW_RETLOADA (cfg, ins);
5711                                                 /* FIXME: it is possible some optimization will pass the a heap pointer for the struct address, so we'll need the write barrier */
5712                                                 handle_stobj (cfg, bblock, ins, *sp, ip, cfg->ret->klass, FALSE, FALSE, FALSE);
5713                                         } else {
5714                                                 ins->opcode = OP_SETRET;
5715                                                 ins->cil_code = ip;
5716                                                 ins->inst_i0 = *sp;;
5717                                                 ins->inst_i1 = NULL;
5718                                                 MONO_ADD_INS (bblock, ins);
5719                                         }
5720                                 }
5721                         }
5722                         if (sp != stack_start)
5723                                 UNVERIFIED;
5724                         MONO_INST_NEW (cfg, ins, OP_BR);
5725                         ins->cil_code = ip++;
5726                         ins->inst_target_bb = end_bblock;
5727                         MONO_ADD_INS (bblock, ins);
5728                         link_bblock (cfg, bblock, end_bblock);
5729                         start_new_bblock = 1;
5730                         break;
5731                 case CEE_BR_S:
5732                         CHECK_OPSIZE (2);
5733                         MONO_INST_NEW (cfg, ins, OP_BR);
5734                         ins->cil_code = ip++;
5735                         MONO_ADD_INS (bblock, ins);
5736                         target = ip + 1 + (signed char)(*ip);
5737                         ++ip;
5738                         GET_BBLOCK (cfg, tblock, target);
5739                         link_bblock (cfg, bblock, tblock);
5740                         CHECK_BBLOCK (target, ip, tblock);
5741                         ins->inst_target_bb = tblock;
5742                         if (sp != stack_start) {
5743                                 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
5744                                 sp = stack_start;
5745                                 CHECK_UNVERIFIABLE (cfg);
5746                         }
5747                         start_new_bblock = 1;
5748                         inline_costs += BRANCH_COST;
5749                         break;
5750                 case CEE_BRFALSE_S:
5751                 case CEE_BRTRUE_S:
5752                         CHECK_OPSIZE (2);
5753                         CHECK_STACK (1);
5754                         if (sp [-1]->type == STACK_VTYPE || sp [-1]->type == STACK_R8)
5755                                 UNVERIFIED;
5756                         MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
5757                         ins->cil_code = ip++;
5758                         target = ip + 1 + *(signed char*)ip;
5759                         ip++;
5760                         ADD_UNCOND (ins->opcode == CEE_BRTRUE);
5761                         if (sp != stack_start) {
5762                                 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
5763                                 sp = stack_start;
5764                                 CHECK_UNVERIFIABLE (cfg);
5765                         }
5766                         inline_costs += BRANCH_COST;
5767                         break;
5768                 case CEE_BEQ_S:
5769                 case CEE_BGE_S:
5770                 case CEE_BGT_S:
5771                 case CEE_BLE_S:
5772                 case CEE_BLT_S:
5773                 case CEE_BNE_UN_S:
5774                 case CEE_BGE_UN_S:
5775                 case CEE_BGT_UN_S:
5776                 case CEE_BLE_UN_S:
5777                 case CEE_BLT_UN_S:
5778                         CHECK_OPSIZE (2);
5779                         CHECK_STACK (2);
5780                         MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
5781                         ins->cil_code = ip++;
5782                         target = ip + 1 + *(signed char*)ip;
5783                         ip++;
5784 #ifdef MONO_ARCH_SOFT_FLOAT
5785                         if (sp [-1]->type == STACK_R8 || sp [-2]->type == STACK_R8) {
5786                                 ins->opcode = condbr_to_fp_br (ins->opcode);
5787                                 sp -= 2;
5788                                 ins->inst_left = sp [0];
5789                                 ins->inst_right = sp [1];
5790                                 ins->type = STACK_I4;
5791                                 *sp++ = emit_tree (cfg, bblock, ins, ins->cil_code);
5792                                 MONO_INST_NEW (cfg, ins, CEE_BRTRUE);
5793                                 ADD_UNCOND (TRUE);
5794                         } else {
5795                                 ADD_BINCOND (NULL);
5796                         }
5797 #else
5798                         ADD_BINCOND (NULL);
5799 #endif
5800                         if (sp != stack_start) {
5801                                 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
5802                                 sp = stack_start;
5803                                 CHECK_UNVERIFIABLE (cfg);
5804                         }
5805                         inline_costs += BRANCH_COST;
5806                         break;
5807                 case CEE_BR:
5808                         CHECK_OPSIZE (5);
5809                         MONO_INST_NEW (cfg, ins, OP_BR);
5810                         ins->cil_code = ip++;
5811                         MONO_ADD_INS (bblock, ins);
5812                         target = ip + 4 + (gint32)read32(ip);
5813                         ip += 4;
5814                         GET_BBLOCK (cfg, tblock, target);
5815                         link_bblock (cfg, bblock, tblock);
5816                         CHECK_BBLOCK (target, ip, tblock);
5817                         ins->inst_target_bb = tblock;
5818                         if (sp != stack_start) {
5819                                 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
5820                                 sp = stack_start;
5821                                 CHECK_UNVERIFIABLE (cfg);
5822                         }
5823                         start_new_bblock = 1;
5824                         inline_costs += BRANCH_COST;
5825                         break;
5826                 case CEE_BRFALSE:
5827                 case CEE_BRTRUE:
5828                         CHECK_OPSIZE (5);
5829                         CHECK_STACK (1);
5830                         if (sp [-1]->type == STACK_VTYPE || sp [-1]->type == STACK_R8)
5831                                 UNVERIFIED;
5832                         MONO_INST_NEW (cfg, ins, *ip);
5833                         ins->cil_code = ip++;
5834                         target = ip + 4 + (gint32)read32(ip);
5835                         ip += 4;
5836                         ADD_UNCOND(ins->opcode == CEE_BRTRUE);
5837                         if (sp != stack_start) {
5838                                 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
5839                                 sp = stack_start;
5840                                 CHECK_UNVERIFIABLE (cfg);
5841                         }
5842                         inline_costs += BRANCH_COST;
5843                         break;
5844                 case CEE_BEQ:
5845                 case CEE_BGE:
5846                 case CEE_BGT:
5847                 case CEE_BLE:
5848                 case CEE_BLT:
5849                 case CEE_BNE_UN:
5850                 case CEE_BGE_UN:
5851                 case CEE_BGT_UN:
5852                 case CEE_BLE_UN:
5853                 case CEE_BLT_UN:
5854                         CHECK_OPSIZE (5);
5855                         CHECK_STACK (2);
5856                         MONO_INST_NEW (cfg, ins, *ip);
5857                         ins->cil_code = ip++;
5858                         target = ip + 4 + (gint32)read32(ip);
5859                         ip += 4;
5860 #ifdef MONO_ARCH_SOFT_FLOAT
5861                         if (sp [-1]->type == STACK_R8 || sp [-2]->type == STACK_R8) {
5862                                 ins->opcode = condbr_to_fp_br (ins->opcode);
5863                                 sp -= 2;
5864                                 ins->inst_left = sp [0];
5865                                 ins->inst_right = sp [1];
5866                                 ins->type = STACK_I4;
5867                                 *sp++ = emit_tree (cfg, bblock, ins, ins->cil_code);
5868                                 MONO_INST_NEW (cfg, ins, CEE_BRTRUE);
5869                                 ADD_UNCOND (TRUE);
5870                         } else {
5871                                 ADD_BINCOND (NULL);
5872                         }
5873 #else
5874                         ADD_BINCOND (NULL);
5875 #endif
5876                         if (sp != stack_start) {
5877                                 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
5878                                 sp = stack_start;
5879                                 CHECK_UNVERIFIABLE (cfg);
5880                         }
5881                         inline_costs += BRANCH_COST;
5882                         break;
5883                 case CEE_SWITCH:
5884                         CHECK_OPSIZE (5);
5885                         CHECK_STACK (1);
5886                         n = read32 (ip + 1);
5887                         MONO_INST_NEW (cfg, ins, OP_SWITCH);
5888                         --sp;
5889                         ins->inst_left = *sp;
5890                         if ((ins->inst_left->type != STACK_I4) && (ins->inst_left->type != STACK_PTR)) 
5891                                 UNVERIFIED;
5892                         ins->cil_code = ip;
5893                         ip += 5;
5894                         CHECK_OPSIZE (n * sizeof (guint32));
5895                         target = ip + n * sizeof (guint32);
5896                         MONO_ADD_INS (bblock, ins);
5897                         GET_BBLOCK (cfg, tblock, target);
5898                         link_bblock (cfg, bblock, tblock);
5899                         ins->klass = GUINT_TO_POINTER (n);
5900                         ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * (n + 1));
5901                         ins->inst_many_bb [n] = tblock;
5902
5903                         for (i = 0; i < n; ++i) {
5904                                 GET_BBLOCK (cfg, tblock, target + (gint32)read32(ip));
5905                                 link_bblock (cfg, bblock, tblock);
5906                                 ins->inst_many_bb [i] = tblock;
5907                                 ip += 4;
5908                         }
5909                         if (sp != stack_start) {
5910                                 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
5911                                 sp = stack_start;
5912                                 CHECK_UNVERIFIABLE (cfg);
5913                         }
5914                         /* Needed by the code generated in inssel.brg */
5915                         mono_get_got_var (cfg);
5916                         inline_costs += (BRANCH_COST * 2);
5917                         break;
5918                 case CEE_LDIND_I1:
5919                 case CEE_LDIND_U1:
5920                 case CEE_LDIND_I2:
5921                 case CEE_LDIND_U2:
5922                 case CEE_LDIND_I4:
5923                 case CEE_LDIND_U4:
5924                 case CEE_LDIND_I8:
5925                 case CEE_LDIND_I:
5926                 case CEE_LDIND_R4:
5927                 case CEE_LDIND_R8:
5928                 case CEE_LDIND_REF:
5929                         CHECK_STACK (1);
5930                         MONO_INST_NEW (cfg, ins, *ip);
5931                         ins->cil_code = ip;
5932                         --sp;
5933                         ins->inst_i0 = *sp;
5934                         *sp++ = ins;
5935                         ins->type = ldind_type [*ip - CEE_LDIND_I1];
5936                         ins->flags |= ins_flag;
5937                         ins_flag = 0;
5938                         if (ins->type == STACK_OBJ)
5939                                 ins->klass = mono_defaults.object_class;
5940 #ifdef MONO_ARCH_SOFT_FLOAT
5941                         if (*ip == CEE_LDIND_R4) {
5942                                 int temp;
5943                                 --sp;
5944                                 temp = handle_load_float (cfg, bblock, ins->inst_i0, ip);
5945                                 NEW_TEMPLOAD (cfg, *sp, temp);
5946                                 sp++;
5947                         }
5948 #endif
5949                         ++ip;
5950                         break;
5951                 case CEE_STIND_REF:
5952                 case CEE_STIND_I1:
5953                 case CEE_STIND_I2:
5954                 case CEE_STIND_I4:
5955                 case CEE_STIND_I8:
5956                 case CEE_STIND_R4:
5957                 case CEE_STIND_R8:
5958                         CHECK_STACK (2);
5959 #ifdef MONO_ARCH_SOFT_FLOAT
5960                         if (*ip == CEE_STIND_R4) {
5961                                 sp -= 2;
5962                                 handle_store_float (cfg, bblock, sp [0], sp [1], ip);
5963                                 ip++;
5964                                 break;
5965                         }
5966 #endif
5967 #if HAVE_WRITE_BARRIERS
5968                         if (*ip == CEE_STIND_REF && method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER && !((sp [-1]->opcode == OP_PCONST) && (sp [-1]->inst_p0 == 0))) {
5969                                 /* insert call to write barrier */
5970                                 MonoMethod *write_barrier = mono_marshal_get_write_barrier ();
5971                                 sp -= 2;
5972                                 mono_emit_method_call_spilled (cfg, bblock, write_barrier, mono_method_signature (write_barrier), sp, ip, NULL);
5973                                 ip++;
5974                                 break;
5975                         }
5976 #endif
5977                         MONO_INST_NEW (cfg, ins, *ip);
5978                         ins->cil_code = ip++;
5979                         sp -= 2;
5980                         handle_loaded_temps (cfg, bblock, stack_start, sp);
5981                         MONO_ADD_INS (bblock, ins);
5982                         ins->inst_i0 = sp [0];
5983                         ins->inst_i1 = sp [1];
5984                         ins->flags |= ins_flag;
5985                         ins_flag = 0;
5986                         inline_costs += 1;
5987                         break;
5988                 case CEE_MUL:
5989                         CHECK_STACK (2);
5990                         ADD_BINOP (*ip);
5991
5992 #ifdef MONO_ARCH_NO_EMULATE_MUL_IMM
5993                         /* FIXME: This breaks with ssapre (mono -O=ssapre loader.exe) */
5994                         if ((ins->inst_right->opcode == OP_ICONST) && !(cfg->opt & MONO_OPT_SSAPRE)) {
5995                                 switch (ins->opcode) {
5996                                 case CEE_MUL:
5997                                         ins->opcode = OP_IMUL_IMM;
5998                                         ins->inst_imm = ins->inst_right->inst_c0;
5999                                         break;
6000                                 case OP_LMUL:
6001                                         ins->opcode = OP_LMUL_IMM;
6002                                         ins->inst_imm = ins->inst_right->inst_c0;
6003                                         break;
6004                                 default:
6005                                         g_assert_not_reached ();
6006                                 }
6007                         }
6008 #endif
6009
6010                         if (mono_find_jit_opcode_emulation (ins->opcode)) {
6011                                 --sp;
6012                                 *sp++ = emit_tree (cfg, bblock, ins, ip + 1);
6013                         }
6014                         ip++;
6015                         break;
6016                 case CEE_ADD:
6017                 case CEE_SUB:
6018                 case CEE_DIV:
6019                 case CEE_DIV_UN:
6020                 case CEE_REM:
6021                 case CEE_REM_UN:
6022                 case CEE_AND:
6023                 case CEE_OR:
6024                 case CEE_XOR:
6025                 case CEE_SHL:
6026                 case CEE_SHR:
6027                 case CEE_SHR_UN:
6028                         CHECK_STACK (2);
6029                         ADD_BINOP (*ip);
6030                         /* special case that gives a nice speedup and happens to workaorund a ppc jit but (for the release)
6031                          * later apply the speedup to the left shift as well
6032                          * See BUG# 57957.
6033                          */
6034                         if ((ins->opcode == OP_LSHR_UN) && (ins->type == STACK_I8) 
6035                                         && (ins->inst_right->opcode == OP_ICONST) && (ins->inst_right->inst_c0 == 32)) {
6036                                 ins->opcode = OP_LONG_SHRUN_32;
6037                                 /*g_print ("applied long shr speedup to %s\n", cfg->method->name);*/
6038                                 ip++;
6039                                 break;
6040                         }
6041                         if (mono_find_jit_opcode_emulation (ins->opcode)) {
6042                                 --sp;
6043                                 *sp++ = emit_tree (cfg, bblock, ins, ip + 1);
6044                         }
6045                         ip++;
6046                         break;
6047                 case CEE_NEG:
6048                 case CEE_NOT:
6049                 case CEE_CONV_I1:
6050                 case CEE_CONV_I2:
6051                 case CEE_CONV_I4:
6052                 case CEE_CONV_R4:
6053                 case CEE_CONV_R8:
6054                 case CEE_CONV_U4:
6055                 case CEE_CONV_I8:
6056                 case CEE_CONV_U8:
6057                 case CEE_CONV_OVF_I8:
6058                 case CEE_CONV_OVF_U8:
6059                 case CEE_CONV_R_UN:
6060                         CHECK_STACK (1);
6061                         ADD_UNOP (*ip);
6062                         if (mono_find_jit_opcode_emulation (ins->opcode)) {
6063                                 --sp;
6064                                 *sp++ = emit_tree (cfg, bblock, ins, ip + 1);
6065                         }
6066                         ip++;                   
6067                         break;
6068                 case CEE_CONV_OVF_I4:
6069                 case CEE_CONV_OVF_I1:
6070                 case CEE_CONV_OVF_I2:
6071                 case CEE_CONV_OVF_I:
6072                 case CEE_CONV_OVF_U:
6073                         CHECK_STACK (1);
6074
6075                         if (sp [-1]->type == STACK_R8) {
6076                                 ADD_UNOP (CEE_CONV_OVF_I8);
6077                                 ADD_UNOP (*ip);
6078                         } else {
6079                                 ADD_UNOP (*ip);
6080                         }
6081
6082                         ip++;
6083                         break;
6084                 case CEE_CONV_OVF_U1:
6085                 case CEE_CONV_OVF_U2:
6086                 case CEE_CONV_OVF_U4:
6087                         CHECK_STACK (1);
6088
6089                         if (sp [-1]->type == STACK_R8) {
6090                                 ADD_UNOP (CEE_CONV_OVF_U8);
6091                                 ADD_UNOP (*ip);
6092                         } else {
6093                                 ADD_UNOP (*ip);
6094                         }
6095
6096                         ip++;
6097                         break;
6098                 case CEE_CONV_OVF_I1_UN:
6099                 case CEE_CONV_OVF_I2_UN:
6100                 case CEE_CONV_OVF_I4_UN:
6101                 case CEE_CONV_OVF_I8_UN:
6102                 case CEE_CONV_OVF_U1_UN:
6103                 case CEE_CONV_OVF_U2_UN:
6104                 case CEE_CONV_OVF_U4_UN:
6105                 case CEE_CONV_OVF_U8_UN:
6106                 case CEE_CONV_OVF_I_UN:
6107                 case CEE_CONV_OVF_U_UN:
6108                         CHECK_STACK (1);
6109                         ADD_UNOP (*ip);
6110                         ip++;
6111                         break;
6112                 case CEE_CPOBJ:
6113                         CHECK_OPSIZE (5);
6114                         CHECK_STACK (2);
6115                         token = read32 (ip + 1);
6116                         klass = mini_get_class (method, token, generic_context);
6117                         CHECK_TYPELOAD (klass);
6118                         sp -= 2;
6119                         if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
6120                                 MonoInst *store, *load;
6121                                 MONO_INST_NEW (cfg, load, CEE_LDIND_REF);
6122                                 load->cil_code = ip;
6123                                 load->inst_i0 = sp [1];
6124                                 load->type = STACK_OBJ;
6125                                 load->klass = klass;
6126                                 load->flags |= ins_flag;
6127                                 MONO_INST_NEW (cfg, store, CEE_STIND_REF);
6128                                 store->cil_code = ip;
6129                                 handle_loaded_temps (cfg, bblock, stack_start, sp);
6130                                 MONO_ADD_INS (bblock, store);
6131                                 store->inst_i0 = sp [0];
6132                                 store->inst_i1 = load;
6133                                 store->flags |= ins_flag;
6134                         } else {
6135                                 guint32 align;
6136
6137                                 n = mono_class_value_size (klass, &align);
6138                                 if ((cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 5) {
6139                                         MonoInst *copy;
6140                                         NEW_MEMCPY (cfg, copy, sp [0], sp [1], n, align);
6141                                         MONO_ADD_INS (bblock, copy);
6142                                 } else {
6143                                         MonoMethod *memcpy_method = get_memcpy_method ();
6144                                         MonoInst *iargs [3];
6145                                         iargs [0] = sp [0];
6146                                         iargs [1] = sp [1];
6147                                         NEW_ICONST (cfg, iargs [2], n);
6148                                         iargs [2]->cil_code = ip;
6149
6150                                         mono_emit_method_call_spilled (cfg, bblock, memcpy_method, memcpy_method->signature, iargs, ip, NULL);
6151                                 }
6152                         }
6153                         ins_flag = 0;
6154                         ip += 5;
6155                         break;
6156                 case CEE_LDOBJ: {
6157                         MonoInst *iargs [3];
6158                         int loc_index = -1;
6159                         int stloc_len = 0;
6160                         guint32 align;
6161
6162                         CHECK_OPSIZE (5);
6163                         CHECK_STACK (1);
6164                         --sp;
6165                         token = read32 (ip + 1);
6166                         klass = mini_get_class (method, token, generic_context);
6167                         CHECK_TYPELOAD (klass);
6168                         if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
6169                                 MONO_INST_NEW (cfg, ins, CEE_LDIND_REF);
6170                                 ins->cil_code = ip;
6171                                 ins->inst_i0 = sp [0];
6172                                 ins->type = STACK_OBJ;
6173                                 ins->klass = klass;
6174                                 ins->flags |= ins_flag;
6175                                 ins_flag = 0;
6176                                 *sp++ = ins;
6177                                 ip += 5;
6178                                 break;
6179                         }
6180
6181                         /* Optimize the common ldobj+stloc combination */
6182                         switch (ip [5]) {
6183                         case CEE_STLOC_S:
6184                                 loc_index = ip [6];
6185                                 stloc_len = 2;
6186                                 break;
6187                         case CEE_STLOC_0:
6188                         case CEE_STLOC_1:
6189                         case CEE_STLOC_2:
6190                         case CEE_STLOC_3:
6191                                 loc_index = ip [5] - CEE_STLOC_0;
6192                                 stloc_len = 1;
6193                                 break;
6194                         default:
6195                                 break;
6196                         }
6197
6198                         if ((loc_index != -1) && ip_in_bb (cfg, bblock, ip + 5)) {
6199                                 CHECK_LOCAL (loc_index);
6200                                 NEW_LOCSTORE (cfg, ins, loc_index, *sp);
6201
6202                                 /* FIXME: handle CEE_STIND_R4 */
6203                                 if (ins->opcode == CEE_STOBJ) {
6204                                         handle_loaded_temps (cfg, bblock, stack_start, sp);
6205                                         ins->cil_code = ip;
6206                                         g_assert (ins->opcode == CEE_STOBJ);
6207                                         NEW_LOCLOADA (cfg, ins, loc_index);
6208                                         handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE, FALSE);
6209                                         ip += 5;
6210                                         ip += stloc_len;
6211                                         break;
6212                                 }
6213                         }
6214
6215                         n = mono_class_value_size (klass, &align);
6216                         ins = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
6217                         NEW_TEMPLOADA (cfg, iargs [0], ins->inst_c0);
6218                         if ((cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 5) {
6219                                 MonoInst *copy;
6220                                 NEW_MEMCPY (cfg, copy, iargs [0], *sp, n, align);
6221                                 MONO_ADD_INS (bblock, copy);
6222                         } else {
6223                                 MonoMethod *memcpy_method = get_memcpy_method ();
6224                                 iargs [1] = *sp;
6225                                 NEW_ICONST (cfg, iargs [2], n);
6226                                 iargs [2]->cil_code = ip;
6227
6228                                 mono_emit_method_call_spilled (cfg, bblock, memcpy_method, memcpy_method->signature, iargs, ip, NULL);
6229                         }
6230                         NEW_TEMPLOAD (cfg, *sp, ins->inst_c0);
6231                         ++sp;
6232                         ip += 5;
6233                         ins_flag = 0;
6234                         inline_costs += 1;
6235                         break;
6236                 }
6237                 case CEE_LDSTR:
6238                         CHECK_STACK_OVF (1);
6239                         CHECK_OPSIZE (5);
6240                         n = read32 (ip + 1);
6241
6242                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
6243                                 /* FIXME: moving GC */
6244                                 NEW_PCONST (cfg, ins, mono_method_get_wrapper_data (method, n));
6245                                 ins->cil_code = ip;
6246                                 ins->type = STACK_OBJ;
6247                                 ins->klass = mono_defaults.string_class;
6248                                 *sp = ins;
6249                         }
6250                         else if (method->wrapper_type != MONO_WRAPPER_NONE) {
6251                                 int temp;
6252                                 MonoInst *iargs [1];
6253
6254                                 NEW_PCONST (cfg, iargs [0], mono_method_get_wrapper_data (method, n));                          
6255                                 temp = mono_emit_jit_icall (cfg, bblock, mono_string_new_wrapper, iargs, ip);
6256                                 NEW_TEMPLOAD (cfg, *sp, temp);
6257
6258                         } else {
6259
6260                                 if (cfg->opt & MONO_OPT_SHARED) {
6261                                         int temp;
6262                                         MonoInst *iargs [3];
6263                                         MonoInst* domain_var;
6264                                         
6265                                         if (cfg->compile_aot) {
6266                                                 /* FIXME: bug when inlining methods from different assemblies (n is a token valid just in one). */
6267                                                 cfg->ldstr_list = g_list_prepend (cfg->ldstr_list, GINT_TO_POINTER (n));
6268                                         }
6269                                         /* avoid depending on undefined C behavior in sequence points */
6270                                         domain_var = mono_get_domainvar (cfg);
6271                                         NEW_TEMPLOAD (cfg, iargs [0], domain_var->inst_c0);
6272                                         NEW_IMAGECONST (cfg, iargs [1], image);
6273                                         NEW_ICONST (cfg, iargs [2], mono_metadata_token_index (n));
6274                                         temp = mono_emit_jit_icall (cfg, bblock, mono_ldstr, iargs, ip);
6275                                         NEW_TEMPLOAD (cfg, *sp, temp);
6276                                         mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
6277                                 } else {
6278                                         if (bblock->out_of_line) {
6279                                                 MonoInst *iargs [2];
6280                                                 int temp;
6281
6282                                                 if (cfg->compile_aot && cfg->method->klass->image == mono_defaults.corlib) {
6283                                                         /* 
6284                                                          * Avoid relocations by using a version of helper_ldstr
6285                                                          * specialized to mscorlib.
6286                                                          */
6287                                                         NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (n));
6288                                                         temp = mono_emit_jit_icall (cfg, bblock, mono_helper_ldstr_mscorlib, iargs, ip);
6289                                                 } else {
6290                                                         /* Avoid creating the string object */
6291                                                         NEW_IMAGECONST (cfg, iargs [0], image);
6292                                                         NEW_ICONST (cfg, iargs [1], mono_metadata_token_index (n));
6293                                                         temp = mono_emit_jit_icall (cfg, bblock, mono_helper_ldstr, iargs, ip);
6294                                                 }
6295                                                 NEW_TEMPLOAD (cfg, *sp, temp);
6296                                         } 
6297                                         else
6298                                         if (cfg->compile_aot) {
6299                                                 NEW_LDSTRCONST (cfg, ins, image, n);
6300                                                 *sp = ins;
6301                                         } 
6302                                         else {
6303                                                 NEW_PCONST (cfg, ins, NULL);
6304                                                 ins->cil_code = ip;
6305                                                 ins->type = STACK_OBJ;
6306                                                 ins->inst_p0 = mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
6307                                                 ins->klass = mono_defaults.string_class;
6308                                                 *sp = ins;
6309                                         }
6310                                 }
6311                         }
6312
6313                         sp++;
6314                         ip += 5;
6315                         break;
6316                 case CEE_NEWOBJ: {
6317                         MonoInst *iargs [2];
6318                         MonoMethodSignature *fsig;
6319                         int temp;
6320
6321                         CHECK_OPSIZE (5);
6322                         token = read32 (ip + 1);
6323                         cmethod = mini_get_method (method, token, NULL, generic_context);
6324                         if (!cmethod)
6325                                 goto load_error;
6326                         fsig = mono_method_get_signature (cmethod, image, token);
6327
6328                         mono_save_token_info (cfg, image, token, cmethod);
6329
6330                         if (!mono_class_init (cmethod->klass))
6331                                 goto load_error;
6332
6333                         if (cfg->generic_sharing_context && mono_method_check_context_used (cmethod))
6334                                 GENERIC_SHARING_FAILURE (CEE_NEWOBJ);
6335
6336                         if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS) {
6337                                 if (check_linkdemand (cfg, method, cmethod, bblock, ip))
6338                                         INLINE_FAILURE;
6339                                 CHECK_CFG_EXCEPTION;
6340                         } else if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR) {
6341                                 ensure_method_is_allowed_to_call_method (cfg, method, cmethod, bblock, ip);
6342                         }
6343
6344                         n = fsig->param_count;
6345                         CHECK_STACK (n);
6346
6347                         /* move the args to allow room for 'this' in the first position */
6348                         while (n--) {
6349                                 --sp;
6350                                 sp [1] = sp [0];
6351                         }
6352
6353                         handle_loaded_temps (cfg, bblock, stack_start, sp);
6354
6355                         if (mini_class_is_system_array (cmethod->klass)) {
6356                                 NEW_METHODCONST (cfg, *sp, cmethod);
6357                                 temp = handle_array_new (cfg, bblock, fsig->param_count, sp, ip);
6358                         } else if (cmethod->string_ctor) {
6359                                 /* we simply pass a null pointer */
6360                                 NEW_PCONST (cfg, *sp, NULL); 
6361                                 /* now call the string ctor */
6362                                 temp = mono_emit_method_call_spilled (cfg, bblock, cmethod, fsig, sp, ip, NULL);
6363                         } else {
6364                                 MonoInst* callvirt_this_arg = NULL;
6365                                 
6366                                 if (cmethod->klass->valuetype) {
6367                                         iargs [0] = mono_compile_create_var (cfg, &cmethod->klass->byval_arg, OP_LOCAL);
6368                                         temp = iargs [0]->inst_c0;
6369
6370                                         NEW_TEMPLOADA (cfg, *sp, temp);
6371
6372                                         handle_initobj (cfg, bblock, *sp, NULL, cmethod->klass, stack_start, sp);
6373
6374                                         NEW_TEMPLOADA (cfg, *sp, temp);
6375
6376                                         /* 
6377                                          * The code generated by mini_emit_virtual_call () expects
6378                                          * iargs [0] to be a boxed instance, but luckily the vcall
6379                                          * will be transformed into a normal call there.
6380                                          */
6381                                 } else {
6382                                         MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
6383                                         if (mini_field_access_needs_cctor_run (cfg, method, vtable) && !(g_slist_find (class_inits, vtable))) {
6384                                                 guint8 *tramp = mono_create_class_init_trampoline (vtable);
6385                                                 mono_emit_native_call (cfg, bblock, tramp, 
6386                                                                                            helper_sig_class_init_trampoline,
6387                                                                                            NULL, ip, FALSE, FALSE);
6388                                                 if (cfg->verbose_level > 2)
6389                                                         g_print ("class %s.%s needs init call for ctor\n", cmethod->klass->name_space, cmethod->klass->name);
6390                                                 class_inits = g_slist_prepend (class_inits, vtable);
6391                                         }
6392                                         temp = handle_alloc (cfg, bblock, cmethod->klass, FALSE, ip);
6393                                         NEW_TEMPLOAD (cfg, *sp, temp);
6394                                 }
6395
6396                                 /* Avoid virtual calls to ctors if possible */
6397                                 if (cmethod->klass->marshalbyref)
6398                                         callvirt_this_arg = sp [0];
6399                                 
6400                                 if ((cfg->opt & MONO_OPT_INLINE) && cmethod &&
6401                                     mono_method_check_inlining (cfg, cmethod) &&
6402                                     !mono_class_is_subclass_of (cmethod->klass, mono_defaults.exception_class, FALSE) &&
6403                                     !g_list_find (dont_inline, cmethod)) {
6404                                         int costs;
6405                                         MonoBasicBlock *ebblock;
6406                                         if ((costs = inline_method (cfg, cmethod, fsig, bblock, sp, ip, real_offset, dont_inline, &ebblock, FALSE))) {
6407
6408                                                 ip += 5;
6409                                                 real_offset += 5;
6410                                                 
6411                                                 GET_BBLOCK (cfg, bblock, ip);
6412                                                 ebblock->next_bb = bblock;
6413                                                 link_bblock (cfg, ebblock, bblock);
6414
6415                                                 NEW_TEMPLOAD (cfg, *sp, temp);
6416                                                 sp++;
6417
6418                                                 /* indicates start of a new block, and triggers a load 
6419                                                    of all stack arguments at bb boundarie */
6420                                                 bblock = ebblock;
6421
6422                                                 inline_costs += costs;
6423                                                 break;
6424                                                 
6425                                         } else {
6426                                                 /* Prevent inlining of methods which call other methods */
6427                                                 INLINE_FAILURE;
6428                                                 mono_emit_method_call_spilled (cfg, bblock, cmethod, fsig, sp, ip, callvirt_this_arg);
6429                                         }
6430                                 } else {
6431                                         /* Prevent inlining of methods which call other methods */
6432                                         INLINE_FAILURE;
6433                                         /* now call the actual ctor */
6434                                         mono_emit_method_call_spilled (cfg, bblock, cmethod, fsig, sp, ip, callvirt_this_arg);
6435                                 }
6436                         }
6437
6438                         NEW_TEMPLOAD (cfg, *sp, temp);
6439                         sp++;
6440                         
6441                         ip += 5;
6442                         inline_costs += 5;
6443                         break;
6444                 }
6445                 case CEE_ISINST:
6446                         CHECK_STACK (1);
6447                         --sp;
6448                         CHECK_OPSIZE (5);
6449                         token = read32 (ip + 1);
6450                         klass = mini_get_class (method, token, generic_context);
6451                         CHECK_TYPELOAD (klass);
6452                         if (sp [0]->type != STACK_OBJ)
6453                                 UNVERIFIED;
6454
6455                         if (cfg->generic_sharing_context && mono_class_check_context_used (klass))
6456                                 GENERIC_SHARING_FAILURE (CEE_ISINST);
6457
6458                         /* Needed by the code generated in inssel.brg */
6459                         mono_get_got_var (cfg);
6460
6461                         if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
6462                         
6463                                 MonoMethod *mono_isinst;
6464                                 MonoInst *iargs [1];
6465                                 MonoBasicBlock *ebblock;
6466                                 int costs;
6467                                 int temp;
6468                                 
6469                                 mono_isinst = mono_marshal_get_isinst (klass); 
6470                                 iargs [0] = sp [0];
6471                                 
6472                                 costs = inline_method (cfg, mono_isinst, mono_method_signature (mono_isinst), bblock, 
6473                                                        iargs, ip, real_offset, dont_inline, &ebblock, TRUE);
6474                         
6475                                 g_assert (costs > 0);
6476                                 
6477                                 ip += 5;
6478                                 real_offset += 5;
6479                         
6480                                 GET_BBLOCK (cfg, bblock, ip);
6481                                 ebblock->next_bb = bblock;
6482                                 link_bblock (cfg, ebblock, bblock);
6483
6484                                 temp = iargs [0]->inst_i0->inst_c0;
6485                                 NEW_TEMPLOAD (cfg, *sp, temp);
6486                                 
6487                                 sp++;
6488                                 bblock = ebblock;
6489                                 inline_costs += costs;
6490                         } else {
6491                                 MONO_INST_NEW (cfg, ins, *ip);
6492                                 ins->type = STACK_OBJ;
6493                                 ins->inst_left = *sp;
6494                                 ins->inst_newa_class = klass;
6495                                 ins->klass = klass;
6496                                 ins->cil_code = ip;
6497                                 *sp++ = emit_tree (cfg, bblock, ins, ip + 5);
6498                                 ip += 5;
6499                         }
6500                         break;
6501                 case CEE_UNBOX_ANY: {
6502                         MonoInst *add, *vtoffset;
6503                         MonoInst *iargs [3];
6504                         guint32 align;
6505
6506                         CHECK_STACK (1);
6507                         --sp;
6508                         CHECK_OPSIZE (5);
6509                         token = read32 (ip + 1);
6510                         klass = mini_get_class (method, token, generic_context);
6511                         CHECK_TYPELOAD (klass);
6512
6513                         if (cfg->generic_sharing_context && mono_class_check_context_used (klass))
6514                                 GENERIC_SHARING_FAILURE (CEE_UNBOX_ANY);
6515
6516                         if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
6517                                 /* CASTCLASS */
6518                                 if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
6519                                         MonoMethod *mono_castclass;
6520                                         MonoInst *iargs [1];
6521                                         MonoBasicBlock *ebblock;
6522                                         int costs;
6523                                         int temp;
6524                                         
6525                                         mono_castclass = mono_marshal_get_castclass (klass); 
6526                                         iargs [0] = sp [0];
6527                                         
6528                                         costs = inline_method (cfg, mono_castclass, mono_method_signature (mono_castclass), bblock, 
6529                                                         iargs, ip, real_offset, dont_inline, &ebblock, TRUE);
6530                                 
6531                                         g_assert (costs > 0);
6532                                         
6533                                         ip += 5;
6534                                         real_offset += 5;
6535                                 
6536                                         GET_BBLOCK (cfg, bblock, ip);
6537                                         ebblock->next_bb = bblock;
6538                                         link_bblock (cfg, ebblock, bblock);
6539         
6540                                         temp = iargs [0]->inst_i0->inst_c0;
6541                                         NEW_TEMPLOAD (cfg, *sp, temp);
6542                                         
6543                                         sp++;
6544                                         bblock = ebblock;
6545                                         inline_costs += costs;                          
6546                                 } else {
6547                                         MONO_INST_NEW (cfg, ins, CEE_CASTCLASS);
6548                                         ins->type = STACK_OBJ;
6549                                         ins->inst_left = *sp;
6550                                         ins->klass = klass;
6551                                         ins->inst_newa_class = klass;
6552                                         ins->cil_code = ip;
6553                                         *sp++ = ins;
6554                                         ip += 5;
6555                                 }
6556                                 break;
6557                         }
6558
6559                         if (mono_class_is_nullable (klass)) {
6560                                 int v = handle_unbox_nullable (cfg, bblock, *sp, ip, klass);
6561                                 NEW_TEMPLOAD (cfg, *sp, v);
6562                                 sp ++;
6563                                 ip += 5;
6564                                 break;
6565                         }
6566
6567                         MONO_INST_NEW (cfg, ins, OP_UNBOXCAST);
6568                         ins->type = STACK_OBJ;
6569                         ins->inst_left = *sp;
6570                         ins->klass = klass;
6571                         ins->inst_newa_class = klass;
6572                         ins->cil_code = ip;
6573
6574                         MONO_INST_NEW (cfg, add, OP_PADD);
6575                         NEW_ICONST (cfg, vtoffset, sizeof (MonoObject));
6576                         add->inst_left = ins;
6577                         add->inst_right = vtoffset;
6578                         add->type = STACK_MP;
6579                         add->klass = mono_defaults.object_class;
6580                         *sp = add;
6581                         ip += 5;
6582                         /* LDOBJ impl */
6583                         n = mono_class_value_size (klass, &align);
6584                         ins = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
6585                         NEW_TEMPLOADA (cfg, iargs [0], ins->inst_c0);
6586                         if ((cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 5) {
6587                                 MonoInst *copy;
6588                                 NEW_MEMCPY (cfg, copy, iargs [0], *sp, n, align);
6589                                 MONO_ADD_INS (bblock, copy);
6590                         } else {
6591                                 MonoMethod *memcpy_method = get_memcpy_method ();
6592                                 iargs [1] = *sp;
6593                                 NEW_ICONST (cfg, iargs [2], n);
6594                                 iargs [2]->cil_code = ip;
6595
6596                                 mono_emit_method_call_spilled (cfg, bblock, memcpy_method, memcpy_method->signature, iargs, ip, NULL);
6597                         }
6598                         NEW_TEMPLOAD (cfg, *sp, ins->inst_c0);
6599                         ++sp;
6600                         inline_costs += 2;
6601                         break;
6602                 }
6603                 case CEE_UNBOX: {
6604                         MonoInst *add, *vtoffset;
6605
6606                         CHECK_STACK (1);
6607                         --sp;
6608                         CHECK_OPSIZE (5);
6609                         token = read32 (ip + 1);
6610                         klass = mini_get_class (method, token, generic_context);
6611                         CHECK_TYPELOAD (klass);
6612
6613                         if (cfg->generic_sharing_context && mono_class_check_context_used (klass))
6614                                 GENERIC_SHARING_FAILURE (CEE_UNBOX);
6615
6616                         if (mono_class_is_nullable (klass)) {
6617                                 int v = handle_unbox_nullable (cfg, bblock, *sp, ip, klass);
6618                                 NEW_TEMPLOAD (cfg, *sp, v);
6619                                 sp ++;
6620                                 ip += 5;
6621                                 break;
6622                         }
6623
6624                         /* Needed by the code generated in inssel.brg */
6625                         mono_get_got_var (cfg);
6626
6627                         MONO_INST_NEW (cfg, ins, OP_UNBOXCAST);
6628                         ins->type = STACK_OBJ;
6629                         ins->inst_left = *sp;
6630                         ins->klass = klass;
6631                         ins->inst_newa_class = klass;
6632                         ins->cil_code = ip;
6633
6634                         MONO_INST_NEW (cfg, add, OP_PADD);
6635                         NEW_ICONST (cfg, vtoffset, sizeof (MonoObject));
6636                         add->inst_left = ins;
6637                         add->inst_right = vtoffset;
6638                         add->type = STACK_MP;
6639                         add->klass = klass;
6640                         *sp++ = add;
6641                         ip += 5;
6642                         inline_costs += 2;
6643                         break;
6644                 }
6645                 case CEE_CASTCLASS:
6646                         CHECK_STACK (1);
6647                         --sp;
6648                         CHECK_OPSIZE (5);
6649                         token = read32 (ip + 1);
6650                         klass = mini_get_class (method, token, generic_context);
6651                         CHECK_TYPELOAD (klass);
6652                         if (sp [0]->type != STACK_OBJ)
6653                                 UNVERIFIED;
6654
6655                         if (cfg->generic_sharing_context && mono_class_check_context_used (klass))
6656                                 GENERIC_SHARING_FAILURE (CEE_CASTCLASS);
6657
6658                         /* Needed by the code generated in inssel.brg */
6659                         mono_get_got_var (cfg);
6660                 
6661                         if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
6662                                 
6663                                 MonoMethod *mono_castclass;
6664                                 MonoInst *iargs [1];
6665                                 MonoBasicBlock *ebblock;
6666                                 int costs;
6667                                 int temp;
6668                                 
6669                                 mono_castclass = mono_marshal_get_castclass (klass); 
6670                                 iargs [0] = sp [0];
6671                                 
6672                                 costs = inline_method (cfg, mono_castclass, mono_method_signature (mono_castclass), bblock, 
6673                                                 iargs, ip, real_offset, dont_inline, &ebblock, TRUE);
6674                         
6675                                 g_assert (costs > 0);
6676                                 
6677                                 ip += 5;
6678                                 real_offset += 5;
6679                         
6680                                 GET_BBLOCK (cfg, bblock, ip);
6681                                 ebblock->next_bb = bblock;
6682                                 link_bblock (cfg, ebblock, bblock);
6683
6684                                 temp = iargs [0]->inst_i0->inst_c0;
6685                                 NEW_TEMPLOAD (cfg, *sp, temp);
6686                                 
6687                                 sp++;
6688                                 bblock = ebblock;
6689                                 inline_costs += costs;
6690                         } else {
6691                                 MONO_INST_NEW (cfg, ins, *ip);
6692                                 ins->type = STACK_OBJ;
6693                                 ins->inst_left = *sp;
6694                                 ins->klass = klass;
6695                                 ins->inst_newa_class = klass;
6696                                 ins->cil_code = ip;
6697                                 *sp++ = emit_tree (cfg, bblock, ins, ip + 5);
6698                                 ip += 5;
6699                         }
6700                         break;
6701                 case CEE_THROW:
6702                         CHECK_STACK (1);
6703                         MONO_INST_NEW (cfg, ins, OP_THROW);
6704                         --sp;
6705                         ins->inst_left = *sp;
6706                         ins->cil_code = ip++;
6707                         bblock->out_of_line = TRUE;
6708                         MONO_ADD_INS (bblock, ins);
6709                         MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
6710                         ins->cil_code = ip - 1;
6711                         MONO_ADD_INS (bblock, ins);
6712                         sp = stack_start;
6713                         
6714                         link_bblock (cfg, bblock, end_bblock);
6715                         start_new_bblock = 1;
6716                         break;
6717                 case CEE_LDFLD:
6718                 case CEE_LDFLDA:
6719                 case CEE_STFLD: {
6720                         MonoInst *offset_ins;
6721                         MonoClassField *field;
6722                         MonoBasicBlock *ebblock;
6723                         int costs;
6724                         guint foffset;
6725
6726                         if (*ip == CEE_STFLD) {
6727                                 CHECK_STACK (2);
6728                                 sp -= 2;
6729                         } else {
6730                                 CHECK_STACK (1);
6731                                 --sp;
6732                         }
6733                         if (sp [0]->type == STACK_I4 || sp [0]->type == STACK_I8 || sp [0]->type == STACK_R8)
6734                                 UNVERIFIED;
6735                         if (*ip != CEE_LDFLD && sp [0]->type == STACK_VTYPE)
6736                                 UNVERIFIED;
6737                         CHECK_OPSIZE (5);
6738                         token = read32 (ip + 1);
6739                         if (method->wrapper_type != MONO_WRAPPER_NONE) {
6740                                 field = mono_method_get_wrapper_data (method, token);
6741                                 klass = field->parent;
6742                         } else {
6743                                 field = mono_field_from_token (image, token, &klass, generic_context);
6744                         }
6745                         if (!field)
6746                                 goto load_error;
6747                         mono_class_init (klass);
6748                         if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_field (method, field))
6749                                 FIELD_ACCESS_FAILURE;
6750
6751                         foffset = klass->valuetype? field->offset - sizeof (MonoObject): field->offset;
6752                         /* FIXME: mark instructions for use in SSA */
6753                         if (*ip == CEE_STFLD) {
6754                                 if (target_type_is_incompatible (cfg, field->type, sp [1]))
6755                                         UNVERIFIED;
6756                                 if ((klass->marshalbyref && !MONO_CHECK_THIS (sp [0])) || klass->contextbound || klass == mono_defaults.marshalbyrefobject_class) {
6757                                         MonoMethod *stfld_wrapper = mono_marshal_get_stfld_wrapper (field->type); 
6758                                         MonoInst *iargs [5];
6759
6760                                         iargs [0] = sp [0];
6761                                         NEW_CLASSCONST (cfg, iargs [1], klass);
6762                                         NEW_FIELDCONST (cfg, iargs [2], field);
6763                                         NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : 
6764                                                     field->offset);
6765                                         iargs [4] = sp [1];
6766
6767                                         if (cfg->opt & MONO_OPT_INLINE) {
6768                                                 costs = inline_method (cfg, stfld_wrapper, mono_method_signature (stfld_wrapper), bblock, 
6769                                                                 iargs, ip, real_offset, dont_inline, &ebblock, TRUE);
6770                                                 g_assert (costs > 0);
6771                                                       
6772                                                 ip += 5;
6773                                                 real_offset += 5;
6774
6775                                                 GET_BBLOCK (cfg, bblock, ip);
6776                                                 ebblock->next_bb = bblock;
6777                                                 link_bblock (cfg, ebblock, bblock);
6778
6779                                                 /* indicates start of a new block, and triggers a load 
6780                                                    of all stack arguments at bb boundarie */
6781                                                 bblock = ebblock;
6782
6783                                                 inline_costs += costs;
6784                                                 break;
6785                                         } else {
6786                                                 mono_emit_method_call_spilled (cfg, bblock, stfld_wrapper, mono_method_signature (stfld_wrapper), iargs, ip, NULL);
6787                                         }
6788 #if HAVE_WRITE_BARRIERS
6789                                 } else if (mini_type_to_stind (cfg, field->type) == CEE_STIND_REF) {
6790                                         /* insert call to write barrier */
6791                                         MonoMethod *write_barrier = mono_marshal_get_write_barrier ();
6792                                         MonoInst *iargs [2];
6793                                         NEW_ICONST (cfg, offset_ins, foffset);
6794                                         MONO_INST_NEW (cfg, ins, OP_PADD);
6795                                         ins->cil_code = ip;
6796                                         ins->inst_left = *sp;
6797                                         ins->inst_right = offset_ins;
6798                                         ins->type = STACK_MP;
6799                                         ins->klass = mono_defaults.object_class;
6800                                         iargs [0] = ins;
6801                                         iargs [1] = sp [1];
6802                                         mono_emit_method_call_spilled (cfg, bblock, write_barrier, mono_method_signature (write_barrier), iargs, ip, NULL);
6803 #endif
6804 #ifdef MONO_ARCH_SOFT_FLOAT
6805                                 } else if (mini_type_to_stind (cfg, field->type) == CEE_STIND_R4) {
6806                                         NEW_ICONST (cfg, offset_ins, foffset);
6807                                         MONO_INST_NEW (cfg, ins, OP_PADD);
6808                                         ins->cil_code = ip;
6809                                         ins->inst_left = *sp;
6810                                         ins->inst_right = offset_ins;
6811                                         ins->type = STACK_MP;
6812                                         ins->klass = mono_defaults.object_class;
6813                                         handle_store_float (cfg, bblock, ins, sp [1], ip);
6814 #endif
6815                                 } else {
6816                                         MonoInst *store;
6817                                         NEW_ICONST (cfg, offset_ins, foffset);
6818                                         MONO_INST_NEW (cfg, ins, OP_PADD);
6819                                         ins->cil_code = ip;
6820                                         ins->inst_left = *sp;
6821                                         ins->inst_right = offset_ins;
6822                                         ins->type = STACK_MP;
6823
6824                                         MONO_INST_NEW (cfg, store, mini_type_to_stind (cfg, field->type));
6825                                         store->cil_code = ip;
6826                                         store->inst_left = ins;
6827                                         store->inst_right = sp [1];
6828                                         handle_loaded_temps (cfg, bblock, stack_start, sp);
6829                                         store->flags |= ins_flag;
6830                                         ins_flag = 0;
6831                                         if (store->opcode == CEE_STOBJ) {
6832                                                 handle_stobj (cfg, bblock, ins, sp [1], ip, 
6833                                                               mono_class_from_mono_type (field->type), FALSE, FALSE, TRUE);
6834                                         } else
6835                                                 MONO_ADD_INS (bblock, store);
6836                                 }
6837                         } else {
6838                                 if ((klass->marshalbyref && !MONO_CHECK_THIS (sp [0])) || klass->contextbound || klass == mono_defaults.marshalbyrefobject_class) {
6839                                         MonoMethod *wrapper = (*ip == CEE_LDFLDA) ? mono_marshal_get_ldflda_wrapper (field->type) : mono_marshal_get_ldfld_wrapper (field->type); 
6840                                         MonoInst *iargs [4];
6841                                         int temp;
6842                                         
6843                                         iargs [0] = sp [0];
6844                                         NEW_CLASSCONST (cfg, iargs [1], klass);
6845                                         NEW_FIELDCONST (cfg, iargs [2], field);
6846                                         NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset);
6847                                         if ((cfg->opt & MONO_OPT_INLINE) && !MONO_TYPE_ISSTRUCT (mono_method_signature (wrapper)->ret)) {
6848                                                 costs = inline_method (cfg, wrapper, mono_method_signature (wrapper), bblock, 
6849                                                                 iargs, ip, real_offset, dont_inline, &ebblock, TRUE);
6850                                                 g_assert (costs > 0);
6851                                                       
6852                                                 ip += 5;
6853                                                 real_offset += 5;
6854
6855                                                 GET_BBLOCK (cfg, bblock, ip);
6856                                                 ebblock->next_bb = bblock;
6857                                                 link_bblock (cfg, ebblock, bblock);
6858
6859                                                 temp = iargs [0]->inst_i0->inst_c0;
6860
6861                                                 NEW_TEMPLOAD (cfg, *sp, temp);
6862                                                 sp++;
6863
6864                                                 /* indicates start of a new block, and triggers a load of
6865                                                    all stack arguments at bb boundarie */
6866                                                 bblock = ebblock;
6867                                                 
6868                                                 inline_costs += costs;
6869                                                 break;
6870                                         } else {
6871                                                 temp = mono_emit_method_call_spilled (cfg, bblock, wrapper, mono_method_signature (wrapper), iargs, ip, NULL);
6872                                                 NEW_TEMPLOAD (cfg, *sp, temp);
6873                                                 sp++;
6874                                         }
6875                                 } else {
6876                                         NEW_ICONST (cfg, offset_ins, foffset);
6877                                         MONO_INST_NEW (cfg, ins, OP_PADD);
6878                                         ins->cil_code = ip;
6879                                         ins->inst_left = *sp;
6880                                         ins->inst_right = offset_ins;
6881                                         ins->type = STACK_MP;
6882
6883                                         if (*ip == CEE_LDFLDA) {
6884                                                 ins->klass = mono_class_from_mono_type (field->type);
6885                                                 *sp++ = ins;
6886                                         } else {
6887                                                 MonoInst *load;
6888                                                 MONO_INST_NEW (cfg, load, mini_type_to_ldind (cfg, field->type));
6889                                                 type_to_eval_stack_type (cfg, field->type, load);
6890                                                 load->cil_code = ip;
6891                                                 load->inst_left = ins;
6892                                                 load->flags |= ins_flag;
6893                                                 ins_flag = 0;
6894 #ifdef MONO_ARCH_SOFT_FLOAT
6895                                                 if (mini_type_to_ldind (cfg, field->type) == CEE_LDIND_R4) {
6896                                                         int temp;
6897                                                         temp = handle_load_float (cfg, bblock, ins, ip);
6898                                                         NEW_TEMPLOAD (cfg, *sp, temp);
6899                                                         sp++;
6900                                                 } else
6901 #endif
6902                                                 *sp++ = load;
6903                                         }
6904                                 }
6905                         }
6906                         ip += 5;
6907                         break;
6908                 }
6909                 case CEE_LDSFLD:
6910                 case CEE_LDSFLDA:
6911                 case CEE_STSFLD: {
6912                         MonoClassField *field;
6913                         gpointer addr = NULL;
6914                         gboolean shared_access = FALSE;
6915                         int relation = 0;
6916
6917                         CHECK_OPSIZE (5);
6918                         token = read32 (ip + 1);
6919                         if (method->wrapper_type != MONO_WRAPPER_NONE) {
6920                                 field = mono_method_get_wrapper_data (method, token);
6921                                 klass = field->parent;
6922                         }
6923                         else
6924                                 field = mono_field_from_token (image, token, &klass, generic_context);
6925                         if (!field)
6926                                 goto load_error;
6927                         mono_class_init (klass);
6928                         if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_field (method, field))
6929                                 FIELD_ACCESS_FAILURE;
6930
6931                         /*
6932                          * We can only support shared generic static
6933                          * field access on architectures where the
6934                          * trampoline code has been extended to handle
6935                          * the generic class init.
6936                          */
6937 #ifndef MONO_ARCH_VTABLE_REG
6938                         GENERIC_SHARING_FAILURE (*ip);
6939 #endif
6940
6941                         if (cfg->generic_sharing_context) {
6942                                 int context_used = mono_class_check_context_used (klass);
6943
6944                                 if (context_used & MONO_GENERIC_CONTEXT_USED_METHOD ||
6945                                                 klass->valuetype)
6946                                         GENERIC_SHARING_FAILURE (*ip);
6947
6948                                 if (context_used) {
6949                                         relation = mono_class_generic_class_relation (klass, MONO_RGCTX_INFO_VTABLE, method->klass, generic_context, NULL);
6950
6951                                         if (!(method->flags & METHOD_ATTRIBUTE_STATIC) /*&& relation != MINI_GENERIC_CLASS_RELATION_OTHER*/)
6952                                                 shared_access = TRUE;
6953                                         else
6954                                                 GENERIC_SHARING_FAILURE (*ip);
6955                                 }
6956                         }
6957
6958                         g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
6959
6960                         if ((*ip) == CEE_STSFLD)
6961                                 handle_loaded_temps (cfg, bblock, stack_start, sp);
6962
6963                         /* The special_static_fields field is init'd in mono_class_vtable, so it needs
6964                          * to be called here.
6965                          */
6966                         if (!(cfg->opt & MONO_OPT_SHARED))
6967                                 mono_class_vtable (cfg->domain, klass);
6968                         mono_domain_lock (cfg->domain);
6969                         if (cfg->domain->special_static_fields)
6970                                 addr = g_hash_table_lookup (cfg->domain->special_static_fields, field);
6971                         mono_domain_unlock (cfg->domain);
6972
6973                         if (shared_access) {
6974                                 MonoInst *this, *rgctx, *static_data;
6975
6976                                 /*
6977                                 g_print ("sharing static field access in %s.%s.%s - depth %d offset %d\n",
6978                                         method->klass->name_space, method->klass->name, method->name,
6979                                         depth, field->offset);
6980                                 */
6981
6982                                 if (mono_class_needs_cctor_run (klass, method)) {
6983                                         MonoMethodSignature *sig = helper_sig_generic_class_init_trampoline;
6984                                         MonoCallInst *call;
6985                                         MonoInst *this, *vtable;
6986
6987                                         NEW_ARGLOAD (cfg, this, 0);
6988
6989                                         if (relation == MINI_GENERIC_CLASS_RELATION_SELF) {
6990                                                 MONO_INST_NEW (cfg, vtable, CEE_LDIND_I);
6991                                                 vtable->cil_code = ip;
6992                                                 vtable->inst_left = this;
6993                                                 vtable->type = STACK_PTR;
6994                                                 vtable->klass = klass;
6995                                         } else {
6996                                                 MonoInst *rgctx = get_runtime_generic_context_from_this (cfg, this, ip);
6997
6998                                                 vtable = get_runtime_generic_context_ptr (cfg, method, bblock, klass,
6999                                                         token, MINI_TOKEN_SOURCE_FIELD, generic_context,
7000                                                         rgctx, MONO_RGCTX_INFO_VTABLE, ip);
7001                                         }
7002
7003                                         call = mono_emit_call_args (cfg, bblock, sig, NULL, FALSE, FALSE, ip, FALSE);
7004                                         call->inst.opcode = OP_TRAMPCALL_VTABLE;
7005                                         call->fptr = mono_get_trampoline_code (MONO_TRAMPOLINE_GENERIC_CLASS_INIT);
7006
7007                                         call->inst.inst_left = vtable;
7008
7009                                         mono_spill_call (cfg, bblock, call, sig, FALSE, ip, FALSE);
7010                                 }
7011
7012                                 /*
7013                                  * The pointer we're computing here is
7014                                  *
7015                                  *   super_info.static_data + field->offset
7016                                  */
7017
7018                                 NEW_ARGLOAD (cfg, this, 0);
7019                                 rgctx = get_runtime_generic_context_from_this (cfg, this, ip);
7020                                 static_data = get_runtime_generic_context_ptr (cfg, method, bblock, klass,
7021                                         token, MINI_TOKEN_SOURCE_FIELD, generic_context,
7022                                         rgctx, MONO_RGCTX_INFO_STATIC_DATA, ip);
7023
7024                                 if (field->offset == 0) {
7025                                         ins = static_data;
7026                                 } else {
7027                                         MonoInst *field_offset;
7028
7029                                         NEW_ICONST (cfg, field_offset, field->offset);
7030
7031                                         MONO_INST_NEW (cfg, ins, OP_PADD);
7032                                         ins->cil_code = ip;
7033                                         ins->inst_left = static_data;
7034                                         ins->inst_right = field_offset;
7035                                         ins->type = STACK_PTR;
7036                                         ins->klass = klass;
7037                                 }
7038                         } else if ((cfg->opt & MONO_OPT_SHARED) || (cfg->compile_aot && addr)) {
7039                                 int temp;
7040                                 MonoInst *iargs [2];
7041                                 MonoInst *domain_var;
7042                                 
7043                                 g_assert (field->parent);
7044                                 /* avoid depending on undefined C behavior in sequence points */
7045                                 domain_var = mono_get_domainvar (cfg);
7046                                 NEW_TEMPLOAD (cfg, iargs [0], domain_var->inst_c0);
7047                                 NEW_FIELDCONST (cfg, iargs [1], field);
7048                                 temp = mono_emit_jit_icall (cfg, bblock, mono_class_static_field_address, iargs, ip);
7049                                 NEW_TEMPLOAD (cfg, ins, temp);
7050                         } else {
7051                                 MonoVTable *vtable;
7052                                 vtable = mono_class_vtable (cfg->domain, klass);
7053                                 if (!addr) {
7054                                         if (mini_field_access_needs_cctor_run (cfg, method, vtable) && !(g_slist_find (class_inits, vtable))) {
7055                                                 guint8 *tramp = mono_create_class_init_trampoline (vtable);
7056                                                 mono_emit_native_call (cfg, bblock, tramp, 
7057                                                                                            helper_sig_class_init_trampoline,
7058                                                                                            NULL, ip, FALSE, FALSE);
7059                                                 if (cfg->verbose_level > 2)
7060                                                         g_print ("class %s.%s needs init call for %s\n", klass->name_space, klass->name, field->name);
7061                                                 class_inits = g_slist_prepend (class_inits, vtable);
7062                                         } else {
7063                                                 if (cfg->run_cctors) {
7064                                                         /* This makes so that inline cannot trigger */
7065                                                         /* .cctors: too many apps depend on them */
7066                                                         /* running with a specific order... */
7067                                                         if (! vtable->initialized)
7068                                                                 INLINE_FAILURE;
7069                                                         mono_runtime_class_init (vtable);
7070                                                 }
7071                                         }
7072                                         addr = (char*)vtable->data + field->offset;
7073
7074                                         if (cfg->compile_aot)
7075                                                 NEW_SFLDACONST (cfg, ins, field);
7076                                         else
7077                                                 NEW_PCONST (cfg, ins, addr);
7078                                         ins->cil_code = ip;
7079                                 } else {
7080                                         /* 
7081                                          * insert call to mono_threads_get_static_data (GPOINTER_TO_UINT (addr)) 
7082                                          * This could be later optimized to do just a couple of
7083                                          * memory dereferences with constant offsets.
7084                                          */
7085                                         int temp;
7086                                         MonoInst *iargs [1];
7087                                         NEW_ICONST (cfg, iargs [0], GPOINTER_TO_UINT (addr));
7088                                         temp = mono_emit_jit_icall (cfg, bblock, mono_get_special_static_data, iargs, ip);
7089                                         NEW_TEMPLOAD (cfg, ins, temp);
7090                                 }
7091                         }
7092
7093                         /* FIXME: mark instructions for use in SSA */
7094                         if (*ip == CEE_LDSFLDA) {
7095                                 ins->klass = mono_class_from_mono_type (field->type);
7096                                 *sp++ = ins;
7097                         } else if (*ip == CEE_STSFLD) {
7098                                 MonoInst *store;
7099                                 CHECK_STACK (1);
7100                                 sp--;
7101                                 MONO_INST_NEW (cfg, store, mini_type_to_stind (cfg, field->type));
7102                                 store->cil_code = ip;
7103                                 store->inst_left = ins;
7104                                 store->inst_right = sp [0];
7105                                 store->flags |= ins_flag;
7106                                 ins_flag = 0;
7107
7108 #ifdef MONO_ARCH_SOFT_FLOAT
7109                                 if (store->opcode == CEE_STIND_R4)
7110                                         handle_store_float (cfg, bblock, ins, sp [0], ip);
7111                                 else
7112 #endif
7113                                 if (store->opcode == CEE_STOBJ) {
7114                                         handle_stobj (cfg, bblock, ins, sp [0], ip, mono_class_from_mono_type (field->type), FALSE, FALSE, FALSE);
7115                                 } else
7116                                         MONO_ADD_INS (bblock, store);
7117                         } else {
7118                                 gboolean is_const = FALSE;
7119                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
7120                                 if (!shared_access && !((cfg->opt & MONO_OPT_SHARED) || cfg->compile_aot) && 
7121                                     vtable->initialized && (field->type->attrs & FIELD_ATTRIBUTE_INIT_ONLY)) {
7122                                         gpointer addr = (char*)vtable->data + field->offset;
7123                                         int ro_type = field->type->type;
7124                                         if (ro_type == MONO_TYPE_VALUETYPE && field->type->data.klass->enumtype) {
7125                                                 ro_type = field->type->data.klass->enum_basetype->type;
7126                                         }
7127                                         /* g_print ("RO-FIELD %s.%s:%s\n", klass->name_space, klass->name, field->name);*/
7128                                         is_const = TRUE;
7129                                         switch (ro_type) {
7130                                         case MONO_TYPE_BOOLEAN:
7131                                         case MONO_TYPE_U1:
7132                                                 NEW_ICONST (cfg, *sp, *((guint8 *)addr));
7133                                                 sp++;
7134                                                 break;
7135                                         case MONO_TYPE_I1:
7136                                                 NEW_ICONST (cfg, *sp, *((gint8 *)addr));
7137                                                 sp++;
7138                                                 break;                                          
7139                                         case MONO_TYPE_CHAR:
7140                                         case MONO_TYPE_U2:
7141                                                 NEW_ICONST (cfg, *sp, *((guint16 *)addr));
7142                                                 sp++;
7143                                                 break;
7144                                         case MONO_TYPE_I2:
7145                                                 NEW_ICONST (cfg, *sp, *((gint16 *)addr));
7146                                                 sp++;
7147                                                 break;
7148                                                 break;
7149                                         case MONO_TYPE_I4:
7150                                                 NEW_ICONST (cfg, *sp, *((gint32 *)addr));
7151                                                 sp++;
7152                                                 break;                                          
7153                                         case MONO_TYPE_U4:
7154                                                 NEW_ICONST (cfg, *sp, *((guint32 *)addr));
7155                                                 sp++;
7156                                                 break;
7157 #ifndef HAVE_MOVING_COLLECTOR
7158                                         case MONO_TYPE_I:
7159                                         case MONO_TYPE_U:
7160                                         case MONO_TYPE_STRING:
7161                                         case MONO_TYPE_OBJECT:
7162                                         case MONO_TYPE_CLASS:
7163                                         case MONO_TYPE_SZARRAY:
7164                                         case MONO_TYPE_PTR:
7165                                         case MONO_TYPE_FNPTR:
7166                                         case MONO_TYPE_ARRAY:
7167                                                 NEW_PCONST (cfg, *sp, *((gpointer *)addr));
7168                                                 type_to_eval_stack_type (cfg, field->type, *sp);
7169                                                 sp++;
7170                                                 break;
7171 #endif
7172                                         case MONO_TYPE_I8:
7173                                         case MONO_TYPE_U8:
7174                                                 MONO_INST_NEW (cfg, *sp, OP_I8CONST);
7175                                                 sp [0]->type = STACK_I8;
7176                                                 sp [0]->inst_l = *((gint64 *)addr);
7177                                                 sp++;
7178                                                 break;
7179                                         case MONO_TYPE_R4:
7180                                         case MONO_TYPE_R8:
7181                                         case MONO_TYPE_VALUETYPE:
7182                                         default:
7183                                                 is_const = FALSE;
7184                                                 break;
7185                                         }
7186                                 }
7187
7188                                 if (!is_const) {
7189                                         MonoInst *load;
7190                                         CHECK_STACK_OVF (1);
7191                                         MONO_INST_NEW (cfg, load, mini_type_to_ldind (cfg, field->type));
7192                                         type_to_eval_stack_type (cfg, field->type, load);
7193                                         load->cil_code = ip;
7194                                         load->inst_left = ins;
7195                                         load->flags |= ins_flag;
7196 #ifdef MONO_ARCH_SOFT_FLOAT
7197                                         if (load->opcode == CEE_LDIND_R4) {
7198                                                 int temp;
7199                                                 temp = handle_load_float (cfg, bblock, ins, ip);
7200                                                 NEW_TEMPLOAD (cfg, load, temp);
7201                                         }
7202 #endif
7203                                         *sp++ = load;
7204                                         ins_flag = 0;
7205                                 }
7206                         }
7207                         ip += 5;
7208                         break;
7209                 }
7210                 case CEE_STOBJ:
7211                         CHECK_STACK (2);
7212                         sp -= 2;
7213                         CHECK_OPSIZE (5);
7214                         token = read32 (ip + 1);
7215                         klass = mini_get_class (method, token, generic_context);
7216                         CHECK_TYPELOAD (klass);
7217                         n = mini_type_to_stind (cfg, &klass->byval_arg);
7218                         /* FIXME: handle CEE_STIND_R4 */
7219                         if (n == CEE_STOBJ) {
7220                                 handle_stobj (cfg, bblock, sp [0], sp [1], ip, klass, FALSE, FALSE, TRUE);
7221                         } else {
7222                                 /* FIXME: should check item at sp [1] is compatible with the type of the store. */
7223                                 MonoInst *store;
7224                                 MONO_INST_NEW (cfg, store, n);
7225                                 store->cil_code = ip;
7226                                 store->inst_left = sp [0];
7227                                 store->inst_right = sp [1];
7228                                 store->flags |= ins_flag;
7229                                 MONO_ADD_INS (bblock, store);
7230                         }
7231                         ins_flag = 0;
7232                         ip += 5;
7233                         inline_costs += 1;
7234                         break;
7235                 case CEE_BOX: {
7236                         MonoInst *val;
7237
7238                         CHECK_STACK (1);
7239                         --sp;
7240                         val = *sp;
7241                         CHECK_OPSIZE (5);
7242                         token = read32 (ip + 1);
7243                         klass = mini_get_class (method, token, generic_context);
7244                         CHECK_TYPELOAD (klass);
7245
7246                         if (cfg->generic_sharing_context && mono_class_check_context_used (klass))
7247                                 GENERIC_SHARING_FAILURE (CEE_BOX);
7248
7249                         if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
7250                                 *sp++ = val;
7251                                 ip += 5;
7252                                 break;
7253                         }
7254                         if (klass == mono_defaults.void_class)
7255                                 UNVERIFIED;
7256                         if (target_type_is_incompatible (cfg, &klass->byval_arg, *sp))
7257                                 UNVERIFIED;
7258                         /* frequent check in generic code: box (struct), brtrue */
7259                         if (!mono_class_is_nullable (klass) &&
7260                             ip + 5 < end && ip_in_bb (cfg, bblock, ip + 5) && (ip [5] == CEE_BRTRUE || ip [5] == CEE_BRTRUE_S)) {
7261                                 /*g_print ("box-brtrue opt at 0x%04x in %s\n", real_offset, method->name);*/
7262                                 MONO_INST_NEW (cfg, ins, CEE_POP);
7263                                 MONO_ADD_INS (bblock, ins);
7264                                 ins->cil_code = ip;
7265                                 ins->inst_i0 = *sp;
7266                                 ip += 5;
7267                                 MONO_INST_NEW (cfg, ins, OP_BR);
7268                                 ins->cil_code = ip;
7269                                 MONO_ADD_INS (bblock, ins);
7270                                 if (*ip == CEE_BRTRUE_S) {
7271                                         CHECK_OPSIZE (2);
7272                                         ip++;
7273                                         target = ip + 1 + (signed char)(*ip);
7274                                         ip++;
7275                                 } else {
7276                                         CHECK_OPSIZE (5);
7277                                         ip++;
7278                                         target = ip + 4 + (gint)(read32 (ip));
7279                                         ip += 4;
7280                                 }
7281                                 GET_BBLOCK (cfg, tblock, target);
7282                                 link_bblock (cfg, bblock, tblock);
7283                                 CHECK_BBLOCK (target, ip, tblock);
7284                                 ins->inst_target_bb = tblock;
7285                                 GET_BBLOCK (cfg, tblock, ip);
7286                                 link_bblock (cfg, bblock, tblock);
7287                                 if (sp != stack_start) {
7288                                         handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
7289                                         sp = stack_start;
7290                                         CHECK_UNVERIFIABLE (cfg);
7291                                 }
7292                                 start_new_bblock = 1;
7293                                 break;
7294                         }
7295                         *sp++ = handle_box (cfg, bblock, val, ip, klass);
7296                         ip += 5;
7297                         inline_costs += 1;
7298                         break;
7299                 }
7300                 case CEE_NEWARR: {
7301                         gboolean shared_access = FALSE;
7302
7303                         CHECK_STACK (1);
7304                         --sp;
7305
7306                         CHECK_OPSIZE (5);
7307                         token = read32 (ip + 1);
7308
7309                         /* allocate the domainvar - becaus this is used in decompose_foreach */
7310                         if (cfg->opt & MONO_OPT_SHARED) {
7311                                 mono_get_domainvar (cfg);
7312                                 /* LAME-IR: Mark it as used since otherwise it will be optimized away */
7313                                 cfg->domainvar->flags |= MONO_INST_VOLATILE;
7314                         }
7315
7316                         /* Ditto */
7317                         mono_get_got_var (cfg);
7318
7319                         klass = mini_get_class (method, token, generic_context);
7320                         CHECK_TYPELOAD (klass);
7321
7322                         if (cfg->generic_sharing_context) {
7323                                 int context_used = mono_class_check_context_used (klass);
7324
7325                                 if (context_used & MONO_GENERIC_CONTEXT_USED_METHOD || klass->valuetype)
7326                                         GENERIC_SHARING_FAILURE (CEE_NEWARR);
7327
7328                                 if (context_used) {
7329                                         if (!(method->flags & METHOD_ATTRIBUTE_STATIC))
7330                                                 shared_access = TRUE;
7331                                         else
7332                                                 GENERIC_SHARING_FAILURE (CEE_NEWARR);
7333                                 }
7334                         }
7335
7336                         if (shared_access) {
7337                                 MonoInst *this, *rgctx;
7338                                 MonoInst *args [3];
7339                                 int temp;
7340
7341                                 /* domain */
7342                                 NEW_DOMAINCONST (cfg, args [0]);
7343
7344                                 /* klass */
7345                                 NEW_ARGLOAD (cfg, this, 0);
7346                                 rgctx = get_runtime_generic_context_from_this (cfg, this, ip);
7347                                 args [1] = get_runtime_generic_context_ptr (cfg, method, bblock, klass,
7348                                         token, MINI_TOKEN_SOURCE_CLASS, generic_context, rgctx, MONO_RGCTX_INFO_KLASS, ip);
7349
7350                                 /* array len */
7351                                 args [2] = *sp;
7352
7353                                 temp = mono_emit_jit_icall (cfg, bblock, mono_array_new, args, ip);
7354                                 NEW_TEMPLOAD (cfg, ins, temp);
7355                         } else {
7356                                 MONO_INST_NEW (cfg, ins, *ip);
7357                                 ins->cil_code = ip;
7358                                 ins->inst_newa_class = klass;
7359                                 ins->inst_newa_len = *sp;
7360                                 ins->type = STACK_OBJ;
7361                                 ins->klass = mono_array_class_get (klass, 1);
7362                         }
7363
7364                         ip += 5;
7365                         *sp++ = ins;
7366                         /* 
7367                          * we store the object so calls to create the array are not interleaved
7368                          * with the arguments of other calls.
7369                          */
7370                         if (1) {
7371                                 MonoInst *store, *temp, *load;
7372                                 const char *data_ptr;
7373                                 int data_size = 0;
7374                                 --sp;
7375                                 temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
7376                                 NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
7377                                 store->cil_code = ins->cil_code;
7378                                 MONO_ADD_INS (bblock, store);
7379                                 /* 
7380                                  * we inline/optimize the initialization sequence if possible.
7381                                  * we should also allocate the array as not cleared, since we spend as much time clearing to 0 as initializing
7382                                  * for small sizes open code the memcpy
7383                                  * ensure the rva field is big enough
7384                                  */
7385                                 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))) {
7386                                         MonoMethod *memcpy_method = get_memcpy_method ();
7387                                         MonoInst *data_offset, *add;
7388                                         MonoInst *iargs [3];
7389                                         NEW_ICONST (cfg, iargs [2], data_size);
7390                                         NEW_TEMPLOAD (cfg, load, temp->inst_c0);
7391                                         load->cil_code = ins->cil_code;
7392                                         NEW_ICONST (cfg, data_offset, G_STRUCT_OFFSET (MonoArray, vector));
7393                                         MONO_INST_NEW (cfg, add, OP_PADD);
7394                                         add->inst_left = load;
7395                                         add->inst_right = data_offset;
7396                                         add->cil_code = ip;
7397                                         iargs [0] = add;
7398                                         if (cfg->compile_aot) {
7399                                                 NEW_AOTCONST_TOKEN (cfg, iargs [1], MONO_PATCH_INFO_RVA, method->klass->image, GPOINTER_TO_UINT(data_ptr), STACK_PTR, NULL);
7400                                         } else {
7401                                                 NEW_PCONST (cfg, iargs [1], (char*)data_ptr);
7402                                         }
7403                                         mono_emit_method_call_spilled (cfg, bblock, memcpy_method, memcpy_method->signature, iargs, ip, NULL);
7404                                         ip += 11;
7405                                 }
7406                                 NEW_TEMPLOAD (cfg, load, temp->inst_c0);
7407                                 load->cil_code = ins->cil_code;
7408                                 *sp++ = load;
7409                         }
7410                         inline_costs += 1;
7411                         break;
7412                 }
7413                 case CEE_LDLEN:
7414                         CHECK_STACK (1);
7415                         --sp;
7416                         if (sp [0]->type != STACK_OBJ)
7417                                 UNVERIFIED;
7418                         MONO_INST_NEW (cfg, ins, *ip);
7419                         ins->cil_code = ip++;
7420                         ins->inst_left = *sp;
7421                         ins->type = STACK_PTR;
7422                         *sp++ = ins;
7423                         break;
7424                 case CEE_LDELEMA:
7425                         CHECK_STACK (2);
7426                         sp -= 2;
7427                         CHECK_OPSIZE (5);
7428                         if (sp [0]->type != STACK_OBJ)
7429                                 UNVERIFIED;
7430
7431                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
7432                         CHECK_TYPELOAD (klass);
7433                         /* we need to make sure that this array is exactly the type it needs
7434                          * to be for correctness. the wrappers are lax with their usage
7435                          * so we need to ignore them here
7436                          */
7437                         if (!klass->valuetype && method->wrapper_type == MONO_WRAPPER_NONE) {
7438                                 MonoInst* check;
7439
7440                                 /* Needed by the code generated in inssel.brg */
7441                                 mono_get_got_var (cfg);
7442
7443                                 MONO_INST_NEW (cfg, check, OP_CHECK_ARRAY_TYPE);
7444                                 check->cil_code = ip;
7445                                 check->klass = klass;
7446                                 check->inst_left = sp [0];
7447                                 check->type = STACK_OBJ;
7448                                 check->klass = klass;
7449                                 sp [0] = check;
7450                         }
7451                         
7452                         mono_class_init (klass);
7453                         NEW_LDELEMA (cfg, ins, sp, klass);
7454                         ins->cil_code = ip;
7455                         *sp++ = ins;
7456                         ip += 5;
7457                         break;
7458                 case CEE_LDELEM_ANY: {
7459                         MonoInst *load;
7460                         CHECK_STACK (2);
7461                         sp -= 2;
7462                         if (sp [0]->type != STACK_OBJ)
7463                                 UNVERIFIED;
7464                         CHECK_OPSIZE (5);
7465                         token = read32 (ip + 1);
7466                         klass = mini_get_class (method, token, generic_context);
7467                         CHECK_TYPELOAD (klass);
7468                         mono_class_init (klass);
7469                         NEW_LDELEMA (cfg, load, sp, klass);
7470                         load->cil_code = ip;
7471                         MONO_INST_NEW (cfg, ins, mini_type_to_ldind (cfg, &klass->byval_arg));
7472                         ins->cil_code = ip;
7473                         ins->inst_left = load;
7474                         *sp++ = ins;
7475                         type_to_eval_stack_type (cfg, &klass->byval_arg, ins);
7476                         ip += 5;
7477                         break;
7478                 }
7479                 case CEE_LDELEM_I1:
7480                 case CEE_LDELEM_U1:
7481                 case CEE_LDELEM_I2:
7482                 case CEE_LDELEM_U2:
7483                 case CEE_LDELEM_I4:
7484                 case CEE_LDELEM_U4:
7485                 case CEE_LDELEM_I8:
7486                 case CEE_LDELEM_I:
7487                 case CEE_LDELEM_R4:
7488                 case CEE_LDELEM_R8:
7489                 case CEE_LDELEM_REF: {
7490                         MonoInst *load;
7491                         /*
7492                          * translate to:
7493                          * ldind.x (ldelema (array, index))
7494                          * ldelema does the bounds check
7495                          */
7496                         CHECK_STACK (2);
7497                         sp -= 2;
7498                         if (sp [0]->type != STACK_OBJ)
7499                                 UNVERIFIED;
7500                         klass = array_access_to_klass (*ip, sp [0]);
7501                         NEW_LDELEMA (cfg, load, sp, klass);
7502                         load->cil_code = ip;
7503 #ifdef MONO_ARCH_SOFT_FLOAT
7504                         if (*ip == CEE_LDELEM_R4) {
7505                                 int temp;
7506                                 temp = handle_load_float (cfg, bblock, load, ip);
7507                                 NEW_TEMPLOAD (cfg, *sp, temp);
7508                                 sp++;
7509                                 ++ip;
7510                                 break;
7511                         }
7512 #endif
7513                         MONO_INST_NEW (cfg, ins, ldelem_to_ldind [*ip - CEE_LDELEM_I1]);
7514                         ins->cil_code = ip;
7515                         ins->inst_left = load;
7516                         *sp++ = ins;
7517                         ins->type = ldind_type [ins->opcode - CEE_LDIND_I1];
7518                         ins->klass = klass;
7519                         ++ip;
7520                         break;
7521                 }
7522                 case CEE_STELEM_I:
7523                 case CEE_STELEM_I1:
7524                 case CEE_STELEM_I2:
7525                 case CEE_STELEM_I4:
7526                 case CEE_STELEM_I8:
7527                 case CEE_STELEM_R4:
7528                 case CEE_STELEM_R8: {
7529                         MonoInst *load;
7530                         /*
7531                          * translate to:
7532                          * stind.x (ldelema (array, index), val)
7533                          * ldelema does the bounds check
7534                          */
7535                         CHECK_STACK (3);
7536                         sp -= 3;
7537                         if (sp [0]->type != STACK_OBJ)
7538                                 UNVERIFIED;
7539                         klass = array_access_to_klass (*ip, sp [0]);
7540                         NEW_LDELEMA (cfg, load, sp, klass);
7541                         load->cil_code = ip;
7542 #ifdef MONO_ARCH_SOFT_FLOAT
7543                         if (*ip == CEE_STELEM_R4) {
7544                                 handle_store_float (cfg, bblock, load, sp [2], ip);
7545                                 ip++;
7546                                 break;
7547                         }
7548 #endif
7549                         MONO_INST_NEW (cfg, ins, stelem_to_stind [*ip - CEE_STELEM_I]);
7550                         ins->cil_code = ip;
7551                         ins->inst_left = load;
7552                         ins->inst_right = sp [2];
7553                         ++ip;
7554                         handle_loaded_temps (cfg, bblock, stack_start, sp);
7555                         MONO_ADD_INS (bblock, ins);
7556                         inline_costs += 1;
7557                         break;
7558                 }
7559                 case CEE_STELEM_ANY: {
7560                         MonoInst *load;
7561                         /*
7562                          * translate to:
7563                          * stind.x (ldelema (array, index), val)
7564                          * ldelema does the bounds check
7565                          */
7566                         CHECK_STACK (3);
7567                         sp -= 3;
7568                         if (sp [0]->type != STACK_OBJ)
7569                                 UNVERIFIED;
7570                         CHECK_OPSIZE (5);
7571                         token = read32 (ip + 1);
7572                         klass = mini_get_class (method, token, generic_context);
7573                         CHECK_TYPELOAD (klass);
7574                         mono_class_init (klass);
7575                         if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
7576                                 /* storing a NULL doesn't need any of the complex checks in stelemref */
7577                                 if (sp [2]->opcode == OP_PCONST && sp [2]->inst_p0 == NULL) {
7578                                         MonoInst *load;
7579                                         NEW_LDELEMA (cfg, load, sp, mono_defaults.object_class);
7580                                         load->cil_code = ip;
7581                                         MONO_INST_NEW (cfg, ins, stelem_to_stind [*ip - CEE_STELEM_I]);
7582                                         ins->cil_code = ip;
7583                                         ins->inst_left = load;
7584                                         ins->inst_right = sp [2];
7585                                         MONO_ADD_INS (bblock, ins);
7586                                 } else {
7587                                         MonoMethod* helper = mono_marshal_get_stelemref ();
7588                                         MonoInst *iargs [3];
7589                                         handle_loaded_temps (cfg, bblock, stack_start, sp);
7590
7591                                         iargs [2] = sp [2];
7592                                         iargs [1] = sp [1];
7593                                         iargs [0] = sp [0];
7594
7595                                         mono_emit_method_call_spilled (cfg, bblock, helper, mono_method_signature (helper), iargs, ip, NULL);
7596                                 }
7597                         } else {
7598                                 NEW_LDELEMA (cfg, load, sp, klass);
7599                                 load->cil_code = ip;
7600
7601                                 n = mini_type_to_stind (cfg, &klass->byval_arg);
7602                                 /* FIXME: CEE_STIND_R4 */
7603                                 if (n == CEE_STOBJ)
7604                                         handle_stobj (cfg, bblock, load, sp [2], ip, klass, FALSE, FALSE, TRUE);
7605                                 else {
7606                                         MONO_INST_NEW (cfg, ins, n);
7607                                         ins->cil_code = ip;
7608                                         ins->inst_left = load;
7609                                         ins->inst_right = sp [2];
7610                                         handle_loaded_temps (cfg, bblock, stack_start, sp);
7611                                         MONO_ADD_INS (bblock, ins);
7612                                 }
7613                         }
7614                         ip += 5;
7615                         inline_costs += 1;
7616                         break;
7617                 }
7618                 case CEE_STELEM_REF: {
7619                         MonoInst *iargs [3];
7620                         MonoMethod* helper = mono_marshal_get_stelemref ();
7621
7622                         CHECK_STACK (3);
7623                         sp -= 3;
7624                         if (sp [0]->type != STACK_OBJ)
7625                                 UNVERIFIED;
7626                         if (sp [2]->type != STACK_OBJ)
7627                                 UNVERIFIED;
7628
7629                         handle_loaded_temps (cfg, bblock, stack_start, sp);
7630
7631                         /* storing a NULL doesn't need any of the complex checks in stelemref */
7632                         if (sp [2]->opcode == OP_PCONST && sp [2]->inst_p0 == NULL) {
7633                                 MonoInst *load;
7634                                 NEW_LDELEMA (cfg, load, sp, mono_defaults.object_class);
7635                                 load->cil_code = ip;
7636                                 MONO_INST_NEW (cfg, ins, stelem_to_stind [*ip - CEE_STELEM_I]);
7637                                 ins->cil_code = ip;
7638                                 ins->inst_left = load;
7639                                 ins->inst_right = sp [2];
7640                                 MONO_ADD_INS (bblock, ins);
7641                         } else {
7642                                 iargs [2] = sp [2];
7643                                 iargs [1] = sp [1];
7644                                 iargs [0] = sp [0];
7645                         
7646                                 mono_emit_method_call_spilled (cfg, bblock, helper, mono_method_signature (helper), iargs, ip, NULL);
7647                                 inline_costs += 1;
7648                         }
7649
7650                         ++ip;
7651                         break;
7652                 }
7653                 case CEE_CKFINITE: {
7654                         MonoInst *store, *temp;
7655                         CHECK_STACK (1);
7656
7657                         /* this instr. can throw exceptions as side effect,
7658                          * so we cant eliminate dead code which contains CKFINITE opdodes.
7659                          * Spilling to memory makes sure that we always perform
7660                          * this check */
7661
7662                         
7663                         MONO_INST_NEW (cfg, ins, OP_CKFINITE);
7664                         ins->cil_code = ip;
7665                         ins->inst_left = sp [-1];
7666                         temp = mono_compile_create_var (cfg, &mono_defaults.double_class->byval_arg, OP_LOCAL);
7667
7668                         NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
7669                         store->cil_code = ip;
7670                         MONO_ADD_INS (bblock, store);
7671
7672                         NEW_TEMPLOAD (cfg, sp [-1], temp->inst_c0);
7673                        
7674                         ++ip;
7675                         break;
7676                 }
7677                 case CEE_REFANYVAL:
7678                         CHECK_STACK (1);
7679                         MONO_INST_NEW (cfg, ins, *ip);
7680                         --sp;
7681                         CHECK_OPSIZE (5);
7682                         klass = mono_class_get_full (image, read32 (ip + 1), generic_context);
7683                         CHECK_TYPELOAD (klass);
7684                         mono_class_init (klass);
7685                         ins->type = STACK_MP;
7686                         ins->inst_left = *sp;
7687                         ins->klass = klass;
7688                         ins->inst_newa_class = klass;
7689                         ins->cil_code = ip;
7690                         ip += 5;
7691                         *sp++ = ins;
7692                         break;
7693                 case CEE_MKREFANY: {
7694                         MonoInst *loc, *klassconst;
7695
7696                         CHECK_STACK (1);
7697                         MONO_INST_NEW (cfg, ins, *ip);
7698                         --sp;
7699                         CHECK_OPSIZE (5);
7700                         klass = mono_class_get_full (image, read32 (ip + 1), generic_context);
7701                         CHECK_TYPELOAD (klass);
7702                         mono_class_init (klass);
7703                         ins->cil_code = ip;
7704
7705                         if (cfg->generic_sharing_context && mono_class_check_context_used (klass))
7706                                 GENERIC_SHARING_FAILURE (CEE_MKREFANY);
7707
7708                         loc = mono_compile_create_var (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL);
7709                         NEW_TEMPLOADA (cfg, ins->inst_right, loc->inst_c0);
7710
7711                         NEW_PCONST (cfg, klassconst, klass);
7712                         NEW_GROUP (cfg, ins->inst_left, *sp, klassconst);
7713                         
7714                         MONO_ADD_INS (bblock, ins);
7715
7716                         NEW_TEMPLOAD (cfg, *sp, loc->inst_c0);
7717                         ++sp;
7718                         ip += 5;
7719                         break;
7720                 }
7721                 case CEE_LDTOKEN: {
7722                         gpointer handle;
7723                         MonoClass *handle_class;
7724
7725                         CHECK_STACK_OVF (1);
7726
7727                         CHECK_OPSIZE (5);
7728                         n = read32 (ip + 1);
7729
7730                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
7731                                 handle = mono_method_get_wrapper_data (method, n);
7732                                 handle_class = mono_method_get_wrapper_data (method, n + 1);
7733                                 if (handle_class == mono_defaults.typehandle_class)
7734                                         handle = &((MonoClass*)handle)->byval_arg;
7735                         }
7736                         else {
7737                                 handle = mono_ldtoken (image, n, &handle_class, generic_context);
7738                                 if (cfg->generic_sharing_context &&
7739                                                 mono_class_check_context_used (handle_class))
7740                                         GENERIC_SHARING_FAILURE (CEE_LDTOKEN);
7741                         }
7742                         if (!handle)
7743                                 goto load_error;
7744                         mono_class_init (handle_class);
7745
7746                         if (cfg->opt & MONO_OPT_SHARED) {
7747                                 int temp;
7748                                 MonoInst *res, *store, *addr, *vtvar, *iargs [3];
7749
7750                                 GENERIC_SHARING_FAILURE (CEE_LDTOKEN);
7751
7752                                 vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL); 
7753
7754                                 NEW_IMAGECONST (cfg, iargs [0], image);
7755                                 NEW_ICONST (cfg, iargs [1], n);
7756                                 NEW_PCONST (cfg, iargs [2], generic_context);
7757                                 temp = mono_emit_jit_icall (cfg, bblock, mono_ldtoken_wrapper, iargs, ip);
7758                                 NEW_TEMPLOAD (cfg, res, temp);
7759                                 NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
7760                                 NEW_INDSTORE (cfg, store, addr, res, &mono_defaults.int_class->byval_arg);
7761                                 MONO_ADD_INS (bblock, store);
7762                                 NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
7763                         } else {
7764                                 if ((ip [5] == CEE_CALL) && (cmethod = mini_get_method (method, read32 (ip + 6), NULL, generic_context)) &&
7765                                                 (cmethod->klass == mono_defaults.monotype_class->parent) &&
7766                                                 (strcmp (cmethod->name, "GetTypeFromHandle") == 0) && ip_in_bb (cfg, bblock, ip + 5)) {
7767                                         MonoClass *tclass = mono_class_from_mono_type (handle);
7768                                         mono_class_init (tclass);
7769                                         if (cfg->compile_aot)
7770                                                 NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, image, n);
7771                                         else
7772                                                 NEW_PCONST (cfg, ins, mono_type_get_object (cfg->domain, handle));
7773                                         ins->type = STACK_OBJ;
7774                                         ins->klass = cmethod->klass;
7775                                         ip += 5;
7776                                 } else {
7777                                         MonoInst *store, *addr, *vtvar;
7778
7779                                         if (cfg->compile_aot)
7780                                                 NEW_LDTOKENCONST (cfg, ins, image, n);
7781                                         else
7782                                                 NEW_PCONST (cfg, ins, handle);
7783                                         vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL);
7784                                         NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
7785                                         NEW_INDSTORE (cfg, store, addr, ins, &mono_defaults.int_class->byval_arg);
7786                                         MONO_ADD_INS (bblock, store);
7787                                         NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
7788                                 }
7789                         }
7790
7791                         *sp++ = ins;
7792                         ip += 5;
7793                         break;
7794                 }
7795                 case CEE_CONV_U2:
7796                 case CEE_CONV_U1:
7797                 case CEE_CONV_I:
7798                         CHECK_STACK (1);
7799                         ADD_UNOP (*ip);
7800                         ip++;
7801                         break;
7802                 case CEE_ADD_OVF:
7803                 case CEE_ADD_OVF_UN:
7804                 case CEE_MUL_OVF:
7805                 case CEE_MUL_OVF_UN:
7806                 case CEE_SUB_OVF:
7807                 case CEE_SUB_OVF_UN:
7808                         CHECK_STACK (2);
7809                         ADD_BINOP (*ip);
7810                         if (mono_find_jit_opcode_emulation (ins->opcode)) {
7811                                 --sp;
7812                                 *sp++ = emit_tree (cfg, bblock, ins, ip + 1);
7813                         }
7814                         ip++;
7815                         break;
7816                 case CEE_ENDFINALLY:
7817                         MONO_INST_NEW (cfg, ins, OP_ENDFINALLY);
7818                         MONO_ADD_INS (bblock, ins);
7819                         ins->cil_code = ip++;
7820                         start_new_bblock = 1;
7821
7822                         /*
7823                          * Control will leave the method so empty the stack, otherwise
7824                          * the next basic block will start with a nonempty stack.
7825                          */
7826                         while (sp != stack_start) {
7827                                 MONO_INST_NEW (cfg, ins, CEE_POP);
7828                                 ins->cil_code = ip;
7829                                 sp--;
7830                                 ins->inst_i0 = *sp;
7831                                 MONO_ADD_INS (bblock, ins);
7832                         }
7833                         break;
7834                 case CEE_LEAVE:
7835                 case CEE_LEAVE_S: {
7836                         GList *handlers;
7837
7838                         if (*ip == CEE_LEAVE) {
7839                                 CHECK_OPSIZE (5);
7840                                 target = ip + 5 + (gint32)read32(ip + 1);
7841                         } else {
7842                                 CHECK_OPSIZE (2);
7843                                 target = ip + 2 + (signed char)(ip [1]);
7844                         }
7845
7846                         /* empty the stack */
7847                         while (sp != stack_start) {
7848                                 MONO_INST_NEW (cfg, ins, CEE_POP);
7849                                 ins->cil_code = ip;
7850                                 sp--;
7851                                 ins->inst_i0 = *sp;
7852                                 MONO_ADD_INS (bblock, ins);
7853                         }
7854
7855                         /* 
7856                          * If this leave statement is in a catch block, check for a
7857                          * pending exception, and rethrow it if necessary.
7858                          */
7859                         for (i = 0; i < header->num_clauses; ++i) {
7860                                 MonoExceptionClause *clause = &header->clauses [i];
7861
7862                                 /* 
7863                                  * Use <= in the final comparison to handle clauses with multiple
7864                                  * leave statements, like in bug #78024.
7865                                  * The ordering of the exception clauses guarantees that we find the
7866                                  * innermost clause.
7867                                  */
7868                                 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)) {
7869                                         int temp;
7870                                         MonoInst *load;
7871
7872                                         NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, clause->handler_offset)->inst_c0);
7873                                         load->cil_code = ip;
7874
7875                                         temp = mono_emit_jit_icall (cfg, bblock, mono_thread_get_undeniable_exception, NULL, ip);
7876                                         NEW_TEMPLOAD (cfg, *sp, temp);
7877                                 
7878                                         MONO_INST_NEW (cfg, ins, OP_THROW_OR_NULL);
7879                                         ins->inst_left = *sp;
7880                                         ins->inst_right = load;
7881                                         ins->cil_code = ip;
7882                                         MONO_ADD_INS (bblock, ins);
7883                                 }
7884                         }
7885
7886                         if ((handlers = mono_find_final_block (cfg, ip, target, MONO_EXCEPTION_CLAUSE_FINALLY))) {
7887                                 GList *tmp;
7888                                 for (tmp = handlers; tmp; tmp = tmp->next) {
7889                                         tblock = tmp->data;
7890                                         link_bblock (cfg, bblock, tblock);
7891                                         MONO_INST_NEW (cfg, ins, OP_CALL_HANDLER);
7892                                         ins->cil_code = ip;
7893                                         ins->inst_target_bb = tblock;
7894                                         MONO_ADD_INS (bblock, ins);
7895                                 }
7896                                 g_list_free (handlers);
7897                         } 
7898
7899                         MONO_INST_NEW (cfg, ins, OP_BR);
7900                         ins->cil_code = ip;
7901                         MONO_ADD_INS (bblock, ins);
7902                         GET_BBLOCK (cfg, tblock, target);
7903                         link_bblock (cfg, bblock, tblock);
7904                         CHECK_BBLOCK (target, ip, tblock);
7905                         ins->inst_target_bb = tblock;
7906                         start_new_bblock = 1;
7907
7908                         if (*ip == CEE_LEAVE)
7909                                 ip += 5;
7910                         else
7911                                 ip += 2;
7912
7913                         break;
7914                 }
7915                 case CEE_STIND_I:
7916                         CHECK_STACK (2);
7917                         MONO_INST_NEW (cfg, ins, *ip);
7918                         sp -= 2;
7919                         handle_loaded_temps (cfg, bblock, stack_start, sp);
7920                         MONO_ADD_INS (bblock, ins);
7921                         ins->cil_code = ip++;
7922                         ins->inst_i0 = sp [0];
7923                         ins->inst_i1 = sp [1];
7924                         inline_costs += 1;
7925                         break;
7926                 case CEE_CONV_U:
7927                         CHECK_STACK (1);
7928                         ADD_UNOP (*ip);
7929                         ip++;
7930                         break;
7931                 /* trampoline mono specific opcodes */
7932                 case MONO_CUSTOM_PREFIX: {
7933
7934                         g_assert (method->wrapper_type != MONO_WRAPPER_NONE);
7935
7936                         CHECK_OPSIZE (2);
7937                         switch (ip [1]) {
7938
7939                         case CEE_MONO_ICALL: {
7940                                 int temp;
7941                                 gpointer func;
7942                                 MonoJitICallInfo *info;
7943
7944                                 token = read32 (ip + 2);
7945                                 func = mono_method_get_wrapper_data (method, token);
7946                                 info = mono_find_jit_icall_by_addr (func);
7947                                 if (info == NULL){
7948                                         g_error ("An attempt has been made to perform an icall to address %p, "
7949                                                  "but the address has not been registered as an icall\n", info);
7950                                         g_assert_not_reached ();
7951                                 }
7952
7953                                 CHECK_STACK (info->sig->param_count);
7954                                 sp -= info->sig->param_count;
7955
7956                                 temp = mono_emit_jit_icall (cfg, bblock, info->func, sp, ip);
7957                                 if (!MONO_TYPE_IS_VOID (info->sig->ret)) {
7958                                         NEW_TEMPLOAD (cfg, *sp, temp);
7959                                         sp++;
7960                                 }
7961
7962                                 ip += 6;
7963                                 inline_costs += 10 * num_calls++;
7964
7965                                 break;
7966                         }
7967                         case CEE_MONO_LDPTR: {
7968                                 gpointer ptr;
7969
7970                                 CHECK_STACK_OVF (1);
7971                                 CHECK_OPSIZE (6);
7972                                 token = read32 (ip + 2);
7973
7974                                 ptr = mono_method_get_wrapper_data (method, token);
7975                                 if (cfg->compile_aot && cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
7976                                         MonoMethod *wrapped = mono_marshal_method_from_wrapper (cfg->method);
7977
7978                                         if (wrapped && ptr != NULL && mono_lookup_internal_call (wrapped) == ptr) {
7979                                                 NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_ICALL_ADDR, wrapped);
7980                                                 ins->cil_code = ip;
7981                                                 *sp++ = ins;
7982                                                 ip += 6;
7983                                                 break;
7984                                         }
7985                                 }
7986                                 NEW_PCONST (cfg, ins, ptr);
7987                                 ins->cil_code = ip;
7988                                 *sp++ = ins;
7989                                 ip += 6;
7990                                 inline_costs += 10 * num_calls++;
7991                                 /* Can't embed random pointers into AOT code */
7992                                 cfg->disable_aot = 1;
7993                                 break;
7994                         }
7995                         case CEE_MONO_VTADDR:
7996                                 CHECK_STACK (1);
7997                                 --sp;
7998                                 MONO_INST_NEW (cfg, ins, OP_VTADDR);
7999                                 ins->cil_code = ip;
8000                                 ins->type = STACK_MP;
8001                                 ins->inst_left = *sp;
8002                                 *sp++ = ins;
8003                                 ip += 2;
8004                                 break;
8005                         case CEE_MONO_NEWOBJ: {
8006                                 MonoInst *iargs [2];
8007                                 int temp;
8008                                 CHECK_STACK_OVF (1);
8009                                 CHECK_OPSIZE (6);
8010                                 token = read32 (ip + 2);
8011                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
8012                                 mono_class_init (klass);
8013                                 NEW_DOMAINCONST (cfg, iargs [0]);
8014                                 NEW_CLASSCONST (cfg, iargs [1], klass);
8015                                 temp = mono_emit_jit_icall (cfg, bblock, mono_object_new, iargs, ip);
8016                                 NEW_TEMPLOAD (cfg, *sp, temp);
8017                                 sp++;
8018                                 ip += 6;
8019                                 inline_costs += 10 * num_calls++;
8020                                 break;
8021                         }
8022                         case CEE_MONO_OBJADDR:
8023                                 CHECK_STACK (1);
8024                                 --sp;
8025                                 MONO_INST_NEW (cfg, ins, OP_OBJADDR);
8026                                 ins->cil_code = ip;
8027                                 ins->type = STACK_MP;
8028                                 ins->inst_left = *sp;
8029                                 *sp++ = ins;
8030                                 ip += 2;
8031                                 break;
8032                         case CEE_MONO_LDNATIVEOBJ:
8033                                 CHECK_STACK (1);
8034                                 CHECK_OPSIZE (6);
8035                                 token = read32 (ip + 2);
8036                                 klass = mono_method_get_wrapper_data (method, token);
8037                                 g_assert (klass->valuetype);
8038                                 mono_class_init (klass);
8039                                 NEW_INDLOAD (cfg, ins, sp [-1], &klass->byval_arg);
8040                                 sp [-1] = ins;
8041                                 ip += 6;
8042                                 break;
8043                         case CEE_MONO_RETOBJ:
8044                                 g_assert (cfg->ret);
8045                                 g_assert (mono_method_signature (method)->pinvoke); 
8046                                 CHECK_STACK (1);
8047                                 --sp;
8048                                 
8049                                 CHECK_OPSIZE (6);
8050                                 token = read32 (ip + 2);    
8051                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
8052
8053                                 NEW_RETLOADA (cfg, ins);
8054                                 handle_stobj (cfg, bblock, ins, *sp, ip, klass, FALSE, TRUE, FALSE);
8055                                 
8056                                 if (sp != stack_start)
8057                                         UNVERIFIED;
8058                                 
8059                                 MONO_INST_NEW (cfg, ins, OP_BR);
8060                                 ins->cil_code = ip;
8061                                 ins->inst_target_bb = end_bblock;
8062                                 MONO_ADD_INS (bblock, ins);
8063                                 link_bblock (cfg, bblock, end_bblock);
8064                                 start_new_bblock = 1;
8065                                 ip += 6;
8066                                 break;
8067                         case CEE_MONO_CISINST:
8068                         case CEE_MONO_CCASTCLASS: {
8069                                 int token;
8070                                 CHECK_STACK (1);
8071                                 --sp;
8072                                 CHECK_OPSIZE (6);
8073                                 token = read32 (ip + 2);
8074                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
8075                                 MONO_INST_NEW (cfg, ins, (ip [1] == CEE_MONO_CISINST) ? OP_CISINST : OP_CCASTCLASS);
8076                                 ins->type = STACK_I4;
8077                                 ins->inst_left = *sp;
8078                                 ins->inst_newa_class = klass;
8079                                 ins->cil_code = ip;
8080                                 *sp++ = emit_tree (cfg, bblock, ins, ip + 6);
8081                                 ip += 6;
8082                                 break;
8083                         }
8084                         case CEE_MONO_SAVE_LMF:
8085                         case CEE_MONO_RESTORE_LMF:
8086 #ifdef MONO_ARCH_HAVE_LMF_OPS
8087                                 MONO_INST_NEW (cfg, ins, (ip [1] == CEE_MONO_SAVE_LMF) ? OP_SAVE_LMF : OP_RESTORE_LMF);
8088                                 MONO_ADD_INS (bblock, ins);
8089                                 cfg->need_lmf_area = TRUE;
8090 #endif
8091                                 ip += 2;
8092                                 break;
8093                         case CEE_MONO_CLASSCONST:
8094                                 CHECK_STACK_OVF (1);
8095                                 CHECK_OPSIZE (6);
8096                                 token = read32 (ip + 2);
8097                                 NEW_CLASSCONST (cfg, ins, mono_method_get_wrapper_data (method, token));
8098                                 ins->cil_code = ip;
8099                                 *sp++ = ins;
8100                                 ip += 6;
8101                                 inline_costs += 10 * num_calls++;
8102                                 break;
8103                         case CEE_MONO_NOT_TAKEN:
8104                                 bblock->out_of_line = TRUE;
8105                                 ip += 2;
8106                                 break;
8107                         case CEE_MONO_TLS:
8108                                 CHECK_STACK_OVF (1);
8109                                 CHECK_OPSIZE (6);
8110                                 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
8111                                 ins->inst_offset = (gint32)read32 (ip + 2);
8112                                 ins->cil_code = ip;
8113                                 ins->type = STACK_PTR;
8114                                 *sp++ = ins;
8115                                 ip += 6;
8116                                 break;
8117                         default:
8118                                 g_error ("opcode 0x%02x 0x%02x not handled", MONO_CUSTOM_PREFIX, ip [1]);
8119                                 break;
8120                         }
8121                         break;
8122                 }
8123                 case CEE_PREFIX1: {
8124                         CHECK_OPSIZE (2);
8125                         switch (ip [1]) {
8126                         case CEE_ARGLIST: {
8127                                 /* somewhat similar to LDTOKEN */
8128                                 MonoInst *addr, *vtvar;
8129                                 CHECK_STACK_OVF (1);
8130                                 vtvar = mono_compile_create_var (cfg, &mono_defaults.argumenthandle_class->byval_arg, OP_LOCAL); 
8131
8132                                 NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
8133                                 addr->cil_code = ip;
8134                                 MONO_INST_NEW (cfg, ins, OP_ARGLIST);
8135                                 ins->cil_code = ip;
8136                                 ins->inst_left = addr;
8137                                 MONO_ADD_INS (bblock, ins);
8138                                 NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
8139                                 ins->cil_code = ip;
8140                                 *sp++ = ins;
8141                                 ip += 2;
8142                                 break;
8143                         }
8144                         case CEE_CEQ:
8145                         case CEE_CGT:
8146                         case CEE_CGT_UN:
8147                         case CEE_CLT:
8148                         case CEE_CLT_UN: {
8149                                 MonoInst *cmp;
8150                                 CHECK_STACK (2);
8151                                 /*
8152                                  * The following transforms:
8153                                  *    CEE_CEQ    into OP_CEQ
8154                                  *    CEE_CGT    into OP_CGT
8155                                  *    CEE_CGT_UN into OP_CGT_UN
8156                                  *    CEE_CLT    into OP_CLT
8157                                  *    CEE_CLT_UN into OP_CLT_UN
8158                                  */
8159                                 MONO_INST_NEW (cfg, cmp, (OP_CEQ - CEE_CEQ) + ip [1]);
8160                                 
8161                                 MONO_INST_NEW (cfg, ins, cmp->opcode);
8162                                 sp -= 2;
8163                                 cmp->inst_i0 = sp [0];
8164                                 cmp->inst_i1 = sp [1];
8165                                 cmp->cil_code = ip;
8166                                 type_from_op (cmp);
8167                                 CHECK_TYPE (cmp);
8168                                 ins->cil_code = ip;
8169                                 ins->type = STACK_I4;
8170                                 ins->inst_i0 = cmp;
8171 #if MONO_ARCH_SOFT_FLOAT
8172                                 if (sp [0]->type == STACK_R8) {
8173                                         cmp->type = STACK_I4;
8174                                         *sp++ = emit_tree (cfg, bblock, cmp, ip + 2);
8175                                         ip += 2;
8176                                         break;
8177                                 }
8178 #endif
8179                                 if ((sp [0]->type == STACK_I8) || ((sizeof (gpointer) == 8) && ((sp [0]->type == STACK_PTR) || (sp [0]->type == STACK_OBJ) || (sp [0]->type == STACK_MP))))
8180                                         cmp->opcode = OP_LCOMPARE;
8181                                 else
8182                                         cmp->opcode = OP_COMPARE;
8183                                 *sp++ = ins;
8184                                 /* spill it to reduce the expression complexity
8185                                  * and workaround bug 54209 
8186                                  */
8187                                 if (cmp->inst_left->type == STACK_I8) {
8188                                         --sp;
8189                                         *sp++ = emit_tree (cfg, bblock, ins, ip + 2);
8190                                 }
8191                                 ip += 2;
8192                                 break;
8193                         }
8194                         case CEE_LDFTN: {
8195                                 MonoInst *argconst;
8196                                 MonoMethod *cil_method, *ctor_method;
8197                                 int temp;
8198
8199                                 CHECK_STACK_OVF (1);
8200                                 CHECK_OPSIZE (6);
8201                                 n = read32 (ip + 2);
8202                                 cmethod = mini_get_method (method, n, NULL, generic_context);
8203                                 if (!cmethod)
8204                                         goto load_error;
8205                                 mono_class_init (cmethod->klass);
8206
8207                                 if (cfg->generic_sharing_context && mono_method_check_context_used (cmethod))
8208                                         GENERIC_SHARING_FAILURE (CEE_LDFTN);
8209
8210                                 cil_method = cmethod;
8211                                 if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_method (method, cmethod))
8212                                         METHOD_ACCESS_FAILURE;
8213                                 if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS) {
8214                                         if (check_linkdemand (cfg, method, cmethod, bblock, ip))
8215                                                 INLINE_FAILURE;
8216                                         CHECK_CFG_EXCEPTION;
8217                                 } else if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR) {
8218                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod, bblock, ip);
8219                                 }
8220
8221                                 /* 
8222                                  * Optimize the common case of ldftn+delegate creation
8223                                  */
8224 #if defined(MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE) && !defined(HAVE_WRITE_BARRIERS)
8225                                 /* FIXME: SGEN support */
8226                                 if ((sp > stack_start) && (ip + 6 + 5 < end) && ip_in_bb (cfg, bblock, ip + 6) && (ip [6] == CEE_NEWOBJ) && (ctor_method = mini_get_method (method, read32 (ip + 7), NULL, generic_context)) && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
8227                                         MonoInst *target_ins;
8228
8229                                         ip += 6;
8230                                         if (cfg->verbose_level > 3)
8231                                                 g_print ("converting (in B%d: stack: %d) %s", bblock->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
8232                                         target_ins = sp [-1];
8233                                         sp --;
8234                                         *sp = handle_delegate_ctor (cfg, bblock, ctor_method->klass, target_ins, cmethod, ip);
8235                                         ip += 5;                                        
8236                                         sp ++;
8237                                         break;
8238                                 }
8239 #endif
8240
8241                                 handle_loaded_temps (cfg, bblock, stack_start, sp);
8242
8243                                 NEW_METHODCONST (cfg, argconst, cmethod);
8244                                 if (method->wrapper_type != MONO_WRAPPER_SYNCHRONIZED)
8245                                         temp = mono_emit_jit_icall (cfg, bblock, mono_ldftn, &argconst, ip);
8246                                 else
8247                                         temp = mono_emit_jit_icall (cfg, bblock, mono_ldftn_nosync, &argconst, ip);
8248                                 NEW_TEMPLOAD (cfg, *sp, temp);
8249                                 sp ++;
8250                                 
8251                                 ip += 6;
8252                                 inline_costs += 10 * num_calls++;
8253                                 break;
8254                         }
8255                         case CEE_LDVIRTFTN: {
8256                                 MonoInst *args [2];
8257                                 int temp;
8258
8259                                 CHECK_STACK (1);
8260                                 CHECK_OPSIZE (6);
8261                                 n = read32 (ip + 2);
8262                                 cmethod = mini_get_method (method, n, NULL, generic_context);
8263                                 if (!cmethod)
8264                                         goto load_error;
8265                                 mono_class_init (cmethod->klass);
8266
8267                                 if (cfg->generic_sharing_context && mono_method_check_context_used (cmethod))
8268                                         GENERIC_SHARING_FAILURE (CEE_LDVIRTFTN);
8269
8270                                 if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS) {
8271                                         if (check_linkdemand (cfg, method, cmethod, bblock, ip))
8272                                                 INLINE_FAILURE;
8273                                         CHECK_CFG_EXCEPTION;
8274                                 } else if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR) {
8275                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod, bblock, ip);
8276                                 }
8277
8278                                 handle_loaded_temps (cfg, bblock, stack_start, sp);
8279
8280                                 --sp;
8281                                 args [0] = *sp;
8282                                 NEW_METHODCONST (cfg, args [1], cmethod);
8283                                 temp = mono_emit_jit_icall (cfg, bblock, mono_ldvirtfn, args, ip);
8284                                 NEW_TEMPLOAD (cfg, *sp, temp);
8285                                 sp ++;
8286
8287                                 ip += 6;
8288                                 inline_costs += 10 * num_calls++;
8289                                 break;
8290                         }
8291                         case CEE_LDARG:
8292                                 CHECK_STACK_OVF (1);
8293                                 CHECK_OPSIZE (4);
8294                                 n = read16 (ip + 2);
8295                                 CHECK_ARG (n);
8296                                 NEW_ARGLOAD (cfg, ins, n);
8297                                 LDARG_SOFT_FLOAT (cfg, ins, n, ip);
8298                                 ins->cil_code = ip;
8299                                 *sp++ = ins;
8300                                 ip += 4;
8301                                 break;
8302                         case CEE_LDARGA:
8303                                 CHECK_STACK_OVF (1);
8304                                 CHECK_OPSIZE (4);
8305                                 n = read16 (ip + 2);
8306                                 CHECK_ARG (n);
8307                                 NEW_ARGLOADA (cfg, ins, n);
8308                                 ins->cil_code = ip;
8309                                 *sp++ = ins;
8310                                 ip += 4;
8311                                 break;
8312                         case CEE_STARG:
8313                                 CHECK_STACK (1);
8314                                 --sp;
8315                                 handle_loaded_temps (cfg, bblock, stack_start, sp);
8316                                 CHECK_OPSIZE (4);
8317                                 n = read16 (ip + 2);
8318                                 CHECK_ARG (n);
8319                                 NEW_ARGSTORE (cfg, ins, n, *sp);
8320                                 ins->cil_code = ip;
8321                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [n], *sp))
8322                                         UNVERIFIED;
8323                                 STARG_SOFT_FLOAT (cfg, ins, n, ip);
8324                                 if (ins->opcode == CEE_STOBJ) {
8325                                         NEW_ARGLOADA (cfg, ins, n);
8326                                         handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE, FALSE);
8327                                 } else
8328                                         MONO_ADD_INS (bblock, ins);
8329                                 ip += 4;
8330                                 break;
8331                         case CEE_LDLOC:
8332                                 CHECK_STACK_OVF (1);
8333                                 CHECK_OPSIZE (4);
8334                                 n = read16 (ip + 2);
8335                                 CHECK_LOCAL (n);
8336                                 NEW_LOCLOAD (cfg, ins, n);
8337                                 LDLOC_SOFT_FLOAT (cfg, ins, n, ip);
8338                                 ins->cil_code = ip;
8339                                 *sp++ = ins;
8340                                 ip += 4;
8341                                 break;
8342                         case CEE_LDLOCA:
8343                                 CHECK_STACK_OVF (1);
8344                                 CHECK_OPSIZE (4);
8345                                 n = read16 (ip + 2);
8346                                 CHECK_LOCAL (n);
8347                                 NEW_LOCLOADA (cfg, ins, n);
8348                                 ins->cil_code = ip;
8349                                 *sp++ = ins;
8350                                 ip += 4;
8351                                 break;
8352                         case CEE_STLOC:
8353                                 CHECK_STACK (1);
8354                                 --sp;
8355                                 CHECK_OPSIZE (4);
8356                                 n = read16 (ip + 2);
8357                                 CHECK_LOCAL (n);
8358                                 handle_loaded_temps (cfg, bblock, stack_start, sp);
8359                                 NEW_LOCSTORE (cfg, ins, n, *sp);
8360                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
8361                                         UNVERIFIED;
8362                                 ins->cil_code = ip;
8363                                 STLOC_SOFT_FLOAT (cfg, ins, n, ip);
8364                                 if (ins->opcode == CEE_STOBJ) {
8365                                         NEW_LOCLOADA (cfg, ins, n);
8366                                         handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE, FALSE);
8367                                 } else
8368                                         MONO_ADD_INS (bblock, ins);
8369                                 ip += 4;
8370                                 inline_costs += 1;
8371                                 break;
8372                         case CEE_LOCALLOC:
8373                                 CHECK_STACK (1);
8374                                 --sp;
8375                                 if (sp != stack_start) 
8376                                         UNVERIFIED;
8377                                 if (cfg->method != method) 
8378                                         /* 
8379                                          * Inlining this into a loop in a parent could lead to 
8380                                          * stack overflows which is different behavior than the
8381                                          * non-inlined case, thus disable inlining in this case.
8382                                          */
8383                                         goto inline_failure;
8384                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
8385                                 ins->inst_left = *sp;
8386                                 ins->cil_code = ip;
8387                                 ins->type = STACK_PTR;
8388
8389                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
8390                                 if (header->init_locals)
8391                                         ins->flags |= MONO_INST_INIT;
8392
8393                                 *sp++ = ins;
8394                                 ip += 2;
8395                                 /* FIXME: set init flag if locals init is set in this method */
8396                                 break;
8397                         case CEE_ENDFILTER: {
8398                                 MonoExceptionClause *clause, *nearest;
8399                                 int cc, nearest_num;
8400
8401                                 CHECK_STACK (1);
8402                                 --sp;
8403                                 if ((sp != stack_start) || (sp [0]->type != STACK_I4)) 
8404                                         UNVERIFIED;
8405                                 MONO_INST_NEW (cfg, ins, OP_ENDFILTER);
8406                                 ins->inst_left = *sp;
8407                                 ins->cil_code = ip;
8408                                 MONO_ADD_INS (bblock, ins);
8409                                 start_new_bblock = 1;
8410                                 ip += 2;
8411
8412                                 nearest = NULL;
8413                                 nearest_num = 0;
8414                                 for (cc = 0; cc < header->num_clauses; ++cc) {
8415                                         clause = &header->clauses [cc];
8416                                         if ((clause->flags & MONO_EXCEPTION_CLAUSE_FILTER) &&
8417                                                 ((ip - header->code) > clause->data.filter_offset && (ip - header->code) <= clause->handler_offset) &&
8418                                             (!nearest || (clause->data.filter_offset < nearest->data.filter_offset))) {
8419                                                 nearest = clause;
8420                                                 nearest_num = cc;
8421                                         }
8422                                 }
8423                                 g_assert (nearest);
8424                                 if ((ip - header->code) != nearest->handler_offset)
8425                                         UNVERIFIED;
8426
8427                                 break;
8428                         }
8429                         case CEE_UNALIGNED_:
8430                                 ins_flag |= MONO_INST_UNALIGNED;
8431                                 /* FIXME: record alignment? we can assume 1 for now */
8432                                 CHECK_OPSIZE (3);
8433                                 ip += 3;
8434                                 break;
8435                         case CEE_VOLATILE_:
8436                                 ins_flag |= MONO_INST_VOLATILE;
8437                                 ip += 2;
8438                                 break;
8439                         case CEE_TAIL_:
8440                                 ins_flag   |= MONO_INST_TAILCALL;
8441                                 cfg->flags |= MONO_CFG_HAS_TAIL;
8442                                 /* Can't inline tail calls at this time */
8443                                 inline_costs += 100000;
8444                                 ip += 2;
8445                                 break;
8446                         case CEE_INITOBJ:
8447                                 CHECK_STACK (1);
8448                                 --sp;
8449                                 CHECK_OPSIZE (6);
8450                                 token = read32 (ip + 2);
8451                                 klass = mini_get_class (method, token, generic_context);
8452                                 CHECK_TYPELOAD (klass);
8453
8454                                 if (cfg->generic_sharing_context && mono_class_check_context_used (klass))
8455                                         GENERIC_SHARING_FAILURE (CEE_INITOBJ);
8456
8457                                 if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
8458                                         MonoInst *store, *load;
8459                                         NEW_PCONST (cfg, load, NULL);
8460                                         load->cil_code = ip;
8461                                         load->type = STACK_OBJ;
8462                                         load->klass = klass;
8463                                         MONO_INST_NEW (cfg, store, CEE_STIND_REF);
8464                                         store->cil_code = ip;
8465                                         handle_loaded_temps (cfg, bblock, stack_start, sp);
8466                                         MONO_ADD_INS (bblock, store);
8467                                         store->inst_i0 = sp [0];
8468                                         store->inst_i1 = load;
8469                                 } else {
8470                                         handle_initobj (cfg, bblock, *sp, NULL, klass, stack_start, sp);
8471                                 }
8472                                 ip += 6;
8473                                 inline_costs += 1;
8474                                 break;
8475                         case CEE_CONSTRAINED_:
8476                                 /* FIXME: implement */
8477                                 CHECK_OPSIZE (6);
8478                                 token = read32 (ip + 2);
8479                                 constrained_call = mono_class_get_full (image, token, generic_context);
8480                                 CHECK_TYPELOAD (constrained_call);
8481                                 ip += 6;
8482                                 break;
8483                         case CEE_CPBLK:
8484                         case CEE_INITBLK: {
8485                                 MonoInst *iargs [3];
8486                                 CHECK_STACK (3);
8487                                 sp -= 3;
8488                                 if ((cfg->opt & MONO_OPT_INTRINS) && (ip [1] == CEE_CPBLK) && (sp [2]->opcode == OP_ICONST) && ((n = sp [2]->inst_c0) <= sizeof (gpointer) * 5)) {
8489                                         MonoInst *copy;
8490                                         NEW_MEMCPY (cfg, copy, sp [0], sp [1], n, 0);
8491                                         MONO_ADD_INS (bblock, copy);
8492                                         ip += 2;
8493                                         break;
8494                                 }
8495                                 iargs [0] = sp [0];
8496                                 iargs [1] = sp [1];
8497                                 iargs [2] = sp [2];
8498                                 handle_loaded_temps (cfg, bblock, stack_start, sp);
8499                                 if (ip [1] == CEE_CPBLK) {
8500                                         MonoMethod *memcpy_method = get_memcpy_method ();
8501                                         mono_emit_method_call_spilled (cfg, bblock, memcpy_method, memcpy_method->signature, iargs, ip, NULL);
8502                                 } else {
8503                                         MonoMethod *memset_method = get_memset_method ();
8504                                         mono_emit_method_call_spilled (cfg, bblock, memset_method, memset_method->signature, iargs, ip, NULL);
8505                                 }
8506                                 ip += 2;
8507                                 inline_costs += 1;
8508                                 break;
8509                         }
8510                         case CEE_NO_:
8511                                 CHECK_OPSIZE (3);
8512                                 if (ip [2] & 0x1)
8513                                         ins_flag |= MONO_INST_NOTYPECHECK;
8514                                 if (ip [2] & 0x2)
8515                                         ins_flag |= MONO_INST_NORANGECHECK;
8516                                 /* we ignore the no-nullcheck for now since we
8517                                  * really do it explicitly only when doing callvirt->call
8518                                  */
8519                                 ip += 3;
8520                                 break;
8521                         case CEE_RETHROW: {
8522                                 MonoInst *load;
8523                                 int handler_offset = -1;
8524
8525                                 for (i = 0; i < header->num_clauses; ++i) {
8526                                         MonoExceptionClause *clause = &header->clauses [i];
8527                                         if (MONO_OFFSET_IN_HANDLER (clause, ip - header->code) && !(clause->flags & MONO_EXCEPTION_CLAUSE_FINALLY))
8528                                                 handler_offset = clause->handler_offset;
8529                                 }
8530
8531                                 bblock->flags |= BB_EXCEPTION_UNSAFE;
8532
8533                                 g_assert (handler_offset != -1);
8534
8535                                 NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, handler_offset)->inst_c0);
8536                                 load->cil_code = ip;
8537                                 MONO_INST_NEW (cfg, ins, OP_RETHROW);
8538                                 ins->inst_left = load;
8539                                 ins->cil_code = ip;
8540                                 MONO_ADD_INS (bblock, ins);
8541                                 sp = stack_start;
8542                                 link_bblock (cfg, bblock, end_bblock);
8543                                 start_new_bblock = 1;
8544                                 ip += 2;
8545                                 break;
8546                         }
8547                         case CEE_SIZEOF:
8548                                 GENERIC_SHARING_FAILURE (CEE_SIZEOF);
8549
8550                                 CHECK_STACK_OVF (1);
8551                                 CHECK_OPSIZE (6);
8552                                 token = read32 (ip + 2);
8553                                 /* FIXXME: handle generics. */
8554                                 if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC) {
8555                                         MonoType *type = mono_type_create_from_typespec (image, token);
8556                                         token = mono_type_size (type, &ialign);
8557                                 } else {
8558                                         MonoClass *klass = mono_class_get_full (image, token, generic_context);
8559                                         CHECK_TYPELOAD (klass);
8560                                         mono_class_init (klass);
8561                                         token = mono_class_value_size (klass, &align);
8562                                 }
8563                                 NEW_ICONST (cfg, ins, token);
8564                                 ins->cil_code = ip;
8565                                 *sp++= ins;
8566                                 ip += 6;
8567                                 break;
8568                         case CEE_REFANYTYPE:
8569                                 CHECK_STACK (1);
8570                                 MONO_INST_NEW (cfg, ins, OP_REFANYTYPE);
8571                                 --sp;
8572                                 ins->type = STACK_MP;
8573                                 ins->inst_left = *sp;
8574                                 ins->type = STACK_VTYPE;
8575                                 ins->klass = mono_defaults.typehandle_class;
8576                                 ins->cil_code = ip;
8577                                 ip += 2;
8578                                 *sp++ = ins;
8579                                 break;
8580                         case CEE_READONLY_:
8581                                 ip += 2;
8582                                 break;
8583                         default:
8584                                 g_error ("opcode 0xfe 0x%02x not handled", ip [1]);
8585                         }
8586                         break;
8587                 }
8588                 default:
8589                         g_error ("opcode 0x%02x not handled", *ip);
8590                 }
8591         }
8592         if (start_new_bblock != 1)
8593                 UNVERIFIED;
8594
8595         bblock->cil_length = ip - bblock->cil_code;
8596         bblock->next_bb = end_bblock;
8597
8598         if (cfg->method == method && cfg->domainvar) {
8599                 MonoInst *store;
8600                 MonoInst *get_domain;
8601                 
8602                 if (! (get_domain = mono_arch_get_domain_intrinsic (cfg))) {
8603                         MonoCallInst *call;
8604                         
8605                         MONO_INST_NEW_CALL (cfg, call, OP_CALL);
8606                         call->signature = helper_sig_domain_get;
8607                         call->inst.type = STACK_PTR;
8608                         call->fptr = mono_domain_get;
8609                         get_domain = (MonoInst*)call;
8610                 }
8611                 
8612                 NEW_TEMPSTORE (cfg, store, cfg->domainvar->inst_c0, get_domain);
8613                 MONO_ADD_INS (init_localsbb, store);
8614         }
8615
8616         if (cfg->method == method && cfg->got_var)
8617                 mono_emit_load_got_addr (cfg);
8618
8619         if (header->init_locals) {
8620                 MonoInst *store;
8621                 for (i = 0; i < header->num_locals; ++i) {
8622                         MonoType *ptype = header->locals [i];
8623                         int t = ptype->type;
8624                         if (t == MONO_TYPE_VALUETYPE && ptype->data.klass->enumtype)
8625                                 t = ptype->data.klass->enum_basetype->type;
8626                         if (ptype->byref) {
8627                                 NEW_PCONST (cfg, ins, NULL);
8628                                 NEW_LOCSTORE (cfg, store, i, ins);
8629                                 MONO_ADD_INS (init_localsbb, store);
8630                         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
8631                                 NEW_ICONST (cfg, ins, 0);
8632                                 NEW_LOCSTORE (cfg, store, i, ins);
8633                                 MONO_ADD_INS (init_localsbb, store);
8634                         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
8635                                 MONO_INST_NEW (cfg, ins, OP_I8CONST);
8636                                 ins->type = STACK_I8;
8637                                 ins->inst_l = 0;
8638                                 NEW_LOCSTORE (cfg, store, i, ins);
8639                                 MONO_ADD_INS (init_localsbb, store);
8640                         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
8641 #ifdef MONO_ARCH_SOFT_FLOAT
8642                                 /* FIXME: handle init of R4 */
8643 #else
8644                                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
8645                                 ins->type = STACK_R8;
8646                                 ins->inst_p0 = (void*)&r8_0;
8647                                 NEW_LOCSTORE (cfg, store, i, ins);
8648                                 MONO_ADD_INS (init_localsbb, store);
8649 #endif
8650                         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
8651                                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (ptype))) {
8652                                 NEW_LOCLOADA (cfg, ins, i);
8653                                 handle_initobj (cfg, init_localsbb, ins, NULL, mono_class_from_mono_type (ptype), NULL, NULL);
8654                         } else {
8655                                 NEW_PCONST (cfg, ins, NULL);
8656                                 NEW_LOCSTORE (cfg, store, i, ins);
8657                                 MONO_ADD_INS (init_localsbb, store);
8658                         }
8659                 }
8660         }
8661
8662         /* resolve backward branches in the middle of an existing basic block */
8663         for (tmp = bb_recheck; tmp; tmp = tmp->next) {
8664                 bblock = tmp->data;
8665                 /*g_print ("need recheck in %s at IL_%04x\n", method->name, bblock->cil_code - header->code);*/
8666                 tblock = find_previous (cfg->cil_offset_to_bb, header->code_size, start_bblock, bblock->cil_code);
8667                 if (tblock != start_bblock) {
8668                         int l;
8669                         split_bblock (cfg, tblock, bblock);
8670                         l = bblock->cil_code - header->code;
8671                         bblock->cil_length = tblock->cil_length - l;
8672                         tblock->cil_length = l;
8673                 } else {
8674                         g_print ("recheck failed.\n");
8675                 }
8676         }
8677
8678         if (cfg->method == method) {
8679                 MonoBasicBlock *bb;
8680                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
8681                         bb->region = mono_find_block_region (cfg, bb->real_offset);
8682                         if (cfg->spvars)
8683                                 mono_create_spvar_for_region (cfg, bb->region);
8684                         if (cfg->verbose_level > 2)
8685                                 g_print ("REGION BB%d IL_%04x ID_%08X\n", bb->block_num, bb->real_offset, bb->region);
8686                 }
8687         }
8688
8689         g_slist_free (class_inits);
8690         dont_inline = g_list_remove (dont_inline, method);
8691
8692         if (inline_costs < 0) {
8693                 char *mname;
8694
8695                 /* Method is too large */
8696                 mname = mono_method_full_name (method, TRUE);
8697                 cfg->exception_type = MONO_EXCEPTION_INVALID_PROGRAM;
8698                 cfg->exception_message = g_strdup_printf ("Method %s is too complex.", mname);
8699                 g_free (mname);
8700                 return -1;
8701         }
8702
8703         return inline_costs;
8704
8705  exception_exit:
8706         g_assert (cfg->exception_type != MONO_EXCEPTION_NONE);
8707         g_slist_free (class_inits);
8708         dont_inline = g_list_remove (dont_inline, method);
8709         return -1;
8710
8711  inline_failure:
8712         g_slist_free (class_inits);
8713         dont_inline = g_list_remove (dont_inline, method);
8714         return -1;
8715
8716  load_error:
8717         g_slist_free (class_inits);
8718         dont_inline = g_list_remove (dont_inline, method);
8719         cfg->exception_type = MONO_EXCEPTION_TYPE_LOAD;
8720         return -1;
8721
8722  unverified:
8723         g_slist_free (class_inits);
8724         dont_inline = g_list_remove (dont_inline, method);
8725         set_exception_type_from_invalid_il (cfg, method, ip);
8726         return -1;
8727 }
8728
8729 void
8730 mono_print_tree (MonoInst *tree) {
8731         int arity;
8732
8733         if (!tree)
8734                 return;
8735
8736         arity = mono_burg_arity [tree->opcode];
8737
8738         printf (" %s%s", arity?"(":"",  mono_inst_name (tree->opcode));
8739
8740         switch (tree->opcode) {
8741         case OP_ICONST:
8742                 printf ("[%d]", (int)tree->inst_c0);
8743                 break;
8744         case OP_I8CONST:
8745                 printf ("[%lld]", (long long)tree->inst_l);
8746                 break;
8747         case OP_R8CONST:
8748                 printf ("[%f]", *(double*)tree->inst_p0);
8749                 break;
8750         case OP_R4CONST:
8751                 printf ("[%f]", *(float*)tree->inst_p0);
8752                 break;
8753         case OP_ARG:
8754         case OP_LOCAL:
8755                 printf ("[%d]", (int)tree->inst_c0);
8756                 break;
8757         case OP_REGOFFSET:
8758                 if (tree->inst_offset < 0)
8759                         printf ("[-0x%x(%s)]", (int)(-tree->inst_offset), mono_arch_regname (tree->inst_basereg));
8760                 else
8761                         printf ("[0x%x(%s)]", (int)(tree->inst_offset), mono_arch_regname (tree->inst_basereg));
8762                 break;
8763         case OP_REGVAR:
8764                 printf ("[%s]", mono_arch_regname (tree->dreg));
8765                 break;
8766         case CEE_NEWARR:
8767                 printf ("[%s]",  tree->inst_newa_class->name);
8768                 mono_print_tree (tree->inst_newa_len);
8769                 break;
8770         case OP_CALL:
8771         case OP_CALLVIRT:
8772         case OP_FCALL:
8773         case OP_FCALLVIRT:
8774         case OP_LCALL:
8775         case OP_LCALLVIRT:
8776         case OP_VCALL:
8777         case OP_VCALLVIRT:
8778         case OP_VOIDCALL:
8779         case OP_VOIDCALLVIRT:
8780         case OP_TRAMPCALL_VTABLE: {
8781                 MonoCallInst *call = (MonoCallInst*)tree;
8782                 if (call->method)
8783                         printf ("[%s]", call->method->name);
8784                 else if (call->fptr) {
8785                         MonoJitICallInfo *info = mono_find_jit_icall_by_addr (call->fptr);
8786                         if (info)
8787                                 printf ("[%s]", info->name);
8788                 }
8789                 break;
8790         }
8791         case OP_PHI: {
8792                 int i;
8793                 printf ("[%d (", (int)tree->inst_c0);
8794                 for (i = 0; i < tree->inst_phi_args [0]; i++) {
8795                         if (i)
8796                                 printf (", ");
8797                         printf ("%d", tree->inst_phi_args [i + 1]);
8798                 }
8799                 printf (")]");
8800                 break;
8801         }
8802         case OP_RENAME:
8803         case OP_RETARG:
8804         case OP_NOP:
8805         case OP_JMP:
8806         case OP_BREAK:
8807                 break;
8808         case OP_LOAD_MEMBASE:
8809         case OP_LOADI4_MEMBASE:
8810         case OP_LOADU4_MEMBASE:
8811         case OP_LOADU1_MEMBASE:
8812         case OP_LOADI1_MEMBASE:
8813         case OP_LOADU2_MEMBASE:
8814         case OP_LOADI2_MEMBASE:
8815                 printf ("[%s] <- [%s + 0x%x]", mono_arch_regname (tree->dreg), mono_arch_regname (tree->inst_basereg), (int)tree->inst_offset);
8816                 break;
8817         case OP_BR:
8818         case OP_CALL_HANDLER:
8819                 printf ("[B%d]", tree->inst_target_bb->block_num);
8820                 break;
8821         case OP_SWITCH:
8822         case CEE_ISINST:
8823         case CEE_CASTCLASS:
8824         case OP_OUTARG:
8825         case OP_CALL_REG:
8826         case OP_FCALL_REG:
8827         case OP_LCALL_REG:
8828         case OP_VCALL_REG:
8829         case OP_VOIDCALL_REG:
8830                 mono_print_tree (tree->inst_left);
8831                 break;
8832         case CEE_BNE_UN:
8833         case CEE_BEQ:
8834         case CEE_BLT:
8835         case CEE_BLT_UN:
8836         case CEE_BGT:
8837         case CEE_BGT_UN:
8838         case CEE_BGE:
8839         case CEE_BGE_UN:
8840         case CEE_BLE:
8841         case CEE_BLE_UN:
8842                 printf ("[B%dB%d]", tree->inst_true_bb->block_num, tree->inst_false_bb->block_num);
8843                 mono_print_tree (tree->inst_left);
8844                 break;
8845         default:
8846                 if (!mono_arch_print_tree(tree, arity)) {
8847                         if (arity) {
8848                                 mono_print_tree (tree->inst_left);
8849                                 if (arity > 1)
8850                                         mono_print_tree (tree->inst_right);
8851                         }
8852                 }
8853                 break;
8854         }
8855
8856         if (arity)
8857                 printf (")");
8858 }
8859
8860 void
8861 mono_print_tree_nl (MonoInst *tree)
8862 {
8863         mono_print_tree (tree);
8864         printf ("\n");
8865 }
8866
8867 static void
8868 create_helper_signature (void)
8869 {
8870         helper_sig_domain_get = mono_create_icall_signature ("ptr");
8871         helper_sig_class_init_trampoline = mono_create_icall_signature ("void");
8872         helper_sig_generic_class_init_trampoline = mono_create_icall_signature ("void");
8873 }
8874
8875 gconstpointer
8876 mono_icall_get_wrapper (MonoJitICallInfo* callinfo)
8877 {
8878         char *name;
8879         MonoMethod *wrapper;
8880         gconstpointer trampoline;
8881         MonoDomain *domain = mono_get_root_domain ();
8882         
8883         if (callinfo->wrapper) {
8884                 return callinfo->wrapper;
8885         }
8886
8887         if (callinfo->trampoline)
8888                 return callinfo->trampoline;
8889
8890         /* 
8891          * We use the lock on the root domain instead of the JIT lock to protect 
8892          * callinfo->trampoline, since we do a lot of stuff inside the critical section.
8893          */
8894         mono_domain_lock (domain);
8895
8896         if (callinfo->trampoline) {
8897                 mono_domain_unlock (domain);
8898                 return callinfo->trampoline;
8899         }
8900
8901         name = g_strdup_printf ("__icall_wrapper_%s", callinfo->name);
8902         wrapper = mono_marshal_get_icall_wrapper (callinfo->sig, name, callinfo->func, check_for_pending_exc);
8903         g_free (name);
8904
8905         trampoline = mono_create_ftnptr (domain, mono_create_jit_trampoline_in_domain (domain, wrapper));
8906         mono_register_jit_icall_wrapper (callinfo, trampoline);
8907
8908         callinfo->trampoline = trampoline;
8909
8910         mono_domain_unlock (domain);
8911         
8912         return callinfo->trampoline;
8913 }
8914
8915 static void
8916 mono_init_trampolines (void)
8917 {
8918         mono_trampoline_code [MONO_TRAMPOLINE_GENERIC] = mono_arch_create_trampoline_code (MONO_TRAMPOLINE_GENERIC);
8919         mono_trampoline_code [MONO_TRAMPOLINE_JUMP] = mono_arch_create_trampoline_code (MONO_TRAMPOLINE_JUMP);
8920         mono_trampoline_code [MONO_TRAMPOLINE_CLASS_INIT] = mono_arch_create_trampoline_code (MONO_TRAMPOLINE_CLASS_INIT);
8921         mono_trampoline_code [MONO_TRAMPOLINE_GENERIC_CLASS_INIT] = mono_arch_create_trampoline_code (MONO_TRAMPOLINE_GENERIC_CLASS_INIT);
8922 #ifdef MONO_ARCH_AOT_SUPPORTED
8923         mono_trampoline_code [MONO_TRAMPOLINE_AOT] = mono_arch_create_trampoline_code (MONO_TRAMPOLINE_AOT);
8924         mono_trampoline_code [MONO_TRAMPOLINE_AOT_PLT] = mono_arch_create_trampoline_code (MONO_TRAMPOLINE_AOT_PLT);
8925 #endif
8926 #ifdef MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE
8927         mono_trampoline_code [MONO_TRAMPOLINE_DELEGATE] = mono_arch_create_trampoline_code (MONO_TRAMPOLINE_DELEGATE);
8928 #endif
8929 }
8930
8931 static void
8932 mono_init_exceptions (void)
8933 {
8934 #ifndef CUSTOM_EXCEPTION_HANDLING
8935         mono_arch_get_restore_context ();
8936         mono_arch_get_call_filter ();
8937         mono_arch_get_throw_exception ();
8938         mono_arch_get_rethrow_exception ();
8939 #endif
8940 }
8941
8942 guint8 *
8943 mono_get_trampoline_code (MonoTrampolineType tramp_type)
8944 {
8945         return mono_trampoline_code [tramp_type];
8946 }
8947
8948 gpointer
8949 mono_create_class_init_trampoline (MonoVTable *vtable)
8950 {
8951         gpointer code, ptr;
8952
8953         g_assert (!vtable->klass->generic_container);
8954
8955         /* previously created trampoline code */
8956         mono_domain_lock (vtable->domain);
8957         ptr = 
8958                 g_hash_table_lookup (vtable->domain->class_init_trampoline_hash,
8959                                                                   vtable);
8960         mono_domain_unlock (vtable->domain);
8961         if (ptr)
8962                 return ptr;
8963
8964         code = mono_arch_create_specific_trampoline (vtable, MONO_TRAMPOLINE_CLASS_INIT, vtable->domain, NULL);
8965
8966         ptr = mono_create_ftnptr (vtable->domain, code);
8967
8968         /* store trampoline address */
8969         mono_domain_lock (vtable->domain);
8970         g_hash_table_insert (vtable->domain->class_init_trampoline_hash,
8971                                                           vtable, ptr);
8972         mono_domain_unlock (vtable->domain);
8973
8974         mono_jit_lock ();
8975         if (!class_init_hash_addr)
8976                 class_init_hash_addr = g_hash_table_new (NULL, NULL);
8977         g_hash_table_insert (class_init_hash_addr, ptr, vtable);
8978         mono_jit_unlock ();
8979
8980         return ptr;
8981 }
8982
8983 gpointer
8984 mono_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, 
8985                                                          gboolean add_sync_wrapper)
8986 {
8987         MonoJitInfo *ji;
8988         gpointer code;
8989         guint32 code_size;
8990
8991         if (add_sync_wrapper && method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
8992                 return mono_create_jump_trampoline (domain, mono_marshal_get_synchronized_wrapper (method), FALSE);
8993
8994         code = mono_jit_find_compiled_method (domain, method);
8995         if (code)
8996                 return code;
8997
8998         mono_domain_lock (domain);
8999         code = g_hash_table_lookup (domain->jump_trampoline_hash, method);
9000         mono_domain_unlock (domain);
9001         if (code)
9002                 return code;
9003
9004         code = mono_arch_create_specific_trampoline (method, MONO_TRAMPOLINE_JUMP, mono_domain_get (), &code_size);
9005
9006         mono_domain_lock (domain);
9007         ji = mono_mempool_alloc0 (domain->mp, sizeof (MonoJitInfo));
9008         mono_domain_unlock (domain);
9009         ji->code_start = code;
9010         ji->code_size = code_size;
9011         ji->method = method;
9012
9013         /*
9014          * mono_delegate_ctor needs to find the method metadata from the 
9015          * trampoline address, so we save it here.
9016          */
9017
9018         mono_jit_info_table_add (domain, ji);
9019
9020         mono_domain_lock (domain);
9021         g_hash_table_insert (domain->jump_trampoline_hash, method, ji->code_start);
9022         mono_domain_unlock (domain);
9023
9024         return ji->code_start;
9025 }
9026
9027 static gpointer
9028 mono_create_jit_trampoline_in_domain (MonoDomain *domain, MonoMethod *method)
9029 {
9030         gpointer tramp;
9031
9032         mono_domain_lock (domain);
9033         tramp = g_hash_table_lookup (domain->jit_trampoline_hash, method);
9034         mono_domain_unlock (domain);
9035         if (tramp)
9036                 return tramp;
9037
9038         if (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
9039                 return mono_create_jit_trampoline (mono_marshal_get_synchronized_wrapper (method));
9040
9041         tramp = mono_arch_create_specific_trampoline (method, MONO_TRAMPOLINE_GENERIC, domain, NULL);
9042         
9043         mono_domain_lock (domain);
9044         g_hash_table_insert (domain->jit_trampoline_hash, method, tramp);
9045         mono_domain_unlock (domain);
9046
9047         mono_jit_stats.method_trampolines++;
9048
9049         return tramp;
9050 }       
9051
9052 gpointer
9053 mono_create_jit_trampoline (MonoMethod *method)
9054 {
9055         return mono_create_jit_trampoline_in_domain (mono_domain_get (), method);
9056 }
9057
9058 #ifdef MONO_ARCH_HAVE_CREATE_TRAMPOLINE_FROM_TOKEN
9059 gpointer
9060 mono_create_jit_trampoline_from_token (MonoImage *image, guint32 token)
9061 {
9062         gpointer tramp;
9063
9064         MonoDomain *domain = mono_domain_get ();
9065         guint8 *buf, *start;
9066
9067         mono_domain_lock (domain);
9068         buf = start = mono_code_manager_reserve (domain->code_mp, 2 * sizeof (gpointer));
9069         mono_domain_unlock (domain);
9070
9071         *(gpointer*)(gpointer)buf = image;
9072         buf += sizeof (gpointer);
9073         *(guint32*)(gpointer)buf = token;
9074
9075         tramp = mono_arch_create_specific_trampoline (start, MONO_TRAMPOLINE_AOT, domain, NULL);
9076
9077         mono_jit_stats.method_trampolines++;
9078
9079         return tramp;
9080 }       
9081 #endif
9082
9083 gpointer
9084 mono_create_delegate_trampoline (MonoClass *klass)
9085 {
9086 #ifdef MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE
9087         MonoDomain *domain = mono_domain_get ();
9088         gpointer ptr;
9089         guint32 code_size;
9090
9091         mono_domain_lock (domain);
9092         ptr = g_hash_table_lookup (domain->delegate_trampoline_hash, klass);
9093         mono_domain_unlock (domain);
9094         if (ptr)
9095                 return ptr;
9096
9097     ptr = mono_arch_create_specific_trampoline (klass, MONO_TRAMPOLINE_DELEGATE, mono_domain_get (), &code_size);
9098
9099         /* store trampoline address */
9100         mono_domain_lock (domain);
9101         g_hash_table_insert (domain->delegate_trampoline_hash,
9102                                                           klass, ptr);
9103         mono_domain_unlock (domain);
9104
9105         mono_jit_lock ();
9106         if (!delegate_trampoline_hash_addr)
9107                 delegate_trampoline_hash_addr = g_hash_table_new (NULL, NULL);
9108         g_hash_table_insert (delegate_trampoline_hash_addr, ptr, klass);
9109         mono_jit_unlock ();
9110
9111         return ptr;
9112 #else
9113         return NULL;
9114 #endif
9115 }
9116
9117 MonoVTable*
9118 mono_find_class_init_trampoline_by_addr (gconstpointer addr)
9119 {
9120         MonoVTable *res;
9121
9122         mono_jit_lock ();
9123         if (class_init_hash_addr)
9124                 res = g_hash_table_lookup (class_init_hash_addr, addr);
9125         else
9126                 res = NULL;
9127         mono_jit_unlock ();
9128         return res;
9129 }
9130
9131 static MonoClass*
9132 mono_find_delegate_trampoline_by_addr (gconstpointer addr)
9133 {
9134         MonoClass *res;
9135
9136         mono_jit_lock ();
9137         if (delegate_trampoline_hash_addr)
9138                 res = g_hash_table_lookup (delegate_trampoline_hash_addr, addr);
9139         else
9140                 res = NULL;
9141         mono_jit_unlock ();
9142         return res;
9143 }
9144
9145 static void
9146 mono_dynamic_code_hash_insert (MonoDomain *domain, MonoMethod *method, MonoJitDynamicMethodInfo *ji)
9147 {
9148         if (!domain->dynamic_code_hash)
9149                 domain->dynamic_code_hash = g_hash_table_new (NULL, NULL);
9150         g_hash_table_insert (domain->dynamic_code_hash, method, ji);
9151 }
9152
9153 static MonoJitDynamicMethodInfo*
9154 mono_dynamic_code_hash_lookup (MonoDomain *domain, MonoMethod *method)
9155 {
9156         MonoJitDynamicMethodInfo *res;
9157
9158         if (domain->dynamic_code_hash)
9159                 res = g_hash_table_lookup (domain->dynamic_code_hash, method);
9160         else
9161                 res = NULL;
9162         return res;
9163 }
9164
9165 typedef struct {
9166         MonoClass *vtype;
9167         GList *active;
9168         GSList *slots;
9169 } StackSlotInfo;
9170
9171 static inline GSList*
9172 g_slist_prepend_mempool (MonoMemPool *mp, GSList   *list,
9173                                                  gpointer  data)
9174 {
9175   GSList *new_list;
9176
9177   new_list = mono_mempool_alloc (mp, sizeof (GSList));
9178   new_list->data = data;
9179   new_list->next = list;
9180
9181   return new_list;
9182 }
9183
9184 /*
9185  *  mono_allocate_stack_slots_full:
9186  *
9187  *  Allocate stack slots for all non register allocated variables using a
9188  * linear scan algorithm.
9189  * Returns: an array of stack offsets.
9190  * STACK_SIZE is set to the amount of stack space needed.
9191  * STACK_ALIGN is set to the alignment needed by the locals area.
9192  */
9193 gint32*
9194 mono_allocate_stack_slots_full (MonoCompile *m, gboolean backward, guint32 *stack_size, guint32 *stack_align)
9195 {
9196         int i, slot, offset, size;
9197         guint32 align;
9198         MonoMethodVar *vmv;
9199         MonoInst *inst;
9200         gint32 *offsets;
9201         GList *vars = NULL, *l;
9202         StackSlotInfo *scalar_stack_slots, *vtype_stack_slots, *slot_info;
9203         MonoType *t;
9204         int nvtypes;
9205
9206         scalar_stack_slots = mono_mempool_alloc0 (m->mempool, sizeof (StackSlotInfo) * MONO_TYPE_PINNED);
9207         vtype_stack_slots = NULL;
9208         nvtypes = 0;
9209
9210         offsets = mono_mempool_alloc (m->mempool, sizeof (gint32) * m->num_varinfo);
9211         for (i = 0; i < m->num_varinfo; ++i)
9212                 offsets [i] = -1;
9213
9214         for (i = m->locals_start; i < m->num_varinfo; i++) {
9215                 inst = m->varinfo [i];
9216                 vmv = MONO_VARINFO (m, i);
9217
9218                 if ((inst->flags & MONO_INST_IS_DEAD) || inst->opcode == OP_REGVAR || inst->opcode == OP_REGOFFSET)
9219                         continue;
9220
9221                 vars = g_list_prepend (vars, vmv);
9222         }
9223
9224         vars = mono_varlist_sort (m, vars, 0);
9225         offset = 0;
9226         *stack_align = 0;
9227         for (l = vars; l; l = l->next) {
9228                 vmv = l->data;
9229                 inst = m->varinfo [vmv->idx];
9230
9231                 /* inst->backend.is_pinvoke indicates native sized value types, this is used by the
9232                 * pinvoke wrappers when they call functions returning structures */
9233                 if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->inst_vtype->type != MONO_TYPE_TYPEDBYREF)
9234                         size = mono_class_native_size (inst->inst_vtype->data.klass, &align);
9235                 else {
9236                         int ialign;
9237
9238                         size = mono_type_size (inst->inst_vtype, &ialign);
9239                         align = ialign;
9240                 }
9241
9242                 t = mono_type_get_underlying_type (inst->inst_vtype);
9243                 if (t->byref) {
9244                         slot_info = &scalar_stack_slots [MONO_TYPE_I];
9245                 } else {
9246                         switch (t->type) {
9247                         case MONO_TYPE_GENERICINST:
9248                                 if (!mono_type_generic_inst_is_valuetype (t)) {
9249                                         slot_info = &scalar_stack_slots [t->type];
9250                                         break;
9251                                 }
9252                                 /* Fall through */
9253                         case MONO_TYPE_VALUETYPE:
9254                                 if (!vtype_stack_slots)
9255                                         vtype_stack_slots = mono_mempool_alloc0 (m->mempool, sizeof (StackSlotInfo) * 256);
9256                                 for (i = 0; i < nvtypes; ++i)
9257                                         if (t->data.klass == vtype_stack_slots [i].vtype)
9258                                                 break;
9259                                 if (i < nvtypes)
9260                                         slot_info = &vtype_stack_slots [i];
9261                                 else {
9262                                         g_assert (nvtypes < 256);
9263                                         vtype_stack_slots [nvtypes].vtype = t->data.klass;
9264                                         slot_info = &vtype_stack_slots [nvtypes];
9265                                         nvtypes ++;
9266                                 }
9267                                 break;
9268                         case MONO_TYPE_CLASS:
9269                         case MONO_TYPE_OBJECT:
9270                         case MONO_TYPE_ARRAY:
9271                         case MONO_TYPE_SZARRAY:
9272                         case MONO_TYPE_STRING:
9273                         case MONO_TYPE_PTR:
9274                         case MONO_TYPE_I:
9275                         case MONO_TYPE_U:
9276 #if SIZEOF_VOID_P == 4
9277                         case MONO_TYPE_I4:
9278 #else
9279                         case MONO_TYPE_I8:
9280 #endif
9281                                 /* Share non-float stack slots of the same size */
9282                                 slot_info = &scalar_stack_slots [MONO_TYPE_CLASS];
9283                                 break;
9284                         default:
9285                                 slot_info = &scalar_stack_slots [t->type];
9286                         }
9287                 }
9288
9289                 slot = 0xffffff;
9290                 if (m->comp_done & MONO_COMP_LIVENESS) {
9291                         //printf ("START  %2d %08x %08x\n",  vmv->idx, vmv->range.first_use.abs_pos, vmv->range.last_use.abs_pos);
9292                         
9293                         /* expire old intervals in active */
9294                         while (slot_info->active) {
9295                                 MonoMethodVar *amv = (MonoMethodVar *)slot_info->active->data;
9296
9297                                 if (amv->range.last_use.abs_pos > vmv->range.first_use.abs_pos)
9298                                         break;
9299
9300                                 //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);
9301
9302                                 slot_info->active = g_list_delete_link (slot_info->active, slot_info->active);
9303                                 slot_info->slots = g_slist_prepend_mempool (m->mempool, slot_info->slots, GINT_TO_POINTER (offsets [amv->idx]));
9304                         }
9305
9306                         /* 
9307                          * This also handles the case when the variable is used in an
9308                          * exception region, as liveness info is not computed there.
9309                          */
9310                         /* 
9311                          * FIXME: All valuetypes are marked as INDIRECT because of LDADDR
9312                          * opcodes.
9313                          */
9314                         if (! (inst->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT))) {
9315                                 if (slot_info->slots) {
9316                                         slot = GPOINTER_TO_INT (slot_info->slots->data);
9317
9318                                         slot_info->slots = slot_info->slots->next;
9319                                 }
9320
9321                                 slot_info->active = mono_varlist_insert_sorted (m, slot_info->active, vmv, TRUE);
9322                         }
9323                 }
9324
9325                 {
9326                         static int count = 0;
9327                         count ++;
9328
9329                         /*
9330                         if (count == atoi (getenv ("COUNT")))
9331                                 printf ("LAST: %s\n", mono_method_full_name (m->method, TRUE));
9332                         if (count > atoi (getenv ("COUNT")))
9333                                 slot = 0xffffff;
9334                         else {
9335                                 mono_print_tree_nl (inst);
9336                                 }
9337                         */
9338                 }
9339                 if (slot == 0xffffff) {
9340                         /*
9341                          * Allways allocate valuetypes to sizeof (gpointer) to allow more
9342                          * efficient copying (and to work around the fact that OP_MEMCPY
9343                          * and OP_MEMSET ignores alignment).
9344                          */
9345                         if (MONO_TYPE_ISSTRUCT (t))
9346                                 align = sizeof (gpointer);
9347
9348                         if (backward) {
9349                                 offset += size;
9350                                 offset += align - 1;
9351                                 offset &= ~(align - 1);
9352                                 slot = offset;
9353                         }
9354                         else {
9355                                 offset += align - 1;
9356                                 offset &= ~(align - 1);
9357                                 slot = offset;
9358                                 offset += size;
9359                         }
9360
9361                         if (*stack_align == 0)
9362                                 *stack_align = align;
9363                 }
9364
9365                 offsets [vmv->idx] = slot;
9366         }
9367         g_list_free (vars);
9368         for (i = 0; i < MONO_TYPE_PINNED; ++i) {
9369                 if (scalar_stack_slots [i].active)
9370                         g_list_free (scalar_stack_slots [i].active);
9371         }
9372         for (i = 0; i < nvtypes; ++i) {
9373                 if (vtype_stack_slots [i].active)
9374                         g_list_free (vtype_stack_slots [i].active);
9375         }
9376
9377         mono_jit_stats.locals_stack_size += offset;
9378
9379         *stack_size = offset;
9380         return offsets;
9381 }
9382
9383 gint32*
9384 mono_allocate_stack_slots (MonoCompile *m, guint32 *stack_size, guint32 *stack_align)
9385 {
9386         return mono_allocate_stack_slots_full (m, TRUE, stack_size, stack_align);
9387 }
9388
9389 void
9390 mono_register_opcode_emulation (int opcode, const char *name, const char *sigstr, gpointer func, gboolean no_throw)
9391 {
9392         MonoJitICallInfo *info;
9393         MonoMethodSignature *sig = mono_create_icall_signature (sigstr);
9394
9395         if (!emul_opcode_map)
9396                 emul_opcode_map = g_new0 (MonoJitICallInfo*, OP_LAST + 1);
9397
9398         g_assert (!sig->hasthis);
9399         g_assert (sig->param_count < 3);
9400
9401         info = mono_register_jit_icall (func, name, sig, no_throw);
9402
9403         emul_opcode_map [opcode] = info;
9404 }
9405
9406 static void
9407 register_icall (gpointer func, const char *name, const char *sigstr, gboolean save)
9408 {
9409         MonoMethodSignature *sig;
9410
9411         if (sigstr)
9412                 sig = mono_create_icall_signature (sigstr);
9413         else
9414                 sig = NULL;
9415
9416         mono_register_jit_icall (func, name, sig, save);
9417 }
9418
9419 static void
9420 decompose_foreach (MonoInst *tree, gpointer data) 
9421 {
9422         static MonoJitICallInfo *newarr_info = NULL;
9423         static MonoJitICallInfo *newarr_specific_info = NULL;
9424         MonoJitICallInfo *info;
9425         int i;
9426
9427         switch (tree->opcode) {
9428         case CEE_NEWARR: {
9429                 MonoCompile *cfg = data;
9430                 MonoInst *iargs [3];
9431
9432                 if (!newarr_info) {
9433                         newarr_info = mono_find_jit_icall_by_addr (mono_array_new);
9434                         g_assert (newarr_info);
9435                         newarr_specific_info = mono_find_jit_icall_by_addr (mono_array_new_specific);
9436                         g_assert (newarr_specific_info);
9437                 }
9438
9439                 if (cfg->opt & MONO_OPT_SHARED) {
9440                         NEW_DOMAINCONST (cfg, iargs [0]);
9441                         NEW_CLASSCONST (cfg, iargs [1], tree->inst_newa_class);
9442                         iargs [2] = tree->inst_newa_len;
9443
9444                         info = newarr_info;
9445                 }
9446                 else {
9447                         MonoVTable *vtable = mono_class_vtable (cfg->domain, mono_array_class_get (tree->inst_newa_class, 1));
9448
9449                         NEW_VTABLECONST (cfg, iargs [0], vtable);
9450                         iargs [1] = tree->inst_newa_len;
9451
9452                         info = newarr_specific_info;
9453                 }
9454
9455                 mono_emulate_opcode (cfg, tree, iargs, info);
9456
9457                 /* Need to decompose arguments after the the opcode is decomposed */
9458                 for (i = 0; i < info->sig->param_count; ++i)
9459                         dec_foreach (iargs [i], cfg);
9460                 break;
9461         }
9462 #ifdef MONO_ARCH_SOFT_FLOAT
9463         case OP_FBEQ:
9464         case OP_FBGE:
9465         case OP_FBGT:
9466         case OP_FBLE:
9467         case OP_FBLT:
9468         case OP_FBNE_UN:
9469         case OP_FBGE_UN:
9470         case OP_FBGT_UN:
9471         case OP_FBLE_UN:
9472         case OP_FBLT_UN: {
9473                 if ((info = mono_find_jit_opcode_emulation (tree->opcode))) {
9474                         MonoCompile *cfg = data;
9475                         MonoInst *iargs [2];
9476                 
9477                         iargs [0] = tree->inst_i0;
9478                         iargs [1] = tree->inst_i1;
9479                 
9480                         mono_emulate_opcode (cfg, tree, iargs, info);
9481
9482                         dec_foreach (iargs [0], cfg);
9483                         dec_foreach (iargs [1], cfg);
9484                         break;
9485                 } else {
9486                         g_assert_not_reached ();
9487                 }
9488                 break;
9489         }
9490         case OP_FCEQ:
9491         case OP_FCGT:
9492         case OP_FCGT_UN:
9493         case OP_FCLT:
9494         case OP_FCLT_UN: {
9495                 if ((info = mono_find_jit_opcode_emulation (tree->opcode))) {
9496                         MonoCompile *cfg = data;
9497                         MonoInst *iargs [2];
9498
9499                         /* the args are in the compare opcode ... */
9500                         iargs [0] = tree->inst_i0;
9501                         iargs [1] = tree->inst_i1;
9502                 
9503                         mono_emulate_opcode (cfg, tree, iargs, info);
9504
9505                         dec_foreach (iargs [0], cfg);
9506                         dec_foreach (iargs [1], cfg);
9507                         break;
9508                 } else {
9509                         g_assert_not_reached ();
9510                 }
9511                 break;
9512         }
9513 #endif
9514
9515         default:
9516                 break;
9517         }
9518 }
9519
9520 void
9521 mono_inst_foreach (MonoInst *tree, MonoInstFunc func, gpointer data) {
9522
9523         switch (mono_burg_arity [tree->opcode]) {
9524         case 0: break;
9525         case 1: 
9526                 mono_inst_foreach (tree->inst_left, func, data);
9527                 break;
9528         case 2: 
9529                 mono_inst_foreach (tree->inst_left, func, data);
9530                 mono_inst_foreach (tree->inst_right, func, data);
9531                 break;
9532         default:
9533                 g_assert_not_reached ();
9534         }
9535         func (tree, data);
9536 }
9537
9538 G_GNUC_UNUSED
9539 static void
9540 mono_print_bb_code (MonoBasicBlock *bb)
9541 {
9542         MonoInst *c;
9543
9544         MONO_BB_FOR_EACH_INS (bb, c) {
9545                 mono_print_tree (c);
9546                 g_print ("\n");
9547         }
9548 }
9549
9550 static void
9551 print_dfn (MonoCompile *cfg) {
9552         int i, j;
9553         char *code;
9554         MonoBasicBlock *bb;
9555
9556         g_print ("IR code for method %s\n", mono_method_full_name (cfg->method, TRUE));
9557
9558         for (i = 0; i < cfg->num_bblocks; ++i) {
9559                 MonoInst *c;
9560
9561                 bb = cfg->bblocks [i];
9562                 /*if (bb->cil_code) {
9563                         char* code1, *code2;
9564                         code1 = mono_disasm_code_one (NULL, cfg->method, bb->cil_code, NULL);
9565                         if (bb->last_ins->cil_code)
9566                                 code2 = mono_disasm_code_one (NULL, cfg->method, bb->last_ins->cil_code, NULL);
9567                         else
9568                                 code2 = g_strdup ("");
9569
9570                         code1 [strlen (code1) - 1] = 0;
9571                         code = g_strdup_printf ("%s -> %s", code1, code2);
9572                         g_free (code1);
9573                         g_free (code2);
9574                 } else*/
9575                         code = g_strdup ("\n");
9576                 g_print ("\nBB%d DFN%d (len: %d): %s", bb->block_num, i, bb->cil_length, code);
9577                 MONO_BB_FOR_EACH_INS (bb, c) {
9578                         mono_print_tree (c);
9579                         g_print ("\n");
9580                 }
9581
9582                 g_print ("\tprev:");
9583                 for (j = 0; j < bb->in_count; ++j) {
9584                         g_print (" BB%d", bb->in_bb [j]->block_num);
9585                 }
9586                 g_print ("\t\tsucc:");
9587                 for (j = 0; j < bb->out_count; ++j) {
9588                         g_print (" BB%d", bb->out_bb [j]->block_num);
9589                 }
9590                 g_print ("\n\tidom: BB%d\n", bb->idom? bb->idom->block_num: -1);
9591
9592                 if (bb->idom)
9593                         g_assert (mono_bitset_test_fast (bb->dominators, bb->idom->dfn));
9594
9595                 if (bb->dominators)
9596                         mono_blockset_print (cfg, bb->dominators, "\tdominators", bb->idom? bb->idom->dfn: -1);
9597                 if (bb->dfrontier)
9598                         mono_blockset_print (cfg, bb->dfrontier, "\tdfrontier", -1);
9599                 g_free (code);
9600         }
9601
9602         g_print ("\n");
9603 }
9604
9605 void
9606 mono_bblock_add_inst (MonoBasicBlock *bb, MonoInst *inst)
9607 {
9608         MONO_INST_LIST_ADD_TAIL (&inst->node, &bb->ins_list);
9609 }
9610
9611 void
9612 mono_destroy_compile (MonoCompile *cfg)
9613 {
9614         //mono_mempool_stats (cfg->mempool);
9615         mono_free_loop_info (cfg);
9616         if (cfg->rs)
9617                 mono_regstate_free (cfg->rs);
9618         if (cfg->spvars)
9619                 g_hash_table_destroy (cfg->spvars);
9620         if (cfg->exvars)
9621                 g_hash_table_destroy (cfg->exvars);
9622         mono_mempool_destroy (cfg->mempool);
9623         g_list_free (cfg->ldstr_list);
9624         g_hash_table_destroy (cfg->token_info_hash);
9625
9626         g_free (cfg->varinfo);
9627         g_free (cfg->vars);
9628         g_free (cfg->exception_message);
9629         g_free (cfg);
9630 }
9631
9632 #ifdef HAVE_KW_THREAD
9633 static __thread gpointer mono_lmf_addr MONO_TLS_FAST;
9634 #ifdef MONO_ARCH_ENABLE_MONO_LMF_VAR
9635 /* 
9636  * When this is defined, the current lmf is stored in this tls variable instead of in 
9637  * jit_tls->lmf.
9638  */
9639 static __thread gpointer mono_lmf MONO_TLS_FAST;
9640 #endif
9641 #endif
9642
9643 guint32
9644 mono_get_jit_tls_key (void)
9645 {
9646         return mono_jit_tls_id;
9647 }
9648
9649 gint32
9650 mono_get_lmf_tls_offset (void)
9651 {
9652 #if defined(HAVE_KW_THREAD) && defined(MONO_ARCH_ENABLE_MONO_LMF_VAR)
9653         int offset;
9654         MONO_THREAD_VAR_OFFSET(mono_lmf,offset);
9655         return offset;
9656 #else
9657         return -1;
9658 #endif
9659 }
9660
9661 gint32
9662 mono_get_lmf_addr_tls_offset (void)
9663 {
9664         int offset;
9665         MONO_THREAD_VAR_OFFSET(mono_lmf_addr,offset);
9666         return offset;
9667 }
9668
9669 MonoLMF *
9670 mono_get_lmf (void)
9671 {
9672 #if defined(HAVE_KW_THREAD) && defined(MONO_ARCH_ENABLE_MONO_LMF_VAR)
9673         return mono_lmf;
9674 #else
9675         MonoJitTlsData *jit_tls;
9676
9677         if ((jit_tls = TlsGetValue (mono_jit_tls_id)))
9678                 return jit_tls->lmf;
9679
9680         g_assert_not_reached ();
9681         return NULL;
9682 #endif
9683 }
9684
9685 MonoLMF **
9686 mono_get_lmf_addr (void)
9687 {
9688 #ifdef HAVE_KW_THREAD
9689         return mono_lmf_addr;
9690 #else
9691         MonoJitTlsData *jit_tls;
9692
9693         if ((jit_tls = TlsGetValue (mono_jit_tls_id)))
9694                 return &jit_tls->lmf;
9695
9696         g_assert_not_reached ();
9697         return NULL;
9698 #endif
9699 }
9700
9701 /* Called by native->managed wrappers */
9702 void
9703 mono_jit_thread_attach (MonoDomain *domain)
9704 {
9705 #ifdef HAVE_KW_THREAD
9706         if (!mono_lmf_addr) {
9707                 mono_thread_attach (domain);
9708         }
9709 #else
9710         if (!TlsGetValue (mono_jit_tls_id))
9711                 mono_thread_attach (domain);
9712 #endif
9713         if (mono_domain_get () != domain)
9714                 mono_domain_set (domain, TRUE);
9715 }       
9716
9717 /**
9718  * mono_thread_abort:
9719  * @obj: exception object
9720  *
9721  * abort the thread, print exception information and stack trace
9722  */
9723 static void
9724 mono_thread_abort (MonoObject *obj)
9725 {
9726         /* MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id); */
9727         
9728         /* handle_remove should be eventually called for this thread, too
9729         g_free (jit_tls);*/
9730
9731         if ((mono_runtime_unhandled_exception_policy_get () == MONO_UNHANLED_POLICY_LEGACY) ||
9732                         (obj->vtable->klass == mono_defaults.threadabortexception_class)) {
9733                 mono_thread_exit ();
9734         } else {
9735                 exit (mono_environment_exitcode_get ());
9736         }
9737 }
9738
9739 static void*
9740 setup_jit_tls_data (gpointer stack_start, gpointer abort_func)
9741 {
9742         MonoJitTlsData *jit_tls;
9743         MonoLMF *lmf;
9744
9745         jit_tls = TlsGetValue (mono_jit_tls_id);
9746         if (jit_tls)
9747                 return jit_tls;
9748
9749         jit_tls = g_new0 (MonoJitTlsData, 1);
9750
9751         TlsSetValue (mono_jit_tls_id, jit_tls);
9752
9753         jit_tls->abort_func = abort_func;
9754         jit_tls->end_of_stack = stack_start;
9755
9756         lmf = g_new0 (MonoLMF, 1);
9757 #ifdef MONO_ARCH_INIT_TOP_LMF_ENTRY
9758         MONO_ARCH_INIT_TOP_LMF_ENTRY (lmf);
9759 #else
9760         lmf->ebp = -1;
9761 #endif
9762
9763         jit_tls->first_lmf = lmf;
9764
9765 #if defined(HAVE_KW_THREAD) && defined(MONO_ARCH_ENABLE_MONO_LMF_VAR)
9766         /* jit_tls->lmf is unused */
9767         mono_lmf = lmf;
9768         mono_lmf_addr = &mono_lmf;
9769 #else
9770 #if defined(HAVE_KW_THREAD)
9771         mono_lmf_addr = &jit_tls->lmf;  
9772 #endif
9773
9774         jit_tls->lmf = lmf;
9775 #endif
9776
9777         mono_arch_setup_jit_tls_data (jit_tls);
9778         mono_setup_altstack (jit_tls);
9779
9780         return jit_tls;
9781 }
9782
9783 static void
9784 mono_thread_start_cb (gsize tid, gpointer stack_start, gpointer func)
9785 {
9786         MonoThread *thread;
9787         void *jit_tls = setup_jit_tls_data (stack_start, mono_thread_abort);
9788         thread = mono_thread_current ();
9789         mono_debugger_thread_created (tid, thread, jit_tls);
9790         if (thread)
9791                 thread->jit_data = jit_tls;
9792 }
9793
9794 void (*mono_thread_attach_aborted_cb ) (MonoObject *obj) = NULL;
9795
9796 static void
9797 mono_thread_abort_dummy (MonoObject *obj)
9798 {
9799   if (mono_thread_attach_aborted_cb)
9800     mono_thread_attach_aborted_cb (obj);
9801   else
9802     mono_thread_abort (obj);
9803 }
9804
9805 static void
9806 mono_thread_attach_cb (gsize tid, gpointer stack_start)
9807 {
9808         MonoThread *thread;
9809         void *jit_tls = setup_jit_tls_data (stack_start, mono_thread_abort_dummy);
9810         thread = mono_thread_current ();
9811         mono_debugger_thread_created (tid, thread, (MonoJitTlsData *) jit_tls);
9812         if (thread)
9813                 thread->jit_data = jit_tls;
9814         if (mono_profiler_get_events () & MONO_PROFILE_STATISTICAL)
9815                 setup_stat_profiler ();
9816 }
9817
9818 static void
9819 mini_thread_cleanup (MonoThread *thread)
9820 {
9821         MonoJitTlsData *jit_tls = thread->jit_data;
9822
9823         if (jit_tls) {
9824                 mono_debugger_thread_cleanup (jit_tls);
9825                 mono_arch_free_jit_tls_data (jit_tls);
9826
9827                 mono_free_altstack (jit_tls);
9828                 g_free (jit_tls->first_lmf);
9829                 g_free (jit_tls);
9830                 thread->jit_data = NULL;
9831                 TlsSetValue (mono_jit_tls_id, NULL);
9832         }
9833 }
9834
9835 void
9836 mono_add_patch_info (MonoCompile *cfg, int ip, MonoJumpInfoType type, gconstpointer target)
9837 {
9838         MonoJumpInfo *ji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo));
9839
9840         ji->ip.i = ip;
9841         ji->type = type;
9842         ji->data.target = target;
9843         ji->next = cfg->patch_info;
9844
9845         cfg->patch_info = ji;
9846 }
9847
9848 void
9849 mono_remove_patch_info (MonoCompile *cfg, int ip)
9850 {
9851         MonoJumpInfo **ji = &cfg->patch_info;
9852
9853         while (*ji) {
9854                 if ((*ji)->ip.i == ip)
9855                         *ji = (*ji)->next;
9856                 else
9857                         ji = &((*ji)->next);
9858         }
9859 }
9860
9861 /**
9862  * mono_patch_info_dup_mp:
9863  *
9864  * Make a copy of PATCH_INFO, allocating memory from the mempool MP.
9865  */
9866 MonoJumpInfo*
9867 mono_patch_info_dup_mp (MonoMemPool *mp, MonoJumpInfo *patch_info)
9868 {
9869         MonoJumpInfo *res = mono_mempool_alloc (mp, sizeof (MonoJumpInfo));
9870         memcpy (res, patch_info, sizeof (MonoJumpInfo));
9871
9872         switch (patch_info->type) {
9873         case MONO_PATCH_INFO_RVA:
9874         case MONO_PATCH_INFO_LDSTR:
9875         case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
9876         case MONO_PATCH_INFO_LDTOKEN:
9877         case MONO_PATCH_INFO_DECLSEC:
9878                 res->data.token = mono_mempool_alloc (mp, sizeof (MonoJumpInfoToken));
9879                 memcpy (res->data.token, patch_info->data.token, sizeof (MonoJumpInfoToken));
9880                 break;
9881         case MONO_PATCH_INFO_SWITCH:
9882                 res->data.table = mono_mempool_alloc (mp, sizeof (MonoJumpInfoBBTable));
9883                 memcpy (res->data.table, patch_info->data.table, sizeof (MonoJumpInfoBBTable));
9884                 break;
9885         default:
9886                 break;
9887         }
9888
9889         return res;
9890 }
9891
9892 guint
9893 mono_patch_info_hash (gconstpointer data)
9894 {
9895         const MonoJumpInfo *ji = (MonoJumpInfo*)data;
9896
9897         switch (ji->type) {
9898         case MONO_PATCH_INFO_RVA:
9899         case MONO_PATCH_INFO_LDSTR:
9900         case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
9901         case MONO_PATCH_INFO_LDTOKEN:
9902         case MONO_PATCH_INFO_DECLSEC:
9903                 return (ji->type << 8) | ji->data.token->token;
9904         case MONO_PATCH_INFO_VTABLE:
9905         case MONO_PATCH_INFO_CLASS:
9906         case MONO_PATCH_INFO_IID:
9907         case MONO_PATCH_INFO_ADJUSTED_IID:
9908                 return (ji->type << 8) | (gssize)ji->data.klass;
9909         case MONO_PATCH_INFO_FIELD:
9910         case MONO_PATCH_INFO_SFLDA:
9911                 return (ji->type << 8) | (gssize)ji->data.field;
9912         case MONO_PATCH_INFO_METHODCONST:
9913         case MONO_PATCH_INFO_METHOD:
9914         case MONO_PATCH_INFO_METHOD_JUMP:
9915                 return (ji->type << 8) | (gssize)ji->data.method;
9916         case MONO_PATCH_INFO_IMAGE:
9917                 return (ji->type << 8) | (gssize)ji->data.image;                
9918         default:
9919                 return (ji->type << 8);
9920         }
9921 }
9922
9923 /* 
9924  * mono_patch_info_equal:
9925  * 
9926  * This might fail to recognize equivalent patches, i.e. floats, so its only
9927  * usable in those cases where this is not a problem, i.e. sharing GOT slots
9928  * in AOT.
9929  */
9930 gint
9931 mono_patch_info_equal (gconstpointer ka, gconstpointer kb)
9932 {
9933         const MonoJumpInfo *ji1 = (MonoJumpInfo*)ka;
9934         const MonoJumpInfo *ji2 = (MonoJumpInfo*)kb;
9935
9936         if (ji1->type != ji2->type)
9937                 return 0;
9938
9939         switch (ji1->type) {
9940         case MONO_PATCH_INFO_RVA:
9941         case MONO_PATCH_INFO_LDSTR:
9942         case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
9943         case MONO_PATCH_INFO_LDTOKEN:
9944         case MONO_PATCH_INFO_DECLSEC:
9945                 if ((ji1->data.token->image != ji2->data.token->image) ||
9946                         (ji1->data.token->token != ji2->data.token->token))
9947                         return 0;
9948                 break;
9949         default:
9950                 if (ji1->data.name != ji2->data.name)
9951                         return 0;
9952                 break;
9953         }
9954
9955         return 1;
9956 }
9957
9958 gpointer
9959 mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *patch_info, gboolean run_cctors)
9960 {
9961         unsigned char *ip = patch_info->ip.i + code;
9962         gconstpointer target = NULL;
9963
9964         switch (patch_info->type) {
9965         case MONO_PATCH_INFO_BB:
9966                 target = patch_info->data.bb->native_offset + code;
9967                 break;
9968         case MONO_PATCH_INFO_ABS:
9969                 target = patch_info->data.target;
9970                 break;
9971         case MONO_PATCH_INFO_LABEL:
9972                 target = patch_info->data.inst->inst_c0 + code;
9973                 break;
9974         case MONO_PATCH_INFO_IP:
9975                 target = ip;
9976                 break;
9977         case MONO_PATCH_INFO_METHOD_REL:
9978                 target = code + patch_info->data.offset;
9979                 break;
9980         case MONO_PATCH_INFO_INTERNAL_METHOD: {
9981                 MonoJitICallInfo *mi = mono_find_jit_icall_by_name (patch_info->data.name);
9982                 if (!mi) {
9983                         g_warning ("unknown MONO_PATCH_INFO_INTERNAL_METHOD %s", patch_info->data.name);
9984                         g_assert_not_reached ();
9985                 }
9986                 target = mono_icall_get_wrapper (mi);
9987                 break;
9988         }
9989         case MONO_PATCH_INFO_METHOD_JUMP: {
9990                 GSList *list;
9991
9992                 /* get the trampoline to the method from the domain */
9993                 target = mono_create_jump_trampoline (domain, patch_info->data.method, TRUE);
9994                 if (!domain->jump_target_hash)
9995                         domain->jump_target_hash = g_hash_table_new (NULL, NULL);
9996                 list = g_hash_table_lookup (domain->jump_target_hash, patch_info->data.method);
9997                 list = g_slist_prepend (list, ip);
9998                 g_hash_table_insert (domain->jump_target_hash, patch_info->data.method, list);
9999                 break;
10000         }
10001         case MONO_PATCH_INFO_METHOD:
10002                 if (patch_info->data.method == method) {
10003                         target = code;
10004                 } else
10005                         /* get the trampoline to the method from the domain */
10006                         target = mono_create_jit_trampoline (patch_info->data.method);
10007                 break;
10008         case MONO_PATCH_INFO_SWITCH: {
10009                 gpointer *jump_table;
10010                 int i;
10011
10012                 if (method && method->dynamic) {
10013                         jump_table = mono_code_manager_reserve (mono_dynamic_code_hash_lookup (domain, method)->code_mp, sizeof (gpointer) * patch_info->data.table->table_size);
10014                 } else {
10015                         mono_domain_lock (domain);
10016                         jump_table = mono_code_manager_reserve (domain->code_mp, sizeof (gpointer) * patch_info->data.table->table_size);
10017                         mono_domain_unlock (domain);
10018                 }
10019
10020                 for (i = 0; i < patch_info->data.table->table_size; i++) {
10021                         jump_table [i] = code + GPOINTER_TO_INT (patch_info->data.table->table [i]);
10022                 }
10023                 target = jump_table;
10024                 break;
10025         }
10026         case MONO_PATCH_INFO_METHODCONST:
10027         case MONO_PATCH_INFO_CLASS:
10028         case MONO_PATCH_INFO_IMAGE:
10029         case MONO_PATCH_INFO_FIELD:
10030                 target = patch_info->data.target;
10031                 break;
10032         case MONO_PATCH_INFO_IID:
10033                 mono_class_init (patch_info->data.klass);
10034                 target = GINT_TO_POINTER ((int)patch_info->data.klass->interface_id);
10035                 break;
10036         case MONO_PATCH_INFO_ADJUSTED_IID:
10037                 mono_class_init (patch_info->data.klass);
10038                 target = GINT_TO_POINTER ((int)(-((patch_info->data.klass->interface_id + 1) * SIZEOF_VOID_P)));
10039                 break;
10040         case MONO_PATCH_INFO_VTABLE:
10041                 target = mono_class_vtable (domain, patch_info->data.klass);
10042                 break;
10043         case MONO_PATCH_INFO_CLASS_INIT:
10044                 target = mono_create_class_init_trampoline (mono_class_vtable (domain, patch_info->data.klass));
10045                 break;
10046         case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE:
10047                 target = mono_create_delegate_trampoline (patch_info->data.klass);
10048                 break;
10049         case MONO_PATCH_INFO_SFLDA: {
10050                 MonoVTable *vtable = mono_class_vtable (domain, patch_info->data.field->parent);
10051                 if (!vtable->initialized && !(vtable->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) && (method && mono_class_needs_cctor_run (vtable->klass, method)))
10052                         /* Done by the generated code */
10053                         ;
10054                 else {
10055                         if (run_cctors)
10056                                 mono_runtime_class_init (vtable);
10057                 }
10058                 target = (char*)vtable->data + patch_info->data.field->offset;
10059                 break;
10060         }
10061         case MONO_PATCH_INFO_RVA:
10062                 target = mono_image_rva_map (patch_info->data.token->image, patch_info->data.token->token);
10063                 break;
10064         case MONO_PATCH_INFO_R4:
10065         case MONO_PATCH_INFO_R8:
10066                 target = patch_info->data.target;
10067                 break;
10068         case MONO_PATCH_INFO_EXC_NAME:
10069                 target = patch_info->data.name;
10070                 break;
10071         case MONO_PATCH_INFO_LDSTR:
10072                 target =
10073                         mono_ldstr (domain, patch_info->data.token->image, 
10074                                                 mono_metadata_token_index (patch_info->data.token->token));
10075                 break;
10076         case MONO_PATCH_INFO_TYPE_FROM_HANDLE: {
10077                 gpointer handle;
10078                 MonoClass *handle_class;
10079
10080                 handle = mono_ldtoken (patch_info->data.token->image, 
10081                                        patch_info->data.token->token, &handle_class, NULL);
10082                 mono_class_init (handle_class);
10083                 mono_class_init (mono_class_from_mono_type (handle));
10084
10085                 target =
10086                         mono_type_get_object (domain, handle);
10087                 break;
10088         }
10089         case MONO_PATCH_INFO_LDTOKEN: {
10090                 gpointer handle;
10091                 MonoClass *handle_class;
10092                 
10093                 handle = mono_ldtoken (patch_info->data.token->image,
10094                                        patch_info->data.token->token, &handle_class, NULL);
10095                 mono_class_init (handle_class);
10096                 
10097                 target = handle;
10098                 break;
10099         }
10100         case MONO_PATCH_INFO_DECLSEC:
10101                 target = (mono_metadata_blob_heap (patch_info->data.token->image, patch_info->data.token->token) + 2);
10102                 break;
10103         case MONO_PATCH_INFO_ICALL_ADDR:
10104                 target = mono_lookup_internal_call (patch_info->data.method);
10105                 break;
10106         case MONO_PATCH_INFO_BB_OVF:
10107         case MONO_PATCH_INFO_EXC_OVF:
10108         case MONO_PATCH_INFO_GOT_OFFSET:
10109         case MONO_PATCH_INFO_NONE:
10110                 break;
10111         default:
10112                 g_assert_not_reached ();
10113         }
10114
10115         return (gpointer)target;
10116 }
10117
10118 static void
10119 dec_foreach (MonoInst *tree, MonoCompile *cfg) {
10120         MonoJitICallInfo *info;
10121
10122         decompose_foreach (tree, cfg);
10123
10124         switch (mono_burg_arity [tree->opcode]) {
10125         case 0: break;
10126         case 1: 
10127                 dec_foreach (tree->inst_left, cfg);
10128
10129                 if ((info = mono_find_jit_opcode_emulation (tree->opcode))) {
10130                         MonoInst *iargs [2];
10131                 
10132                         iargs [0] = tree->inst_left;
10133
10134                         mono_emulate_opcode (cfg, tree, iargs, info);
10135                         return;
10136                 }
10137
10138                 break;
10139         case 2:
10140 #ifdef MONO_ARCH_BIGMUL_INTRINS
10141                 if (tree->opcode == OP_LMUL
10142                                 && (cfg->opt & MONO_OPT_INTRINS)
10143                                 && (tree->inst_left->opcode == CEE_CONV_I8 
10144                                         || tree->inst_left->opcode == CEE_CONV_U8)
10145                                 && tree->inst_left->inst_left->type == STACK_I4
10146                                 && (tree->inst_right->opcode == CEE_CONV_I8 
10147                                         || tree->inst_right->opcode == CEE_CONV_U8)
10148                                 && tree->inst_right->inst_left->type == STACK_I4
10149                                 && tree->inst_left->opcode == tree->inst_right->opcode) {
10150                         tree->opcode = (tree->inst_left->opcode == CEE_CONV_I8 ? OP_BIGMUL: OP_BIGMUL_UN);
10151                         tree->inst_left = tree->inst_left->inst_left;
10152                         tree->inst_right = tree->inst_right->inst_left;
10153                         dec_foreach (tree, cfg);
10154                 } else 
10155 #endif
10156                         if ((info = mono_find_jit_opcode_emulation (tree->opcode))) {
10157                         MonoInst *iargs [2];
10158                 
10159                         iargs [0] = tree->inst_i0;
10160                         iargs [1] = tree->inst_i1;
10161                 
10162                         mono_emulate_opcode (cfg, tree, iargs, info);
10163
10164                         dec_foreach (iargs [0], cfg);
10165                         dec_foreach (iargs [1], cfg);
10166                         return;
10167                 } else {
10168                         dec_foreach (tree->inst_left, cfg);
10169                         dec_foreach (tree->inst_right, cfg);
10170                 }
10171                 break;
10172         default:
10173                 g_assert_not_reached ();
10174         }
10175 }
10176
10177 static void
10178 decompose_pass (MonoCompile *cfg) {
10179         MonoBasicBlock *bb;
10180
10181         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
10182                 MonoInst *tree;
10183                 cfg->cbb = bb;
10184                 cfg->prev_ins = NULL;
10185                 MONO_BB_FOR_EACH_INS (cfg->cbb, tree) {
10186                         dec_foreach (tree, cfg);
10187                         cfg->prev_ins = tree;
10188                 }
10189         }
10190 }
10191
10192 static void
10193 nullify_basic_block (MonoBasicBlock *bb) 
10194 {
10195         bb->in_count = 0;
10196         bb->out_count = 0;
10197         bb->in_bb = NULL;
10198         bb->out_bb = NULL;
10199         bb->next_bb = NULL;
10200         MONO_INST_LIST_INIT (&bb->ins_list);
10201         bb->cil_code = NULL;
10202 }
10203
10204 static void 
10205 replace_out_block (MonoBasicBlock *bb, MonoBasicBlock *orig,  MonoBasicBlock *repl)
10206 {
10207         int i;
10208
10209         for (i = 0; i < bb->out_count; i++) {
10210                 MonoBasicBlock *ob = bb->out_bb [i];
10211                 if (ob == orig) {
10212                         if (!repl) {
10213                                 if (bb->out_count > 1) {
10214                                         bb->out_bb [i] = bb->out_bb [bb->out_count - 1];
10215                                 }
10216                                 bb->out_count--;
10217                         } else {
10218                                 bb->out_bb [i] = repl;
10219                         }
10220                 }
10221         }
10222 }
10223
10224 static void 
10225 replace_in_block (MonoBasicBlock *bb, MonoBasicBlock *orig, MonoBasicBlock *repl)
10226 {
10227         int i;
10228
10229         for (i = 0; i < bb->in_count; i++) {
10230                 MonoBasicBlock *ib = bb->in_bb [i];
10231                 if (ib == orig) {
10232                         if (!repl) {
10233                                 if (bb->in_count > 1) {
10234                                         bb->in_bb [i] = bb->in_bb [bb->in_count - 1];
10235                                 }
10236                                 bb->in_count--;
10237                         } else {
10238                                 bb->in_bb [i] = repl;
10239                         }
10240                 }
10241         }
10242 }
10243
10244 static void
10245 replace_out_block_in_code (MonoBasicBlock *bb, MonoBasicBlock *orig, MonoBasicBlock *repl) {
10246         MonoInst *inst;
10247         
10248         MONO_BB_FOR_EACH_INS (bb, inst) {
10249                 if (inst->opcode == OP_CALL_HANDLER) {
10250                         if (inst->inst_target_bb == orig)
10251                                 inst->inst_target_bb = repl;
10252                 }
10253         }
10254
10255         inst = mono_inst_list_last (&bb->ins_list);
10256         if (!inst)
10257                 return;
10258
10259         switch (inst->opcode) {
10260         case OP_BR:
10261                 if (inst->inst_target_bb == orig)
10262                         inst->inst_target_bb = repl;
10263                 break;
10264         case OP_SWITCH: {
10265                 int i;
10266                 int n = GPOINTER_TO_INT (inst->klass);
10267                 for (i = 0; i < n; i++ ) {
10268                         if (inst->inst_many_bb [i] == orig)
10269                                 inst->inst_many_bb [i] = repl;
10270                 }
10271                 break;
10272         }
10273         case CEE_BNE_UN:
10274         case CEE_BEQ:
10275         case CEE_BLT:
10276         case CEE_BLT_UN:
10277         case CEE_BGT:
10278         case CEE_BGT_UN:
10279         case CEE_BGE:
10280         case CEE_BGE_UN:
10281         case CEE_BLE:
10282         case CEE_BLE_UN:
10283                 if (inst->inst_true_bb == orig)
10284                         inst->inst_true_bb = repl;
10285                 if (inst->inst_false_bb == orig)
10286                         inst->inst_false_bb = repl;
10287                 break;
10288         default:
10289                 break;
10290         }
10291 }
10292
10293 static void 
10294 replace_basic_block (MonoBasicBlock *bb, MonoBasicBlock *orig,  MonoBasicBlock *repl)
10295 {
10296         int i, j;
10297
10298         for (i = 0; i < bb->out_count; i++) {
10299                 MonoBasicBlock *ob = bb->out_bb [i];
10300                 for (j = 0; j < ob->in_count; j++) {
10301                         if (ob->in_bb [j] == orig) {
10302                                 ob->in_bb [j] = repl;
10303                         }
10304                 }
10305         }
10306
10307 }
10308
10309 /**
10310   * Check if a bb is useless (is just made of NOPs and ends with an
10311   * unconditional branch, or nothing).
10312   * If it is so, unlink it from the CFG and nullify it, and return TRUE.
10313   * Otherwise, return FALSE;
10314   */
10315 static gboolean
10316 remove_block_if_useless (MonoCompile *cfg, MonoBasicBlock *bb, MonoBasicBlock *previous_bb) {
10317         MonoBasicBlock *target_bb = NULL;
10318         MonoInst *inst;
10319         
10320         /* Do not touch handlers */
10321         if (bb->region != -1) {
10322                 bb->not_useless = TRUE;
10323                 return FALSE;
10324         }
10325         
10326         MONO_BB_FOR_EACH_INS (bb, inst) {
10327                 switch (inst->opcode) {
10328                 case OP_NOP:
10329                         break;
10330                 case OP_BR:
10331                         target_bb = inst->inst_target_bb;
10332                         break;
10333                 default:
10334                         bb->not_useless = TRUE;
10335                         return FALSE;
10336                 }
10337         }
10338         
10339         if (target_bb == NULL) {
10340                 if ((bb->out_count == 1) && (bb->out_bb [0] == bb->next_bb)) {
10341                         target_bb = bb->next_bb;
10342                 } else {
10343                         /* Do not touch empty BBs that do not "fall through" to their next BB (like the exit BB) */
10344                         return FALSE;
10345                 }
10346         }
10347         
10348         /* Do not touch BBs following a switch (they are the "default" branch) */
10349         inst = mono_inst_list_last (&previous_bb->ins_list);
10350         if (inst && inst->opcode == OP_SWITCH)
10351                 return FALSE;
10352         
10353         /* Do not touch BBs following the entry BB and jumping to something that is not */
10354         /* thiry "next" bb (the entry BB cannot contain the branch) */
10355         if ((previous_bb == cfg->bb_entry) && (bb->next_bb != target_bb)) {
10356                 return FALSE;
10357         }
10358
10359         /* 
10360          * Do not touch BBs following a try block as the code in 
10361          * mini_method_compile needs them to compute the length of the try block.
10362          */
10363         if (MONO_BBLOCK_IS_IN_REGION (previous_bb, MONO_REGION_TRY))
10364                 return FALSE;
10365         
10366         /* Check that there is a target BB, and that bb is not an empty loop (Bug 75061) */
10367         if ((target_bb != NULL) && (target_bb != bb)) {
10368                 MonoInst *last_ins;
10369                 int i;
10370
10371                 if (cfg->verbose_level > 1) {
10372                         printf ("remove_block_if_useless %s, removed BB%d\n", mono_method_full_name (cfg->method, TRUE), bb->block_num);
10373                 }
10374                 
10375                 /* unlink_bblock () modifies the bb->in_bb array so can't use a for loop here */
10376                 while (bb->in_count) {
10377                         MonoBasicBlock *in_bb = bb->in_bb [0];
10378                         mono_unlink_bblock (cfg, in_bb, bb);
10379                         link_bblock (cfg, in_bb, target_bb);
10380                         replace_out_block_in_code (in_bb, bb, target_bb);
10381                 }
10382                 
10383                 mono_unlink_bblock (cfg, bb, target_bb);
10384                 
10385                 last_ins = mono_inst_list_last (&previous_bb->ins_list);
10386
10387                 if ((previous_bb != cfg->bb_entry) &&
10388                                 (previous_bb->region == bb->region) &&
10389                                 ((last_ins == NULL) ||
10390                                 ((last_ins->opcode != OP_BR) &&
10391                                 (!(MONO_IS_COND_BRANCH_OP (last_ins))) &&
10392                                 (last_ins->opcode != OP_SWITCH)))) {
10393                         for (i = 0; i < previous_bb->out_count; i++) {
10394                                 if (previous_bb->out_bb [i] == target_bb) {
10395                                         MonoInst *jump;
10396                                         MONO_INST_NEW (cfg, jump, OP_BR);
10397                                         MONO_ADD_INS (previous_bb, jump);
10398                                         jump->cil_code = previous_bb->cil_code;
10399                                         jump->inst_target_bb = target_bb;
10400                                         break;
10401                                 }
10402                         }
10403                 }
10404                 
10405                 previous_bb->next_bb = bb->next_bb;
10406                 nullify_basic_block (bb);
10407                 
10408                 return TRUE;
10409         } else {
10410                 return FALSE;
10411         }
10412 }
10413
10414 static void
10415 merge_basic_blocks (MonoBasicBlock *bb, MonoBasicBlock *bbn) 
10416 {
10417         MonoInst *last_ins;
10418
10419         bb->out_count = bbn->out_count;
10420         bb->out_bb = bbn->out_bb;
10421
10422         replace_basic_block (bb, bbn, bb);
10423
10424         last_ins = mono_inst_list_last (&bb->ins_list);
10425
10426         /* Nullify branch at the end of bb */
10427         if (last_ins && MONO_IS_BRANCH_OP (last_ins))
10428                 last_ins->opcode = OP_NOP;
10429
10430         MONO_INST_LIST_SPLICE_TAIL_INIT (&bbn->ins_list, &bb->ins_list);
10431
10432         bb->next_bb = bbn->next_bb;
10433         nullify_basic_block (bbn);
10434 }
10435
10436 static void
10437 move_basic_block_to_end (MonoCompile *cfg, MonoBasicBlock *bb)
10438 {
10439         MonoBasicBlock *bbn, *next;
10440         MonoInst *last_ins;
10441
10442         next = bb->next_bb;
10443
10444         /* Find the previous */
10445         for (bbn = cfg->bb_entry; bbn->next_bb && bbn->next_bb != bb; bbn = bbn->next_bb)
10446                 ;
10447         if (bbn->next_bb) {
10448                 bbn->next_bb = bb->next_bb;
10449         }
10450
10451         /* Find the last */
10452         for (bbn = cfg->bb_entry; bbn->next_bb; bbn = bbn->next_bb)
10453                 ;
10454         bbn->next_bb = bb;
10455         bb->next_bb = NULL;
10456
10457         last_ins = mono_inst_list_last (&bb->ins_list);
10458
10459         /* Add a branch */
10460         if (next && (!last_ins || (last_ins->opcode != OP_NOT_REACHED))) {
10461                 MonoInst *ins;
10462
10463                 MONO_INST_NEW (cfg, ins, OP_BR);
10464                 MONO_ADD_INS (bb, ins);
10465                 link_bblock (cfg, bb, next);
10466                 ins->inst_target_bb = next;
10467         }               
10468 }
10469
10470 /* checks that a and b represent the same instructions, conservatively,
10471  * it can return FALSE also for two trees that are equal.
10472  * FIXME: also make sure there are no side effects.
10473  */
10474 static int
10475 same_trees (MonoInst *a, MonoInst *b)
10476 {
10477         int arity;
10478         if (a->opcode != b->opcode)
10479                 return FALSE;
10480         arity = mono_burg_arity [a->opcode];
10481         if (arity == 1) {
10482                 if (a->ssa_op == b->ssa_op && a->ssa_op == MONO_SSA_LOAD && a->inst_i0 == b->inst_i0)
10483                         return TRUE;
10484                 return same_trees (a->inst_left, b->inst_left);
10485         } else if (arity == 2) {
10486                 return same_trees (a->inst_left, b->inst_left) && same_trees (a->inst_right, b->inst_right);
10487         } else if (arity == 0) {
10488                 switch (a->opcode) {
10489                 case OP_ICONST:
10490                         return a->inst_c0 == b->inst_c0;
10491                 default:
10492                         return FALSE;
10493                 }
10494         }
10495         return FALSE;
10496 }
10497
10498 static int
10499 get_unsigned_condbranch (int opcode)
10500 {
10501         switch (opcode) {
10502         case CEE_BLE: return CEE_BLE_UN;
10503         case CEE_BLT: return CEE_BLT_UN;
10504         case CEE_BGE: return CEE_BGE_UN;
10505         case CEE_BGT: return CEE_BGT_UN;
10506         }
10507         g_assert_not_reached ();
10508         return 0;
10509 }
10510
10511 static int
10512 tree_is_unsigned (MonoInst* ins) {
10513         switch (ins->opcode) {
10514         case OP_ICONST:
10515                 return (int)ins->inst_c0 >= 0;
10516         /* array lengths are positive as are string sizes */
10517         case CEE_LDLEN:
10518         case OP_STRLEN:
10519                 return TRUE;
10520         case CEE_CONV_U1:
10521         case CEE_CONV_U2:
10522         case CEE_CONV_U4:
10523         case CEE_CONV_OVF_U1:
10524         case CEE_CONV_OVF_U2:
10525         case CEE_CONV_OVF_U4:
10526                 return TRUE;
10527         case CEE_LDIND_U1:
10528         case CEE_LDIND_U2:
10529         case CEE_LDIND_U4:
10530                 return TRUE;
10531         default:
10532                 return FALSE;
10533         }
10534 }
10535
10536 /* check if an unsigned compare can be used instead of two signed compares
10537  * for (val < 0 || val > limit) conditionals.
10538  * Returns TRUE if the optimization has been applied.
10539  * Note that this can't be applied if the second arg is not positive...
10540  */
10541 static int
10542 try_unsigned_compare (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *bb_last)
10543 {
10544         MonoBasicBlock *truet, *falset;
10545         MonoInst *cmp_inst = bb_last->inst_left;
10546         MonoInst *condb;
10547         if (!cmp_inst->inst_right->inst_c0 == 0)
10548                 return FALSE;
10549         truet = bb_last->inst_true_bb;
10550         falset = bb_last->inst_false_bb;
10551         if (falset->in_count != 1)
10552                 return FALSE;
10553         condb = mono_inst_list_last (&falset->ins_list);
10554         /* target bb must have one instruction */
10555         if (!condb || (condb->node.next != &falset->ins_list))
10556                 return FALSE;
10557         if ((((condb->opcode == CEE_BLE || condb->opcode == CEE_BLT) && (condb->inst_false_bb == truet))
10558                         || ((condb->opcode == CEE_BGE || condb->opcode == CEE_BGT) && (condb->inst_true_bb == truet)))
10559                         && same_trees (cmp_inst->inst_left, condb->inst_left->inst_left)) {
10560                 if (!tree_is_unsigned (condb->inst_left->inst_right))
10561                         return FALSE;
10562                 condb->opcode = get_unsigned_condbranch (condb->opcode);
10563                 /* change the original condbranch to just point to the new unsigned check */
10564                 bb_last->opcode = OP_BR;
10565                 bb_last->inst_target_bb = falset;
10566                 replace_out_block (bb, truet, NULL);
10567                 replace_in_block (truet, bb, NULL);
10568                 return TRUE;
10569         }
10570         return FALSE;
10571 }
10572
10573 /*
10574  * Optimizes the branches on the Control Flow Graph
10575  *
10576  */
10577 static void
10578 optimize_branches (MonoCompile *cfg)
10579 {
10580         int i, changed = FALSE;
10581         MonoBasicBlock *bb, *bbn;
10582         guint32 niterations;
10583
10584         /*
10585          * Some crazy loops could cause the code below to go into an infinite
10586          * loop, see bug #53003 for an example. To prevent this, we put an upper
10587          * bound on the number of iterations.
10588          */
10589         if (cfg->num_bblocks > 1000)
10590                 niterations = cfg->num_bblocks * 2;
10591         else
10592                 niterations = 1000;
10593
10594         do {
10595                 MonoBasicBlock *previous_bb;
10596                 changed = FALSE;
10597                 niterations --;
10598
10599                 /* we skip the entry block (exit is handled specially instead ) */
10600                 for (previous_bb = cfg->bb_entry, bb = cfg->bb_entry->next_bb; bb; previous_bb = bb, bb = bb->next_bb) {
10601                         MonoInst *last_ins;
10602
10603                         /* dont touch code inside exception clauses */
10604                         if (bb->region != -1)
10605                                 continue;
10606
10607                         if (!bb->not_useless && remove_block_if_useless (cfg, bb, previous_bb)) {
10608                                 changed = TRUE;
10609                                 continue;
10610                         }
10611
10612                         if ((bbn = bb->next_bb) && bbn->in_count == 0 && bb->region == bbn->region) {
10613                                 if (cfg->verbose_level > 2)
10614                                         g_print ("nullify block triggered %d\n", bbn->block_num);
10615
10616                                 bb->next_bb = bbn->next_bb;
10617
10618                                 for (i = 0; i < bbn->out_count; i++)
10619                                         replace_in_block (bbn->out_bb [i], bbn, NULL);
10620
10621                                 nullify_basic_block (bbn);                      
10622                                 changed = TRUE;
10623                         }
10624
10625                         last_ins = mono_inst_list_last (&bb->ins_list);
10626                         if (bb->out_count == 1) {
10627                                 bbn = bb->out_bb [0];
10628
10629                                 /* conditional branches where true and false targets are the same can be also replaced with OP_BR */
10630                                 if (last_ins && MONO_IS_COND_BRANCH_OP (last_ins)) {
10631                                         MonoInst *pop;
10632                                         MONO_INST_NEW (cfg, pop, CEE_POP);
10633                                         pop->inst_left = last_ins->inst_left->inst_left;
10634                                         mono_add_ins_to_end (bb, pop);
10635                                         MONO_INST_NEW (cfg, pop, CEE_POP);
10636                                         pop->inst_left = last_ins->inst_left->inst_right;
10637                                         mono_add_ins_to_end (bb, pop);
10638                                         last_ins->opcode = OP_BR;
10639                                         last_ins->inst_target_bb = last_ins->inst_true_bb;
10640                                         changed = TRUE;
10641                                         if (cfg->verbose_level > 2)
10642                                                 g_print ("cond branch removal triggered in %d %d\n", bb->block_num, bb->out_count);
10643                                 }
10644
10645                                 if (bb->region == bbn->region && bb->next_bb == bbn) {
10646                                         /* the block are in sequence anyway ... */
10647
10648                                         /* branches to the following block can be removed */
10649                                         if (last_ins && last_ins->opcode == OP_BR) {
10650                                                 last_ins->opcode = OP_NOP;
10651                                                 changed = TRUE;
10652                                                 if (cfg->verbose_level > 2)
10653                                                         g_print ("br removal triggered %d -> %d\n", bb->block_num, bbn->block_num);
10654                                         }
10655
10656                                         if (bbn->in_count == 1) {
10657
10658                                                 if (bbn != cfg->bb_exit) {
10659                                                         if (cfg->verbose_level > 2)
10660                                                                 g_print ("block merge triggered %d -> %d\n", bb->block_num, bbn->block_num);
10661                                                         merge_basic_blocks (bb, bbn);
10662                                                         changed = TRUE;
10663                                                         continue;
10664                                                 }
10665
10666                                                 //mono_print_bb_code (bb);
10667                                         }
10668                                 }
10669                         }
10670                         if ((bbn = bb->next_bb) && bbn->in_count == 0 && bb->region == bbn->region) {
10671                                 if (cfg->verbose_level > 2) {
10672                                         g_print ("nullify block triggered %d\n", bbn->block_num);
10673                                 }
10674                                 bb->next_bb = bbn->next_bb;
10675
10676                                 for (i = 0; i < bbn->out_count; i++)
10677                                         replace_in_block (bbn->out_bb [i], bbn, NULL);
10678
10679                                 nullify_basic_block (bbn);                      
10680                                 changed = TRUE;
10681                                 continue;
10682                         }
10683
10684                         if (bb->out_count == 1) {
10685                                 bbn = bb->out_bb [0];
10686
10687                                 if (last_ins && last_ins->opcode == OP_BR) {
10688                                         MonoInst *bbn_code;
10689
10690                                         bbn = last_ins->inst_target_bb;
10691                                         bbn_code = mono_inst_list_first (&bbn->ins_list);
10692                                         if (bb->region == bbn->region && bbn_code &&
10693                                                         bbn_code->opcode == OP_BR &&
10694                                                         bbn_code->inst_target_bb->region == bb->region) {
10695                                                 if (cfg->verbose_level > 2)
10696                                                         g_print ("in %s branch to branch triggered %d -> %d -> %d\n", cfg->method->name, 
10697                                                                  bb->block_num, bbn->block_num, bbn_code->inst_target_bb->block_num);
10698
10699                                                 replace_in_block (bbn, bb, NULL);
10700                                                 replace_out_block (bb, bbn, bbn_code->inst_target_bb);
10701                                                 link_bblock (cfg, bb, bbn_code->inst_target_bb);
10702                                                 last_ins->inst_target_bb = bbn_code->inst_target_bb;
10703                                                 changed = TRUE;
10704                                                 continue;
10705                                         }
10706                                 }
10707                         } else if (bb->out_count == 2) {
10708                                 if (last_ins && MONO_IS_COND_BRANCH_NOFP (last_ins)) {
10709                                         int branch_result = mono_eval_cond_branch (last_ins);
10710                                         MonoBasicBlock *taken_branch_target = NULL, *untaken_branch_target = NULL;
10711                                         MonoInst *bbn_code;
10712
10713                                         if (branch_result == BRANCH_TAKEN) {
10714                                                 taken_branch_target = last_ins->inst_true_bb;
10715                                                 untaken_branch_target = last_ins->inst_false_bb;
10716                                         } else if (branch_result == BRANCH_NOT_TAKEN) {
10717                                                 taken_branch_target = last_ins->inst_false_bb;
10718                                                 untaken_branch_target = last_ins->inst_true_bb;
10719                                         }
10720                                         if (taken_branch_target) {
10721                                                 /* if mono_eval_cond_branch () is ever taken to handle 
10722                                                  * non-constant values to compare, issue a pop here.
10723                                                  */
10724                                                 last_ins->opcode = OP_BR;
10725                                                 last_ins->inst_target_bb = taken_branch_target;
10726                                                 mono_unlink_bblock (cfg, bb, untaken_branch_target);
10727                                                 changed = TRUE;
10728                                                 continue;
10729                                         }
10730                                         bbn = last_ins->inst_true_bb;
10731                                         bbn_code = mono_inst_list_first (&bbn->ins_list);
10732                                         if (bb->region == bbn->region && bbn_code && bbn_code->opcode == OP_BR &&
10733                                                         bbn_code->inst_target_bb->region == bb->region) {
10734                                                 if (cfg->verbose_level > 2)             
10735                                                         g_print ("cbranch1 to branch triggered %d -> (%d) %d (0x%02x)\n", 
10736                                                                  bb->block_num, bbn->block_num, bbn_code->inst_target_bb->block_num, 
10737                                                                  bbn_code->opcode);
10738
10739                                                 /* 
10740                                                  * Unlink, then relink bblocks to avoid various
10741                                                  * tricky situations when the two targets of the branch
10742                                                  * are equal, or will become equal after the change.
10743                                                  */
10744                                                 mono_unlink_bblock (cfg, bb, last_ins->inst_true_bb);
10745                                                 mono_unlink_bblock (cfg, bb, last_ins->inst_false_bb);
10746
10747                                                 last_ins->inst_true_bb = bbn_code->inst_target_bb;
10748
10749                                                 link_bblock (cfg, bb, last_ins->inst_true_bb);
10750                                                 link_bblock (cfg, bb, last_ins->inst_false_bb);
10751
10752                                                 changed = TRUE;
10753                                                 continue;
10754                                         }
10755
10756                                         bbn = last_ins->inst_false_bb;
10757                                         bbn_code = mono_inst_list_first (&bbn->ins_list);
10758                                         if (bb->region == bbn->region && bbn_code && bbn_code->opcode == OP_BR &&
10759                                                         bbn_code->inst_target_bb->region == bb->region) {
10760                                                 if (cfg->verbose_level > 2)
10761                                                         g_print ("cbranch2 to branch triggered %d -> (%d) %d (0x%02x)\n", 
10762                                                                  bb->block_num, bbn->block_num, bbn_code->inst_target_bb->block_num, 
10763                                                                  bbn_code->opcode);
10764
10765                                                 mono_unlink_bblock (cfg, bb, last_ins->inst_true_bb);
10766                                                 mono_unlink_bblock (cfg, bb, last_ins->inst_false_bb);
10767
10768                                                 last_ins->inst_false_bb = bbn_code->inst_target_bb;
10769
10770                                                 link_bblock (cfg, bb, last_ins->inst_true_bb);
10771                                                 link_bblock (cfg, bb, last_ins->inst_false_bb);
10772
10773                                                 changed = TRUE;
10774                                                 continue;
10775                                         }
10776                                 }
10777
10778                                 /* detect and optimize to unsigned compares checks like: if (v < 0 || v > limit */
10779                                 if (last_ins && last_ins->opcode == CEE_BLT && last_ins->inst_left->inst_right->opcode == OP_ICONST) {
10780                                         if (try_unsigned_compare (cfg, bb, last_ins)) {
10781                                                 /*g_print ("applied in bb %d (->%d) %s\n", bb->block_num, last_ins->inst_target_bb->block_num, mono_method_full_name (cfg->method, TRUE));*/
10782                                                 changed = TRUE;
10783                                                 continue;
10784                                         }
10785                                 }
10786
10787                                 if (last_ins && MONO_IS_COND_BRANCH_NOFP (last_ins)) {
10788                                         if (last_ins->inst_false_bb->out_of_line && (bb->region == last_ins->inst_false_bb->region)) {
10789                                                 /* Reverse the branch */
10790                                                 last_ins->opcode = reverse_branch_op (last_ins->opcode);
10791                                                 bbn = last_ins->inst_false_bb;
10792                                                 last_ins->inst_false_bb = last_ins->inst_true_bb;
10793                                                 last_ins->inst_true_bb = bbn;
10794
10795                                                 move_basic_block_to_end (cfg, last_ins->inst_true_bb);
10796                                                 if (cfg->verbose_level > 2)
10797                                                         g_print ("cbranch to throw block triggered %d.\n", 
10798                                                                          bb->block_num);
10799                                         }
10800                                 }
10801                         }
10802                 }
10803         } while (changed && (niterations > 0));
10804
10805 }
10806
10807 static void
10808 mono_compile_create_vars (MonoCompile *cfg)
10809 {
10810         MonoMethodSignature *sig;
10811         MonoMethodHeader *header;
10812         int i;
10813
10814         header = mono_method_get_header (cfg->method);
10815
10816         sig = mono_method_signature (cfg->method);
10817         
10818         if (!MONO_TYPE_IS_VOID (sig->ret)) {
10819                 cfg->ret = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst));
10820                 cfg->ret->opcode = OP_RETARG;
10821                 cfg->ret->inst_vtype = sig->ret;
10822                 cfg->ret->klass = mono_class_from_mono_type (sig->ret);
10823         }
10824         if (cfg->verbose_level > 2)
10825                 g_print ("creating vars\n");
10826
10827         cfg->args = mono_mempool_alloc0 (cfg->mempool, (sig->param_count + sig->hasthis) * sizeof (MonoInst*));
10828
10829         if (sig->hasthis)
10830                 cfg->args [0] = mono_compile_create_var (cfg, &cfg->method->klass->this_arg, OP_ARG);
10831
10832         for (i = 0; i < sig->param_count; ++i) {
10833                 cfg->args [i + sig->hasthis] = mono_compile_create_var (cfg, sig->params [i], OP_ARG);
10834                 if (sig->params [i]->byref) {
10835                         cfg->disable_ssa = TRUE;
10836                 }
10837         }
10838
10839         cfg->locals_start = cfg->num_varinfo;
10840
10841         if (cfg->verbose_level > 2)
10842                 g_print ("creating locals\n");
10843
10844         for (i = 0; i < header->num_locals; ++i)
10845                 mono_compile_create_var (cfg, header->locals [i], OP_LOCAL);
10846         if (cfg->verbose_level > 2)
10847                 g_print ("locals done\n");
10848
10849 #ifdef MONO_ARCH_HAVE_CREATE_VARS
10850         mono_arch_create_vars (cfg);
10851 #endif
10852 }
10853
10854 void
10855 mono_print_code (MonoCompile *cfg)
10856 {
10857         MonoBasicBlock *bb;
10858         
10859         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
10860                 MonoInst *tree;
10861
10862                 if (!MONO_INST_LIST_EMPTY (&bb->ins_list))
10863                         g_print ("CODE BLOCK %d (nesting %d):\n",
10864                                  bb->block_num, bb->nesting);
10865
10866                 MONO_BB_FOR_EACH_INS (bb, tree) {
10867                         mono_print_tree (tree);
10868                         g_print ("\n");
10869                 }
10870         }
10871 }
10872
10873 extern const char * const mono_burg_rule_string [];
10874
10875 static void
10876 emit_state (MonoCompile *cfg, MBState *state, int goal)
10877 {
10878         MBState *kids [10];
10879         int ern = mono_burg_rule (state, goal);
10880         const guint16 *nts = mono_burg_nts_data + mono_burg_nts [ern];
10881
10882         //g_print ("rule: %s\n", mono_burg_rule_string [ern]);
10883         switch (goal) {
10884         case MB_NTERM_reg:
10885                 //if (state->reg2)
10886                 //      state->reg1 = state->reg2; /* chain rule */
10887                 //else
10888 #ifdef MONO_ARCH_ENABLE_EMIT_STATE_OPT
10889                 if (!state->reg1)
10890 #endif
10891                         state->reg1 = mono_regstate_next_int (cfg->rs);
10892                 //g_print ("alloc symbolic R%d (reg2: R%d) in block %d\n", state->reg1, state->reg2, cfg->cbb->block_num);
10893                 break;
10894         case MB_NTERM_lreg:
10895                 state->reg1 = mono_regstate_next_int (cfg->rs);
10896                 state->reg2 = mono_regstate_next_int (cfg->rs);
10897                 break;
10898         case MB_NTERM_freg:
10899 #ifdef MONO_ARCH_SOFT_FLOAT
10900                 state->reg1 = mono_regstate_next_int (cfg->rs);
10901                 state->reg2 = mono_regstate_next_int (cfg->rs);
10902 #else
10903                 state->reg1 = mono_regstate_next_float (cfg->rs);
10904 #endif
10905                 break;
10906         default:
10907 #ifdef MONO_ARCH_ENABLE_EMIT_STATE_OPT
10908                 /*
10909                  * Enabling this might cause bugs to surface in the local register
10910                  * allocators on some architectures like x86.
10911                  */
10912                 if ((state->tree->ssa_op == MONO_SSA_STORE) && (state->left->tree->opcode == OP_REGVAR)) {
10913                         /* Do not optimize away reg-reg moves */
10914                         if (! ((state->right->tree->ssa_op == MONO_SSA_LOAD) && (state->right->left->tree->opcode == OP_REGVAR))) {
10915                                 state->right->reg1 = state->left->tree->dreg;
10916                         }
10917                 }
10918 #endif
10919
10920                 /* do nothing */
10921                 break;
10922         }
10923         if (nts [0]) {
10924                 mono_burg_kids (state, ern, kids);
10925
10926                 emit_state (cfg, kids [0], nts [0]);
10927                 if (nts [1]) {
10928                         emit_state (cfg, kids [1], nts [1]);
10929                         if (nts [2]) {
10930                                 g_assert (!nts [3]);
10931                                 emit_state (cfg, kids [2], nts [2]);
10932                         }
10933                 }
10934         }
10935
10936 //      g_print ("emit: %s (%p)\n", mono_burg_rule_string [ern], state);
10937         mono_burg_emit (ern, state, state->tree, cfg);
10938 }
10939
10940 #define DEBUG_SELECTION
10941
10942 static void 
10943 mini_select_instructions (MonoCompile *cfg)
10944 {
10945         MonoBasicBlock *bb;
10946         
10947         cfg->state_pool = mono_mempool_new ();
10948         cfg->rs = mono_regstate_new ();
10949
10950         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
10951                 MonoInst *last_ins = mono_inst_list_last (&bb->ins_list);
10952
10953                 if (last_ins && MONO_IS_COND_BRANCH_OP (last_ins) &&
10954                                 bb->next_bb != last_ins->inst_false_bb) {
10955
10956                         /* we are careful when inverting, since bugs like #59580
10957                          * could show up when dealing with NaNs.
10958                          */
10959                         if (MONO_IS_COND_BRANCH_NOFP(last_ins) && bb->next_bb == last_ins->inst_true_bb) {
10960                                 MonoBasicBlock *tmp =  last_ins->inst_true_bb;
10961                                 last_ins->inst_true_bb = last_ins->inst_false_bb;
10962                                 last_ins->inst_false_bb = tmp;
10963
10964                                 last_ins->opcode = reverse_branch_op (last_ins->opcode);
10965                         } else {                        
10966                                 MonoInst *inst = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst));
10967                                 inst->opcode = OP_BR;
10968                                 inst->inst_target_bb = last_ins->inst_false_bb;
10969                                 mono_bblock_add_inst (bb, inst);
10970                         }
10971                 }
10972         }
10973
10974 #ifdef DEBUG_SELECTION
10975         if (cfg->verbose_level >= 4) {
10976         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
10977                 MonoInst *tree; 
10978                 g_print ("DUMP BLOCK %d:\n", bb->block_num);
10979
10980                 MONO_BB_FOR_EACH_INS (bb, tree) {
10981                         mono_print_tree (tree);
10982                         g_print ("\n");
10983                 }
10984         }
10985         }
10986 #endif
10987
10988         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
10989                 MonoInst *tree, *n;     
10990                 MonoInstList head;
10991                 MBState *mbstate;
10992
10993                 MONO_INST_LIST_INIT (&head);
10994                 if (MONO_INST_LIST_EMPTY (&bb->ins_list))
10995                         continue;
10996                 MONO_INST_LIST_SPLICE_INIT (&bb->ins_list, &head);
10997                 
10998                 cfg->cbb = bb;
10999                 mono_regstate_reset (cfg->rs);
11000
11001 #ifdef DEBUG_SELECTION
11002                 if (cfg->verbose_level >= 3)
11003                         g_print ("LABEL BLOCK %d:\n", bb->block_num);
11004 #endif
11005                 MONO_INST_LIST_FOR_EACH_ENTRY_SAFE (tree, n, &head, node) {
11006 #ifdef DEBUG_SELECTION
11007                         if (cfg->verbose_level >= 3) {
11008                                 mono_print_tree (tree);
11009                                 g_print ("\n");
11010                         }
11011 #endif
11012
11013                         if (!(mbstate = mono_burg_label (tree, cfg))) {
11014                                 g_warning ("unable to label tree %p", tree);
11015                                 mono_print_tree (tree);
11016                                 g_print ("\n");                         
11017                                 g_assert_not_reached ();
11018                         }
11019                         emit_state (cfg, mbstate, MB_NTERM_stmt);
11020                 }
11021                 bb->max_vreg = cfg->rs->next_vreg;
11022
11023                 mono_mempool_empty (cfg->state_pool); 
11024         }
11025         mono_mempool_destroy (cfg->state_pool); 
11026 }
11027
11028 /*
11029  * mono_normalize_opcodes:
11030  *
11031  *   Replace CEE_ and OP_ opcodes with the corresponding OP_I or OP_L opcodes.
11032  */
11033
11034 static gint16 *remap_table;
11035
11036 #if SIZEOF_VOID_P == 8
11037 #define REMAP_OPCODE(opcode) OP_L ## opcode
11038 #else
11039 #define REMAP_OPCODE(opcode) OP_I ## opcode
11040 #endif
11041
11042 static G_GNUC_UNUSED void
11043 mono_normalize_opcodes (MonoCompile *cfg, MonoBasicBlock *bb)
11044 {
11045         MonoInst *ins;
11046
11047         if (!remap_table) {
11048                 remap_table = g_new0 (gint16, OP_LAST);
11049
11050 #if SIZEOF_VOID_P == 8
11051                 remap_table [CEE_CONV_U8] = OP_ZEXT_I4;
11052                 remap_table [CEE_CONV_U] = OP_ZEXT_I4;
11053                 remap_table [CEE_CONV_I8] = OP_SEXT_I4;
11054                 remap_table [CEE_CONV_I] = OP_SEXT_I4;
11055                 remap_table [CEE_CONV_OVF_U4] = OP_LCONV_TO_OVF_U4;
11056                 remap_table [CEE_CONV_OVF_I4_UN] = OP_LCONV_TO_OVF_I4_UN;
11057 #else
11058 #endif
11059                 remap_table [CEE_CONV_R4] = OP_ICONV_TO_R4;
11060                 remap_table [CEE_CONV_R8] = OP_ICONV_TO_R8;
11061                 remap_table [CEE_CONV_I4] = OP_MOVE;
11062                 remap_table [CEE_CONV_U4] = OP_MOVE;
11063                 remap_table [CEE_CONV_I1] = REMAP_OPCODE (CONV_TO_I1);
11064                 remap_table [CEE_CONV_I2] = REMAP_OPCODE (CONV_TO_I2);
11065                 remap_table [CEE_CONV_U1] = REMAP_OPCODE (CONV_TO_U1);
11066                 remap_table [CEE_CONV_U2] = REMAP_OPCODE (CONV_TO_U2);
11067                 remap_table [CEE_CONV_R_UN] = REMAP_OPCODE (CONV_TO_R_UN);
11068                 remap_table [CEE_ADD] = REMAP_OPCODE (ADD);
11069                 remap_table [CEE_SUB] = REMAP_OPCODE (SUB);
11070                 remap_table [CEE_MUL] = REMAP_OPCODE (MUL);
11071                 remap_table [CEE_DIV] = REMAP_OPCODE (DIV);
11072                 remap_table [CEE_REM] = REMAP_OPCODE (REM);
11073                 remap_table [CEE_DIV_UN] = REMAP_OPCODE (DIV_UN);
11074                 remap_table [CEE_REM_UN] = REMAP_OPCODE (REM_UN);
11075                 remap_table [CEE_AND] = REMAP_OPCODE (AND);
11076                 remap_table [CEE_OR] = REMAP_OPCODE (OR);
11077                 remap_table [CEE_XOR] = REMAP_OPCODE (XOR);
11078                 remap_table [CEE_SHL] = REMAP_OPCODE (SHL);
11079                 remap_table [CEE_SHR] = REMAP_OPCODE (SHR);
11080                 remap_table [CEE_SHR_UN] = REMAP_OPCODE (SHR_UN);
11081                 remap_table [CEE_NOT] = REMAP_OPCODE (NOT);
11082                 remap_table [CEE_NEG] = REMAP_OPCODE (NEG);
11083                 remap_table [CEE_CALL] = OP_CALL;
11084                 remap_table [CEE_BEQ] = REMAP_OPCODE (BEQ);
11085                 remap_table [CEE_BNE_UN] = REMAP_OPCODE (BNE_UN);
11086                 remap_table [CEE_BLT] = REMAP_OPCODE (BLT);
11087                 remap_table [CEE_BLT_UN] = REMAP_OPCODE (BLT_UN);
11088                 remap_table [CEE_BGT] = REMAP_OPCODE (BGT);
11089                 remap_table [CEE_BGT_UN] = REMAP_OPCODE (BGT_UN);
11090                 remap_table [CEE_BGE] = REMAP_OPCODE (BGE);
11091                 remap_table [CEE_BGE_UN] = REMAP_OPCODE (BGE_UN);
11092                 remap_table [CEE_BLE] = REMAP_OPCODE (BLE);
11093                 remap_table [CEE_BLE_UN] = REMAP_OPCODE (BLE_UN);
11094                 remap_table [CEE_ADD_OVF] = REMAP_OPCODE (ADD_OVF);
11095                 remap_table [CEE_ADD_OVF_UN] = REMAP_OPCODE (ADD_OVF_UN);
11096                 remap_table [CEE_SUB_OVF] = REMAP_OPCODE (SUB_OVF);
11097                 remap_table [CEE_SUB_OVF_UN] = REMAP_OPCODE (SUB_OVF_UN);
11098                 remap_table [CEE_MUL_OVF] = REMAP_OPCODE (MUL_OVF);
11099                 remap_table [CEE_MUL_OVF_UN] = REMAP_OPCODE (MUL_OVF_UN);
11100         }
11101
11102         MONO_BB_FOR_EACH_INS (bb, ins) {
11103                 int remapped = remap_table [ins->opcode];
11104                 if (remapped)
11105                         ins->opcode = remapped;
11106         }
11107 }
11108
11109 void
11110 mono_codegen (MonoCompile *cfg)
11111 {
11112         MonoJumpInfo *patch_info;
11113         MonoBasicBlock *bb;
11114         int i, max_epilog_size;
11115         guint8 *code;
11116
11117         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
11118                 cfg->spill_count = 0;
11119                 /* we reuse dfn here */
11120                 /* bb->dfn = bb_count++; */
11121 #ifdef MONO_ARCH_ENABLE_NORMALIZE_OPCODES
11122                 mono_normalize_opcodes (cfg, bb);
11123 #endif
11124
11125                 mono_arch_lowering_pass (cfg, bb);
11126
11127                 if (cfg->opt & MONO_OPT_PEEPHOLE)
11128                         mono_arch_peephole_pass_1 (cfg, bb);
11129
11130                 mono_local_regalloc (cfg, bb);
11131
11132                 if (cfg->opt & MONO_OPT_PEEPHOLE)
11133                         mono_arch_peephole_pass_2 (cfg, bb);
11134         }
11135
11136         if (cfg->prof_options & MONO_PROFILE_COVERAGE)
11137                 cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, cfg->num_bblocks);
11138
11139         code = mono_arch_emit_prolog (cfg);
11140
11141         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
11142                 code = mono_arch_instrument_prolog (cfg, mono_profiler_method_enter, code, FALSE);
11143
11144         cfg->code_len = code - cfg->native_code;
11145         cfg->prolog_end = cfg->code_len;
11146
11147         mono_debug_open_method (cfg);
11148
11149         /* emit code all basic blocks */
11150         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
11151                 bb->native_offset = cfg->code_len;
11152                 mono_arch_output_basic_block (cfg, bb);
11153
11154                 if (bb == cfg->bb_exit) {
11155                         cfg->epilog_begin = cfg->code_len;
11156
11157                         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE) {
11158                                 code = cfg->native_code + cfg->code_len;
11159                                 code = mono_arch_instrument_epilog (cfg, mono_profiler_method_leave, code, FALSE);
11160                                 cfg->code_len = code - cfg->native_code;
11161                                 g_assert (cfg->code_len < cfg->code_size);
11162                         }
11163
11164                         mono_arch_emit_epilog (cfg);
11165                 }
11166         }
11167
11168         mono_arch_emit_exceptions (cfg);
11169
11170         max_epilog_size = 0;
11171
11172         code = cfg->native_code + cfg->code_len;
11173
11174         /* we always allocate code in cfg->domain->code_mp to increase locality */
11175         cfg->code_size = cfg->code_len + max_epilog_size;
11176         /* fixme: align to MONO_ARCH_CODE_ALIGNMENT */
11177
11178         if (cfg->method->dynamic) {
11179                 /* Allocate the code into a separate memory pool so it can be freed */
11180                 cfg->dynamic_info = g_new0 (MonoJitDynamicMethodInfo, 1);
11181                 cfg->dynamic_info->code_mp = mono_code_manager_new_dynamic ();
11182                 mono_domain_lock (cfg->domain);
11183                 mono_dynamic_code_hash_insert (cfg->domain, cfg->method, cfg->dynamic_info);
11184                 mono_domain_unlock (cfg->domain);
11185
11186                 code = mono_code_manager_reserve (cfg->dynamic_info->code_mp, cfg->code_size);
11187         } else {
11188                 mono_domain_lock (cfg->domain);
11189                 code = mono_code_manager_reserve (cfg->domain->code_mp, cfg->code_size);
11190                 mono_domain_unlock (cfg->domain);
11191         }
11192
11193         memcpy (code, cfg->native_code, cfg->code_len);
11194         g_free (cfg->native_code);
11195         cfg->native_code = code;
11196         code = cfg->native_code + cfg->code_len;
11197   
11198         /* g_assert (((int)cfg->native_code & (MONO_ARCH_CODE_ALIGNMENT - 1)) == 0); */
11199         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
11200                 switch (patch_info->type) {
11201                 case MONO_PATCH_INFO_ABS: {
11202                         MonoJitICallInfo *info = mono_find_jit_icall_by_addr (patch_info->data.target);
11203                         if (info) {
11204                                 //printf ("TEST %s %p\n", info->name, patch_info->data.target);
11205                                 if ((cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) && 
11206                                         strstr (cfg->method->name, info->name))
11207                                         /*
11208                                          * This is an icall wrapper, and this is a call to the
11209                                          * wrapped function.
11210                                          */
11211                                         ;
11212                                 else {
11213                                         /* for these array methods we currently register the same function pointer
11214                                          * since it's a vararg function. But this means that mono_find_jit_icall_by_addr ()
11215                                          * will return the incorrect one depending on the order they are registered.
11216                                          * See tests/test-arr.cs
11217                                          */
11218                                         if (strstr (info->name, "ves_array_new_va_") == NULL && strstr (info->name, "ves_array_element_address_") == NULL) {
11219                                                 patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
11220                                                 patch_info->data.name = info->name;
11221                                         }
11222                                 }
11223                         }
11224                         else {
11225                                 MonoVTable *vtable = mono_find_class_init_trampoline_by_addr (patch_info->data.target);
11226                                 if (vtable) {
11227                                         patch_info->type = MONO_PATCH_INFO_CLASS_INIT;
11228                                         patch_info->data.klass = vtable->klass;
11229                                 } else {
11230                                         MonoClass *klass = mono_find_delegate_trampoline_by_addr (patch_info->data.target);
11231                                         if (klass) {
11232                                                 patch_info->type = MONO_PATCH_INFO_DELEGATE_TRAMPOLINE;
11233                                                 patch_info->data.klass = klass;
11234                                         }
11235                                 }
11236                         }
11237                         break;
11238                 }
11239                 case MONO_PATCH_INFO_SWITCH: {
11240                         gpointer *table;
11241                         if (cfg->method->dynamic) {
11242                                 table = mono_code_manager_reserve (cfg->dynamic_info->code_mp, sizeof (gpointer) * patch_info->data.table->table_size);
11243                         } else {
11244                                 mono_domain_lock (cfg->domain);
11245                                 table = mono_code_manager_reserve (cfg->domain->code_mp, sizeof (gpointer) * patch_info->data.table->table_size);
11246                                 mono_domain_unlock (cfg->domain);
11247                         }
11248
11249                         if (!cfg->compile_aot)
11250                                 /* In the aot case, the patch already points to the correct location */
11251                                 patch_info->ip.i = patch_info->ip.label->inst_c0;
11252                         for (i = 0; i < patch_info->data.table->table_size; i++) {
11253                                 table [i] = GINT_TO_POINTER (patch_info->data.table->table [i]->native_offset);
11254                         }
11255                         patch_info->data.table->table = (MonoBasicBlock**)table;
11256                         break;
11257                 }
11258                 default:
11259                         /* do nothing */
11260                         break;
11261                 }
11262         }
11263
11264 #ifdef VALGRIND_JIT_REGISTER_MAP
11265 if (valgrind_register){
11266                 char* nm = mono_method_full_name (cfg->method, TRUE);
11267                 VALGRIND_JIT_REGISTER_MAP (nm, cfg->native_code, cfg->native_code + cfg->code_len);
11268                 g_free (nm);
11269         }
11270 #endif
11271  
11272         if (cfg->verbose_level > 0) {
11273                 char* nm = mono_method_full_name (cfg->method, TRUE);
11274                 g_print ("Method %s emitted at %p to %p (code length %d) [%s]\n", 
11275                                  nm, 
11276                                  cfg->native_code, cfg->native_code + cfg->code_len, cfg->code_len, cfg->domain->friendly_name);
11277                 g_free (nm);
11278         }
11279
11280 #ifdef MONO_ARCH_HAVE_SAVE_UNWIND_INFO
11281         mono_arch_save_unwind_info (cfg);
11282 #endif
11283         
11284         mono_arch_patch_code (cfg->method, cfg->domain, cfg->native_code, cfg->patch_info, cfg->run_cctors);
11285
11286         if (cfg->method->dynamic) {
11287                 mono_code_manager_commit (cfg->dynamic_info->code_mp, cfg->native_code, cfg->code_size, cfg->code_len);
11288         } else {
11289                 mono_domain_lock (cfg->domain);
11290                 mono_code_manager_commit (cfg->domain->code_mp, cfg->native_code, cfg->code_size, cfg->code_len);
11291                 mono_domain_unlock (cfg->domain);
11292         }
11293         
11294         mono_arch_flush_icache (cfg->native_code, cfg->code_len);
11295
11296         mono_debug_close_method (cfg);
11297 }
11298
11299
11300
11301 static void
11302 remove_critical_edges (MonoCompile *cfg) {
11303         MonoBasicBlock *bb;
11304         MonoBasicBlock *previous_bb;
11305         
11306         if (cfg->verbose_level > 3) {
11307                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
11308                         MonoInst *last_ins;
11309                         int i;
11310                         printf ("remove_critical_edges %s, BEFORE BB%d (in:", mono_method_full_name (cfg->method, TRUE), bb->block_num);
11311                         for (i = 0; i < bb->in_count; i++) {
11312                                 printf (" %d", bb->in_bb [i]->block_num);
11313                         }
11314                         printf (") (out:");
11315                         for (i = 0; i < bb->out_count; i++) {
11316                                 printf (" %d", bb->out_bb [i]->block_num);
11317                         }
11318                         printf (")");
11319                         last_ins = mono_inst_list_last (&bb->ins_list);
11320                         if (last_ins) {
11321                                 printf (" ");
11322                                 mono_print_tree (last_ins);
11323                         }
11324                         printf ("\n");
11325                 }
11326         }
11327         
11328         for (previous_bb = cfg->bb_entry, bb = previous_bb->next_bb; bb != NULL; previous_bb = previous_bb->next_bb, bb = bb->next_bb) {
11329                 if (bb->in_count > 1) {
11330                         int in_bb_index;
11331                         for (in_bb_index = 0; in_bb_index < bb->in_count; in_bb_index++) {
11332                                 MonoBasicBlock *in_bb = bb->in_bb [in_bb_index];
11333                                 if (in_bb->out_count > 1) {
11334                                         MonoBasicBlock *new_bb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
11335                                         MONO_INST_LIST_INIT (&new_bb->ins_list);
11336                                         new_bb->block_num = cfg->num_bblocks++;
11337 //                                      new_bb->real_offset = bb->real_offset;
11338                                         new_bb->region = bb->region;
11339                                         
11340                                         /* Do not alter the CFG while altering the BB list */
11341                                         if (previous_bb->region == bb->region) {
11342                                                 if (previous_bb != cfg->bb_entry) {
11343                                                         MonoInst *last_ins;
11344                                                         /* If previous_bb "followed through" to bb, */
11345                                                         /* keep it linked with a OP_BR */
11346                                                         last_ins = mono_inst_list_last (&previous_bb->ins_list);
11347                                                         if ((last_ins == NULL) ||
11348                                                                         ((last_ins->opcode != OP_BR) &&
11349                                                                         (!(MONO_IS_COND_BRANCH_OP (last_ins))) &&
11350                                                                         (last_ins->opcode != OP_SWITCH))) {
11351                                                                 int i;
11352                                                                 /* Make sure previous_bb really falls through bb */
11353                                                                 for (i = 0; i < previous_bb->out_count; i++) {
11354                                                                         if (previous_bb->out_bb [i] == bb) {
11355                                                                                 MonoInst *jump;
11356                                                                                 MONO_INST_NEW (cfg, jump, OP_BR);
11357                                                                                 MONO_ADD_INS (previous_bb, jump);
11358                                                                                 jump->cil_code = previous_bb->cil_code;
11359                                                                                 jump->inst_target_bb = bb;
11360                                                                                 break;
11361                                                                         }
11362                                                                 }
11363                                                         }
11364                                                 } else {
11365                                                         /* We cannot add any inst to the entry BB, so we must */
11366                                                         /* put a new BB in the middle to hold the OP_BR */
11367                                                         MonoInst *jump;
11368                                                         MonoBasicBlock *new_bb_after_entry = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
11369                                                         MONO_INST_LIST_INIT (&new_bb_after_entry->ins_list);
11370                                                         new_bb_after_entry->block_num = cfg->num_bblocks++;
11371 //                                                      new_bb_after_entry->real_offset = bb->real_offset;
11372                                                         new_bb_after_entry->region = bb->region;
11373                                                         
11374                                                         MONO_INST_NEW (cfg, jump, OP_BR);
11375                                                         MONO_ADD_INS (new_bb_after_entry, jump);
11376                                                         jump->cil_code = bb->cil_code;
11377                                                         jump->inst_target_bb = bb;
11378                                                         
11379                                                         previous_bb->next_bb = new_bb_after_entry;
11380                                                         previous_bb = new_bb_after_entry;
11381                                                         
11382                                                         if (cfg->verbose_level > 2) {
11383                                                                 printf ("remove_critical_edges %s, added helper BB%d jumping to BB%d\n", mono_method_full_name (cfg->method, TRUE), new_bb_after_entry->block_num, bb->block_num);
11384                                                         }
11385                                                 }
11386                                         }
11387                                         
11388                                         /* Insert new_bb in the BB list */
11389                                         previous_bb->next_bb = new_bb;
11390                                         new_bb->next_bb = bb;
11391                                         previous_bb = new_bb;
11392                                         
11393                                         /* Setup in_bb and out_bb */
11394                                         new_bb->in_bb = mono_mempool_alloc ((cfg)->mempool, sizeof (MonoBasicBlock*));
11395                                         new_bb->in_bb [0] = in_bb;
11396                                         new_bb->in_count = 1;
11397                                         new_bb->out_bb = mono_mempool_alloc ((cfg)->mempool, sizeof (MonoBasicBlock*));
11398                                         new_bb->out_bb [0] = bb;
11399                                         new_bb->out_count = 1;
11400                                         
11401                                         /* Relink in_bb and bb to (from) new_bb */
11402                                         replace_out_block (in_bb, bb, new_bb);
11403                                         replace_out_block_in_code (in_bb, bb, new_bb);
11404                                         replace_in_block (bb, in_bb, new_bb);
11405                                         
11406                                         if (cfg->verbose_level > 2) {
11407                                                 printf ("remove_critical_edges %s, removed critical edge from BB%d to BB%d (added BB%d)\n", mono_method_full_name (cfg->method, TRUE), in_bb->block_num, bb->block_num, new_bb->block_num);
11408                                         }
11409                                 }
11410                         }
11411                 }
11412         }
11413         
11414         if (cfg->verbose_level > 3) {
11415                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
11416                         MonoInst *last_ins;
11417                         int i;
11418                         printf ("remove_critical_edges %s, AFTER BB%d (in:", mono_method_full_name (cfg->method, TRUE), bb->block_num);
11419                         for (i = 0; i < bb->in_count; i++) {
11420                                 printf (" %d", bb->in_bb [i]->block_num);
11421                         }
11422                         printf (") (out:");
11423                         for (i = 0; i < bb->out_count; i++) {
11424                                 printf (" %d", bb->out_bb [i]->block_num);
11425                         }
11426                         printf (")");
11427                         last_ins = mono_inst_list_last (&bb->ins_list);
11428                         if (last_ins) {
11429                                 printf (" ");
11430                                 mono_print_tree (last_ins);
11431                         }
11432                         printf ("\n");
11433                 }
11434         }
11435 }
11436
11437 /*
11438  * mini_method_compile:
11439  * @method: the method to compile
11440  * @opts: the optimization flags to use
11441  * @domain: the domain where the method will be compiled in
11442  * @run_cctors: whether we should run type ctors if possible
11443  * @compile_aot: whether this is an AOT compilation
11444  * @parts: debug flag
11445  *
11446  * Returns: a MonoCompile* pointer. Caller must check the exception_type
11447  * field in the returned struct to see if compilation succeded.
11448  */
11449 MonoCompile*
11450 mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gboolean run_cctors, gboolean compile_aot, int parts)
11451 {
11452         MonoMethodHeader *header = mono_method_get_header (method);
11453         guint8 *ip;
11454         MonoCompile *cfg;
11455         MonoJitInfo *jinfo;
11456         int dfn = 0, i, code_size_ratio;
11457         gboolean deadce_has_run = FALSE;
11458         gboolean try_generic_shared;
11459         MonoMethod *method_to_compile;
11460         int gsctx_size;
11461
11462         mono_jit_stats.methods_compiled++;
11463         if (mono_profiler_get_events () & MONO_PROFILE_JIT_COMPILATION)
11464                 mono_profiler_method_jit (method);
11465  
11466         if (compile_aot)
11467                 /* We are passed the original generic method definition */
11468                 try_generic_shared = mono_class_generic_sharing_enabled (method->klass) &&
11469                         (opts & MONO_OPT_GSHARED) && (method->generic_container || method->klass->generic_container);
11470         else
11471                 try_generic_shared = mono_class_generic_sharing_enabled (method->klass) &&
11472                         (opts & MONO_OPT_GSHARED) && mono_method_is_generic_sharable_impl (method);
11473
11474         if (opts & MONO_OPT_GSHARED) {
11475                 if (try_generic_shared)
11476                         mono_stats.generics_sharable_methods++;
11477                 else if (mono_method_is_generic_impl (method))
11478                         mono_stats.generics_unsharable_methods++;
11479         }
11480
11481  restart_compile:
11482         if (try_generic_shared) {
11483                 MonoMethod *declaring_method;
11484                 MonoGenericContext *shared_context;
11485
11486                 if (compile_aot) {
11487                         declaring_method = method;
11488                 } else {
11489                         declaring_method = mono_method_get_declaring_generic_method (method);
11490                         g_assert (method->klass->generic_class->container_class == declaring_method->klass);
11491                 }
11492
11493                 if (declaring_method->generic_container)
11494                         shared_context = &declaring_method->generic_container->context;
11495                 else
11496                         shared_context = &declaring_method->klass->generic_container->context;
11497
11498                 method_to_compile = mono_class_inflate_generic_method (declaring_method, shared_context);
11499                 g_assert (method_to_compile);
11500         } else {
11501                 method_to_compile = method;
11502         }
11503
11504         cfg = g_new0 (MonoCompile, 1);
11505         cfg->method = method_to_compile;
11506         cfg->mempool = mono_mempool_new ();
11507         cfg->opt = opts;
11508         cfg->prof_options = mono_profiler_get_events ();
11509         cfg->run_cctors = run_cctors;
11510         cfg->domain = domain;
11511         cfg->verbose_level = mini_verbose;
11512         cfg->compile_aot = compile_aot;
11513         cfg->skip_visibility = method->skip_visibility;
11514         if (try_generic_shared)
11515                 cfg->generic_sharing_context = (MonoGenericSharingContext*)&cfg->generic_sharing_context;
11516         cfg->token_info_hash = g_hash_table_new (NULL, NULL);
11517         if (!header) {
11518                 cfg->exception_type = MONO_EXCEPTION_INVALID_PROGRAM;
11519                 cfg->exception_message = g_strdup_printf ("Missing or incorrect header for method %s", cfg->method->name);
11520                 if (cfg->prof_options & MONO_PROFILE_JIT_COMPILATION)
11521                         mono_profiler_method_end_jit (method, NULL, MONO_PROFILE_FAILED);
11522                 return cfg;
11523         }
11524
11525         ip = (guint8 *)header->code;
11526
11527         cfg->intvars = mono_mempool_alloc0 (cfg->mempool, sizeof (guint16) * STACK_MAX * header->max_stack);
11528         cfg->aliasing_info = NULL;
11529         
11530         if (cfg->verbose_level > 2)
11531                 g_print ("converting method %s\n", mono_method_full_name (method, TRUE));
11532
11533         /*
11534          * create MonoInst* which represents arguments and local variables
11535          */
11536         mono_compile_create_vars (cfg);
11537
11538         if ((i = mono_method_to_ir (cfg, method_to_compile, NULL, NULL, cfg->locals_start, NULL, NULL, NULL, 0, FALSE)) < 0) {
11539                 if (try_generic_shared && cfg->exception_type == MONO_EXCEPTION_GENERIC_SHARING_FAILED) {
11540                         if (compile_aot)
11541                                 return cfg;
11542                         mono_destroy_compile (cfg);
11543                         try_generic_shared = FALSE;
11544                         goto restart_compile;
11545                 }
11546                 g_assert (cfg->exception_type != MONO_EXCEPTION_GENERIC_SHARING_FAILED);
11547
11548                 if (cfg->prof_options & MONO_PROFILE_JIT_COMPILATION)
11549                         mono_profiler_method_end_jit (method, NULL, MONO_PROFILE_FAILED);
11550                 /* cfg contains the details of the failure, so let the caller cleanup */
11551                 return cfg;
11552         }
11553
11554         mono_jit_stats.basic_blocks += cfg->num_bblocks;
11555         mono_jit_stats.max_basic_blocks = MAX (cfg->num_bblocks, mono_jit_stats.max_basic_blocks);
11556
11557         if ((cfg->num_varinfo > 2000) && !cfg->compile_aot) {
11558                 /* 
11559                  * we disable some optimizations if there are too many variables
11560                  * because JIT time may become too expensive. The actual number needs 
11561                  * to be tweaked and eventually the non-linear algorithms should be fixed.
11562                  */
11563                 cfg->opt &= ~ (MONO_OPT_LINEARS | MONO_OPT_COPYPROP | MONO_OPT_CONSPROP);
11564                 cfg->disable_ssa = TRUE;
11565         }
11566
11567         /*g_print ("numblocks = %d\n", cfg->num_bblocks);*/
11568
11569         if (cfg->opt & MONO_OPT_BRANCH)
11570                 optimize_branches (cfg);
11571
11572         if (cfg->opt & MONO_OPT_SSAPRE) {
11573                 remove_critical_edges (cfg);
11574         }
11575
11576         /* Depth-first ordering on basic blocks */
11577         cfg->bblocks = mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * (cfg->num_bblocks + 1));
11578
11579         df_visit (cfg->bb_entry, &dfn, cfg->bblocks);
11580         if (cfg->num_bblocks != dfn + 1) {
11581                 MonoBasicBlock *bb;
11582
11583                 cfg->num_bblocks = dfn + 1;
11584
11585                 if (!header->clauses) {
11586                         /* remove unreachable code, because the code in them may be 
11587                          * inconsistent  (access to dead variables for example) */
11588                         for (bb = cfg->bb_entry; bb;) {
11589                                 MonoBasicBlock *bbn = bb->next_bb;
11590
11591                                 if (bbn && bbn->region == -1 && !bbn->dfn) {
11592                                         if (cfg->verbose_level > 1)
11593                                                 g_print ("found unreachable code in BB%d\n", bbn->block_num);
11594                                         bb->next_bb = bbn->next_bb;
11595                                         nullify_basic_block (bbn);                      
11596                                 } else {
11597                                         bb = bb->next_bb;
11598                                 }
11599                         }
11600                 }
11601         }
11602
11603         if (cfg->opt & MONO_OPT_LOOP) {
11604                 mono_compile_dominator_info (cfg, MONO_COMP_DOM | MONO_COMP_IDOM);
11605                 mono_compute_natural_loops (cfg);
11606         }
11607
11608         /* after method_to_ir */
11609         if (parts == 1)
11610                 return cfg;
11611
11612 //#define DEBUGSSA "logic_run"
11613 #define DEBUGSSA_CLASS "Tests"
11614 #ifdef DEBUGSSA
11615
11616         if (!header->num_clauses && !cfg->disable_ssa) {
11617                 mono_local_cprop (cfg);
11618 #ifndef DISABLE_SSA
11619                 mono_ssa_compute (cfg);
11620 #endif
11621         }
11622 #else 
11623
11624         /* fixme: add all optimizations which requires SSA */
11625         if (cfg->opt & (MONO_OPT_SSA | MONO_OPT_ABCREM | MONO_OPT_SSAPRE)) {
11626                 if (!(cfg->comp_done & MONO_COMP_SSA) && !header->num_clauses && !cfg->disable_ssa) {
11627                         mono_local_cprop (cfg);
11628 #ifndef DISABLE_SSA
11629                         mono_ssa_compute (cfg);
11630 #endif
11631
11632                         if (cfg->verbose_level >= 2) {
11633                                 print_dfn (cfg);
11634                         }
11635                 }
11636         }
11637 #endif
11638
11639         /* after SSA translation */
11640         if (parts == 2)
11641                 return cfg;
11642
11643         if ((cfg->opt & MONO_OPT_CONSPROP) || (cfg->opt & MONO_OPT_COPYPROP)) {
11644                 if (cfg->comp_done & MONO_COMP_SSA) {
11645 #ifndef DISABLE_SSA
11646                         mono_ssa_cprop (cfg);
11647 #endif
11648                 } else {
11649                         mono_local_cprop (cfg);
11650                 }
11651         }
11652
11653 #ifndef DISABLE_SSA
11654         if (cfg->comp_done & MONO_COMP_SSA) {                   
11655                 //mono_ssa_deadce (cfg);
11656
11657                 //mono_ssa_strength_reduction (cfg);
11658
11659                 if (cfg->opt & MONO_OPT_SSAPRE) {
11660                         mono_perform_ssapre (cfg);
11661                         //mono_local_cprop (cfg);
11662                 }
11663                 
11664                 if (cfg->opt & MONO_OPT_DEADCE) {
11665                         mono_ssa_deadce (cfg);
11666                         deadce_has_run = TRUE;
11667                 }
11668                 
11669                 if ((cfg->flags & MONO_CFG_HAS_LDELEMA) && (cfg->opt & MONO_OPT_ABCREM))
11670                         mono_perform_abc_removal (cfg);
11671                 
11672                 mono_ssa_remove (cfg);
11673
11674                 if (cfg->opt & MONO_OPT_BRANCH)
11675                         optimize_branches (cfg);
11676         }
11677 #endif
11678
11679         /* after SSA removal */
11680         if (parts == 3)
11681                 return cfg;
11682
11683         if (cfg->verbose_level > 4) {
11684                 printf ("BEFORE DECOMPSE START\n");
11685                 mono_print_code (cfg);
11686                 printf ("BEFORE DECOMPSE END\n");
11687         }
11688         
11689         decompose_pass (cfg);
11690
11691         if (cfg->got_var) {
11692                 GList *regs;
11693
11694                 g_assert (cfg->got_var_allocated);
11695
11696                 /* 
11697                  * Allways allocate the GOT var to a register, because keeping it
11698                  * in memory will increase the number of live temporaries in some
11699                  * code created by inssel.brg, leading to the well known spills+
11700                  * branches problem. Testcase: mcs crash in 
11701                  * System.MonoCustomAttrs:GetCustomAttributes.
11702                  */
11703                 regs = mono_arch_get_global_int_regs (cfg);
11704                 g_assert (regs);
11705                 cfg->got_var->opcode = OP_REGVAR;
11706                 cfg->got_var->dreg = GPOINTER_TO_INT (regs->data);
11707                 cfg->used_int_regs |= 1LL << cfg->got_var->dreg;
11708                 
11709                 g_list_free (regs);
11710         }
11711
11712         /* todo: remove code when we have verified that the liveness for try/catch blocks
11713          * works perfectly 
11714          */
11715         /* 
11716          * Currently, this can't be commented out since exception blocks are not
11717          * processed during liveness analysis.
11718          */
11719         mono_liveness_handle_exception_clauses (cfg);
11720
11721         if (cfg->opt & MONO_OPT_LINEARS) {
11722                 GList *vars, *regs;
11723                 
11724                 /* For now, compute aliasing info only if needed for deadce... */
11725                 if ((cfg->opt & MONO_OPT_DEADCE) && (! deadce_has_run) && (header->num_clauses == 0)) {
11726                         cfg->aliasing_info = mono_build_aliasing_information (cfg);
11727                 }
11728
11729                 /* fixme: maybe we can avoid to compute livenesss here if already computed ? */
11730                 cfg->comp_done &= ~MONO_COMP_LIVENESS;
11731                 if (!(cfg->comp_done & MONO_COMP_LIVENESS))
11732                         mono_analyze_liveness (cfg);
11733
11734                 if (cfg->aliasing_info != NULL) {
11735                         mono_aliasing_deadce (cfg->aliasing_info);
11736                         deadce_has_run = TRUE;
11737                 }
11738                 
11739                 if ((vars = mono_arch_get_allocatable_int_vars (cfg))) {
11740                         regs = mono_arch_get_global_int_regs (cfg);
11741                         if (cfg->got_var)
11742                                 regs = g_list_delete_link (regs, regs);
11743                         mono_linear_scan (cfg, vars, regs, &cfg->used_int_regs);
11744                 }
11745                 
11746                 if (cfg->aliasing_info != NULL) {
11747                         mono_destroy_aliasing_information (cfg->aliasing_info);
11748                         cfg->aliasing_info = NULL;
11749                 }
11750         }
11751
11752         //mono_print_code (cfg);
11753
11754     //print_dfn (cfg);
11755         
11756         /* variables are allocated after decompose, since decompose could create temps */
11757         mono_arch_allocate_vars (cfg);
11758
11759         if (cfg->opt & MONO_OPT_CFOLD)
11760                 mono_constant_fold (cfg);
11761
11762         mini_select_instructions (cfg);
11763
11764         mono_codegen (cfg);
11765         if (cfg->verbose_level >= 2) {
11766                 char *id =  mono_method_full_name (cfg->method, FALSE);
11767                 mono_disassemble_code (cfg, cfg->native_code, cfg->code_len, id + 3);
11768                 g_free (id);
11769         }
11770
11771         if (cfg->generic_sharing_context)
11772                 gsctx_size = sizeof (MonoGenericSharingContext*);
11773         else
11774                 gsctx_size = 0;
11775
11776         if (cfg->method->dynamic) {
11777                 jinfo = g_malloc0 (sizeof (MonoJitInfo) + (header->num_clauses * sizeof (MonoJitExceptionInfo)) +
11778                                 gsctx_size);
11779         } else {
11780                 /* we access cfg->domain->mp */
11781                 mono_domain_lock (cfg->domain);
11782                 jinfo = mono_mempool_alloc0 (cfg->domain->mp, sizeof (MonoJitInfo) +
11783                                 (header->num_clauses * sizeof (MonoJitExceptionInfo)) +
11784                                 gsctx_size);
11785                 mono_domain_unlock (cfg->domain);
11786         }
11787
11788         jinfo->method = method;
11789         jinfo->code_start = cfg->native_code;
11790         jinfo->code_size = cfg->code_len;
11791         jinfo->used_regs = cfg->used_int_regs;
11792         jinfo->domain_neutral = (cfg->opt & MONO_OPT_SHARED) != 0;
11793         jinfo->cas_inited = FALSE; /* initialization delayed at the first stalk walk using this method */
11794         jinfo->num_clauses = header->num_clauses;
11795
11796         if (cfg->generic_sharing_context) {
11797                 jinfo->has_generic_sharing_context = 1;
11798                 mono_jit_info_set_generic_sharing_context (jinfo, cfg->generic_sharing_context);
11799         }
11800
11801         if (header->num_clauses) {
11802                 int i;
11803
11804                 for (i = 0; i < header->num_clauses; i++) {
11805                         MonoExceptionClause *ec = &header->clauses [i];
11806                         MonoJitExceptionInfo *ei = &jinfo->clauses [i];
11807                         MonoBasicBlock *tblock;
11808                         MonoInst *exvar;
11809
11810                         ei->flags = ec->flags;
11811
11812                         exvar = mono_find_exvar_for_offset (cfg, ec->handler_offset);
11813                         ei->exvar_offset = exvar ? exvar->inst_offset : 0;
11814
11815                         if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
11816                                 tblock = cfg->cil_offset_to_bb [ec->data.filter_offset];
11817                                 g_assert (tblock);
11818                                 ei->data.filter = cfg->native_code + tblock->native_offset;
11819                         } else {
11820                                 ei->data.catch_class = ec->data.catch_class;
11821                         }
11822
11823                         tblock = cfg->cil_offset_to_bb [ec->try_offset];
11824                         g_assert (tblock);
11825                         ei->try_start = cfg->native_code + tblock->native_offset;
11826                         g_assert (tblock->native_offset);
11827                         tblock = cfg->cil_offset_to_bb [ec->try_offset + ec->try_len];
11828                         g_assert (tblock);
11829                         ei->try_end = cfg->native_code + tblock->native_offset;
11830                         g_assert (tblock->native_offset);
11831                         tblock = cfg->cil_offset_to_bb [ec->handler_offset];
11832                         g_assert (tblock);
11833                         ei->handler_start = cfg->native_code + tblock->native_offset;
11834                 }
11835         }
11836
11837         cfg->jit_info = jinfo;
11838 #if defined(__arm__)
11839         mono_arch_fixup_jinfo (cfg);
11840 #endif
11841
11842         mono_domain_lock (cfg->domain);
11843         mono_jit_info_table_add (cfg->domain, jinfo);
11844
11845         if (cfg->method->dynamic)
11846                 mono_dynamic_code_hash_lookup (cfg->domain, cfg->method)->ji = jinfo;
11847         mono_domain_unlock (cfg->domain);
11848
11849         /* collect statistics */
11850         mono_jit_stats.allocated_code_size += cfg->code_len;
11851         code_size_ratio = cfg->code_len;
11852         if (code_size_ratio > mono_jit_stats.biggest_method_size) {
11853                         mono_jit_stats.biggest_method_size = code_size_ratio;
11854                         mono_jit_stats.biggest_method = method;
11855         }
11856         code_size_ratio = (code_size_ratio * 100) / mono_method_get_header (method)->code_size;
11857         if (code_size_ratio > mono_jit_stats.max_code_size_ratio) {
11858                 mono_jit_stats.max_code_size_ratio = code_size_ratio;
11859                 mono_jit_stats.max_ratio_method = method;
11860         }
11861         mono_jit_stats.native_code_size += cfg->code_len;
11862
11863         if (cfg->prof_options & MONO_PROFILE_JIT_COMPILATION)
11864                 mono_profiler_method_end_jit (method, jinfo, MONO_PROFILE_OK);
11865
11866         return cfg;
11867 }
11868
11869 static MonoJitInfo*
11870 lookup_generic_method (MonoDomain *domain, MonoMethod *method)
11871 {
11872         MonoMethod *open_method;
11873
11874         if (!mono_method_is_generic_sharable_impl (method))
11875                 return NULL;
11876
11877         open_method = mono_method_get_declaring_generic_method (method);
11878
11879         return mono_domain_lookup_shared_generic (domain, open_method);
11880 }
11881
11882 static MonoJitInfo*
11883 lookup_method (MonoDomain *domain, MonoMethod *method)
11884 {
11885         MonoJitInfo *ji = mono_internal_hash_table_lookup (&domain->jit_code_hash, method);
11886
11887         if (ji != NULL)
11888                 return ji;
11889
11890         return lookup_generic_method (domain, method);
11891 }
11892
11893 static gpointer
11894 mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, int opt)
11895 {
11896         MonoCompile *cfg;
11897         gpointer code = NULL;
11898         MonoJitInfo *info;
11899
11900 #ifdef MONO_USE_AOT_COMPILER
11901         if ((opt & MONO_OPT_AOT) && !(mono_profiler_get_events () & MONO_PROFILE_JIT_COMPILATION)) {
11902                 MonoDomain *domain = mono_domain_get ();
11903
11904                 mono_class_init (method->klass);
11905
11906                 mono_domain_lock (domain);
11907                 if ((code = mono_aot_get_method (domain, method))) {
11908                         mono_domain_unlock (domain);
11909                         mono_runtime_class_init (mono_class_vtable (domain, method->klass));
11910                         return code;
11911                 }
11912
11913                 mono_domain_unlock (domain);
11914         }
11915 #endif
11916
11917         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
11918             (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
11919                 MonoMethod *nm;
11920                 MonoMethodPInvoke* piinfo = (MonoMethodPInvoke *) method;
11921
11922                 if (method->iflags & METHOD_IMPL_ATTRIBUTE_NATIVE && !MONO_CLASS_IS_IMPORT(method->klass))
11923                         g_error ("Method '%s' in assembly '%s' contains native code and mono can't run it. The assembly was probably created by Managed C++.\n", mono_method_full_name (method, TRUE), method->klass->image->name);
11924
11925                 if (!piinfo->addr) {
11926                         if (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL)
11927                                 piinfo->addr = mono_lookup_internal_call (method);
11928                         else
11929                                 if (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
11930                                         mono_lookup_pinvoke_call (method, NULL, NULL);
11931                 }
11932                         nm = mono_marshal_get_native_wrapper (method, check_for_pending_exc);
11933                         return mono_get_addr_from_ftnptr (mono_compile_method (nm));
11934
11935                         //if (mono_debug_format != MONO_DEBUG_FORMAT_NONE) 
11936                         //mono_debug_add_wrapper (method, nm);
11937         } else if ((method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME)) {
11938                 const char *name = method->name;
11939                 MonoMethod *nm;
11940
11941                 if (method->klass->parent == mono_defaults.multicastdelegate_class) {
11942                         if (*name == '.' && (strcmp (name, ".ctor") == 0)) {
11943                                 MonoJitICallInfo *mi = mono_find_jit_icall_by_name ("mono_delegate_ctor");
11944                                 g_assert (mi);
11945                                 return mono_get_addr_from_ftnptr ((gpointer)mono_icall_get_wrapper (mi));
11946                         } else if (*name == 'I' && (strcmp (name, "Invoke") == 0)) {
11947 #ifdef MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE
11948                                 return mono_create_delegate_trampoline (method->klass);
11949 #else
11950                                 nm = mono_marshal_get_delegate_invoke (method, NULL);
11951                                 return mono_get_addr_from_ftnptr (mono_compile_method (nm));
11952 #endif
11953                         } else if (*name == 'B' && (strcmp (name, "BeginInvoke") == 0)) {
11954                                 nm = mono_marshal_get_delegate_begin_invoke (method);
11955                                 return mono_get_addr_from_ftnptr (mono_compile_method (nm));
11956                         } else if (*name == 'E' && (strcmp (name, "EndInvoke") == 0)) {
11957                                 nm = mono_marshal_get_delegate_end_invoke (method);
11958                                 return mono_get_addr_from_ftnptr (mono_compile_method (nm));
11959                         }
11960                 }
11961                 return NULL;
11962         }
11963
11964         cfg = mini_method_compile (method, opt, target_domain, TRUE, FALSE, 0);
11965
11966         switch (cfg->exception_type) {
11967         case MONO_EXCEPTION_NONE: break;
11968         case MONO_EXCEPTION_TYPE_LOAD:
11969         case MONO_EXCEPTION_MISSING_FIELD:
11970         case MONO_EXCEPTION_MISSING_METHOD:
11971         case MONO_EXCEPTION_FILE_NOT_FOUND: {
11972                 /* Throw a type load exception if needed */
11973                 MonoLoaderError *error = mono_loader_get_last_error ();
11974                 MonoException *ex;
11975
11976                 if (error) {
11977                         ex = mono_loader_error_prepare_exception (error);
11978                 } else {
11979                         if (cfg->exception_ptr) {
11980                                 ex = mono_class_get_exception_for_failure (cfg->exception_ptr);
11981                         } else {
11982                                 if (cfg->exception_type == MONO_EXCEPTION_MISSING_FIELD)
11983                                         ex = mono_exception_from_name_msg (mono_defaults.corlib, "System", "MissingFieldException", cfg->exception_message);
11984                                 else if (cfg->exception_type == MONO_EXCEPTION_MISSING_METHOD)
11985                                         ex = mono_exception_from_name_msg (mono_defaults.corlib, "System", "MissingMethodException", cfg->exception_message);
11986                                 else if (cfg->exception_type == MONO_EXCEPTION_TYPE_LOAD)
11987                                         ex = mono_exception_from_name_msg (mono_defaults.corlib, "System", "TypeLoadException", cfg->exception_message);
11988                                 else if (cfg->exception_type == MONO_EXCEPTION_FILE_NOT_FOUND)
11989                                         ex = mono_exception_from_name_msg (mono_defaults.corlib, "System", "FileNotFoundException", cfg->exception_message);
11990                                 else
11991                                         g_assert_not_reached ();
11992                         }
11993                 }
11994                 mono_destroy_compile (cfg);
11995                 mono_raise_exception (ex);
11996                 break;
11997         }
11998         case MONO_EXCEPTION_INVALID_PROGRAM: {
11999                 MonoException *ex = mono_exception_from_name_msg (mono_defaults.corlib, "System", "InvalidProgramException", cfg->exception_message);
12000                 mono_destroy_compile (cfg);
12001                 mono_raise_exception (ex);
12002                 break;
12003         }
12004         case MONO_EXCEPTION_UNVERIFIABLE_IL: {
12005                 MonoException *ex = mono_exception_from_name_msg (mono_defaults.corlib, "System.Security", "VerificationException", cfg->exception_message);
12006                 mono_destroy_compile (cfg);
12007                 mono_raise_exception (ex);
12008                 break;
12009         }
12010         case MONO_EXCEPTION_METHOD_ACCESS: {
12011                 MonoException *ex = mono_exception_from_name_msg (mono_defaults.corlib, "System", "MethodAccessException", cfg->exception_message);
12012                 mono_destroy_compile (cfg);
12013                 mono_raise_exception (ex);
12014                 break;
12015         }
12016         case MONO_EXCEPTION_FIELD_ACCESS: {
12017                 MonoException *ex = mono_exception_from_name_msg (mono_defaults.corlib, "System", "FieldAccessException", cfg->exception_message);
12018                 mono_destroy_compile (cfg);
12019                 mono_raise_exception (ex);
12020                 break;
12021         }
12022         /* this can only be set if the security manager is active */
12023         case MONO_EXCEPTION_SECURITY_LINKDEMAND: {
12024                 MonoSecurityManager* secman = mono_security_manager_get_methods ();
12025                 MonoObject *exc = NULL;
12026                 gpointer args [2];
12027
12028                 args [0] = &cfg->exception_data;
12029                 args [1] = &method;
12030                 mono_runtime_invoke (secman->linkdemandsecurityexception, NULL, args, &exc);
12031
12032                 mono_destroy_compile (cfg);
12033                 cfg = NULL;
12034
12035                 mono_raise_exception ((MonoException*)exc);
12036         }
12037         default:
12038                 g_assert_not_reached ();
12039         }
12040
12041         mono_domain_lock (target_domain);
12042
12043         /* Check if some other thread already did the job. In this case, we can
12044        discard the code this thread generated. */
12045
12046         if ((info = lookup_method (target_domain, method))) {
12047                 /* We can't use a domain specific method in another domain */
12048                 if ((target_domain == mono_domain_get ()) || info->domain_neutral) {
12049                         code = info->code_start;
12050 //                      printf("Discarding code for method %s\n", method->name);
12051                 }
12052         }
12053         
12054         if (code == NULL) {
12055                 mono_internal_hash_table_insert (&target_domain->jit_code_hash, method, cfg->jit_info);
12056                 code = cfg->native_code;
12057
12058                 if (cfg->generic_sharing_context && mono_method_is_generic_sharable_impl (method)) {
12059                         /* g_print ("inserting method %s.%s.%s\n", method->klass->name_space, method->klass->name, method->name); */
12060                         mono_domain_register_shared_generic (target_domain, 
12061                                 mono_method_get_declaring_generic_method (method), cfg->jit_info);
12062                         mono_stats.generics_shared_methods++;
12063                 }
12064         }
12065
12066         mono_destroy_compile (cfg);
12067
12068         if (target_domain->jump_target_hash) {
12069                 MonoJumpInfo patch_info;
12070                 GSList *list, *tmp;
12071                 list = g_hash_table_lookup (target_domain->jump_target_hash, method);
12072                 if (list) {
12073                         patch_info.next = NULL;
12074                         patch_info.ip.i = 0;
12075                         patch_info.type = MONO_PATCH_INFO_METHOD_JUMP;
12076                         patch_info.data.method = method;
12077                         g_hash_table_remove (target_domain->jump_target_hash, method);
12078                 }
12079                 for (tmp = list; tmp; tmp = tmp->next)
12080                         mono_arch_patch_code (NULL, target_domain, tmp->data, &patch_info, TRUE);
12081                 g_slist_free (list);
12082         }
12083
12084         mono_domain_unlock (target_domain);
12085
12086         mono_runtime_class_init (mono_class_vtable (target_domain, method->klass));
12087         return code;
12088 }
12089
12090 static gpointer
12091 mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt)
12092 {
12093         MonoDomain *target_domain, *domain = mono_domain_get ();
12094         MonoJitInfo *info;
12095         gpointer p;
12096         MonoJitICallInfo *callinfo = NULL;
12097
12098         /*
12099          * ICALL wrappers are handled specially, since there is only one copy of them
12100          * shared by all appdomains.
12101          */
12102         if ((method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) && (strstr (method->name, "__icall_wrapper_") == method->name)) {
12103                 const char *icall_name;
12104
12105                 icall_name = method->name + strlen ("__icall_wrapper_");
12106                 g_assert (icall_name);
12107                 callinfo = mono_find_jit_icall_by_name (icall_name);
12108                 g_assert (callinfo);
12109
12110                 /* Must be domain neutral since there is only one copy */
12111                 opt |= MONO_OPT_SHARED;
12112         }
12113
12114         if (opt & MONO_OPT_SHARED)
12115                 target_domain = mono_get_root_domain ();
12116         else 
12117                 target_domain = domain;
12118
12119         mono_domain_lock (target_domain);
12120
12121         if ((info = lookup_method (target_domain, method))) {
12122                 /* We can't use a domain specific method in another domain */
12123                 if (! ((domain != target_domain) && !info->domain_neutral)) {
12124                         mono_domain_unlock (target_domain);
12125                         mono_jit_stats.methods_lookups++;
12126                         mono_runtime_class_init (mono_class_vtable (domain, method->klass));
12127                         return mono_create_ftnptr (target_domain, info->code_start);
12128                 }
12129         }
12130
12131         mono_domain_unlock (target_domain);
12132         p = mono_create_ftnptr (target_domain, mono_jit_compile_method_inner (method, target_domain, opt));
12133
12134         if (callinfo) {
12135                 mono_jit_lock ();
12136                 if (!callinfo->wrapper) {
12137                         callinfo->wrapper = p;
12138                         mono_register_jit_icall_wrapper (callinfo, p);
12139                         mono_debug_add_icall_wrapper (method, callinfo);
12140                 }
12141                 mono_jit_unlock ();
12142         }
12143
12144         return p;
12145 }
12146
12147 static gpointer
12148 mono_jit_compile_method (MonoMethod *method)
12149 {
12150         return mono_jit_compile_method_with_opt (method, default_opt);
12151 }
12152
12153 static void
12154 invalidated_delegate_trampoline (char *desc)
12155 {
12156         g_error ("Unmanaged code called delegate of type %s which was already garbage collected.\n"
12157                  "See http://www.go-mono.com/delegate.html for an explanation and ways to fix this.",
12158                  desc);
12159 }
12160
12161 /*
12162  * mono_jit_free_method:
12163  *
12164  *  Free all memory allocated by the JIT for METHOD.
12165  */
12166 static void
12167 mono_jit_free_method (MonoDomain *domain, MonoMethod *method)
12168 {
12169         MonoJitDynamicMethodInfo *ji;
12170         gboolean destroy = TRUE;
12171
12172         g_assert (method->dynamic);
12173
12174         mono_domain_lock (domain);
12175         ji = mono_dynamic_code_hash_lookup (domain, method);
12176         mono_domain_unlock (domain);
12177
12178         if (!ji)
12179                 return;
12180         mono_domain_lock (domain);
12181         g_hash_table_remove (domain->dynamic_code_hash, method);
12182         mono_internal_hash_table_remove (&domain->jit_code_hash, method);
12183         g_hash_table_remove (domain->jump_trampoline_hash, method);
12184         mono_domain_unlock (domain);
12185
12186 #ifdef MONO_ARCH_HAVE_INVALIDATE_METHOD
12187         if (debug_options.keep_delegates && method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
12188                 /*
12189                  * Instead of freeing the code, change it to call an error routine
12190                  * so people can fix their code.
12191                  */
12192                 char *type = mono_type_full_name (&method->klass->byval_arg);
12193                 char *type_and_method = g_strdup_printf ("%s.%s", type, method->name);
12194
12195                 g_free (type);
12196                 mono_arch_invalidate_method (ji->ji, invalidated_delegate_trampoline, type_and_method);
12197                 destroy = FALSE;
12198         }
12199 #endif
12200
12201         /* 
12202          * This needs to be done before freeing code_mp, since the code address is the
12203          * key in the table, so if we free the code_mp first, another thread can grab the
12204          * same code address and replace our entry in the table.
12205          */
12206         mono_jit_info_table_remove (domain, ji->ji);
12207
12208         if (destroy)
12209                 mono_code_manager_destroy (ji->code_mp);
12210         mono_thread_hazardous_free_or_queue (ji->ji, g_free);
12211         g_free (ji);
12212 }
12213
12214 static gpointer
12215 mono_jit_find_compiled_method (MonoDomain *domain, MonoMethod *method)
12216 {
12217         MonoDomain *target_domain;
12218         MonoJitInfo *info;
12219
12220         if (default_opt & MONO_OPT_SHARED)
12221                 target_domain = mono_get_root_domain ();
12222         else 
12223                 target_domain = domain;
12224
12225         mono_domain_lock (target_domain);
12226
12227         if ((info = lookup_method (target_domain, method))) {
12228                 /* We can't use a domain specific method in another domain */
12229                 if (! ((domain != target_domain) && !info->domain_neutral)) {
12230                         mono_domain_unlock (target_domain);
12231                         mono_jit_stats.methods_lookups++;
12232                         return info->code_start;
12233                 }
12234         }
12235
12236         mono_domain_unlock (target_domain);
12237
12238         return NULL;
12239 }
12240
12241 /**
12242  * mono_jit_runtime_invoke:
12243  * @method: the method to invoke
12244  * @obj: this pointer
12245  * @params: array of parameter values.
12246  * @exc: used to catch exceptions objects
12247  */
12248 static MonoObject*
12249 mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
12250 {
12251         MonoMethod *invoke;
12252         MonoObject *(*runtime_invoke) (MonoObject *this, void **params, MonoObject **exc, void* compiled_method);
12253         void* compiled_method;
12254
12255         if (obj == NULL && !(method->flags & METHOD_ATTRIBUTE_STATIC) && !method->string_ctor && (method->wrapper_type == 0)) {
12256                 g_warning ("Ignoring invocation of an instance method on a NULL instance.\n");
12257                 return NULL;
12258         }
12259
12260         invoke = mono_marshal_get_runtime_invoke (method);
12261         runtime_invoke = mono_jit_compile_method (invoke);
12262         
12263         /* We need this here becuase mono_marshal_get_runtime_invoke can be place 
12264          * the helper method in System.Object and not the target class
12265          */
12266         mono_runtime_class_init (mono_class_vtable (mono_domain_get (), method->klass));
12267
12268         if (method->klass->rank && (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) &&
12269                 (method->iflags & METHOD_IMPL_ATTRIBUTE_NATIVE)) {
12270                 /* 
12271                  * Array Get/Set/Address methods. The JIT implements them using inline code 
12272                  * inside the runtime invoke wrappers, so no need to compile them.
12273                  */
12274                 compiled_method = NULL;
12275         } else {
12276                 compiled_method = mono_jit_compile_method (method);
12277         }
12278         return runtime_invoke (obj, params, exc, compiled_method);
12279 }
12280
12281 #ifdef MONO_GET_CONTEXT
12282 #define GET_CONTEXT MONO_GET_CONTEXT
12283 #endif
12284
12285 #ifndef GET_CONTEXT
12286 #ifdef PLATFORM_WIN32
12287 #define GET_CONTEXT \
12288         struct sigcontext *ctx = (struct sigcontext*)_dummy;
12289 #else
12290 #ifdef MONO_ARCH_USE_SIGACTION
12291 #define GET_CONTEXT \
12292     void *ctx = context;
12293 #elif defined(__sparc__)
12294 #define GET_CONTEXT \
12295     void *ctx = sigctx;
12296 #else
12297 #define GET_CONTEXT \
12298         void **_p = (void **)&_dummy; \
12299         struct sigcontext *ctx = (struct sigcontext *)++_p;
12300 #endif
12301 #endif
12302 #endif
12303
12304 #ifdef MONO_ARCH_USE_SIGACTION
12305 #define SIG_HANDLER_SIGNATURE(ftn) ftn (int _dummy, siginfo_t *info, void *context)
12306 #elif defined(__sparc__)
12307 #define SIG_HANDLER_SIGNATURE(ftn) ftn (int _dummy, void *sigctx)
12308 #else
12309 #define SIG_HANDLER_SIGNATURE(ftn) ftn (int _dummy)
12310 #endif
12311
12312 static void
12313 SIG_HANDLER_SIGNATURE (sigfpe_signal_handler)
12314 {
12315         MonoException *exc = NULL;
12316 #ifndef MONO_ARCH_USE_SIGACTION
12317         void *info = NULL;
12318 #endif
12319         GET_CONTEXT;
12320
12321 #if defined(MONO_ARCH_HAVE_IS_INT_OVERFLOW)
12322         if (mono_arch_is_int_overflow (ctx, info))
12323                 exc = mono_get_exception_arithmetic ();
12324         else
12325                 exc = mono_get_exception_divide_by_zero ();
12326 #else
12327         exc = mono_get_exception_divide_by_zero ();
12328 #endif
12329         
12330         mono_arch_handle_exception (ctx, exc, FALSE);
12331 }
12332
12333 static void
12334 SIG_HANDLER_SIGNATURE (sigill_signal_handler)
12335 {
12336         MonoException *exc;
12337         GET_CONTEXT;
12338
12339         exc = mono_get_exception_execution_engine ("SIGILL");
12340         
12341         mono_arch_handle_exception (ctx, exc, FALSE);
12342 }
12343
12344 static void
12345 SIG_HANDLER_SIGNATURE (sigsegv_signal_handler)
12346 {
12347 #ifndef MONO_ARCH_SIGSEGV_ON_ALTSTACK
12348         MonoException *exc = NULL;
12349 #endif
12350         MonoJitInfo *ji;
12351
12352 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
12353         MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
12354 #endif
12355         GET_CONTEXT;
12356
12357 #ifdef MONO_ARCH_USE_SIGACTION
12358         if (debug_options.collect_pagefault_stats) {
12359                 if (mono_raw_buffer_is_pagefault (info->si_addr)) {
12360                         mono_raw_buffer_handle_pagefault (info->si_addr);
12361                         return;
12362                 }
12363                 if (mono_aot_is_pagefault (info->si_addr)) {
12364                         mono_aot_handle_pagefault (info->si_addr);
12365                         return;
12366                 }
12367         }
12368 #endif
12369
12370         ji = mono_jit_info_table_find (mono_domain_get (), mono_arch_ip_from_context (ctx));
12371
12372 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
12373         /* we got a stack overflow in the soft-guard pages
12374          * There are two cases:
12375          * 1) managed code caused the overflow: we unprotect the soft-guard page
12376          * and let the arch-specific code trigger the exception handling mechanism
12377          * in the thread stack. The soft-guard pages will be protected again as the stack is unwound.
12378          * 2) unmanaged code caused the overflow: we unprotect the soft-guard page
12379          * and hope we can continue with those enabled, at least until the hard-guard page
12380          * is hit. The alternative to continuing here is to just print a message and abort.
12381          * We may add in the future the code to protect the pages again in the codepath
12382          * when we return from unmanaged to managed code.
12383          */
12384         if (jit_tls->stack_ovf_guard_size && (guint8*)info->si_addr >= (guint8*)jit_tls->stack_ovf_guard_base &&
12385                         (guint8*)info->si_addr < (guint8*)jit_tls->stack_ovf_guard_base + jit_tls->stack_ovf_guard_size) {
12386                 mono_mprotect (jit_tls->stack_ovf_guard_base, jit_tls->stack_ovf_guard_size, MONO_MMAP_READ|MONO_MMAP_WRITE|MONO_MMAP_EXEC);
12387                 if (ji) {
12388                         mono_arch_handle_altstack_exception (ctx, info->si_addr, TRUE);
12389                 } else {
12390                         /* We print a message: after this even managed stack overflows
12391                          * may crash the runtime
12392                          */
12393                         fprintf (stderr, "Stack overflow in unmanaged: IP: %p, fault addr: %p\n", mono_arch_ip_from_context (ctx), (gpointer)info->si_addr);
12394                 }
12395                 return;
12396         }
12397         /* The hard-guard page has been hit: there is not much we can do anymore
12398          * Print a hopefully clear message and abort.
12399          */
12400         if (jit_tls->stack_size && 
12401                         ABS ((guint8*)info->si_addr - ((guint8*)jit_tls->end_of_stack - jit_tls->stack_size)) < 32768) {
12402                 const char *method;
12403                 /* we don't do much now, but we can warn the user with a useful message */
12404                 fprintf (stderr, "Stack overflow: IP: %p, fault addr: %p\n", mono_arch_ip_from_context (ctx), (gpointer)info->si_addr);
12405                 if (ji && ji->method)
12406                         method = mono_method_full_name (ji->method, TRUE);
12407                 else
12408                         method = "Unmanaged";
12409                 fprintf (stderr, "At %s\n", method);
12410                 abort ();
12411         } else {
12412                 mono_arch_handle_altstack_exception (ctx, info->si_addr, FALSE);
12413         }
12414 #else
12415
12416         if (!ji) {
12417                 mono_handle_native_sigsegv (SIGSEGV, ctx);
12418         }
12419                         
12420         mono_arch_handle_exception (ctx, exc, FALSE);
12421 #endif
12422 }
12423
12424 #ifndef PLATFORM_WIN32
12425
12426 static void
12427 SIG_HANDLER_SIGNATURE (sigabrt_signal_handler)
12428 {
12429         MonoJitInfo *ji;
12430         GET_CONTEXT;
12431
12432         ji = mono_jit_info_table_find (mono_domain_get (), mono_arch_ip_from_context(ctx));
12433         if (!ji) {
12434                 mono_handle_native_sigsegv (SIGABRT, ctx);
12435         }
12436 }
12437
12438 static void
12439 SIG_HANDLER_SIGNATURE (sigusr1_signal_handler)
12440 {
12441         gboolean running_managed;
12442         MonoException *exc;
12443         MonoThread *thread = mono_thread_current ();
12444         void *ji;
12445         
12446         GET_CONTEXT;
12447
12448         if (thread->thread_dump_requested) {
12449                 thread->thread_dump_requested = FALSE;
12450
12451                 mono_print_thread_dump (ctx);
12452         }
12453
12454         /*
12455          * FIXME:
12456          * This is an async signal, so the code below must not call anything which
12457          * is not async safe. That includes the pthread locking functions. If we
12458          * know that we interrupted managed code, then locking is safe.
12459          */
12460         ji = mono_jit_info_table_find (mono_domain_get (), mono_arch_ip_from_context(ctx));
12461         running_managed = ji != NULL;
12462         
12463         exc = mono_thread_request_interruption (running_managed); 
12464         if (!exc) return;
12465
12466         mono_arch_handle_exception (ctx, exc, FALSE);
12467 }
12468
12469 static void
12470 SIG_HANDLER_SIGNATURE (sigprof_signal_handler)
12471 {
12472         GET_CONTEXT;
12473
12474         mono_profiler_stat_hit (mono_arch_ip_from_context (ctx), ctx);
12475 }
12476
12477 static void
12478 SIG_HANDLER_SIGNATURE (sigquit_signal_handler)
12479 {
12480         GET_CONTEXT;
12481
12482         printf ("Full thread dump:\n");
12483
12484         mono_threads_request_thread_dump ();
12485
12486         /*
12487          * print_thread_dump () skips the current thread, since sending a signal
12488          * to it would invoke the signal handler below the sigquit signal handler,
12489          * and signal handlers don't create an lmf, so the stack walk could not
12490          * be performed.
12491          */
12492         mono_print_thread_dump (ctx);
12493 }
12494
12495 static void
12496 SIG_HANDLER_SIGNATURE (sigusr2_signal_handler)
12497 {
12498         gboolean enabled = mono_trace_is_enabled ();
12499
12500         mono_trace_enable (!enabled);
12501 }
12502
12503 #endif
12504
12505 static void
12506 SIG_HANDLER_SIGNATURE (sigint_signal_handler)
12507 {
12508         MonoException *exc;
12509         GET_CONTEXT;
12510
12511         exc = mono_get_exception_execution_engine ("Interrupted (SIGINT).");
12512         
12513         mono_arch_handle_exception (ctx, exc, FALSE);
12514 }
12515
12516 #ifdef PLATFORM_MACOSX
12517
12518 /*
12519  * This code disables the CrashReporter of MacOS X by installing
12520  * a dummy Mach exception handler.
12521  */
12522
12523 /*
12524  * http://darwinsource.opendarwin.org/10.4.3/xnu-792.6.22/osfmk/man/exc_server.html
12525  */
12526 extern
12527 boolean_t
12528 exc_server (mach_msg_header_t *request_msg,
12529             mach_msg_header_t *reply_msg);
12530
12531 /*
12532  * The exception message
12533  */
12534 typedef struct {
12535         mach_msg_base_t msg;  /* common mach message header */
12536         char payload [1024];  /* opaque */
12537 } mach_exception_msg_t;
12538
12539 /* The exception port */
12540 static mach_port_t mach_exception_port = VM_MAP_NULL;
12541
12542 /*
12543  * Implicitly called by exc_server. Must be public.
12544  *
12545  * http://darwinsource.opendarwin.org/10.4.3/xnu-792.6.22/osfmk/man/catch_exception_raise.html
12546  */
12547 kern_return_t
12548 catch_exception_raise (
12549         mach_port_t exception_port,
12550         mach_port_t thread,
12551         mach_port_t task,
12552         exception_type_t exception,
12553         exception_data_t code,
12554         mach_msg_type_number_t code_count)
12555 {
12556         /* consume the exception */
12557         return KERN_FAILURE;
12558 }
12559
12560 /*
12561  * Exception thread handler.
12562  */
12563 static
12564 void *
12565 mach_exception_thread (void *arg)
12566 {
12567         for (;;) {
12568                 mach_exception_msg_t request;
12569                 mach_exception_msg_t reply;
12570                 mach_msg_return_t result;
12571
12572                 /* receive from "mach_exception_port" */
12573                 result = mach_msg (&request.msg.header,
12574                                    MACH_RCV_MSG | MACH_RCV_LARGE,
12575                                    0,
12576                                    sizeof (request),
12577                                    mach_exception_port,
12578                                    MACH_MSG_TIMEOUT_NONE,
12579                                    MACH_PORT_NULL);
12580
12581                 g_assert (result == MACH_MSG_SUCCESS);
12582
12583                 /* dispatch to catch_exception_raise () */
12584                 exc_server (&request.msg.header, &reply.msg.header);
12585
12586                 /* send back to sender */
12587                 result = mach_msg (&reply.msg.header,
12588                                    MACH_SEND_MSG,
12589                                    reply.msg.header.msgh_size,
12590                                    0,
12591                                    MACH_PORT_NULL,
12592                                    MACH_MSG_TIMEOUT_NONE,
12593                                    MACH_PORT_NULL);
12594
12595                 g_assert (result == MACH_MSG_SUCCESS);
12596         }
12597         return NULL;
12598 }
12599
12600 static void
12601 macosx_register_exception_handler ()
12602 {
12603         mach_port_t task;
12604         pthread_attr_t attr;
12605         pthread_t thread;
12606
12607         if (mach_exception_port != VM_MAP_NULL)
12608                 return;
12609
12610         task = mach_task_self ();
12611
12612         /* create the "mach_exception_port" with send & receive rights */
12613         g_assert (mach_port_allocate (task, MACH_PORT_RIGHT_RECEIVE,
12614                                       &mach_exception_port) == KERN_SUCCESS);
12615         g_assert (mach_port_insert_right (task, mach_exception_port, mach_exception_port,
12616                                           MACH_MSG_TYPE_MAKE_SEND) == KERN_SUCCESS);
12617
12618         /* create the exception handler thread */
12619         g_assert (!pthread_attr_init (&attr));
12620         g_assert (!pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED));
12621         g_assert (!pthread_create (&thread, &attr, mach_exception_thread, NULL));
12622         pthread_attr_destroy (&attr);
12623
12624         /*
12625          * register "mach_exception_port" as a receiver for the
12626          * EXC_BAD_ACCESS exception
12627          *
12628          * http://darwinsource.opendarwin.org/10.4.3/xnu-792.6.22/osfmk/man/task_set_exception_ports.html
12629          */
12630         g_assert (task_set_exception_ports (task, EXC_MASK_BAD_ACCESS,
12631                                             mach_exception_port,
12632                                             EXCEPTION_DEFAULT,
12633                                             MACHINE_THREAD_STATE) == KERN_SUCCESS);
12634 }
12635 #endif
12636
12637 #ifndef PLATFORM_WIN32
12638 static void
12639 add_signal_handler (int signo, gpointer handler)
12640 {
12641         struct sigaction sa;
12642
12643 #ifdef MONO_ARCH_USE_SIGACTION
12644         sa.sa_sigaction = handler;
12645         sigemptyset (&sa.sa_mask);
12646         sa.sa_flags = SA_SIGINFO;
12647 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
12648         if (signo == SIGSEGV)
12649                 sa.sa_flags |= SA_ONSTACK;
12650 #endif
12651 #else
12652         sa.sa_handler = handler;
12653         sigemptyset (&sa.sa_mask);
12654         sa.sa_flags = 0;
12655 #endif
12656         g_assert (sigaction (signo, &sa, NULL) != -1);
12657 }
12658
12659 static void
12660 remove_signal_handler (int signo)
12661 {
12662         struct sigaction sa;
12663
12664         sa.sa_handler = SIG_DFL;
12665         sigemptyset (&sa.sa_mask);
12666         sa.sa_flags = 0;
12667
12668         g_assert (sigaction (signo, &sa, NULL) != -1);
12669 }
12670 #endif
12671
12672 static void
12673 mono_runtime_install_handlers (void)
12674 {
12675 #ifdef PLATFORM_WIN32
12676         win32_seh_init();
12677         win32_seh_set_handler(SIGFPE, sigfpe_signal_handler);
12678         win32_seh_set_handler(SIGILL, sigill_signal_handler);
12679         win32_seh_set_handler(SIGSEGV, sigsegv_signal_handler);
12680         if (debug_options.handle_sigint)
12681                 win32_seh_set_handler(SIGINT, sigint_signal_handler);
12682
12683 #else /* !PLATFORM_WIN32 */
12684
12685
12686 #ifdef PLATFORM_MACOSX
12687         macosx_register_exception_handler ();
12688 #endif
12689
12690         if (debug_options.handle_sigint)
12691                 add_signal_handler (SIGINT, sigint_signal_handler);
12692
12693         add_signal_handler (SIGFPE, sigfpe_signal_handler);
12694         add_signal_handler (SIGQUIT, sigquit_signal_handler);
12695         add_signal_handler (SIGILL, sigill_signal_handler);
12696         add_signal_handler (SIGBUS, sigsegv_signal_handler);
12697         if (mono_jit_trace_calls != NULL)
12698                 add_signal_handler (SIGUSR2, sigusr2_signal_handler);
12699
12700         add_signal_handler (mono_thread_get_abort_signal (), sigusr1_signal_handler);
12701         signal (SIGPIPE, SIG_IGN);
12702
12703         add_signal_handler (SIGABRT, sigabrt_signal_handler);
12704
12705         /* catch SIGSEGV */
12706         add_signal_handler (SIGSEGV, sigsegv_signal_handler);
12707 #endif /* PLATFORM_WIN32 */
12708 }
12709
12710 static void
12711 mono_runtime_cleanup_handlers (void)
12712 {
12713 #ifdef PLATFORM_WIN32
12714         win32_seh_cleanup();
12715 #else
12716         if (debug_options.handle_sigint)
12717                 remove_signal_handler (SIGINT);
12718
12719         remove_signal_handler (SIGFPE);
12720         remove_signal_handler (SIGQUIT);
12721         remove_signal_handler (SIGILL);
12722         remove_signal_handler (SIGBUS);
12723         if (mono_jit_trace_calls != NULL)
12724                 remove_signal_handler (SIGUSR2);
12725
12726         remove_signal_handler (mono_thread_get_abort_signal ());
12727
12728         remove_signal_handler (SIGABRT);
12729
12730         remove_signal_handler (SIGSEGV);
12731 #endif /* PLATFORM_WIN32 */
12732 }
12733
12734
12735 #ifdef HAVE_LINUX_RTC_H
12736 #include <linux/rtc.h>
12737 #include <sys/ioctl.h>
12738 #include <fcntl.h>
12739 static int rtc_fd = -1;
12740
12741 static int
12742 enable_rtc_timer (gboolean enable)
12743 {
12744         int flags;
12745         flags = fcntl (rtc_fd, F_GETFL);
12746         if (flags < 0) {
12747                 perror ("getflags");
12748                 return 0;
12749         }
12750         if (enable)
12751                 flags |= FASYNC;
12752         else
12753                 flags &= ~FASYNC;
12754         if (fcntl (rtc_fd, F_SETFL, flags) == -1) {
12755                 perror ("setflags");
12756                 return 0;
12757         }
12758         return 1;
12759 }
12760 #endif
12761
12762 #ifdef PLATFORM_WIN32
12763 static HANDLE win32_main_thread;
12764 static MMRESULT win32_timer;
12765
12766 static void CALLBACK
12767 win32_time_proc (UINT uID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2)
12768 {
12769         CONTEXT context;
12770
12771         context.ContextFlags = CONTEXT_CONTROL;
12772         if (GetThreadContext (win32_main_thread, &context)) {
12773 #ifdef _WIN64
12774                 mono_profiler_stat_hit ((guchar *) context.Rip, &context);
12775 #else
12776                 mono_profiler_stat_hit ((guchar *) context.Eip, &context);
12777 #endif
12778         }
12779 }
12780 #endif
12781
12782 static void
12783 setup_stat_profiler (void)
12784 {
12785 #ifdef ITIMER_PROF
12786         struct itimerval itval;
12787         static int inited = 0;
12788 #ifdef HAVE_LINUX_RTC_H
12789         const char *rtc_freq;
12790         if (!inited && (rtc_freq = g_getenv ("MONO_RTC"))) {
12791                 int freq = 0;
12792                 inited = 1;
12793                 if (*rtc_freq)
12794                         freq = atoi (rtc_freq);
12795                 if (!freq)
12796                         freq = 1024;
12797                 rtc_fd = open ("/dev/rtc", O_RDONLY);
12798                 if (rtc_fd == -1) {
12799                         perror ("open /dev/rtc");
12800                         return;
12801                 }
12802                 add_signal_handler (SIGPROF, sigprof_signal_handler);
12803                 if (ioctl (rtc_fd, RTC_IRQP_SET, freq) == -1) {
12804                         perror ("set rtc freq");
12805                         return;
12806                 }
12807                 if (ioctl (rtc_fd, RTC_PIE_ON, 0) == -1) {
12808                         perror ("start rtc");
12809                         return;
12810                 }
12811                 if (fcntl (rtc_fd, F_SETSIG, SIGPROF) == -1) {
12812                         perror ("setsig");
12813                         return;
12814                 }
12815                 if (fcntl (rtc_fd, F_SETOWN, getpid ()) == -1) {
12816                         perror ("setown");
12817                         return;
12818                 }
12819                 enable_rtc_timer (TRUE);
12820                 return;
12821         }
12822         if (rtc_fd >= 0)
12823                 return;
12824 #endif
12825
12826         itval.it_interval.tv_usec = 999;
12827         itval.it_interval.tv_sec = 0;
12828         itval.it_value = itval.it_interval;
12829         setitimer (ITIMER_PROF, &itval, NULL);
12830         if (inited)
12831                 return;
12832         inited = 1;
12833         add_signal_handler (SIGPROF, sigprof_signal_handler);
12834 #elif defined (PLATFORM_WIN32)
12835         static int inited = 0;
12836         TIMECAPS timecaps;
12837
12838         if (inited)
12839                 return;
12840
12841         inited = 1;
12842         if (timeGetDevCaps (&timecaps, sizeof (timecaps)) != TIMERR_NOERROR)
12843                 return;
12844
12845         if ((win32_main_thread = OpenThread (READ_CONTROL | THREAD_GET_CONTEXT, FALSE, GetCurrentThreadId ())) == NULL)
12846                 return;
12847
12848         if (timeBeginPeriod (1) != TIMERR_NOERROR)
12849                 return;
12850
12851         if ((win32_timer = timeSetEvent (1, 0, win32_time_proc, 0, TIME_PERIODIC)) == 0) {
12852                 timeEndPeriod (1);
12853                 return;
12854         }
12855 #endif
12856 }
12857
12858 /* mono_jit_create_remoting_trampoline:
12859  * @method: pointer to the method info
12860  *
12861  * Creates a trampoline which calls the remoting functions. This
12862  * is used in the vtable of transparent proxies.
12863  * 
12864  * Returns: a pointer to the newly created code 
12865  */
12866 static gpointer
12867 mono_jit_create_remoting_trampoline (MonoMethod *method, MonoRemotingTarget target)
12868 {
12869         MonoMethod *nm;
12870         guint8 *addr = NULL;
12871
12872         if ((method->flags & METHOD_ATTRIBUTE_ABSTRACT) || 
12873             (mono_method_signature (method)->hasthis && (method->klass->marshalbyref || method->klass == mono_defaults.object_class))) {
12874                 nm = mono_marshal_get_remoting_invoke_for_target (method, target);
12875                 addr = mono_compile_method (nm);
12876         } else {
12877                 addr = mono_compile_method (method);
12878         }
12879         return mono_get_addr_from_ftnptr (addr);
12880 }
12881
12882 #ifdef MONO_ARCH_HAVE_IMT
12883 static gpointer
12884 mini_get_imt_trampoline (void)
12885 {
12886         static gpointer tramp = NULL;
12887         if (!tramp)
12888                 tramp =  mono_arch_create_specific_trampoline (MONO_FAKE_IMT_METHOD, MONO_TRAMPOLINE_GENERIC, mono_get_root_domain (), NULL);
12889         return tramp;
12890 }
12891 #endif
12892
12893 #ifdef MONO_ARCH_COMMON_VTABLE_TRAMPOLINE
12894 gpointer
12895 mini_get_vtable_trampoline (void)
12896 {
12897         static gpointer tramp = NULL;
12898         if (!tramp)
12899                 tramp =  mono_arch_create_specific_trampoline (MONO_FAKE_VTABLE_METHOD, MONO_TRAMPOLINE_GENERIC, mono_get_root_domain (), NULL);
12900         return tramp;
12901 }
12902 #endif
12903
12904 static void
12905 mini_parse_debug_options (void)
12906 {
12907         char *options = getenv ("MONO_DEBUG");
12908         gchar **args, **ptr;
12909         
12910         if (!options)
12911                 return;
12912
12913         args = g_strsplit (options, ",", -1);
12914
12915         for (ptr = args; ptr && *ptr; ptr++) {
12916                 const char *arg = *ptr;
12917
12918                 if (!strcmp (arg, "handle-sigint"))
12919                         debug_options.handle_sigint = TRUE;
12920                 else if (!strcmp (arg, "keep-delegates"))
12921                         debug_options.keep_delegates = TRUE;
12922                 else if (!strcmp (arg, "collect-pagefault-stats"))
12923                         debug_options.collect_pagefault_stats = TRUE;
12924                 else if (!strcmp (arg, "break-on-unverified"))
12925                         debug_options.break_on_unverified = TRUE;
12926                 else {
12927                         fprintf (stderr, "Invalid option for the MONO_DEBUG env variable: %s\n", arg);
12928                         fprintf (stderr, "Available options: 'handle-sigint', 'keep-delegates', 'collect-pagefault-stats', 'break-on-unverified'\n");
12929                         exit (1);
12930                 }
12931         }
12932 }
12933
12934 MonoDomain *
12935 mini_init (const char *filename, const char *runtime_version)
12936 {
12937         MonoDomain *domain;
12938
12939 #ifdef __linux__
12940         if (access ("/proc/self/maps", F_OK) != 0) {
12941                 g_print ("Mono requires /proc to be mounted.\n");
12942                 exit (1);
12943         }
12944 #endif
12945
12946         /* Happens when using the embedding interface */
12947         if (!default_opt_set)
12948                 default_opt = mono_parse_default_optimizations (NULL);
12949
12950         InitializeCriticalSection (&jit_mutex);
12951
12952         if (!global_codeman)
12953                 global_codeman = mono_code_manager_new ();
12954         jit_icall_name_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
12955
12956         mono_arch_cpu_init ();
12957
12958         mono_arch_init ();
12959
12960         mono_init_trampolines ();
12961
12962         mono_init_exceptions ();
12963
12964         if (!g_thread_supported ())
12965                 g_thread_init (NULL);
12966
12967         if (getenv ("MONO_DEBUG") != NULL)
12968                 mini_parse_debug_options ();
12969
12970         mono_gc_base_init ();
12971
12972         mono_jit_tls_id = TlsAlloc ();
12973         setup_jit_tls_data ((gpointer)-1, mono_thread_abort);
12974
12975         mono_burg_init ();
12976
12977         if (default_opt & MONO_OPT_AOT)
12978                 mono_aot_init ();
12979
12980         mono_runtime_install_handlers ();
12981         mono_threads_install_cleanup (mini_thread_cleanup);
12982
12983 #ifdef MONO_ARCH_HAVE_NOTIFY_PENDING_EXC
12984         // This is experimental code so provide an env var to switch it off
12985         if (getenv ("MONO_DISABLE_PENDING_EXCEPTIONS")) {
12986                 printf ("MONO_DISABLE_PENDING_EXCEPTIONS env var set.\n");
12987         } else {
12988                 check_for_pending_exc = FALSE;
12989                 mono_threads_install_notify_pending_exc (mono_arch_notify_pending_exc);
12990         }
12991 #endif
12992
12993 #define JIT_TRAMPOLINES_WORK
12994 #ifdef JIT_TRAMPOLINES_WORK
12995         mono_install_compile_method (mono_jit_compile_method);
12996         mono_install_free_method (mono_jit_free_method);
12997         mono_install_trampoline (mono_create_jit_trampoline);
12998         mono_install_jump_trampoline (mono_create_jump_trampoline);
12999         mono_install_remoting_trampoline (mono_jit_create_remoting_trampoline);
13000         mono_install_delegate_trampoline (mono_create_delegate_trampoline);
13001 #endif
13002 #define JIT_INVOKE_WORKS
13003 #ifdef JIT_INVOKE_WORKS
13004         mono_install_runtime_invoke (mono_jit_runtime_invoke);
13005         mono_install_handler (mono_arch_get_throw_exception ());
13006 #endif
13007         mono_install_stack_walk (mono_jit_walk_stack);
13008         mono_install_init_vtable (mono_aot_init_vtable);
13009         mono_install_get_cached_class_info (mono_aot_get_cached_class_info);
13010         mono_install_get_class_from_name (mono_aot_get_class_from_name);
13011         mono_install_jit_info_find_in_aot (mono_aot_find_jit_info);
13012
13013         if (debug_options.collect_pagefault_stats) {
13014                 mono_raw_buffer_set_make_unreadable (TRUE);
13015                 mono_aot_set_make_unreadable (TRUE);
13016         }
13017
13018         if (runtime_version)
13019                 domain = mono_init_version (filename, runtime_version);
13020         else
13021                 domain = mono_init_from_assembly (filename, filename);
13022 #ifdef MONO_ARCH_HAVE_IMT
13023         mono_install_imt_thunk_builder (mono_arch_build_imt_thunk);
13024         mono_install_imt_trampoline (mini_get_imt_trampoline ());
13025 #if MONO_ARCH_COMMON_VTABLE_TRAMPOLINE
13026         mono_install_vtable_trampoline (mini_get_vtable_trampoline ());
13027 #endif
13028 #endif
13029         mono_icall_init ();
13030
13031         mono_add_internal_call ("System.Diagnostics.StackFrame::get_frame_info", 
13032                                 ves_icall_get_frame_info);
13033         mono_add_internal_call ("System.Diagnostics.StackTrace::get_trace", 
13034                                 ves_icall_get_trace);
13035         mono_add_internal_call ("System.Exception::get_trace", 
13036                                 ves_icall_System_Exception_get_trace);
13037         mono_add_internal_call ("System.Security.SecurityFrame::_GetSecurityFrame",
13038                                 ves_icall_System_Security_SecurityFrame_GetSecurityFrame);
13039         mono_add_internal_call ("System.Security.SecurityFrame::_GetSecurityStack",
13040                                 ves_icall_System_Security_SecurityFrame_GetSecurityStack);
13041         mono_add_internal_call ("Mono.Runtime::mono_runtime_install_handlers", 
13042                                 mono_runtime_install_handlers);
13043
13044
13045         create_helper_signature ();
13046
13047 #define JIT_CALLS_WORK
13048 #ifdef JIT_CALLS_WORK
13049         /* Needs to be called here since register_jit_icall depends on it */
13050         mono_marshal_init ();
13051
13052         mono_arch_register_lowlevel_calls ();
13053         register_icall (mono_profiler_method_enter, "mono_profiler_method_enter", NULL, TRUE);
13054         register_icall (mono_profiler_method_leave, "mono_profiler_method_leave", NULL, TRUE);
13055         register_icall (mono_trace_enter_method, "mono_trace_enter_method", NULL, TRUE);
13056         register_icall (mono_trace_leave_method, "mono_trace_leave_method", NULL, TRUE);
13057         register_icall (mono_get_lmf_addr, "mono_get_lmf_addr", "ptr", TRUE);
13058         register_icall (mono_jit_thread_attach, "mono_jit_thread_attach", "void", TRUE);
13059         register_icall (mono_domain_get, "mono_domain_get", "ptr", TRUE);
13060
13061         register_icall (mono_arch_get_throw_exception (), "mono_arch_throw_exception", "void object", TRUE);
13062         register_icall (mono_arch_get_rethrow_exception (), "mono_arch_rethrow_exception", "void object", TRUE);
13063         register_icall (mono_arch_get_throw_exception_by_name (), "mono_arch_throw_exception_by_name", "void ptr", TRUE); 
13064 #if MONO_ARCH_HAVE_THROW_CORLIB_EXCEPTION
13065         register_icall (mono_arch_get_throw_corlib_exception (), "mono_arch_throw_corlib_exception", 
13066                                  "void ptr", TRUE);
13067 #endif
13068         register_icall (mono_thread_get_undeniable_exception, "mono_thread_get_undeniable_exception", "object", FALSE);
13069         register_icall (mono_thread_interruption_checkpoint, "mono_thread_interruption_checkpoint", "void", FALSE);
13070         register_icall (mono_thread_force_interruption_checkpoint, "mono_thread_force_interruption_checkpoint", "void", FALSE);
13071         register_icall (mono_load_remote_field_new, "mono_load_remote_field_new", "object object ptr ptr", FALSE);
13072         register_icall (mono_store_remote_field_new, "mono_store_remote_field_new", "void object ptr ptr object", FALSE);
13073
13074         /* 
13075          * NOTE, NOTE, NOTE, NOTE:
13076          * when adding emulation for some opcodes, remember to also add a dummy
13077          * rule to the burg files, because we need the arity information to be correct.
13078          */
13079 #ifndef MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS
13080         mono_register_opcode_emulation (OP_LMUL, "__emul_lmul", "long long long", mono_llmult, TRUE);
13081         mono_register_opcode_emulation (OP_LDIV, "__emul_ldiv", "long long long", mono_lldiv, FALSE);
13082         mono_register_opcode_emulation (OP_LDIV_UN, "__emul_ldiv_un", "long long long", mono_lldiv_un, FALSE);
13083         mono_register_opcode_emulation (OP_LREM, "__emul_lrem", "long long long", mono_llrem, FALSE);
13084         mono_register_opcode_emulation (OP_LREM_UN, "__emul_lrem_un", "long long long", mono_llrem_un, FALSE);
13085         mono_register_opcode_emulation (OP_LMUL_OVF_UN, "__emul_lmul_ovf_un", "long long long", mono_llmult_ovf_un, FALSE);
13086         mono_register_opcode_emulation (OP_LMUL_OVF, "__emul_lmul_ovf", "long long long", mono_llmult_ovf, FALSE);
13087 #endif
13088
13089 #ifndef MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
13090         mono_register_opcode_emulation (OP_LSHL, "__emul_lshl", "long long int32", mono_lshl, TRUE);
13091         mono_register_opcode_emulation (OP_LSHR, "__emul_lshr", "long long int32", mono_lshr, TRUE);
13092         mono_register_opcode_emulation (OP_LSHR_UN, "__emul_lshr_un", "long long int32", mono_lshr_un, TRUE);
13093 #endif
13094
13095 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
13096         mono_register_opcode_emulation (CEE_DIV, "__emul_idiv", "int32 int32 int32", mono_idiv, FALSE);
13097         mono_register_opcode_emulation (CEE_DIV_UN, "__emul_idiv_un", "int32 int32 int32", mono_idiv_un, FALSE);
13098         mono_register_opcode_emulation (CEE_REM, "__emul_irem", "int32 int32 int32", mono_irem, FALSE);
13099         mono_register_opcode_emulation (CEE_REM_UN, "__emul_irem_un", "int32 int32 int32", mono_irem_un, FALSE);
13100 #endif
13101
13102 #ifdef MONO_ARCH_EMULATE_MUL_DIV
13103         mono_register_opcode_emulation (CEE_MUL_OVF, "__emul_imul_ovf", "int32 int32 int32", mono_imul_ovf, FALSE);
13104         mono_register_opcode_emulation (CEE_MUL_OVF_UN, "__emul_imul_ovf_un", "int32 int32 int32", mono_imul_ovf_un, FALSE);
13105         mono_register_opcode_emulation (CEE_MUL, "__emul_imul", "int32 int32 int32", mono_imul, TRUE);
13106 #endif
13107 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_SOFT_FLOAT)
13108         mono_register_opcode_emulation (OP_FDIV, "__emul_fdiv", "double double double", mono_fdiv, FALSE);
13109 #endif
13110
13111         mono_register_opcode_emulation (OP_FCONV_TO_U8, "__emul_fconv_to_u8", "ulong double", mono_fconv_u8, FALSE);
13112         mono_register_opcode_emulation (OP_FCONV_TO_U4, "__emul_fconv_to_u4", "uint32 double", mono_fconv_u4, FALSE);
13113         mono_register_opcode_emulation (OP_FCONV_TO_OVF_I8, "__emul_fconv_to_ovf_i8", "long double", mono_fconv_ovf_i8, FALSE);
13114         mono_register_opcode_emulation (OP_FCONV_TO_OVF_U8, "__emul_fconv_to_ovf_u8", "ulong double", mono_fconv_ovf_u8, FALSE);
13115
13116 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
13117         mono_register_opcode_emulation (OP_FCONV_TO_I8, "__emul_fconv_to_i8", "long double", mono_fconv_i8, FALSE);
13118 #endif
13119 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
13120         mono_register_opcode_emulation (CEE_CONV_R_UN, "__emul_conv_r_un", "double int32", mono_conv_to_r8_un, FALSE);
13121 #endif
13122 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
13123         mono_register_opcode_emulation (OP_LCONV_TO_R8, "__emul_lconv_to_r8", "double long", mono_lconv_to_r8, FALSE);
13124 #endif
13125 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
13126         mono_register_opcode_emulation (OP_LCONV_TO_R4, "__emul_lconv_to_r4", "float long", mono_lconv_to_r4, FALSE);
13127 #endif
13128 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
13129         mono_register_opcode_emulation (OP_LCONV_TO_R_UN, "__emul_lconv_to_r8_un", "double long", mono_lconv_to_r8_un, FALSE);
13130 #endif
13131 #ifdef MONO_ARCH_EMULATE_FREM
13132         mono_register_opcode_emulation (OP_FREM, "__emul_frem", "double double double", fmod, FALSE);
13133 #endif
13134
13135 #ifdef MONO_ARCH_SOFT_FLOAT
13136         mono_register_opcode_emulation (OP_FSUB, "__emul_fsub", "double double double", mono_fsub, FALSE);
13137         mono_register_opcode_emulation (OP_FADD, "__emul_fadd", "double double double", mono_fadd, FALSE);
13138         mono_register_opcode_emulation (OP_FMUL, "__emul_fmul", "double double double", mono_fmul, FALSE);
13139         mono_register_opcode_emulation (OP_FNEG, "__emul_fneg", "double double", mono_fneg, FALSE);
13140         mono_register_opcode_emulation (CEE_CONV_R8, "__emul_conv_r8", "double int32", mono_conv_to_r8, FALSE);
13141         mono_register_opcode_emulation (CEE_CONV_R4, "__emul_conv_r4", "double int32", mono_conv_to_r4, FALSE);
13142         mono_register_opcode_emulation (OP_FCONV_TO_R4, "__emul_fconv_to_r4", "double double", mono_fconv_r4, FALSE);
13143         mono_register_opcode_emulation (OP_FCONV_TO_I1, "__emul_fconv_to_i1", "int8 double", mono_fconv_i1, FALSE);
13144         mono_register_opcode_emulation (OP_FCONV_TO_I2, "__emul_fconv_to_i2", "int16 double", mono_fconv_i2, FALSE);
13145         mono_register_opcode_emulation (OP_FCONV_TO_I4, "__emul_fconv_to_i4", "int32 double", mono_fconv_i4, FALSE);
13146         mono_register_opcode_emulation (OP_FCONV_TO_U1, "__emul_fconv_to_u1", "uint8 double", mono_fconv_u1, FALSE);
13147         mono_register_opcode_emulation (OP_FCONV_TO_U2, "__emul_fconv_to_u2", "uint16 double", mono_fconv_u2, FALSE);
13148
13149         mono_register_opcode_emulation (OP_FBEQ, "__emul_fcmp_eq", "uint32 double double", mono_fcmp_eq, FALSE);
13150         mono_register_opcode_emulation (OP_FBLT, "__emul_fcmp_lt", "uint32 double double", mono_fcmp_lt, FALSE);
13151         mono_register_opcode_emulation (OP_FBGT, "__emul_fcmp_gt", "uint32 double double", mono_fcmp_gt, FALSE);
13152         mono_register_opcode_emulation (OP_FBLE, "__emul_fcmp_le", "uint32 double double", mono_fcmp_le, FALSE);
13153         mono_register_opcode_emulation (OP_FBGE, "__emul_fcmp_ge", "uint32 double double", mono_fcmp_ge, FALSE);
13154         mono_register_opcode_emulation (OP_FBNE_UN, "__emul_fcmp_ne_un", "uint32 double double", mono_fcmp_ne_un, FALSE);
13155         mono_register_opcode_emulation (OP_FBLT_UN, "__emul_fcmp_lt_un", "uint32 double double", mono_fcmp_lt_un, FALSE);
13156         mono_register_opcode_emulation (OP_FBGT_UN, "__emul_fcmp_gt_un", "uint32 double double", mono_fcmp_gt_un, FALSE);
13157         mono_register_opcode_emulation (OP_FBLE_UN, "__emul_fcmp_le_un", "uint32 double double", mono_fcmp_le_un, FALSE);
13158         mono_register_opcode_emulation (OP_FBGE_UN, "__emul_fcmp_ge_un", "uint32 double double", mono_fcmp_ge_un, FALSE);
13159
13160         mono_register_opcode_emulation (OP_FCEQ, "__emul_fcmp_ceq", "uint32 double double", mono_fceq, FALSE);
13161         mono_register_opcode_emulation (OP_FCGT, "__emul_fcmp_cgt", "uint32 double double", mono_fcgt, FALSE);
13162         mono_register_opcode_emulation (OP_FCGT_UN, "__emul_fcmp_cgt_un", "uint32 double double", mono_fcgt_un, FALSE);
13163         mono_register_opcode_emulation (OP_FCLT, "__emul_fcmp_clt", "uint32 double double", mono_fclt, FALSE);
13164         mono_register_opcode_emulation (OP_FCLT_UN, "__emul_fcmp_clt_un", "uint32 double double", mono_fclt_un, FALSE);
13165
13166         register_icall (mono_fload_r4, "mono_fload_r4", "double ptr", FALSE);
13167         register_icall (mono_fstore_r4, "mono_fstore_r4", "void double ptr", FALSE);
13168         register_icall (mono_fload_r4_arg, "mono_fload_r4_arg", "uint32 double", FALSE);
13169 #endif
13170
13171 #if SIZEOF_VOID_P == 4
13172         mono_register_opcode_emulation (OP_FCONV_TO_U, "__emul_fconv_to_u", "uint32 double", mono_fconv_u4, TRUE);
13173 #endif
13174
13175         /* other jit icalls */
13176         register_icall (mono_delegate_ctor, "mono_delegate_ctor", "void object object ptr", FALSE);
13177         register_icall (mono_class_static_field_address , "mono_class_static_field_address", 
13178                                  "ptr ptr ptr", FALSE);
13179         register_icall (mono_ldtoken_wrapper, "mono_ldtoken_wrapper", "ptr ptr ptr ptr", FALSE);
13180         register_icall (mono_get_special_static_data, "mono_get_special_static_data", "ptr int", FALSE);
13181         register_icall (mono_ldstr, "mono_ldstr", "object ptr ptr int32", FALSE);
13182         register_icall (mono_helper_stelem_ref_check, "helper_stelem_ref_check", "void object object", FALSE);
13183         register_icall (mono_object_new, "mono_object_new", "object ptr ptr", FALSE);
13184         register_icall (mono_object_new_specific, "mono_object_new_specific", "object ptr", FALSE);
13185         register_icall (mono_array_new, "mono_array_new", "object ptr ptr int32", FALSE);
13186         register_icall (mono_array_new_specific, "mono_array_new_specific", "object ptr int32", FALSE);
13187         register_icall (mono_runtime_class_init, "mono_runtime_class_init", "void ptr", FALSE);
13188         register_icall (mono_ldftn, "mono_ldftn", "ptr ptr", FALSE);
13189         register_icall (mono_ldftn_nosync, "mono_ldftn_nosync", "ptr ptr", FALSE);
13190         register_icall (mono_ldvirtfn, "mono_ldvirtfn", "ptr object ptr", FALSE);
13191         register_icall (mono_helper_compile_generic_method, "compile_generic_method", "ptr object ptr ptr ptr", FALSE);
13192         register_icall (mono_helper_ldstr, "helper_ldstr", "object ptr int", FALSE);
13193         register_icall (mono_helper_ldstr_mscorlib, "helper_ldstr_mscorlib", "object int", FALSE);
13194         register_icall (mono_helper_newobj_mscorlib, "helper_newobj_mscorlib", "object int", FALSE);
13195         register_icall (mono_value_copy, "mono_value_copy", "void ptr ptr ptr", FALSE);
13196         register_icall (mono_helper_get_rgctx_other_ptr, "get_rgctx_other_ptr", "ptr ptr ptr int32 int32 int32 int32", FALSE);
13197         register_icall (mono_break, "mono_break", NULL, TRUE);
13198 #endif
13199
13200 #define JIT_RUNTIME_WORKS
13201 #ifdef JIT_RUNTIME_WORKS
13202         mono_install_runtime_cleanup ((MonoDomainFunc)mini_cleanup);
13203         mono_runtime_init (domain, mono_thread_start_cb, mono_thread_attach_cb);
13204 #endif
13205
13206         mono_generic_sharing_init ();
13207
13208         mono_thread_attach (domain);
13209         return domain;
13210 }
13211
13212 MonoJitStats mono_jit_stats = {0};
13213
13214 static void 
13215 print_jit_stats (void)
13216 {
13217         if (mono_jit_stats.enabled) {
13218                 g_print ("Mono Jit statistics\n");
13219                 g_print ("Compiled methods:       %ld\n", mono_jit_stats.methods_compiled);
13220                 g_print ("Methods from AOT:       %ld\n", mono_jit_stats.methods_aot);
13221                 g_print ("Methods cache lookup:   %ld\n", mono_jit_stats.methods_lookups);
13222                 g_print ("Method trampolines:     %ld\n", mono_jit_stats.method_trampolines);
13223                 g_print ("Basic blocks:           %ld\n", mono_jit_stats.basic_blocks);
13224                 g_print ("Max basic blocks:       %ld\n", mono_jit_stats.max_basic_blocks);
13225                 g_print ("Allocated vars:         %ld\n", mono_jit_stats.allocate_var);
13226                 g_print ("Analyze stack repeat:   %ld\n", mono_jit_stats.analyze_stack_repeat);
13227                 g_print ("Compiled CIL code size: %ld\n", mono_jit_stats.cil_code_size);
13228                 g_print ("Native code size:       %ld\n", mono_jit_stats.native_code_size);
13229                 g_print ("Max code size ratio:    %.2f (%s::%s)\n", mono_jit_stats.max_code_size_ratio/100.0,
13230                                 mono_jit_stats.max_ratio_method->klass->name, mono_jit_stats.max_ratio_method->name);
13231                 g_print ("Biggest method:         %ld (%s::%s)\n", mono_jit_stats.biggest_method_size,
13232                                 mono_jit_stats.biggest_method->klass->name, mono_jit_stats.biggest_method->name);
13233                 g_print ("Code reallocs:          %ld\n", mono_jit_stats.code_reallocs);
13234                 g_print ("Allocated code size:    %ld\n", mono_jit_stats.allocated_code_size);
13235                 g_print ("Inlineable methods:     %ld\n", mono_jit_stats.inlineable_methods);
13236                 g_print ("Inlined methods:        %ld\n", mono_jit_stats.inlined_methods);
13237                 g_print ("Locals stack size:      %ld\n", mono_jit_stats.locals_stack_size);
13238
13239                 g_print ("\nCreated object count:   %ld\n", mono_stats.new_object_count);
13240                 g_print ("Delegates created:      %ld\n", mono_stats.delegate_creations);
13241                 g_print ("Initialized classes:    %ld\n", mono_stats.initialized_class_count);
13242                 g_print ("Used classes:           %ld\n", mono_stats.used_class_count);
13243                 g_print ("Generic vtables:        %ld\n", mono_stats.generic_vtable_count);
13244                 g_print ("Methods:                %ld\n", mono_stats.method_count);
13245                 g_print ("Static data size:       %ld\n", mono_stats.class_static_data_size);
13246                 g_print ("VTable data size:       %ld\n", mono_stats.class_vtable_size);
13247                 g_print ("Mscorlib mempool size:  %d\n", mono_mempool_get_allocated (mono_defaults.corlib->mempool));
13248
13249                 g_print ("\nGeneric instances:      %ld\n", mono_stats.generic_instance_count);
13250                 g_print ("Initialized classes:    %ld\n", mono_stats.generic_class_count);
13251                 g_print ("Inflated methods:       %ld / %ld\n", mono_stats.inflated_method_count_2,
13252                          mono_stats.inflated_method_count);
13253                 g_print ("Inflated types:         %ld\n", mono_stats.inflated_type_count);
13254                 g_print ("Generics metadata size: %ld\n", mono_stats.generics_metadata_size);
13255                 g_print ("Generics virtual invokes: %ld\n", mono_jit_stats.generic_virtual_invocations);
13256
13257                 g_print ("Sharable generic methods: %ld\n", mono_stats.generics_sharable_methods);
13258                 g_print ("Unsharable generic methods: %ld\n", mono_stats.generics_unsharable_methods);
13259                 g_print ("Shared generic methods: %ld\n", mono_stats.generics_shared_methods);
13260
13261                 g_print ("Dynamic code allocs:    %ld\n", mono_stats.dynamic_code_alloc_count);
13262                 g_print ("Dynamic code bytes:     %ld\n", mono_stats.dynamic_code_bytes_count);
13263                 g_print ("Dynamic code frees:     %ld\n", mono_stats.dynamic_code_frees_count);
13264
13265                 g_print ("IMT tables size:        %ld\n", mono_stats.imt_tables_size);
13266                 g_print ("IMT number of tables:   %ld\n", mono_stats.imt_number_of_tables);
13267                 g_print ("IMT number of methods:  %ld\n", mono_stats.imt_number_of_methods);
13268                 g_print ("IMT used slots:         %ld\n", mono_stats.imt_used_slots);
13269                 g_print ("IMT colliding slots:    %ld\n", mono_stats.imt_slots_with_collisions);
13270                 g_print ("IMT max collisions:     %ld\n", mono_stats.imt_max_collisions_in_slot);
13271                 g_print ("IMT methods at max col: %ld\n", mono_stats.imt_method_count_when_max_collisions);
13272                 g_print ("IMT thunks size:        %ld\n", mono_stats.imt_thunks_size);
13273
13274                 g_print ("JIT info table inserts: %ld\n", mono_stats.jit_info_table_insert_count);
13275                 g_print ("JIT info table removes: %ld\n", mono_stats.jit_info_table_remove_count);
13276                 g_print ("JIT info table lookups: %ld\n", mono_stats.jit_info_table_lookup_count);
13277
13278                 g_print ("Hazardous pointers:     %ld\n", mono_stats.hazardous_pointer_count);
13279 #ifdef HAVE_SGEN_GC
13280                 g_print ("Minor GC collections:   %ld\n", mono_stats.minor_gc_count);
13281                 g_print ("Major GC collections:   %ld\n", mono_stats.major_gc_count);
13282                 g_print ("Minor GC time in msecs: %lf\n", (double)mono_stats.minor_gc_time_usecs / 1000.0);
13283                 g_print ("Major GC time in msecs: %lf\n", (double)mono_stats.major_gc_time_usecs / 1000.0);
13284 #endif
13285                 if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS) {
13286                         g_print ("\nDecl security check   : %ld\n", mono_jit_stats.cas_declsec_check);
13287                         g_print ("LinkDemand (user)     : %ld\n", mono_jit_stats.cas_linkdemand);
13288                         g_print ("LinkDemand (icall)    : %ld\n", mono_jit_stats.cas_linkdemand_icall);
13289                         g_print ("LinkDemand (pinvoke)  : %ld\n", mono_jit_stats.cas_linkdemand_pinvoke);
13290                         g_print ("LinkDemand (aptc)     : %ld\n", mono_jit_stats.cas_linkdemand_aptc);
13291                         g_print ("Demand (code gen)     : %ld\n", mono_jit_stats.cas_demand_generation);
13292                 }
13293                 if (debug_options.collect_pagefault_stats) {
13294                         g_print ("Metadata pagefaults   : %d\n", mono_raw_buffer_get_n_pagefaults ());
13295                         g_print ("AOT pagefaults        : %d\n", mono_aot_get_n_pagefaults ());
13296                 }
13297         }
13298 }
13299
13300 void
13301 mini_cleanup (MonoDomain *domain)
13302 {
13303 #ifdef HAVE_LINUX_RTC_H
13304         if (rtc_fd >= 0)
13305                 enable_rtc_timer (FALSE);
13306 #endif
13307
13308         /* 
13309          * mono_runtime_cleanup() and mono_domain_finalize () need to
13310          * be called early since they need the execution engine still
13311          * fully working (mono_domain_finalize may invoke managed finalizers
13312          * and mono_runtime_cleanup will wait for other threads to finish).
13313          */
13314         mono_domain_finalize (domain, 2000);
13315
13316         /* This accesses metadata so needs to be called before runtime shutdown */
13317         print_jit_stats ();
13318
13319         mono_runtime_cleanup (domain);
13320
13321         mono_profiler_shutdown ();
13322
13323         mono_icall_cleanup ();
13324
13325         mono_runtime_cleanup_handlers ();
13326
13327         mono_domain_free (domain, TRUE);
13328
13329         mono_debugger_cleanup ();
13330
13331         mono_code_manager_destroy (global_codeman);
13332         g_hash_table_destroy (jit_icall_name_hash);
13333         if (class_init_hash_addr)
13334                 g_hash_table_destroy (class_init_hash_addr);
13335         if (delegate_trampoline_hash_addr)
13336                 g_hash_table_destroy (delegate_trampoline_hash_addr);
13337         g_free (emul_opcode_map);
13338
13339         mono_arch_cleanup ();
13340
13341         mono_cleanup ();
13342
13343         mono_trace_cleanup ();
13344
13345         mono_counters_dump (-1, stdout);
13346
13347         if (mono_inject_async_exc_method)
13348                 mono_method_desc_free (mono_inject_async_exc_method);
13349
13350         TlsFree(mono_jit_tls_id);
13351
13352         DeleteCriticalSection (&jit_mutex);
13353
13354         DeleteCriticalSection (&mono_delegate_section);
13355 }
13356
13357 void
13358 mono_set_defaults (int verbose_level, guint32 opts)
13359 {
13360         mini_verbose = verbose_level;
13361         default_opt = opts;
13362         default_opt_set = TRUE;
13363 }
13364
13365 static void
13366 mono_precompile_assembly (MonoAssembly *ass, void *user_data)
13367 {
13368         GHashTable *assemblies = (GHashTable*)user_data;
13369         MonoImage *image = mono_assembly_get_image (ass);
13370         MonoMethod *method, *invoke;
13371         int i, count = 0;
13372
13373         if (g_hash_table_lookup (assemblies, ass))
13374                 return;
13375
13376         g_hash_table_insert (assemblies, ass, ass);
13377
13378         if (mini_verbose > 0)
13379                 printf ("PRECOMPILE: %s.\n", mono_image_get_filename (image));
13380
13381         for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_METHOD); ++i) {
13382                 method = mono_get_method (image, MONO_TOKEN_METHOD_DEF | (i + 1), NULL);
13383                 if (method->flags & METHOD_ATTRIBUTE_ABSTRACT)
13384                         continue;
13385
13386                 count++;
13387                 if (mini_verbose > 1) {
13388                         char * desc = mono_method_full_name (method, TRUE);
13389                         g_print ("Compiling %d %s\n", count, desc);
13390                         g_free (desc);
13391                 }
13392                 mono_compile_method (method);
13393                 if (strcmp (method->name, "Finalize") == 0) {
13394                         invoke = mono_marshal_get_runtime_invoke (method);
13395                         mono_compile_method (invoke);
13396                 }
13397                 if (method->klass->marshalbyref && mono_method_signature (method)->hasthis) {
13398                         invoke = mono_marshal_get_remoting_invoke_with_check (method);
13399                         mono_compile_method (invoke);
13400                 }
13401         }
13402
13403         /* Load and precompile referenced assemblies as well */
13404         for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_ASSEMBLYREF); ++i) {
13405                 mono_assembly_load_reference (image, i);
13406                 if (image->references [i])
13407                         mono_precompile_assembly (image->references [i], assemblies);
13408         }
13409 }
13410
13411 void mono_precompile_assemblies ()
13412 {
13413         GHashTable *assemblies = g_hash_table_new (NULL, NULL);
13414
13415         mono_assembly_foreach ((GFunc)mono_precompile_assembly, assemblies);
13416
13417         g_hash_table_destroy (assemblies);
13418 }