2008-06-13 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 HAVE_VALGRIND_MEMCHECK_H
30 #include <valgrind/memcheck.h>
31 #endif
32
33 #include <mono/metadata/assembly.h>
34 #include <mono/metadata/loader.h>
35 #include <mono/metadata/tabledefs.h>
36 #include <mono/metadata/class.h>
37 #include <mono/metadata/object.h>
38 #include <mono/metadata/exception.h>
39 #include <mono/metadata/opcodes.h>
40 #include <mono/metadata/mono-endian.h>
41 #include <mono/metadata/tokentype.h>
42 #include <mono/metadata/tabledefs.h>
43 #include <mono/metadata/threads.h>
44 #include <mono/metadata/marshal.h>
45 #include <mono/metadata/socket-io.h>
46 #include <mono/metadata/appdomain.h>
47 #include <mono/metadata/debug-helpers.h>
48 #include <mono/io-layer/io-layer.h>
49 #include "mono/metadata/profiler.h"
50 #include <mono/metadata/profiler-private.h>
51 #include <mono/metadata/mono-config.h>
52 #include <mono/metadata/environment.h>
53 #include <mono/metadata/mono-debug.h>
54 #include <mono/metadata/monitor.h>
55 #include <mono/metadata/gc-internal.h>
56 #include <mono/metadata/security-manager.h>
57 #include <mono/metadata/threads-types.h>
58 #include <mono/metadata/rawbuffer.h>
59 #include <mono/metadata/security-core-clr.h>
60 #include <mono/metadata/verify.h>
61 #include <mono/metadata/verify-internals.h>
62 #include <mono/utils/mono-math.h>
63 #include <mono/utils/mono-compiler.h>
64 #include <mono/utils/mono-counters.h>
65 #include <mono/utils/mono-logger.h>
66 #include <mono/utils/mono-mmap.h>
67 #include <mono/utils/dtrace.h>
68
69 #include "mini.h"
70 #include <string.h>
71 #include <ctype.h>
72 #include "inssel.h"
73 #include "trace.h"
74
75 #include "jit-icalls.h"
76
77 #include "aliasing.h"
78
79 #include "debug-mini.h"
80
81 #define BRANCH_COST 100
82 #define INLINE_LENGTH_LIMIT 20
83 #define INLINE_FAILURE do {\
84                 if ((cfg->method != method) && (method->wrapper_type == MONO_WRAPPER_NONE))\
85                         goto inline_failure;\
86         } while (0)
87 #define CHECK_CFG_EXCEPTION do {\
88                 if (cfg->exception_type != MONO_EXCEPTION_NONE)\
89                         goto exception_exit;\
90         } while (0)
91 #define METHOD_ACCESS_FAILURE do {      \
92                 char *method_fname = mono_method_full_name (method, TRUE);      \
93                 char *cil_method_fname = mono_method_full_name (cil_method, TRUE);      \
94                 cfg->exception_type = MONO_EXCEPTION_METHOD_ACCESS;     \
95                 cfg->exception_message = g_strdup_printf ("Method `%s' is inaccessible from method `%s'\n", cil_method_fname, method_fname);    \
96                 g_free (method_fname);  \
97                 g_free (cil_method_fname);      \
98                 goto exception_exit;    \
99         } while (0)
100 #define FIELD_ACCESS_FAILURE do {       \
101                 char *method_fname = mono_method_full_name (method, TRUE);      \
102                 char *field_fname = mono_field_full_name (field);       \
103                 cfg->exception_type = MONO_EXCEPTION_FIELD_ACCESS;      \
104                 cfg->exception_message = g_strdup_printf ("Field `%s' is inaccessible from method `%s'\n", field_fname, method_fname);  \
105                 g_free (method_fname);  \
106                 g_free (field_fname);   \
107                 goto exception_exit;    \
108         } while (0)
109 #define GENERIC_SHARING_FAILURE(opcode) do {            \
110                 if (cfg->generic_sharing_context) {     \
111             if (cfg->verbose_level > 1) \
112                             printf ("sharing failed for method %s.%s.%s/%d opcode %s line %d\n", method->klass->name_space, method->klass->name, method->name, method->signature->param_count, mono_opcode_name ((opcode)), __LINE__); \
113                         cfg->exception_type = MONO_EXCEPTION_GENERIC_SHARING_FAILED;    \
114                         goto exception_exit;    \
115                 }                       \
116         } while (0)
117 #define GENERIC_SHARING_FAILURE_IF_VALUETYPE_METHOD(opcode) do {                        \
118                 if (method->klass->valuetype)   \
119                         GENERIC_SHARING_FAILURE ((opcode)); \
120         } while (0)
121 #define GET_RGCTX(rgctx) do {                                           \
122                 MonoInst *this = NULL;                                  \
123                 GENERIC_SHARING_FAILURE_IF_VALUETYPE_METHOD(*ip);       \
124                 if (!(method->flags & METHOD_ATTRIBUTE_STATIC))         \
125                         NEW_ARGLOAD (cfg, this, 0);                     \
126                 (rgctx) = get_runtime_generic_context (cfg, method, this, ip); \
127         } while (0)
128
129 #define MONO_CHECK_THIS(ins) (mono_method_signature (cfg->method)->hasthis && (ins)->ssa_op == MONO_SSA_LOAD && (ins)->inst_left->inst_c0 == 0)
130
131 static void setup_stat_profiler (void);
132 gboolean  mono_arch_print_tree(MonoInst *tree, int arity);
133 static gpointer mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt);
134 static gpointer mono_jit_compile_method (MonoMethod *method);
135 inline static int mono_emit_jit_icall (MonoCompile *cfg, MonoBasicBlock *bblock, gconstpointer func, MonoInst **args, const guint8 *ip);
136
137 static void handle_stobj (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *dest, MonoInst *src, 
138                           const unsigned char *ip, MonoClass *klass, gboolean to_end, gboolean native, gboolean write_barrier);
139
140 static void dec_foreach (MonoInst *tree, MonoCompile *cfg);
141
142 static int mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock, 
143                    int locals_offset, MonoInst *return_var, GList *dont_inline, MonoInst **inline_args, 
144                    guint inline_offset, gboolean is_virtual_call);
145
146 #ifdef MONO_ARCH_SOFT_FLOAT
147 static void
148 handle_store_float (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *ptr, MonoInst *val, const unsigned char *ip);
149 #endif
150
151 /* helper methods signature */
152 static MonoMethodSignature *helper_sig_class_init_trampoline = NULL;
153 static MonoMethodSignature *helper_sig_generic_class_init_trampoline = NULL;
154 static MonoMethodSignature *helper_sig_rgctx_lazy_fetch_trampoline = NULL;
155 static MonoMethodSignature *helper_sig_domain_get = NULL;
156
157 static guint32 default_opt = 0;
158 static gboolean default_opt_set = FALSE;
159
160 guint32 mono_jit_tls_id = -1;
161
162 #ifdef HAVE_KW_THREAD
163 static __thread gpointer mono_jit_tls MONO_TLS_FAST;
164 #endif
165
166 MonoTraceSpec *mono_jit_trace_calls = NULL;
167 gboolean mono_break_on_exc = FALSE;
168 #ifndef DISABLE_AOT
169 gboolean mono_compile_aot = FALSE;
170 #endif
171 MonoMethodDesc *mono_inject_async_exc_method = NULL;
172 int mono_inject_async_exc_pos;
173 MonoMethodDesc *mono_break_at_bb_method = NULL;
174 int mono_break_at_bb_bb_num;
175
176 static int mini_verbose = 0;
177
178 #define mono_jit_lock() EnterCriticalSection (&jit_mutex)
179 #define mono_jit_unlock() LeaveCriticalSection (&jit_mutex)
180 static CRITICAL_SECTION jit_mutex;
181
182 static GHashTable *rgctx_lazy_fetch_trampoline_hash = NULL;
183
184 static MonoCodeManager *global_codeman = NULL;
185
186 static GHashTable *jit_icall_name_hash = NULL;
187
188 static MonoDebugOptions debug_options;
189
190 #ifdef VALGRIND_JIT_REGISTER_MAP
191 static int valgrind_register = 0;
192 #endif
193
194 /*
195  * Table written to by the debugger with a 1-based index into the
196  * mono_breakpoint_info table, which contains changes made to
197  * the JIT instructions by the debugger.
198  */
199 gssize
200 mono_breakpoint_info_index [MONO_BREAKPOINT_ARRAY_SIZE];
201
202 /* Whenever to check for pending exceptions in managed-to-native wrappers */
203 gboolean check_for_pending_exc = TRUE;
204
205 gboolean
206 mono_running_on_valgrind (void)
207 {
208 #ifdef HAVE_VALGRIND_MEMCHECK_H
209                 if (RUNNING_ON_VALGRIND){
210 #ifdef VALGRIND_JIT_REGISTER_MAP
211                         valgrind_register = TRUE;
212 #endif
213                         return TRUE;
214                 } else
215                         return FALSE;
216 #else
217                 return FALSE;
218 #endif
219 }
220
221 typedef struct {
222         void *ip;
223         MonoMethod *method;
224 } FindTrampUserData;
225
226 static void
227 find_tramp (gpointer key, gpointer value, gpointer user_data)
228 {
229         FindTrampUserData *ud = (FindTrampUserData*)user_data;
230
231         if (value == ud->ip)
232                 ud->method = (MonoMethod*)key;
233 }
234
235 /* debug function */
236 G_GNUC_UNUSED static char*
237 get_method_from_ip (void *ip)
238 {
239         MonoJitInfo *ji;
240         char *method;
241         char *res;
242         MonoDomain *domain = mono_domain_get ();
243         MonoDebugSourceLocation *location;
244         FindTrampUserData user_data;
245         
246         ji = mono_jit_info_table_find (domain, ip);
247         if (!ji) {
248                 user_data.ip = ip;
249                 user_data.method = NULL;
250                 mono_domain_lock (domain);
251                 g_hash_table_foreach (domain->jit_trampoline_hash, find_tramp, &user_data);
252                 mono_domain_unlock (domain);
253                 if (user_data.method) {
254                         char *mname = mono_method_full_name (user_data.method, TRUE);
255                         res = g_strdup_printf ("<%p - JIT trampoline for %s>", ip, mname);
256                         g_free (mname);
257                         return res;
258                 }
259                 else
260                         return NULL;
261         }
262         method = mono_method_full_name (ji->method, TRUE);
263         /* FIXME: unused ? */
264         location = mono_debug_lookup_source_location (ji->method, (guint32)((guint8*)ip - (guint8*)ji->code_start), domain);
265
266         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);
267
268         mono_debug_free_source_location (location);
269         g_free (method);
270
271         return res;
272 }
273
274 /** 
275  * mono_pmip:
276  * @ip: an instruction pointer address
277  *
278  * This method is used from a debugger to get the name of the
279  * method at address @ip.   This routine is typically invoked from
280  * a debugger like this:
281  *
282  * (gdb) print mono_pmip ($pc)
283  *
284  * Returns: the name of the method at address @ip.
285  */
286 G_GNUC_UNUSED char *
287 mono_pmip (void *ip)
288 {
289         return get_method_from_ip (ip);
290 }
291
292 /** 
293  * mono_print_method_from_ip
294  * @ip: an instruction pointer address
295  *
296  * This method is used from a debugger to get the name of the
297  * method at address @ip.
298  *
299  * This prints the name of the method at address @ip in the standard
300  * output.  Unlike mono_pmip which returns a string, this routine
301  * prints the value on the standard output. 
302  */
303 void
304 mono_print_method_from_ip (void *ip)
305 {
306         MonoJitInfo *ji;
307         char *method;
308         MonoDebugSourceLocation *source;
309         MonoDomain *domain = mono_domain_get ();
310         FindTrampUserData user_data;
311         
312         ji = mono_jit_info_table_find (domain, ip);
313         if (!ji) {
314                 user_data.ip = ip;
315                 user_data.method = NULL;
316                 mono_domain_lock (domain);
317                 g_hash_table_foreach (domain->jit_trampoline_hash, find_tramp, &user_data);
318                 mono_domain_unlock (domain);
319                 if (user_data.method) {
320                         char *mname = mono_method_full_name (user_data.method, TRUE);
321                         printf ("IP %p is a JIT trampoline for %s\n", ip, mname);
322                         g_free (mname);
323                 }
324                 else
325                         g_print ("No method at %p\n", ip);
326                 return;
327         }
328         method = mono_method_full_name (ji->method, TRUE);
329         source = mono_debug_lookup_source_location (ji->method, (guint32)((guint8*)ip - (guint8*)ji->code_start), domain);
330
331         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);
332
333         if (source)
334                 g_print ("%s:%d\n", source->source_file, source->row);
335
336         mono_debug_free_source_location (source);
337         g_free (method);
338 }
339         
340 /* 
341  * mono_method_same_domain:
342  *
343  * Determine whenever two compiled methods are in the same domain, thus
344  * the address of the callee can be embedded in the caller.
345  */
346 gboolean mono_method_same_domain (MonoJitInfo *caller, MonoJitInfo *callee)
347 {
348         if (!caller || !callee)
349                 return FALSE;
350
351         /*
352          * If the call was made from domain-neutral to domain-specific 
353          * code, we can't patch the call site.
354          */
355         if (caller->domain_neutral && !callee->domain_neutral)
356                 return FALSE;
357
358         if ((caller->method->klass == mono_defaults.appdomain_class) &&
359                 (strstr (caller->method->name, "InvokeInDomain"))) {
360                  /* The InvokeInDomain methods change the current appdomain */
361                 return FALSE;
362         }
363
364         return TRUE;
365 }
366
367 /*
368  * mono_global_codeman_reserve:
369  *
370  *  Allocate code memory from the global code manager.
371  */
372 void *mono_global_codeman_reserve (int size)
373 {
374         void *ptr;
375
376         if (!global_codeman) {
377                 /* This can happen during startup */
378                 global_codeman = mono_code_manager_new ();
379                 return mono_code_manager_reserve (global_codeman, size);
380         }
381         else {
382                 mono_jit_lock ();
383                 ptr = mono_code_manager_reserve (global_codeman, size);
384                 mono_jit_unlock ();
385                 return ptr;
386         }
387 }
388
389 MonoJumpInfoToken *
390 mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
391 {
392         MonoJumpInfoToken *res = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoToken));
393         res->image = image;
394         res->token = token;
395
396         return res;
397 }
398
399 #define MONO_INIT_VARINFO(vi,id) do { \
400         (vi)->range.first_use.pos.bid = 0xffff; \
401         (vi)->reg = -1; \
402         (vi)->idx = (id); \
403 } while (0)
404
405 //#define UNVERIFIED do { G_BREAKPOINT (); goto unverified; } while (0)
406 #define UNVERIFIED do { if (debug_options.break_on_unverified) G_BREAKPOINT (); else goto unverified; } while (0)
407
408 /*
409  * Basic blocks have two numeric identifiers:
410  * dfn: Depth First Number
411  * block_num: unique ID assigned at bblock creation
412  */
413 #define NEW_BBLOCK(cfg,new_bb) do {     \
414                 new_bb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock)); \
415                 MONO_INST_LIST_INIT (&new_bb->ins_list); \
416         } while (0)
417
418 #define ADD_BBLOCK(cfg,b) do {  \
419                 cfg->cil_offset_to_bb [(b)->cil_code - cfg->cil_start] = (b);   \
420                 (b)->block_num = cfg->num_bblocks++;    \
421                 (b)->real_offset = real_offset; \
422         } while (0)
423
424 #define GET_BBLOCK(cfg,tblock,ip) do {  \
425                 (tblock) = cfg->cil_offset_to_bb [(ip) - cfg->cil_start]; \
426                 if (!(tblock)) {        \
427                         if ((ip) >= end || (ip) < header->code) UNVERIFIED; \
428                         NEW_BBLOCK (cfg, (tblock));     \
429                         (tblock)->cil_code = (ip);      \
430                         ADD_BBLOCK (cfg, (tblock));     \
431                 } \
432         } while (0)
433
434 #define CHECK_BBLOCK(target,ip,tblock) do {     \
435                 if ((target) < (ip) && \
436                                 MONO_INST_LIST_EMPTY (&(tblock)->ins_list)) { \
437                         bb_recheck = g_list_prepend (bb_recheck, (tblock)); \
438                         if (cfg->verbose_level > 2) \
439                                 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)); \
440                 } \
441         } while (0)
442
443 #define NEW_ICONST(cfg,dest,val) do {   \
444                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
445                 (dest)->opcode = OP_ICONST;     \
446                 (dest)->inst_c0 = (val);        \
447                 (dest)->type = STACK_I4;        \
448         } while (0)
449
450 #define NEW_PCONST(cfg,dest,val) do {   \
451                 MONO_INST_NEW ((cfg), (dest), OP_PCONST);       \
452                 (dest)->inst_p0 = (val);        \
453                 (dest)->type = STACK_PTR;       \
454         } while (0)
455
456
457 #ifdef MONO_ARCH_NEED_GOT_VAR
458
459 #define NEW_PATCH_INFO(cfg,dest,el1,el2) do {   \
460                 MONO_INST_NEW ((cfg), (dest), OP_PATCH_INFO);   \
461                 (dest)->inst_left = (gpointer)(el1);    \
462                 (dest)->inst_right = (gpointer)(el2);   \
463         } while (0)
464
465 #define NEW_AOTCONST(cfg,dest,patch_type,cons) do {                     \
466                 MONO_INST_NEW ((cfg), (dest), OP_NOP); \
467                 (dest)->opcode = cfg->compile_aot ? OP_GOT_ENTRY : OP_PCONST; \
468                 if (cfg->compile_aot) {                                 \
469                         MonoInst *group, *got_var, *got_loc;            \
470                         got_loc = mono_get_got_var (cfg);               \
471                         NEW_TEMPLOAD ((cfg), got_var, got_loc->inst_c0); \
472                         NEW_PATCH_INFO ((cfg), group, cons, patch_type); \
473                         (dest)->inst_p0 = got_var;                      \
474                         (dest)->inst_p1 = group;                        \
475                 } else {                                                \
476                         (dest)->inst_p0 = (cons);                       \
477                         (dest)->inst_i1 = (gpointer)(patch_type);       \
478                 }                                                       \
479                 (dest)->type = STACK_PTR;                               \
480         } while (0)
481
482 #define NEW_AOTCONST_TOKEN(cfg,dest,patch_type,image,token,stack_type,stack_class) do { \
483                 MonoInst *group, *got_var, *got_loc;                    \
484                 MONO_INST_NEW ((cfg), (dest), OP_GOT_ENTRY); \
485                 got_loc = mono_get_got_var (cfg);                       \
486                 NEW_TEMPLOAD ((cfg), got_var, got_loc->inst_c0);        \
487                 NEW_PATCH_INFO ((cfg), group, NULL, patch_type);        \
488                 group->inst_p0 = mono_jump_info_token_new ((cfg)->mempool, (image), (token)); \
489                 (dest)->inst_p0 = got_var;                              \
490                 (dest)->inst_p1 = group;                                \
491                 (dest)->type = (stack_type);                    \
492         (dest)->klass = (stack_class);          \
493         } while (0)
494
495 #else
496
497 #define NEW_AOTCONST(cfg,dest,patch_type,cons) do {    \
498                 MONO_INST_NEW ((cfg), (dest), OP_NOP);  \
499                 (dest)->opcode = cfg->compile_aot ? OP_AOTCONST : OP_PCONST;    \
500                 (dest)->inst_p0 = (cons);       \
501                 (dest)->inst_i1 = (gpointer)(patch_type); \
502                 (dest)->type = STACK_PTR;       \
503     } while (0)
504
505 #define NEW_AOTCONST_TOKEN(cfg,dest,patch_type,image,token,stack_type,stack_class) do { \
506                 MONO_INST_NEW ((cfg), (dest), OP_AOTCONST);     \
507                 (dest)->inst_p0 = mono_jump_info_token_new ((cfg)->mempool, (image), (token));  \
508                 (dest)->inst_p1 = (gpointer)(patch_type); \
509                 (dest)->type = (stack_type);    \
510         (dest)->klass = (stack_class);          \
511     } while (0)
512
513 #endif
514
515 #define NEW_CLASSCONST(cfg,dest,val) NEW_AOTCONST ((cfg), (dest), MONO_PATCH_INFO_CLASS, (val))
516
517 #define NEW_IMAGECONST(cfg,dest,val) NEW_AOTCONST ((cfg), (dest), MONO_PATCH_INFO_IMAGE, (val))
518
519 #define NEW_FIELDCONST(cfg,dest,val) NEW_AOTCONST ((cfg), (dest), MONO_PATCH_INFO_FIELD, (val))
520
521 #define NEW_METHODCONST(cfg,dest,val) NEW_AOTCONST ((cfg), (dest), MONO_PATCH_INFO_METHODCONST, (val))
522
523 #define NEW_VTABLECONST(cfg,dest,vtable) NEW_AOTCONST ((cfg), (dest), MONO_PATCH_INFO_VTABLE, cfg->compile_aot ? (gpointer)((vtable)->klass) : (vtable))
524
525 #define NEW_SFLDACONST(cfg,dest,val) NEW_AOTCONST ((cfg), (dest), MONO_PATCH_INFO_SFLDA, (val))
526
527 #define NEW_LDSTRCONST(cfg,dest,image,token) NEW_AOTCONST_TOKEN ((cfg), (dest), MONO_PATCH_INFO_LDSTR, (image), (token), STACK_OBJ, mono_defaults.string_class)
528
529 #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)
530
531 #define NEW_LDTOKENCONST(cfg,dest,image,token) NEW_AOTCONST_TOKEN ((cfg), (dest), MONO_PATCH_INFO_LDTOKEN, (image), (token), STACK_PTR, NULL)
532
533 #define NEW_DECLSECCONST(cfg,dest,image,entry) do { \
534                 if (cfg->compile_aot) { \
535                         NEW_AOTCONST_TOKEN (cfg, dest, MONO_PATCH_INFO_DECLSEC, image, (entry).index, STACK_OBJ, NULL); \
536                 } else { \
537                         NEW_PCONST (cfg, args [0], (entry).blob); \
538                 } \
539         } while (0)
540
541 #define NEW_DOMAINCONST(cfg,dest) do { \
542                 if (cfg->opt & MONO_OPT_SHARED) { \
543                         /* avoid depending on undefined C behavior in sequence points */ \
544                         MonoInst* __domain_var = mono_get_domainvar (cfg); \
545                         NEW_TEMPLOAD (cfg, dest, __domain_var->inst_c0); \
546                 } else { \
547                         NEW_PCONST (cfg, dest, (cfg)->domain); \
548                 } \
549         } while (0)
550
551 #define GET_VARINFO_INST(cfg,num) ((cfg)->varinfo [(num)]->inst)
552
553 #define NEW_ARGLOAD(cfg,dest,num) do {  \
554                 if (arg_array [(num)]->opcode == OP_ICONST) (dest) = arg_array [(num)]; else { \
555                 MONO_INST_NEW ((cfg), (dest), OP_NOP);  \
556                 (dest)->ssa_op = MONO_SSA_LOAD; \
557                 (dest)->inst_i0 = arg_array [(num)];    \
558                 (dest)->opcode = mini_type_to_ldind ((cfg), (dest)->inst_i0->inst_vtype); \
559                 type_to_eval_stack_type ((cfg), param_types [(num)], (dest));   \
560                 (dest)->klass = (dest)->inst_i0->klass; \
561         }} while (0)
562
563 #define NEW_LOCLOAD(cfg,dest,num) do {  \
564                 MONO_INST_NEW ((cfg), (dest), OP_NOP);  \
565                 (dest)->ssa_op = MONO_SSA_LOAD; \
566                 (dest)->inst_i0 = (cfg)->varinfo [locals_offset + (num)];       \
567                 (dest)->opcode = mini_type_to_ldind ((cfg), (dest)->inst_i0->inst_vtype); \
568                 type_to_eval_stack_type ((cfg), header->locals [(num)], (dest));        \
569                 (dest)->klass = (dest)->inst_i0->klass; \
570         } while (0)
571
572 #define NEW_LOCLOADA(cfg,dest,num) do { \
573                 MONO_INST_NEW ((cfg), (dest), OP_LDADDR);       \
574                 (dest)->ssa_op = MONO_SSA_ADDRESS_TAKEN;        \
575                 (dest)->inst_i0 = (cfg)->varinfo [locals_offset + (num)];       \
576                 (dest)->inst_i0->flags |= MONO_INST_INDIRECT;   \
577                 (dest)->type = STACK_MP;        \
578                 (dest)->klass = (dest)->inst_i0->klass; \
579         if (!MONO_TYPE_ISSTRUCT (header->locals [(num)])) \
580            (cfg)->disable_ssa = TRUE; \
581         } while (0)
582
583 #define NEW_RETLOADA(cfg,dest) do {     \
584         if (cfg->vret_addr) { \
585                     MONO_INST_NEW ((cfg), (dest), OP_NOP);      \
586                     (dest)->ssa_op = MONO_SSA_LOAD;     \
587                     (dest)->inst_i0 = cfg->vret_addr; \
588                     (dest)->opcode = mini_type_to_ldind ((cfg), (dest)->inst_i0->inst_vtype); \
589             (dest)->type = STACK_MP; \
590                     (dest)->klass = (dest)->inst_i0->klass;     \
591         } else { \
592                         MONO_INST_NEW ((cfg), (dest), OP_NOP);  \
593                     (dest)->ssa_op = MONO_SSA_ADDRESS_TAKEN;    \
594                     (dest)->inst_i0 = (cfg)->ret;       \
595                     (dest)->inst_i0->flags |= MONO_INST_INDIRECT;       \
596                     (dest)->opcode = cfg->ret_var_is_local ? OP_LDADDR : CEE_LDIND_I;   \
597                     (dest)->type = STACK_MP;    \
598                     (dest)->klass = (dest)->inst_i0->klass;     \
599             (cfg)->disable_ssa = TRUE; \
600         } \
601         } while (0)
602
603 #define NEW_ARGLOADA(cfg,dest,num) do { \
604                 if (arg_array [(num)]->opcode == OP_ICONST) goto inline_failure; \
605                 MONO_INST_NEW ((cfg), (dest), OP_LDADDR);       \
606                 (dest)->ssa_op = MONO_SSA_ADDRESS_TAKEN;        \
607                 (dest)->inst_i0 = arg_array [(num)];    \
608                 (dest)->inst_i0->flags |= MONO_INST_INDIRECT;   \
609                 (dest)->type = STACK_MP;        \
610                 (dest)->klass = (dest)->inst_i0->klass; \
611                 (cfg)->disable_ssa = TRUE; \
612         } while (0)
613
614 #define NEW_TEMPLOAD(cfg,dest,num) do { \
615                 MONO_INST_NEW ((cfg), (dest), OP_NOP);  \
616                 (dest)->ssa_op = MONO_SSA_LOAD; \
617                 (dest)->inst_i0 = (cfg)->varinfo [(num)];       \
618                 (dest)->opcode = mini_type_to_ldind ((cfg), (dest)->inst_i0->inst_vtype); \
619                 type_to_eval_stack_type ((cfg), (dest)->inst_i0->inst_vtype, (dest));   \
620                 (dest)->klass = (dest)->inst_i0->klass; \
621         } while (0)
622
623 #define NEW_TEMPLOADA(cfg,dest,num) do {        \
624                 MONO_INST_NEW ((cfg), (dest), OP_LDADDR);       \
625                 (dest)->ssa_op = MONO_SSA_ADDRESS_TAKEN;        \
626                 (dest)->inst_i0 = (cfg)->varinfo [(num)];       \
627                 (dest)->inst_i0->flags |= MONO_INST_INDIRECT;   \
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                 MONO_INST_NEW ((cfg), (dest), OP_NOP);  \
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                 MONO_INST_NEW ((cfg), (dest), OP_NOP);  \
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                 MONO_INST_NEW ((cfg), (dest), OP_NOP);  \
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                 MONO_INST_NEW ((cfg), (dest), OP_NOP);  \
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                 MONO_INST_NEW ((cfg), (dest), OP_NOP);  \
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)->backend.memcpy_args = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoMemcpyArgs)); \
684                 (dest)->backend.memcpy_args->size = (memcpy_size); \
685                 (dest)->backend.memcpy_args->align = (memcpy_align); \
686     } while (0)
687
688 #define NEW_MEMSET(cfg,dest,dst,imm,memcpy_size,memcpy_align) do { \
689                 MONO_INST_NEW (cfg, dest, OP_MEMSET); \
690         (dest)->inst_left = (dst); \
691                 (dest)->inst_imm = (imm); \
692         (dest)->backend.memcpy_args = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoMemcpyArgs)); \
693                 (dest)->backend.memcpy_args->size = (memcpy_size); \
694                 (dest)->backend.memcpy_args->align = (memcpy_align); \
695     } while (0)
696
697 #define NEW_DUMMY_USE(cfg,dest,load) do { \
698                 MONO_INST_NEW ((cfg), (dest), OP_DUMMY_USE);    \
699                 (dest)->inst_left = (load); \
700     } while (0)
701
702 #define NEW_DUMMY_STORE(cfg,dest,num) do { \
703                 MONO_INST_NEW ((cfg), (dest), OP_DUMMY_STORE);  \
704                 (dest)->inst_i0 = (cfg)->varinfo [(num)];       \
705                 (dest)->klass = (dest)->inst_i0->klass; \
706         } while (0)
707
708 #define ADD_BINOP(op) do {      \
709                 MONO_INST_NEW (cfg, ins, (op)); \
710                 sp -= 2;        \
711                 ins->inst_i0 = sp [0];  \
712                 ins->inst_i1 = sp [1];  \
713                 *sp++ = ins;    \
714                 type_from_op (ins);     \
715                 CHECK_TYPE (ins);       \
716         } while (0)
717
718 #define ADD_UNOP(op) do {       \
719                 MONO_INST_NEW (cfg, ins, (op)); \
720                 sp--;   \
721                 ins->inst_i0 = sp [0];  \
722                 *sp++ = ins;    \
723                 type_from_op (ins);     \
724                 CHECK_TYPE (ins);       \
725         } while (0)
726
727 #define ADD_BINCOND(next_block) do {    \
728                 MonoInst *cmp;  \
729                 sp -= 2;                \
730                 MONO_INST_NEW(cfg, cmp, OP_COMPARE);    \
731                 cmp->inst_i0 = sp [0];  \
732                 cmp->inst_i1 = sp [1];  \
733                 cmp->cil_code = ins->cil_code;  \
734                 type_from_op (cmp);     \
735                 CHECK_TYPE (cmp);       \
736                 ins->inst_i0 = cmp;     \
737                 MONO_ADD_INS (bblock, ins);     \
738                 ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);      \
739                 GET_BBLOCK (cfg, tblock, target);               \
740                 link_bblock (cfg, bblock, tblock);      \
741                 ins->inst_true_bb = tblock;     \
742                 CHECK_BBLOCK (target, ip, tblock);      \
743                 if ((next_block)) {     \
744                         link_bblock (cfg, bblock, (next_block));        \
745                         ins->inst_false_bb = (next_block);      \
746                         start_new_bblock = 1;   \
747                 } else {        \
748                         GET_BBLOCK (cfg, tblock, ip);           \
749                         link_bblock (cfg, bblock, tblock);      \
750                         ins->inst_false_bb = tblock;    \
751                         start_new_bblock = 2;   \
752                 }       \
753         } while (0)
754
755 /* FIXME: handle float, long ... */
756 #define ADD_UNCOND(istrue) do { \
757                 MonoInst *cmp;  \
758                 sp--;           \
759                 MONO_INST_NEW(cfg, cmp, OP_COMPARE);    \
760                 cmp->inst_i0 = sp [0];  \
761                 switch (cmp->inst_i0->type) { \
762                 case STACK_I8: \
763                         cmp->inst_i1 = zero_int64; break; \
764                 case STACK_R8: \
765                         cmp->inst_i1 = zero_r8; break; \
766                 case STACK_PTR: \
767                 case STACK_MP: \
768                         cmp->inst_i1 = zero_ptr; break; \
769                 case STACK_OBJ: \
770                         cmp->inst_i1 = zero_obj; break; \
771                 default: \
772                         cmp->inst_i1 = zero_int32;  \
773                 }  \
774                 cmp->cil_code = ins->cil_code;  \
775                 type_from_op (cmp);     \
776                 CHECK_TYPE (cmp);       \
777                 ins->inst_i0 = cmp;     \
778                 ins->opcode = (istrue)? CEE_BNE_UN: CEE_BEQ;    \
779                 MONO_ADD_INS (bblock, ins);     \
780                 ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);      \
781                 GET_BBLOCK (cfg, tblock, target);               \
782                 link_bblock (cfg, bblock, tblock);      \
783                 ins->inst_true_bb = tblock;     \
784                 CHECK_BBLOCK (target, ip, tblock);      \
785                 GET_BBLOCK (cfg, tblock, ip);           \
786                 link_bblock (cfg, bblock, tblock);      \
787                 ins->inst_false_bb = tblock;    \
788                 start_new_bblock = 2;   \
789         } while (0)
790
791 #define NEW_LDELEMA(cfg,dest,sp,k) do { \
792                 MONO_INST_NEW ((cfg), (dest), CEE_LDELEMA);     \
793                 (dest)->inst_left = (sp) [0];   \
794                 (dest)->inst_right = (sp) [1];  \
795                 (dest)->type = STACK_MP;        \
796                 (dest)->klass = (k);    \
797                 (cfg)->flags |= MONO_CFG_HAS_LDELEMA; \
798         } while (0)
799
800 #define NEW_GROUP(cfg,dest,el1,el2) do {        \
801                 MONO_INST_NEW ((cfg), (dest), OP_GROUP);        \
802                 (dest)->inst_left = (el1);      \
803                 (dest)->inst_right = (el2);     \
804         } while (0)
805
806 #if 0
807 static gint
808 compare_bblock (gconstpointer a, gconstpointer b)
809 {
810         const MonoBasicBlock *b1 = a;
811         const MonoBasicBlock *b2 = b;
812
813         return b2->cil_code - b1->cil_code;
814 }
815 #endif
816
817 /* *
818  * link_bblock: Links two basic blocks
819  *
820  * links two basic blocks in the control flow graph, the 'from'
821  * argument is the starting block and the 'to' argument is the block
822  * the control flow ends to after 'from'.
823  */
824 static void
825 link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
826 {
827         MonoBasicBlock **newa;
828         int i, found;
829
830 #if 0
831         if (from->cil_code) {
832                 if (to->cil_code)
833                         g_print ("edge from IL%04x to IL_%04x\n", from->cil_code - cfg->cil_code, to->cil_code - cfg->cil_code);
834                 else
835                         g_print ("edge from IL%04x to exit\n", from->cil_code - cfg->cil_code);
836         } else {
837                 if (to->cil_code)
838                         g_print ("edge from entry to IL_%04x\n", to->cil_code - cfg->cil_code);
839                 else
840                         g_print ("edge from entry to exit\n");
841         }
842 #endif
843         found = FALSE;
844         for (i = 0; i < from->out_count; ++i) {
845                 if (to == from->out_bb [i]) {
846                         found = TRUE;
847                         break;
848                 }
849         }
850         if (!found) {
851                 newa = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (from->out_count + 1));
852                 for (i = 0; i < from->out_count; ++i) {
853                         newa [i] = from->out_bb [i];
854                 }
855                 newa [i] = to;
856                 from->out_count++;
857                 from->out_bb = newa;
858         }
859
860         found = FALSE;
861         for (i = 0; i < to->in_count; ++i) {
862                 if (from == to->in_bb [i]) {
863                         found = TRUE;
864                         break;
865                 }
866         }
867         if (!found) {
868                 newa = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (to->in_count + 1));
869                 for (i = 0; i < to->in_count; ++i) {
870                         newa [i] = to->in_bb [i];
871                 }
872                 newa [i] = from;
873                 to->in_count++;
874                 to->in_bb = newa;
875         }
876 }
877
878 /**
879  * mono_unlink_bblock:
880  *
881  *   Unlink two basic blocks.
882  */
883 static void
884 mono_unlink_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
885 {
886         int i, pos;
887         gboolean found;
888
889         found = FALSE;
890         for (i = 0; i < from->out_count; ++i) {
891                 if (to == from->out_bb [i]) {
892                         found = TRUE;
893                         break;
894                 }
895         }
896         if (found) {
897                 pos = 0;
898                 for (i = 0; i < from->out_count; ++i) {
899                         if (from->out_bb [i] != to)
900                                 from->out_bb [pos ++] = from->out_bb [i];
901                 }
902                 g_assert (pos == from->out_count - 1);
903                 from->out_count--;
904         }
905
906         found = FALSE;
907         for (i = 0; i < to->in_count; ++i) {
908                 if (from == to->in_bb [i]) {
909                         found = TRUE;
910                         break;
911                 }
912         }
913         if (found) {
914                 pos = 0;
915                 for (i = 0; i < to->in_count; ++i) {
916                         if (to->in_bb [i] != from)
917                                 to->in_bb [pos ++] = to->in_bb [i];
918                 }
919                 g_assert (pos == to->in_count - 1);
920                 to->in_count--;
921         }
922 }
923
924 /**
925  * mono_find_block_region:
926  *
927  *   We mark each basic block with a region ID. We use that to avoid BB
928  *   optimizations when blocks are in different regions.
929  *
930  * Returns:
931  *   A region token that encodes where this region is, and information
932  *   about the clause owner for this block.
933  *
934  *   The region encodes the try/catch/filter clause that owns this block
935  *   as well as the type.  -1 is a special value that represents a block
936  *   that is in none of try/catch/filter.
937  */
938 static int
939 mono_find_block_region (MonoCompile *cfg, int offset)
940 {
941         MonoMethod *method = cfg->method;
942         MonoMethodHeader *header = mono_method_get_header (method);
943         MonoExceptionClause *clause;
944         int i;
945
946         /* first search for handlers and filters */
947         for (i = 0; i < header->num_clauses; ++i) {
948                 clause = &header->clauses [i];
949                 if ((clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) && (offset >= clause->data.filter_offset) &&
950                     (offset < (clause->handler_offset)))
951                         return ((i + 1) << 8) | MONO_REGION_FILTER | clause->flags;
952                            
953                 if (MONO_OFFSET_IN_HANDLER (clause, offset)) {
954                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY)
955                                 return ((i + 1) << 8) | MONO_REGION_FINALLY | clause->flags;
956                         else if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
957                                 return ((i + 1) << 8) | MONO_REGION_FAULT | clause->flags;
958                         else if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE)
959                                 return ((i + 1) << 8) | MONO_REGION_CATCH | clause->flags;
960                 }
961         }
962
963         /* search the try blocks */
964         for (i = 0; i < header->num_clauses; ++i) {
965                 clause = &header->clauses [i];
966                 if (MONO_OFFSET_IN_CLAUSE (clause, offset))
967                         return ((i + 1) << 8) | clause->flags;
968         }
969
970         return -1;
971 }
972
973 static GList*
974 mono_find_final_block (MonoCompile *cfg, unsigned char *ip, unsigned char *target, int type)
975 {
976         MonoMethod *method = cfg->method;
977         MonoMethodHeader *header = mono_method_get_header (method);
978         MonoExceptionClause *clause;
979         MonoBasicBlock *handler;
980         int i;
981         GList *res = NULL;
982
983         for (i = 0; i < header->num_clauses; ++i) {
984                 clause = &header->clauses [i];
985                 if (MONO_OFFSET_IN_CLAUSE (clause, (ip - header->code)) && 
986                     (!MONO_OFFSET_IN_CLAUSE (clause, (target - header->code)))) {
987                         if (clause->flags == type) {
988                                 handler = cfg->cil_offset_to_bb [clause->handler_offset];
989                                 g_assert (handler);
990                                 res = g_list_append (res, handler);
991                         }
992                 }
993         }
994         return res;
995 }
996
997 MonoInst *
998 mono_find_spvar_for_region (MonoCompile *cfg, int region)
999 {
1000         return g_hash_table_lookup (cfg->spvars, GINT_TO_POINTER (region));
1001 }
1002
1003 static void
1004 mono_create_spvar_for_region (MonoCompile *cfg, int region)
1005 {
1006         MonoInst *var;
1007
1008         var = g_hash_table_lookup (cfg->spvars, GINT_TO_POINTER (region));
1009         if (var)
1010                 return;
1011
1012         var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1013         /* prevent it from being register allocated */
1014         var->flags |= MONO_INST_INDIRECT;
1015
1016         g_hash_table_insert (cfg->spvars, GINT_TO_POINTER (region), var);
1017 }
1018
1019 static MonoInst *
1020 mono_find_exvar_for_offset (MonoCompile *cfg, int offset)
1021 {
1022         return g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
1023 }
1024
1025 static MonoInst*
1026 mono_create_exvar_for_offset (MonoCompile *cfg, int offset)
1027 {
1028         MonoInst *var;
1029
1030         var = g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
1031         if (var)
1032                 return var;
1033
1034         var = mono_compile_create_var (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL);
1035         /* prevent it from being register allocated */
1036         var->flags |= MONO_INST_INDIRECT;
1037
1038         g_hash_table_insert (cfg->exvars, GINT_TO_POINTER (offset), var);
1039
1040         return var;
1041 }
1042
1043 static void
1044 df_visit (MonoBasicBlock *start, int *dfn, MonoBasicBlock **array)
1045 {
1046         int i;
1047
1048         array [*dfn] = start;
1049         /*g_print ("visit %d at %p (BB%ld)\n", *dfn, start->cil_code, start->block_num);*/
1050         for (i = 0; i < start->out_count; ++i) {
1051                 if (start->out_bb [i]->dfn)
1052                         continue;
1053                 (*dfn)++;
1054                 start->out_bb [i]->dfn = *dfn;
1055                 start->out_bb [i]->df_parent = start;
1056                 array [*dfn] = start->out_bb [i];
1057                 df_visit (start->out_bb [i], dfn, array);
1058         }
1059 }
1060
1061 static MonoBasicBlock*
1062 find_previous (MonoBasicBlock **bblocks, guint32 n_bblocks, MonoBasicBlock *start, const guchar *code)
1063 {
1064         MonoBasicBlock *best = start;
1065         int i;
1066
1067         for (i = 0; i < n_bblocks; ++i) {
1068                 if (bblocks [i]) {
1069                         MonoBasicBlock *bb = bblocks [i];
1070
1071                         if (bb->cil_code && bb->cil_code < code && bb->cil_code > best->cil_code)
1072                                 best = bb;
1073                 }
1074         }
1075
1076         return best;
1077 }
1078
1079 static void
1080 split_bblock (MonoCompile *cfg, MonoBasicBlock *first, MonoBasicBlock *second) {
1081         int i, j;
1082         MonoInst *inst;
1083         MonoBasicBlock *bb;
1084
1085         if (!MONO_INST_LIST_EMPTY (&second->ins_list))
1086                 return;
1087         
1088         /* 
1089          * FIXME: take into account all the details:
1090          * second may have been the target of more than one bblock
1091          */
1092         second->out_count = first->out_count;
1093         second->out_bb = first->out_bb;
1094
1095         for (i = 0; i < first->out_count; ++i) {
1096                 bb = first->out_bb [i];
1097                 for (j = 0; j < bb->in_count; ++j) {
1098                         if (bb->in_bb [j] == first)
1099                                 bb->in_bb [j] = second;
1100                 }
1101         }
1102
1103         first->out_count = 0;
1104         first->out_bb = NULL;
1105         link_bblock (cfg, first, second);
1106
1107         /*g_print ("start search at %p for %p\n", first->cil_code, second->cil_code);*/
1108         MONO_BB_FOR_EACH_INS (first, inst) {
1109                 MonoInst *inst_next;
1110
1111                 /*char *code = mono_disasm_code_one (NULL, cfg->method, inst->next->cil_code, NULL);
1112                 g_print ("found %p: %s", inst->next->cil_code, code);
1113                 g_free (code);*/
1114                 if (inst->cil_code >= second->cil_code)
1115                         continue;
1116
1117                 inst_next = mono_inst_list_next (&inst->node, &first->ins_list);
1118                 if (!inst_next)
1119                         break;
1120
1121                 if (inst_next->cil_code < second->cil_code)
1122                         continue;
1123                         
1124                 second->ins_list.next = inst->node.next;
1125                 second->ins_list.prev = first->ins_list.prev;
1126                 inst->node.next = &first->ins_list;
1127                 first->ins_list.prev = &inst->node;
1128
1129                 second->next_bb = first->next_bb;
1130                 first->next_bb = second;
1131                 return;
1132         }
1133         if (MONO_INST_LIST_EMPTY (&second->ins_list)) {
1134                 g_warning ("bblock split failed in %s::%s\n", cfg->method->klass->name, cfg->method->name);
1135                 //G_BREAKPOINT ();
1136         }
1137 }
1138
1139 static guint32
1140 reverse_branch_op (guint32 opcode)
1141 {
1142         static const int reverse_map [] = {
1143                 CEE_BNE_UN, CEE_BLT, CEE_BLE, CEE_BGT, CEE_BGE,
1144                 CEE_BEQ, CEE_BLT_UN, CEE_BLE_UN, CEE_BGT_UN, CEE_BGE_UN
1145         };
1146         static const int reverse_fmap [] = {
1147                 OP_FBNE_UN, OP_FBLT, OP_FBLE, OP_FBGT, OP_FBGE,
1148                 OP_FBEQ, OP_FBLT_UN, OP_FBLE_UN, OP_FBGT_UN, OP_FBGE_UN
1149         };
1150         static const int reverse_lmap [] = {
1151                 OP_LBNE_UN, OP_LBLT, OP_LBLE, OP_LBGT, OP_LBGE,
1152                 OP_LBEQ, OP_LBLT_UN, OP_LBLE_UN, OP_LBGT_UN, OP_LBGE_UN
1153         };
1154         static const int reverse_imap [] = {
1155                 OP_IBNE_UN, OP_IBLT, OP_IBLE, OP_IBGT, OP_IBGE,
1156                 OP_IBEQ, OP_IBLT_UN, OP_IBLE_UN, OP_IBGT_UN, OP_IBGE_UN
1157         };
1158                                 
1159         if (opcode >= CEE_BEQ && opcode <= CEE_BLT_UN) {
1160                 opcode = reverse_map [opcode - CEE_BEQ];
1161         } else if (opcode >= OP_FBEQ && opcode <= OP_FBLT_UN) {
1162                 opcode = reverse_fmap [opcode - OP_FBEQ];
1163         } else if (opcode >= OP_LBEQ && opcode <= OP_LBLT_UN) {
1164                 opcode = reverse_lmap [opcode - OP_LBEQ];
1165         } else if (opcode >= OP_IBEQ && opcode <= OP_IBLT_UN) {
1166                 opcode = reverse_imap [opcode - OP_IBEQ];
1167         } else
1168                 g_assert_not_reached ();
1169
1170         return opcode;
1171 }
1172
1173 #ifdef MONO_ARCH_SOFT_FLOAT
1174 static int
1175 condbr_to_fp_br (int opcode)
1176 {
1177         switch (opcode) {
1178         case CEE_BEQ: return OP_FBEQ;
1179         case CEE_BGE: return OP_FBGE;
1180         case CEE_BGT: return OP_FBGT;
1181         case CEE_BLE: return OP_FBLE;
1182         case CEE_BLT: return OP_FBLT;
1183         case CEE_BNE_UN: return OP_FBNE_UN;
1184         case CEE_BGE_UN: return OP_FBGE_UN;
1185         case CEE_BGT_UN: return OP_FBGT_UN;
1186         case CEE_BLE_UN: return OP_FBLE_UN;
1187         case CEE_BLT_UN: return OP_FBLT_UN;
1188         }
1189         g_assert_not_reached ();
1190         return 0;
1191 }
1192 #endif
1193
1194 /*
1195  * Returns the type used in the eval stack when @type is loaded.
1196  * FIXME: return a MonoType/MonoClass for the byref and VALUETYPE cases.
1197  */
1198 static void
1199 type_to_eval_stack_type (MonoCompile *cfg, MonoType *type, MonoInst *inst)
1200 {
1201         MonoClass *klass;
1202
1203         inst->klass = klass = mono_class_from_mono_type (type);
1204         if (type->byref) {
1205                 inst->type = STACK_MP;
1206                 return;
1207         }
1208
1209 handle_enum:
1210         switch (type->type) {
1211         case MONO_TYPE_VOID:
1212                 inst->type = STACK_INV;
1213                 return;
1214         case MONO_TYPE_I1:
1215         case MONO_TYPE_U1:
1216         case MONO_TYPE_BOOLEAN:
1217         case MONO_TYPE_I2:
1218         case MONO_TYPE_U2:
1219         case MONO_TYPE_CHAR:
1220         case MONO_TYPE_I4:
1221         case MONO_TYPE_U4:
1222                 inst->type = STACK_I4;
1223                 return;
1224         case MONO_TYPE_I:
1225         case MONO_TYPE_U:
1226         case MONO_TYPE_PTR:
1227         case MONO_TYPE_FNPTR:
1228                 inst->type = STACK_PTR;
1229                 return;
1230         case MONO_TYPE_CLASS:
1231         case MONO_TYPE_STRING:
1232         case MONO_TYPE_OBJECT:
1233         case MONO_TYPE_SZARRAY:
1234         case MONO_TYPE_ARRAY:    
1235                 inst->type = STACK_OBJ;
1236                 return;
1237         case MONO_TYPE_I8:
1238         case MONO_TYPE_U8:
1239                 inst->type = STACK_I8;
1240                 return;
1241         case MONO_TYPE_R4:
1242         case MONO_TYPE_R8:
1243                 inst->type = STACK_R8;
1244                 return;
1245         case MONO_TYPE_VALUETYPE:
1246                 if (type->data.klass->enumtype) {
1247                         type = type->data.klass->enum_basetype;
1248                         goto handle_enum;
1249                 } else {
1250                         inst->klass = klass;
1251                         inst->type = STACK_VTYPE;
1252                         return;
1253                 }
1254         case MONO_TYPE_TYPEDBYREF:
1255                 inst->klass = mono_defaults.typed_reference_class;
1256                 inst->type = STACK_VTYPE;
1257                 return;
1258         case MONO_TYPE_GENERICINST:
1259                 type = &type->data.generic_class->container_class->byval_arg;
1260                 goto handle_enum;
1261         case MONO_TYPE_VAR :
1262         case MONO_TYPE_MVAR :
1263                 /* FIXME: all the arguments must be references for now,
1264                  * later look inside cfg and see if the arg num is
1265                  * really a reference
1266                  */
1267                 g_assert (cfg->generic_sharing_context);
1268                 inst->type = STACK_OBJ;
1269                 return;
1270         default:
1271                 g_error ("unknown type 0x%02x in eval stack type", type->type);
1272         }
1273 }
1274
1275 /*
1276  * The following tables are used to quickly validate the IL code in type_from_op ().
1277  */
1278 static const char
1279 bin_num_table [STACK_MAX] [STACK_MAX] = {
1280         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1281         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
1282         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1283         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
1284         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_R8,  STACK_INV, STACK_INV, STACK_INV},
1285         {STACK_INV, STACK_MP,  STACK_INV, STACK_MP,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV},
1286         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1287         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
1288 };
1289
1290 static const char 
1291 neg_table [] = {
1292         STACK_INV, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_INV, STACK_INV, STACK_INV
1293 };
1294
1295 /* reduce the size of this table */
1296 static const char
1297 bin_int_table [STACK_MAX] [STACK_MAX] = {
1298         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1299         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1300         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1301         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1302         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1303         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1304         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1305         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
1306 };
1307
1308 static const char
1309 bin_comp_table [STACK_MAX] [STACK_MAX] = {
1310 /*      Inv i  L  p  F  &  O  vt */
1311         {0},
1312         {0, 1, 0, 1, 0, 0, 0, 0}, /* i, int32 */
1313         {0, 0, 1, 0, 0, 0, 0, 0}, /* L, int64 */
1314         {0, 1, 0, 1, 0, 2, 4, 0}, /* p, ptr */
1315         {0, 0, 0, 0, 1, 0, 0, 0}, /* F, R8 */
1316         {0, 0, 0, 2, 0, 1, 0, 0}, /* &, managed pointer */
1317         {0, 0, 0, 4, 0, 0, 3, 0}, /* O, reference */
1318         {0, 0, 0, 0, 0, 0, 0, 0}, /* vt value type */
1319 };
1320
1321 /* reduce the size of this table */
1322 static const char
1323 shift_table [STACK_MAX] [STACK_MAX] = {
1324         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1325         {STACK_INV, STACK_I4,  STACK_INV, STACK_I4,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1326         {STACK_INV, STACK_I8,  STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1327         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1328         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1329         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1330         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1331         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
1332 };
1333
1334 /*
1335  * Tables to map from the non-specific opcode to the matching
1336  * type-specific opcode.
1337  */
1338 /* handles from CEE_ADD to CEE_SHR_UN (CEE_REM_UN for floats) */
1339 static const guint16
1340 binops_op_map [STACK_MAX] = {
1341         0, 0, OP_LADD-CEE_ADD, OP_PADD-CEE_ADD, OP_FADD-CEE_ADD, OP_PADD-CEE_ADD
1342 };
1343
1344 /* handles from CEE_NEG to CEE_CONV_U8 */
1345 static const guint16
1346 unops_op_map [STACK_MAX] = {
1347         0, 0, OP_LNEG-CEE_NEG, OP_PNEG-CEE_NEG, OP_FNEG-CEE_NEG, OP_PNEG-CEE_NEG
1348 };
1349
1350 /* handles from CEE_CONV_U2 to CEE_SUB_OVF_UN */
1351 static const guint16
1352 ovfops_op_map [STACK_MAX] = {
1353         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
1354 };
1355
1356 /* handles from CEE_CONV_OVF_I1_UN to CEE_CONV_OVF_U_UN */
1357 static const guint16
1358 ovf2ops_op_map [STACK_MAX] = {
1359         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
1360 };
1361
1362 /* handles from CEE_CONV_OVF_I1 to CEE_CONV_OVF_U8 */
1363 static const guint16
1364 ovf3ops_op_map [STACK_MAX] = {
1365         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
1366 };
1367
1368 /* handles from CEE_CEQ to CEE_CLT_UN */
1369 static const guint16
1370 ceqops_op_map [STACK_MAX] = {
1371         0, 0, OP_LCEQ-OP_CEQ, OP_PCEQ-OP_CEQ, OP_FCEQ-OP_CEQ, OP_LCEQ-OP_CEQ
1372 };
1373
1374 /*
1375  * Sets ins->type (the type on the eval stack) according to the
1376  * type of the opcode and the arguments to it.
1377  * Invalid IL code is marked by setting ins->type to the invalid value STACK_INV.
1378  *
1379  * FIXME: this function sets ins->type unconditionally in some cases, but
1380  * it should set it to invalid for some types (a conv.x on an object)
1381  */
1382 static void
1383 type_from_op (MonoInst *ins) {
1384         switch (ins->opcode) {
1385         /* binops */
1386         case CEE_ADD:
1387         case CEE_SUB:
1388         case CEE_MUL:
1389         case CEE_DIV:
1390         case CEE_REM:
1391                 /* FIXME: check unverifiable args for STACK_MP */
1392                 ins->type = bin_num_table [ins->inst_i0->type] [ins->inst_i1->type];
1393                 ins->opcode += binops_op_map [ins->type];
1394                 return;
1395         case CEE_DIV_UN:
1396         case CEE_REM_UN:
1397         case CEE_AND:
1398         case CEE_OR:
1399         case CEE_XOR:
1400                 ins->type = bin_int_table [ins->inst_i0->type] [ins->inst_i1->type];
1401                 ins->opcode += binops_op_map [ins->type];
1402                 return;
1403         case CEE_SHL:
1404         case CEE_SHR:
1405         case CEE_SHR_UN:
1406                 ins->type = shift_table [ins->inst_i0->type] [ins->inst_i1->type];
1407                 ins->opcode += binops_op_map [ins->type];
1408                 return;
1409         case OP_COMPARE:
1410         case OP_LCOMPARE:
1411                 /* FIXME: handle some specifics with ins->next->type */
1412                 ins->type = bin_comp_table [ins->inst_i0->type] [ins->inst_i1->type] ? STACK_I4: STACK_INV;
1413                 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))))
1414                         ins->opcode = OP_LCOMPARE;
1415                 return;
1416         case OP_CEQ:
1417                 ins->type = bin_comp_table [ins->inst_i0->type] [ins->inst_i1->type] ? STACK_I4: STACK_INV;
1418                 ins->opcode += ceqops_op_map [ins->inst_i0->type];
1419                 return;
1420                 
1421         case OP_CGT:
1422         case OP_CGT_UN:
1423         case OP_CLT:
1424         case OP_CLT_UN:
1425                 ins->type = (bin_comp_table [ins->inst_i0->type] [ins->inst_i1->type] & 1) ? STACK_I4: STACK_INV;
1426                 ins->opcode += ceqops_op_map [ins->inst_i0->type];
1427                 return;
1428         /* unops */
1429         case CEE_NEG:
1430                 ins->type = neg_table [ins->inst_i0->type];
1431                 ins->opcode += unops_op_map [ins->type];
1432                 return;
1433         case CEE_NOT:
1434                 if (ins->inst_i0->type >= STACK_I4 && ins->inst_i0->type <= STACK_PTR)
1435                         ins->type = ins->inst_i0->type;
1436                 else
1437                         ins->type = STACK_INV;
1438                 ins->opcode += unops_op_map [ins->type];
1439                 return;
1440         case CEE_CONV_I1:
1441         case CEE_CONV_I2:
1442         case CEE_CONV_I4:
1443         case CEE_CONV_U4:
1444                 ins->type = STACK_I4;
1445                 ins->opcode += unops_op_map [ins->inst_i0->type];
1446                 return;
1447         case CEE_CONV_R_UN:
1448                 ins->type = STACK_R8;
1449                 switch (ins->inst_i0->type) {
1450                 case STACK_I4:
1451                 case STACK_PTR:
1452                         break;
1453                 case STACK_I8:
1454                         ins->opcode = OP_LCONV_TO_R_UN; 
1455                         break;
1456                 }
1457                 return;
1458         case CEE_CONV_OVF_I1:
1459         case CEE_CONV_OVF_U1:
1460         case CEE_CONV_OVF_I2:
1461         case CEE_CONV_OVF_U2:
1462         case CEE_CONV_OVF_I4:
1463         case CEE_CONV_OVF_U4:
1464                 ins->type = STACK_I4;
1465                 ins->opcode += ovf3ops_op_map [ins->inst_i0->type];
1466                 return;
1467         case CEE_CONV_OVF_I_UN:
1468         case CEE_CONV_OVF_U_UN:
1469                 ins->type = STACK_PTR;
1470                 ins->opcode += ovf2ops_op_map [ins->inst_i0->type];
1471                 return;
1472         case CEE_CONV_OVF_I1_UN:
1473         case CEE_CONV_OVF_I2_UN:
1474         case CEE_CONV_OVF_I4_UN:
1475         case CEE_CONV_OVF_U1_UN:
1476         case CEE_CONV_OVF_U2_UN:
1477         case CEE_CONV_OVF_U4_UN:
1478                 ins->type = STACK_I4;
1479                 ins->opcode += ovf2ops_op_map [ins->inst_i0->type];
1480                 return;
1481         case CEE_CONV_U:
1482                 ins->type = STACK_PTR;
1483                 switch (ins->inst_i0->type) {
1484                 case STACK_I4:
1485                         break;
1486                 case STACK_PTR:
1487                 case STACK_MP:
1488 #if SIZEOF_VOID_P == 8
1489                         ins->opcode = OP_LCONV_TO_U;
1490 #endif
1491                         break;
1492                 case STACK_I8:
1493                         ins->opcode = OP_LCONV_TO_U;
1494                         break;
1495                 case STACK_R8:
1496                         ins->opcode = OP_FCONV_TO_U;
1497                         break;
1498                 }
1499                 return;
1500         case CEE_CONV_I8:
1501         case CEE_CONV_U8:
1502                 ins->type = STACK_I8;
1503                 ins->opcode += unops_op_map [ins->inst_i0->type];
1504                 return;
1505         case CEE_CONV_OVF_I8:
1506         case CEE_CONV_OVF_U8:
1507                 ins->type = STACK_I8;
1508                 ins->opcode += ovf3ops_op_map [ins->inst_i0->type];
1509                 return;
1510         case CEE_CONV_OVF_U8_UN:
1511         case CEE_CONV_OVF_I8_UN:
1512                 ins->type = STACK_I8;
1513                 ins->opcode += ovf2ops_op_map [ins->inst_i0->type];
1514                 return;
1515         case CEE_CONV_R4:
1516         case CEE_CONV_R8:
1517                 ins->type = STACK_R8;
1518                 ins->opcode += unops_op_map [ins->inst_i0->type];
1519                 return;
1520         case OP_CKFINITE:
1521                 ins->type = STACK_R8;           
1522                 return;
1523         case CEE_CONV_U2:
1524         case CEE_CONV_U1:
1525                 ins->type = STACK_I4;
1526                 ins->opcode += ovfops_op_map [ins->inst_i0->type];
1527                 break;
1528         case CEE_CONV_I:
1529         case CEE_CONV_OVF_I:
1530         case CEE_CONV_OVF_U:
1531                 ins->type = STACK_PTR;
1532                 ins->opcode += ovfops_op_map [ins->inst_i0->type];
1533                 return;
1534         case CEE_ADD_OVF:
1535         case CEE_ADD_OVF_UN:
1536         case CEE_MUL_OVF:
1537         case CEE_MUL_OVF_UN:
1538         case CEE_SUB_OVF:
1539         case CEE_SUB_OVF_UN:
1540                 ins->type = bin_num_table [ins->inst_i0->type] [ins->inst_i1->type];
1541                 ins->opcode += ovfops_op_map [ins->inst_i0->type];
1542                 if (ins->type == STACK_R8)
1543                         ins->type = STACK_INV;
1544                 return;
1545         default:
1546                 g_error ("opcode 0x%04x not handled in type from op", ins->opcode);
1547                 break;
1548         }
1549 }
1550
1551 static const char 
1552 ldind_type [] = {
1553         STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_R8, STACK_OBJ
1554 };
1555
1556 /* map ldelem.x to the matching ldind.x opcode */
1557 static const guchar
1558 ldelem_to_ldind [] = {
1559         CEE_LDIND_I1,
1560         CEE_LDIND_U1,
1561         CEE_LDIND_I2,
1562         CEE_LDIND_U2,
1563         CEE_LDIND_I4,
1564         CEE_LDIND_U4,
1565         CEE_LDIND_I8,
1566         CEE_LDIND_I,
1567         CEE_LDIND_R4,
1568         CEE_LDIND_R8,
1569         CEE_LDIND_REF
1570 };
1571
1572 /* map stelem.x to the matching stind.x opcode */
1573 static const guchar
1574 stelem_to_stind [] = {
1575         CEE_STIND_I,
1576         CEE_STIND_I1,
1577         CEE_STIND_I2,
1578         CEE_STIND_I4,
1579         CEE_STIND_I8,
1580         CEE_STIND_R4,
1581         CEE_STIND_R8,
1582         CEE_STIND_REF
1583 };
1584
1585 #if 0
1586
1587 static const char
1588 param_table [STACK_MAX] [STACK_MAX] = {
1589         {0},
1590 };
1591
1592 static int
1593 check_values_to_signature (MonoInst *args, MonoType *this, MonoMethodSignature *sig)
1594 {
1595         int i;
1596
1597         if (sig->hasthis) {
1598                 switch (args->type) {
1599                 case STACK_I4:
1600                 case STACK_I8:
1601                 case STACK_R8:
1602                 case STACK_VTYPE:
1603                 case STACK_INV:
1604                         return 0;
1605                 }
1606                 args++;
1607         }
1608         for (i = 0; i < sig->param_count; ++i) {
1609                 switch (args [i].type) {
1610                 case STACK_INV:
1611                         return 0;
1612                 case STACK_MP:
1613                         if (!sig->params [i]->byref)
1614                                 return 0;
1615                         continue;
1616                 case STACK_OBJ:
1617                         if (sig->params [i]->byref)
1618                                 return 0;
1619                         switch (sig->params [i]->type) {
1620                         case MONO_TYPE_CLASS:
1621                         case MONO_TYPE_STRING:
1622                         case MONO_TYPE_OBJECT:
1623                         case MONO_TYPE_SZARRAY:
1624                         case MONO_TYPE_ARRAY:
1625                                 break;
1626                         default:
1627                                 return 0;
1628                         }
1629                         continue;
1630                 case STACK_R8:
1631                         if (sig->params [i]->byref)
1632                                 return 0;
1633                         if (sig->params [i]->type != MONO_TYPE_R4 && sig->params [i]->type != MONO_TYPE_R8)
1634                                 return 0;
1635                         continue;
1636                 case STACK_PTR:
1637                 case STACK_I4:
1638                 case STACK_I8:
1639                 case STACK_VTYPE:
1640                         break;
1641                 }
1642                 /*if (!param_table [args [i].type] [sig->params [i]->type])
1643                         return 0;*/
1644         }
1645         return 1;
1646 }
1647 #endif
1648
1649 static guint
1650 mini_type_to_ldind (MonoCompile* cfg, MonoType *type)
1651 {
1652         if (cfg->generic_sharing_context && !type->byref) {
1653                 /* FIXME: all the arguments must be references for now,
1654                  * later look inside cfg and see if the arg num is
1655                  * really a reference
1656                  */
1657                 if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)
1658                         return CEE_LDIND_REF;
1659         }
1660         return mono_type_to_ldind (type);
1661 }
1662
1663 static guint
1664 mini_type_to_stind (MonoCompile* cfg, MonoType *type)
1665 {
1666         if (cfg->generic_sharing_context && !type->byref) {
1667                 /* FIXME: all the arguments must be references for now,
1668                  * later look inside cfg and see if the arg num is
1669                  * really a reference
1670                  */
1671                 if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)
1672                         return CEE_STIND_REF;
1673         }
1674         return mono_type_to_stind (type);
1675 }
1676
1677 int
1678 mono_op_imm_to_op (int opcode)
1679 {
1680         switch (opcode) {
1681         case OP_ADD_IMM:
1682                 return OP_PADD;
1683         case OP_IADD_IMM:
1684                 return OP_IADD;
1685         case OP_LADD_IMM:
1686                 return OP_LADD;
1687         case OP_ISUB_IMM:
1688                 return OP_ISUB;
1689         case OP_LSUB_IMM:
1690                 return OP_LSUB;
1691         case OP_AND_IMM:
1692 #if SIZEOF_VOID_P == 4
1693                 return OP_IAND;
1694 #else
1695                 return OP_LAND;
1696 #endif
1697         case OP_IAND_IMM:
1698                 return OP_IAND;
1699         case OP_LAND_IMM:
1700                 return OP_LAND;
1701         case OP_IOR_IMM:
1702                 return OP_IOR;
1703         case OP_LOR_IMM:
1704                 return OP_LOR;
1705         case OP_IXOR_IMM:
1706                 return OP_IXOR;
1707         case OP_LXOR_IMM:
1708                 return OP_LXOR;
1709         case OP_ISHL_IMM:
1710                 return OP_ISHL;
1711         case OP_LSHL_IMM:
1712                 return OP_LSHL;
1713         case OP_ISHR_IMM:
1714                 return OP_ISHR;
1715         case OP_LSHR_IMM:
1716                 return OP_LSHR;
1717         case OP_ISHR_UN_IMM:
1718                 return OP_ISHR_UN;
1719         case OP_LSHR_UN_IMM:
1720                 return OP_LSHR_UN;
1721         case OP_IDIV_IMM:
1722                 return OP_IDIV;
1723         case OP_IDIV_UN_IMM:
1724                 return OP_IDIV_UN;
1725         case OP_IREM_UN_IMM:
1726                 return OP_IREM_UN;
1727         case OP_IREM_IMM:
1728                 return OP_IREM;
1729         case OP_DIV_IMM:
1730 #if SIZEOF_VOID_P == 4
1731                 return OP_IDIV;
1732 #else
1733                 return OP_LDIV;
1734 #endif
1735         case OP_REM_IMM:
1736 #if SIZEOF_VOID_P == 4
1737                 return OP_IREM;
1738 #else
1739                 return OP_LREM;
1740 #endif
1741         case OP_ADDCC_IMM:
1742                 return OP_ADDCC;
1743         case OP_ADC_IMM:
1744                 return OP_ADC;
1745         case OP_SUBCC_IMM:
1746                 return OP_SUBCC;
1747         case OP_SBB_IMM:
1748                 return OP_SBB;
1749         case OP_IADC_IMM:
1750                 return OP_IADC;
1751         case OP_ISBB_IMM:
1752                 return OP_ISBB;
1753         case OP_COMPARE_IMM:
1754                 return OP_COMPARE;
1755         case OP_ICOMPARE_IMM:
1756                 return OP_ICOMPARE;
1757         default:
1758                 printf ("%s\n", mono_inst_name (opcode));
1759                 g_assert_not_reached ();
1760         }
1761 }
1762
1763 /*
1764  * mono_decompose_op_imm:
1765  *
1766  *   Replace the OP_.._IMM INS with its non IMM variant.
1767  */
1768 void
1769 mono_decompose_op_imm (MonoCompile *cfg, MonoInst *ins)
1770 {
1771         MonoInst *temp;
1772
1773         MONO_INST_NEW (cfg, temp, OP_ICONST);
1774         temp->inst_c0 = ins->inst_imm;
1775         temp->dreg = mono_regstate_next_int (cfg->rs);
1776         MONO_INST_LIST_ADD_TAIL (&(temp)->node, &(ins)->node);
1777         ins->opcode = mono_op_imm_to_op (ins->opcode);
1778         ins->sreg2 = temp->dreg;
1779 }
1780
1781 /*
1782  * When we need a pointer to the current domain many times in a method, we
1783  * call mono_domain_get() once and we store the result in a local variable.
1784  * This function returns the variable that represents the MonoDomain*.
1785  */
1786 inline static MonoInst *
1787 mono_get_domainvar (MonoCompile *cfg)
1788 {
1789         if (!cfg->domainvar)
1790                 cfg->domainvar = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1791         return cfg->domainvar;
1792 }
1793
1794 /*
1795  * The got_var contains the address of the Global Offset Table when AOT 
1796  * compiling.
1797  */
1798 inline static MonoInst *
1799 mono_get_got_var (MonoCompile *cfg)
1800 {
1801 #ifdef MONO_ARCH_NEED_GOT_VAR
1802         if (!cfg->compile_aot)
1803                 return NULL;
1804         if (!cfg->got_var) {
1805                 cfg->got_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1806         }
1807         return cfg->got_var;
1808 #else
1809         return NULL;
1810 #endif
1811 }
1812
1813 static MonoInst *
1814 mono_get_vtable_var (MonoCompile *cfg)
1815 {
1816         g_assert (cfg->generic_sharing_context);
1817
1818         if (!cfg->rgctx_var) {
1819                 cfg->rgctx_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1820                 /* force the var to be stack allocated */
1821                 cfg->rgctx_var->flags |= MONO_INST_INDIRECT;
1822         }
1823
1824         return cfg->rgctx_var;
1825 }
1826
1827 MonoInst*
1828 mono_compile_create_var (MonoCompile *cfg, MonoType *type, int opcode)
1829 {
1830         MonoInst *inst;
1831         int num = cfg->num_varinfo;
1832
1833         if ((num + 1) >= cfg->varinfo_count) {
1834                 int orig_count = cfg->varinfo_count;
1835                 cfg->varinfo_count = (cfg->varinfo_count + 2) * 2;
1836                 cfg->varinfo = (MonoInst **)g_realloc (cfg->varinfo, sizeof (MonoInst*) * cfg->varinfo_count);
1837                 cfg->vars = (MonoMethodVar *)g_realloc (cfg->vars, sizeof (MonoMethodVar) * cfg->varinfo_count);
1838                 memset (&cfg->vars [orig_count], 0, (cfg->varinfo_count - orig_count) * sizeof (MonoMethodVar));
1839         }
1840
1841         /*g_print ("created temp %d of type 0x%x\n", num, type->type);*/
1842         mono_jit_stats.allocate_var++;
1843
1844         MONO_INST_NEW (cfg, inst, opcode);
1845         inst->inst_c0 = num;
1846         inst->inst_vtype = type;
1847         inst->klass = mono_class_from_mono_type (type);
1848         /* if set to 1 the variable is native */
1849         inst->backend.is_pinvoke = 0;
1850
1851         cfg->varinfo [num] = inst;
1852
1853         MONO_INIT_VARINFO (&cfg->vars [num], num);
1854
1855         cfg->num_varinfo++;
1856         if (cfg->verbose_level > 2)
1857                 g_print ("created temp %d of type %s\n", num, mono_type_get_name (type));
1858         return inst;
1859 }
1860
1861 /*
1862  * Transform a MonoInst into a load from the variable of index var_index.
1863  */
1864 void
1865 mono_compile_make_var_load (MonoCompile *cfg, MonoInst *dest, gssize var_index) {
1866         memset (dest, 0, sizeof (MonoInst));
1867         dest->ssa_op = MONO_SSA_LOAD;
1868         dest->inst_i0 = cfg->varinfo [var_index];
1869         dest->opcode = mini_type_to_ldind (cfg, dest->inst_i0->inst_vtype);
1870         type_to_eval_stack_type (cfg, dest->inst_i0->inst_vtype, dest);
1871         dest->klass = dest->inst_i0->klass;
1872 }
1873
1874 /*
1875  * Create a MonoInst that is a load from the variable of index var_index.
1876  */
1877 MonoInst*
1878 mono_compile_create_var_load (MonoCompile *cfg, gssize var_index) {
1879         MonoInst *dest;
1880         NEW_TEMPLOAD (cfg,dest,var_index);
1881         return dest;
1882 }
1883
1884 /*
1885  * Create a MonoInst that is a store of the given value into the variable of index var_index.
1886  */
1887 MonoInst*
1888 mono_compile_create_var_store (MonoCompile *cfg, gssize var_index, MonoInst *value) {
1889         MonoInst *dest;
1890         NEW_TEMPSTORE (cfg, dest, var_index, value);
1891         return dest;
1892 }
1893
1894 static MonoType*
1895 type_from_stack_type (MonoInst *ins) {
1896         switch (ins->type) {
1897         case STACK_I4: return &mono_defaults.int32_class->byval_arg;
1898         case STACK_I8: return &mono_defaults.int64_class->byval_arg;
1899         case STACK_PTR: return &mono_defaults.int_class->byval_arg;
1900         case STACK_R8: return &mono_defaults.double_class->byval_arg;
1901         case STACK_MP:
1902                 /* 
1903                  * this if used to be commented without any specific reason, but
1904                  * it breaks #80235 when commented
1905                  */
1906                 if (ins->klass)
1907                         return &ins->klass->this_arg;
1908                 else
1909                         return &mono_defaults.object_class->this_arg;
1910         case STACK_OBJ:
1911                 /* ins->klass may not be set for ldnull.
1912                  * Also, if we have a boxed valuetype, we want an object lass,
1913                  * not the valuetype class
1914                  */
1915                 if (ins->klass && !ins->klass->valuetype)
1916                         return &ins->klass->byval_arg;
1917                 return &mono_defaults.object_class->byval_arg;
1918         case STACK_VTYPE: return &ins->klass->byval_arg;
1919         default:
1920                 g_error ("stack type %d to montype not handled\n", ins->type);
1921         }
1922         return NULL;
1923 }
1924
1925 MonoType*
1926 mono_type_from_stack_type (MonoInst *ins) {
1927         return type_from_stack_type (ins);
1928 }
1929
1930 static MonoClass*
1931 array_access_to_klass (int opcode, MonoInst *array_obj)
1932 {
1933         switch (opcode) {
1934         case CEE_LDELEM_U1:
1935                 return mono_defaults.byte_class;
1936         case CEE_LDELEM_U2:
1937                 return mono_defaults.uint16_class;
1938         case CEE_LDELEM_I:
1939         case CEE_STELEM_I:
1940                 return mono_defaults.int_class;
1941         case CEE_LDELEM_I1:
1942         case CEE_STELEM_I1:
1943                 return mono_defaults.sbyte_class;
1944         case CEE_LDELEM_I2:
1945         case CEE_STELEM_I2:
1946                 return mono_defaults.int16_class;
1947         case CEE_LDELEM_I4:
1948         case CEE_STELEM_I4:
1949                 return mono_defaults.int32_class;
1950         case CEE_LDELEM_U4:
1951                 return mono_defaults.uint32_class;
1952         case CEE_LDELEM_I8:
1953         case CEE_STELEM_I8:
1954                 return mono_defaults.int64_class;
1955         case CEE_LDELEM_R4:
1956         case CEE_STELEM_R4:
1957                 return mono_defaults.single_class;
1958         case CEE_LDELEM_R8:
1959         case CEE_STELEM_R8:
1960                 return mono_defaults.double_class;
1961         case CEE_LDELEM_REF:
1962         case CEE_STELEM_REF: {
1963                 MonoClass *klass = array_obj->klass;
1964                 /* FIXME: add assert */
1965                 if (klass && klass->rank)
1966                         return klass->element_class;
1967                 return mono_defaults.object_class;
1968         }
1969         default:
1970                 g_assert_not_reached ();
1971         }
1972         return NULL;
1973 }
1974
1975 void
1976 mono_add_ins_to_end (MonoBasicBlock *bb, MonoInst *inst)
1977 {
1978         MonoInst *last = mono_inst_list_last (&bb->ins_list);
1979
1980         if (last && ((last->opcode >= CEE_BEQ &&
1981                         last->opcode <= CEE_BLT_UN) ||
1982                         last->opcode == OP_BR ||
1983                         last->opcode == OP_SWITCH)) {
1984                 MONO_INST_LIST_ADD_TAIL (&inst->node, &last->node);
1985         } else {
1986                 MONO_ADD_INS (bb, inst);
1987         }
1988 }
1989
1990 void
1991 mono_add_varcopy_to_end (MonoCompile *cfg, MonoBasicBlock *bb, int src, int dest)
1992 {
1993         MonoInst *inst, *load;
1994
1995         NEW_TEMPLOAD (cfg, load, src);
1996
1997         NEW_TEMPSTORE (cfg, inst, dest, load);
1998         /* FIXME: handle CEE_STIND_R4 */
1999         if (inst->opcode == CEE_STOBJ) {
2000                 NEW_TEMPLOADA (cfg, inst, dest);
2001                 handle_stobj (cfg, bb, inst, load, NULL, inst->klass, TRUE, FALSE, FALSE);
2002         } else {
2003                 inst->cil_code = NULL;
2004                 mono_add_ins_to_end (bb, inst);
2005         }
2006 }
2007
2008 /*
2009  * This function is called to handle items that are left on the evaluation stack
2010  * at basic block boundaries. What happens is that we save the values to local variables
2011  * and we reload them later when first entering the target basic block (with the
2012  * handle_loaded_temps () function).
2013  * It is also used to handle items on the stack in store opcodes, since it is
2014  * possible that the variable to be stored into is already on the stack, in
2015  * which case its old value should be used.
2016  * A single joint point will use the same variables (stored in the array bb->out_stack or
2017  * bb->in_stack, if the basic block is before or after the joint point).
2018  * If the stack merge fails at a join point, cfg->unverifiable is set.
2019  */
2020 static void
2021 handle_stack_args (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst **sp, int count)
2022 {
2023         int i, bindex;
2024         MonoBasicBlock *outb;
2025         MonoInst *inst, **locals;
2026         gboolean found;
2027
2028         if (!count)
2029                 return;
2030         if (cfg->verbose_level > 3)
2031                 g_print ("%d item(s) on exit from B%d\n", count, bb->block_num);
2032
2033         if (!bb->out_scount) {
2034                 bb->out_scount = count;
2035                 //g_print ("bblock %d has out:", bb->block_num);
2036                 found = FALSE;
2037                 for (i = 0; i < bb->out_count; ++i) {
2038                         outb = bb->out_bb [i];
2039                         /* exception handlers are linked, but they should not be considered for stack args */
2040                         if (outb->flags & BB_EXCEPTION_HANDLER)
2041                                 continue;
2042                         //g_print (" %d", outb->block_num);
2043                         if (outb->in_stack) {
2044                                 found = TRUE;
2045                                 bb->out_stack = outb->in_stack;
2046                                 break;
2047                         }
2048                 }
2049                 //g_print ("\n");
2050                 if (!found) {
2051                         bb->out_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * count);
2052                         for (i = 0; i < count; ++i) {
2053                                 /* 
2054                                  * try to reuse temps already allocated for this purpouse, if they occupy the same
2055                                  * stack slot and if they are of the same type.
2056                                  * This won't cause conflicts since if 'local' is used to 
2057                                  * store one of the values in the in_stack of a bblock, then
2058                                  * the same variable will be used for the same outgoing stack 
2059                                  * slot as well. 
2060                                  * This doesn't work when inlining methods, since the bblocks
2061                                  * in the inlined methods do not inherit their in_stack from
2062                                  * the bblock they are inlined to. See bug #58863 for an
2063                                  * example.
2064                                  * This hack is disabled since it also prevents proper tracking of types.
2065                                  */
2066 #if 1
2067                                 bb->out_stack [i] = mono_compile_create_var (cfg, type_from_stack_type (sp [i]), OP_LOCAL);
2068 #else
2069                                 if (cfg->inlined_method)
2070                                         bb->out_stack [i] = mono_compile_create_var (cfg, type_from_stack_type (sp [i]), OP_LOCAL);
2071                                 else
2072                                         bb->out_stack [i] = mono_compile_get_interface_var (cfg, i, sp [i]);
2073 #endif
2074                         }
2075                 }
2076         }
2077
2078         for (i = 0; i < bb->out_count; ++i) {
2079                 outb = bb->out_bb [i];
2080                 /* exception handlers are linked, but they should not be considered for stack args */
2081                 if (outb->flags & BB_EXCEPTION_HANDLER)
2082                         continue;
2083                 if (outb->in_scount) {
2084                         if (outb->in_scount != bb->out_scount) {
2085                                 cfg->unverifiable = TRUE;
2086                                 return;
2087                         }
2088                         continue; /* check they are the same locals */
2089                 }
2090                 outb->in_scount = count;
2091                 outb->in_stack = bb->out_stack;
2092         }
2093
2094         locals = bb->out_stack;
2095         for (i = 0; i < count; ++i) {
2096                 /* add store ops at the end of the bb, before the branch */
2097                 NEW_TEMPSTORE (cfg, inst, locals [i]->inst_c0, sp [i]);
2098                 if (inst->opcode == CEE_STOBJ) {
2099                         NEW_TEMPLOADA (cfg, inst, locals [i]->inst_c0);
2100                         handle_stobj (cfg, bb, inst, sp [i], sp [i]->cil_code, inst->klass, TRUE, FALSE, FALSE);
2101                 } else {
2102                         inst->cil_code = sp [i]->cil_code;
2103                         mono_add_ins_to_end (bb, inst);
2104                 }
2105                 if (cfg->verbose_level > 3)
2106                         g_print ("storing %d to temp %d\n", i, (int)locals [i]->inst_c0);
2107         }
2108
2109         /*
2110          * It is possible that the out bblocks already have in_stack assigned, and
2111          * the in_stacks differ. In this case, we will store to all the different 
2112          * in_stacks.
2113          */
2114
2115         found = TRUE;
2116         bindex = 0;
2117         while (found) {
2118                 /* Find a bblock which has a different in_stack */
2119                 found = FALSE;
2120                 while (bindex < bb->out_count) {
2121                         outb = bb->out_bb [bindex];
2122                         /* exception handlers are linked, but they should not be considered for stack args */
2123                         if (outb->flags & BB_EXCEPTION_HANDLER) {
2124                                 bindex++;
2125                                 continue;
2126                         }
2127                         if (outb->in_stack != locals) {
2128                                 /* 
2129                                  * Instead of storing sp [i] to locals [i], we need to store
2130                                  * locals [i] to <new locals>[i], since the sp [i] tree can't
2131                                  * be shared between trees.
2132                                  */
2133                                 for (i = 0; i < count; ++i)
2134                                         mono_add_varcopy_to_end (cfg, bb, locals [i]->inst_c0, outb->in_stack [i]->inst_c0);
2135                                 locals = outb->in_stack;
2136                                 found = TRUE;
2137                                 break;
2138                         }
2139                         bindex ++;
2140                 }
2141         }
2142 }
2143
2144 static int
2145 ret_type_to_call_opcode (MonoType *type, int calli, int virt, MonoGenericSharingContext *gsctx)
2146 {
2147         if (type->byref)
2148                 return calli? OP_CALL_REG: virt? OP_CALLVIRT: OP_CALL;
2149
2150 handle_enum:
2151         type = mini_get_basic_type_from_generic (gsctx, type);
2152         switch (type->type) {
2153         case MONO_TYPE_VOID:
2154                 return calli? OP_VOIDCALL_REG: virt? OP_VOIDCALLVIRT: OP_VOIDCALL;
2155         case MONO_TYPE_I1:
2156         case MONO_TYPE_U1:
2157         case MONO_TYPE_BOOLEAN:
2158         case MONO_TYPE_I2:
2159         case MONO_TYPE_U2:
2160         case MONO_TYPE_CHAR:
2161         case MONO_TYPE_I4:
2162         case MONO_TYPE_U4:
2163                 return calli? OP_CALL_REG: virt? OP_CALLVIRT: OP_CALL;
2164         case MONO_TYPE_I:
2165         case MONO_TYPE_U:
2166         case MONO_TYPE_PTR:
2167         case MONO_TYPE_FNPTR:
2168                 return calli? OP_CALL_REG: virt? OP_CALLVIRT: OP_CALL;
2169         case MONO_TYPE_CLASS:
2170         case MONO_TYPE_STRING:
2171         case MONO_TYPE_OBJECT:
2172         case MONO_TYPE_SZARRAY:
2173         case MONO_TYPE_ARRAY:    
2174                 return calli? OP_CALL_REG: virt? OP_CALLVIRT: OP_CALL;
2175         case MONO_TYPE_I8:
2176         case MONO_TYPE_U8:
2177                 return calli? OP_LCALL_REG: virt? OP_LCALLVIRT: OP_LCALL;
2178         case MONO_TYPE_R4:
2179         case MONO_TYPE_R8:
2180                 return calli? OP_FCALL_REG: virt? OP_FCALLVIRT: OP_FCALL;
2181         case MONO_TYPE_VALUETYPE:
2182                 if (type->data.klass->enumtype) {
2183                         type = type->data.klass->enum_basetype;
2184                         goto handle_enum;
2185                 } else
2186                         return calli? OP_VCALL_REG: virt? OP_VCALLVIRT: OP_VCALL;
2187         case MONO_TYPE_TYPEDBYREF:
2188                 return calli? OP_VCALL_REG: virt? OP_VCALLVIRT: OP_VCALL;
2189         case MONO_TYPE_GENERICINST:
2190                 type = &type->data.generic_class->container_class->byval_arg;
2191                 goto handle_enum;
2192         default:
2193                 g_error ("unknown type 0x%02x in ret_type_to_call_opcode", type->type);
2194         }
2195         return -1;
2196 }
2197
2198 void
2199 mono_create_jump_table (MonoCompile *cfg, MonoInst *label, MonoBasicBlock **bbs, int num_blocks)
2200 {
2201         MonoJumpInfo *ji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo));
2202         MonoJumpInfoBBTable *table;
2203
2204         table = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfoBBTable));
2205         table->table = bbs;
2206         table->table_size = num_blocks;
2207         
2208         ji->ip.label = label;
2209         ji->type = MONO_PATCH_INFO_SWITCH;
2210         ji->data.table = table;
2211         ji->next = cfg->patch_info;
2212         cfg->patch_info = ji;
2213 }
2214
2215 static void
2216 mono_save_token_info (MonoCompile *cfg, MonoImage *image, guint32 token, gpointer key)
2217 {
2218         if (cfg->compile_aot) {
2219                 MonoJumpInfoToken *jump_info_token = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoToken));
2220                 jump_info_token->image = image;
2221                 jump_info_token->token = token;
2222                 g_hash_table_insert (cfg->token_info_hash, key, jump_info_token);
2223         }
2224 }
2225
2226 /*
2227  * When we add a tree of instructions, we need to ensure the instructions currently
2228  * on the stack are executed before (like, if we load a value from a local).
2229  * We ensure this by saving the currently loaded values to temps and rewriting the
2230  * instructions to load the values.
2231  * This is not done for opcodes that terminate a basic block (because it's handled already
2232  * by handle_stack_args ()) and for opcodes that can't change values, like POP.
2233  */
2234 static void
2235 handle_loaded_temps (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst **stack, MonoInst **sp)
2236 {
2237         MonoInst *load, *store, *temp, *ins;
2238
2239         while (stack < sp) {
2240                 ins = *stack;
2241                 /* handle also other constants */
2242                 if ((ins->opcode != OP_ICONST) &&
2243                     /* temps never get written to again, so we can safely avoid duplicating them */
2244                     !(ins->ssa_op == MONO_SSA_LOAD && ins->inst_i0->opcode == OP_LOCAL && ins->inst_i0->flags & MONO_INST_IS_TEMP)) {
2245                         temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
2246                         temp->flags |= MONO_INST_IS_TEMP;
2247                         NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
2248                         store->cil_code = ins->cil_code;
2249                         if (store->opcode == CEE_STOBJ) {
2250                                 NEW_TEMPLOADA (cfg, store, temp->inst_c0);
2251                                 handle_stobj (cfg, bblock, store, ins, ins->cil_code, temp->klass, FALSE, FALSE, FALSE);
2252                         } else
2253                                 MONO_ADD_INS (bblock, store);
2254                         NEW_TEMPLOAD (cfg, load, temp->inst_c0);
2255                         load->cil_code = ins->cil_code;
2256                         *stack = load;
2257                 }
2258                 stack++;
2259         }
2260 }
2261
2262 /*
2263  * target_type_is_incompatible:
2264  * @cfg: MonoCompile context
2265  *
2266  * Check that the item @arg on the evaluation stack can be stored
2267  * in the target type (can be a local, or field, etc).
2268  * The cfg arg can be used to check if we need verification or just
2269  * validity checks.
2270  *
2271  * Returns: non-0 value if arg can't be stored on a target.
2272  */
2273 static int
2274 target_type_is_incompatible (MonoCompile *cfg, MonoType *target, MonoInst *arg)
2275 {
2276         MonoType *simple_type;
2277         MonoClass *klass;
2278
2279         if (target->byref) {
2280                 /* FIXME: check that the pointed to types match */
2281                 if (arg->type == STACK_MP)
2282                         return arg->klass != mono_class_from_mono_type (target);
2283                 if (arg->type == STACK_PTR)
2284                         return 0;
2285                 return 1;
2286         }
2287         simple_type = mono_type_get_underlying_type (target);
2288         switch (simple_type->type) {
2289         case MONO_TYPE_VOID:
2290                 return 1;
2291         case MONO_TYPE_I1:
2292         case MONO_TYPE_U1:
2293         case MONO_TYPE_BOOLEAN:
2294         case MONO_TYPE_I2:
2295         case MONO_TYPE_U2:
2296         case MONO_TYPE_CHAR:
2297         case MONO_TYPE_I4:
2298         case MONO_TYPE_U4:
2299                 if (arg->type != STACK_I4 && arg->type != STACK_PTR)
2300                         return 1;
2301                 return 0;
2302         case MONO_TYPE_PTR:
2303                 /* STACK_MP is needed when setting pinned locals */
2304                 if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
2305                         return 1;
2306                 return 0;
2307         case MONO_TYPE_I:
2308         case MONO_TYPE_U:
2309         case MONO_TYPE_FNPTR:
2310                 if (arg->type != STACK_I4 && arg->type != STACK_PTR)
2311                         return 1;
2312                 return 0;
2313         case MONO_TYPE_OBJECT:
2314                 if (arg->type != STACK_OBJ)
2315                         return 1;
2316                 return 0;
2317         case MONO_TYPE_STRING:
2318                 if (arg->type != STACK_OBJ)
2319                         return 1;
2320                 /* ldnull has arg->klass unset */
2321                 /*if (arg->klass && arg->klass != mono_defaults.string_class) {
2322                         G_BREAKPOINT ();
2323                         return 1;
2324                 }*/
2325                 return 0;
2326         case MONO_TYPE_CLASS:
2327         case MONO_TYPE_SZARRAY:
2328         case MONO_TYPE_ARRAY:    
2329                 if (arg->type != STACK_OBJ)
2330                         return 1;
2331                 /* FIXME: check type compatibility */
2332                 return 0;
2333         case MONO_TYPE_I8:
2334         case MONO_TYPE_U8:
2335                 if (arg->type != STACK_I8)
2336                         return 1;
2337                 return 0;
2338         case MONO_TYPE_R4:
2339         case MONO_TYPE_R8:
2340                 if (arg->type != STACK_R8)
2341                         return 1;
2342                 return 0;
2343         case MONO_TYPE_VALUETYPE:
2344                 if (arg->type != STACK_VTYPE)
2345                         return 1;
2346                 klass = mono_class_from_mono_type (simple_type);
2347                 if (klass != arg->klass)
2348                         return 1;
2349                 return 0;
2350         case MONO_TYPE_TYPEDBYREF:
2351                 if (arg->type != STACK_VTYPE)
2352                         return 1;
2353                 klass = mono_class_from_mono_type (simple_type);
2354                 if (klass != arg->klass)
2355                         return 1;
2356                 return 0;
2357         case MONO_TYPE_GENERICINST:
2358                 if (mono_type_generic_inst_is_valuetype (simple_type)) {
2359                         klass = mono_class_from_mono_type (simple_type);
2360                         if (klass->enumtype)
2361                                 return target_type_is_incompatible (cfg, klass->enum_basetype, arg);
2362                         if (arg->type != STACK_VTYPE)
2363                                 return 1;
2364                         if (klass != arg->klass)
2365                                 return 1;
2366                         return 0;
2367                 } else {
2368                         if (arg->type != STACK_OBJ)
2369                                 return 1;
2370                         /* FIXME: check type compatibility */
2371                         return 0;
2372                 }
2373         case MONO_TYPE_VAR:
2374         case MONO_TYPE_MVAR:
2375                 /* FIXME: all the arguments must be references for now,
2376                  * later look inside cfg and see if the arg num is
2377                  * really a reference
2378                  */
2379                 g_assert (cfg->generic_sharing_context);
2380                 if (arg->type != STACK_OBJ)
2381                         return 1;
2382                 return 0;
2383         default:
2384                 g_error ("unknown type 0x%02x in target_type_is_incompatible", simple_type->type);
2385         }
2386         return 1;
2387 }
2388
2389 /*
2390  * Prepare arguments for passing to a function call.
2391  * Return a non-zero value if the arguments can't be passed to the given
2392  * signature.
2393  * The type checks are not yet complete and some conversions may need
2394  * casts on 32 or 64 bit architectures.
2395  *
2396  * FIXME: implement this using target_type_is_incompatible ()
2397  */
2398 static int
2399 check_call_signature (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args)
2400 {
2401         MonoType *simple_type;
2402         int i;
2403
2404         if (sig->hasthis) {
2405                 if (args [0]->type != STACK_OBJ && args [0]->type != STACK_MP && args [0]->type != STACK_PTR)
2406                         return 1;
2407                 args++;
2408         }
2409         for (i = 0; i < sig->param_count; ++i) {
2410                 if (sig->params [i]->byref) {
2411                         if (args [i]->type != STACK_MP && args [i]->type != STACK_PTR)
2412                                 return 1;
2413                         continue;
2414                 }
2415                 simple_type = sig->params [i];
2416                 simple_type = mini_get_basic_type_from_generic (cfg->generic_sharing_context, simple_type);
2417 handle_enum:
2418                 switch (simple_type->type) {
2419                 case MONO_TYPE_VOID:
2420                         return 1;
2421                         continue;
2422                 case MONO_TYPE_I1:
2423                 case MONO_TYPE_U1:
2424                 case MONO_TYPE_BOOLEAN:
2425                 case MONO_TYPE_I2:
2426                 case MONO_TYPE_U2:
2427                 case MONO_TYPE_CHAR:
2428                 case MONO_TYPE_I4:
2429                 case MONO_TYPE_U4:
2430                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR)
2431                                 return 1;
2432                         continue;
2433                 case MONO_TYPE_I:
2434                 case MONO_TYPE_U:
2435                 case MONO_TYPE_PTR:
2436                 case MONO_TYPE_FNPTR:
2437                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR && args [i]->type != STACK_MP && args [i]->type != STACK_OBJ)
2438                                 return 1;
2439                         continue;
2440                 case MONO_TYPE_CLASS:
2441                 case MONO_TYPE_STRING:
2442                 case MONO_TYPE_OBJECT:
2443                 case MONO_TYPE_SZARRAY:
2444                 case MONO_TYPE_ARRAY:    
2445                         if (args [i]->type != STACK_OBJ)
2446                                 return 1;
2447                         continue;
2448                 case MONO_TYPE_I8:
2449                 case MONO_TYPE_U8:
2450                         if (args [i]->type != STACK_I8)
2451                                 return 1;
2452                         continue;
2453                 case MONO_TYPE_R4:
2454                 case MONO_TYPE_R8:
2455                         if (args [i]->type != STACK_R8)
2456                                 return 1;
2457                         continue;
2458                 case MONO_TYPE_VALUETYPE:
2459                         if (simple_type->data.klass->enumtype) {
2460                                 simple_type = simple_type->data.klass->enum_basetype;
2461                                 goto handle_enum;
2462                         }
2463                         if (args [i]->type != STACK_VTYPE)
2464                                 return 1;
2465                         continue;
2466                 case MONO_TYPE_TYPEDBYREF:
2467                         if (args [i]->type != STACK_VTYPE)
2468                                 return 1;
2469                         continue;
2470                 case MONO_TYPE_GENERICINST:
2471                         simple_type = &simple_type->data.generic_class->container_class->byval_arg;
2472                         goto handle_enum;
2473
2474                 default:
2475                         g_error ("unknown type 0x%02x in check_call_signature",
2476                                  simple_type->type);
2477                 }
2478         }
2479         return 0;
2480 }
2481
2482 inline static int
2483 mono_spill_call (MonoCompile *cfg, MonoBasicBlock *bblock, MonoCallInst *call, MonoMethodSignature *sig, gboolean ret_object, 
2484                  const guint8 *ip, gboolean to_end)
2485 {
2486         MonoInst *temp, *store, *ins = (MonoInst*)call;
2487         MonoType *ret = sig->ret;
2488
2489         if (!MONO_TYPE_IS_VOID (ret) || ret_object) {
2490                 if (ret_object) {
2491                         call->inst.type = STACK_OBJ;
2492                         call->inst.opcode = OP_CALL;
2493                         temp = mono_compile_create_var (cfg, &mono_defaults.string_class->byval_arg, OP_LOCAL);
2494                 } else {
2495                         type_to_eval_stack_type (cfg, ret, ins);
2496                         temp = mono_compile_create_var (cfg, ret, OP_LOCAL);
2497                 }
2498                 
2499                 temp->flags |= MONO_INST_IS_TEMP;
2500
2501                 if (MONO_TYPE_ISSTRUCT (ret)) {
2502                         MonoInst *loada, *dummy_store;
2503
2504                         /* 
2505                          * Emit a dummy store to the local holding the result so the
2506                          * liveness info remains correct.
2507                          */
2508                         NEW_DUMMY_STORE (cfg, dummy_store, temp->inst_c0);
2509                         if (to_end)
2510                                 mono_add_ins_to_end (bblock, dummy_store);
2511                         else
2512                                 MONO_ADD_INS (bblock, dummy_store);
2513
2514                         /* we use this to allocate native sized structs */
2515                         temp->backend.is_pinvoke = sig->pinvoke;
2516
2517                         NEW_TEMPLOADA (cfg, loada, temp->inst_c0);
2518                         if (call->inst.opcode == OP_VCALL || call->inst.opcode == OP_VCALL_RGCTX)
2519                                 ins->inst_left = loada;
2520                         else
2521                                 ins->inst_right = loada; /* a virtual or indirect call */
2522
2523                         if (to_end)
2524                                 mono_add_ins_to_end (bblock, ins);
2525                         else
2526                                 MONO_ADD_INS (bblock, ins);
2527                 } else {
2528                         NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
2529                         store->cil_code = ip;
2530                         
2531 #ifdef MONO_ARCH_SOFT_FLOAT
2532                         if (store->opcode == CEE_STIND_R4) {
2533                                 /*FIXME implement proper support for to_end*/
2534                                 g_assert (!to_end);
2535                                 NEW_TEMPLOADA (cfg, store, temp->inst_c0);
2536                                 handle_store_float (cfg, bblock, store, ins, ip);
2537                         } else
2538 #endif
2539                         if (to_end)
2540                                 mono_add_ins_to_end (bblock, store);
2541                         else
2542                                 MONO_ADD_INS (bblock, store);
2543                 }
2544                 return temp->inst_c0;
2545         } else {
2546                 if (to_end)
2547                         mono_add_ins_to_end (bblock, ins);
2548                 else
2549                         MONO_ADD_INS (bblock, ins);
2550                 return -1;
2551         }
2552 }
2553
2554 inline static MonoCallInst *
2555 mono_emit_call_args (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethodSignature *sig, 
2556                      MonoInst **args, int calli, int virtual, const guint8 *ip, gboolean to_end)
2557 {
2558         MonoCallInst *call;
2559         MonoInst *arg, *n;
2560
2561         MONO_INST_NEW_CALL (cfg, call, ret_type_to_call_opcode (sig->ret, calli, virtual, cfg->generic_sharing_context));
2562
2563 #ifdef MONO_ARCH_SOFT_FLOAT
2564         /* we need to convert the r4 value to an int value */
2565         {
2566                 int i;
2567                 for (i = 0; i < sig->param_count; ++i) {
2568                         if (!sig->params [i]->byref && sig->params [i]->type == MONO_TYPE_R4) {
2569                                 MonoInst *iargs [1];
2570                                 int temp;
2571                                 iargs [0] = args [i + sig->hasthis];
2572
2573                                 temp = mono_emit_jit_icall (cfg, bblock, mono_fload_r4_arg, iargs, ip);
2574                                 NEW_TEMPLOAD (cfg, arg, temp);
2575                                 args [i + sig->hasthis] = arg;
2576                         }
2577                 }
2578         }
2579 #endif
2580
2581         call->inst.cil_code = ip;
2582         call->args = args;
2583         call->signature = sig;
2584         call = mono_arch_call_opcode (cfg, bblock, call, virtual);
2585         type_to_eval_stack_type (cfg, sig->ret, &call->inst);
2586
2587         MONO_INST_LIST_FOR_EACH_ENTRY_SAFE (arg, n, &call->out_args, node) {
2588                 if (!arg->cil_code)
2589                         arg->cil_code = ip;
2590                 if (to_end)
2591                         mono_add_ins_to_end (bblock, arg);
2592                 else
2593                         MONO_ADD_INS (bblock, arg);
2594         }
2595         return call;
2596 }
2597
2598 inline static MonoCallInst*
2599 mono_emit_calli (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethodSignature *sig, 
2600                  MonoInst **args, MonoInst *addr, const guint8 *ip)
2601 {
2602         MonoCallInst *call = mono_emit_call_args (cfg, bblock, sig, args, TRUE, FALSE, ip, FALSE);
2603
2604         call->inst.inst_i0 = addr;
2605
2606         return call;
2607 }
2608
2609 inline static MonoCallInst*
2610 mono_emit_rgctx_calli (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethodSignature *sig,
2611         MonoInst **args, MonoInst *addr, MonoInst *rgctx_arg, const guint8 *ip)
2612 {
2613         MonoCallInst *call = mono_emit_calli (cfg, bblock, sig, args, addr, ip);
2614
2615         if (rgctx_arg) {
2616                 switch (call->inst.opcode) {
2617                 case OP_CALL_REG: call->inst.opcode = OP_CALL_REG_RGCTX; break;
2618                 case OP_VOIDCALL_REG: call->inst.opcode = OP_VOIDCALL_REG_RGCTX; break;
2619                 case OP_FCALL_REG: call->inst.opcode = OP_FCALL_REG_RGCTX; break;
2620                 case OP_LCALL_REG: call->inst.opcode = OP_LCALL_REG_RGCTX; break;
2621                 case OP_VCALL_REG: {
2622                         MonoInst *group;
2623
2624                         NEW_GROUP (cfg, group, call->inst.inst_left, NULL);
2625                         call->inst.inst_left = group;
2626                         call->inst.opcode = OP_VCALL_REG_RGCTX;
2627                         break;
2628                 }
2629                 default: g_assert_not_reached ();
2630                 }
2631
2632                 if (call->inst.opcode != OP_VCALL_REG_RGCTX) {
2633                         g_assert (!call->inst.inst_right);
2634                         call->inst.inst_right = rgctx_arg;
2635                 } else {
2636                         g_assert (!call->inst.inst_left->inst_right);
2637                         call->inst.inst_left->inst_right = rgctx_arg;
2638                 }
2639         }
2640
2641         return call;
2642 }
2643
2644 inline static int
2645 mono_emit_calli_spilled (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethodSignature *sig, 
2646                                                  MonoInst **args, MonoInst *addr, const guint8 *ip)
2647 {
2648         MonoCallInst *call = mono_emit_calli (cfg, bblock, sig, args, addr, ip);
2649
2650         return mono_spill_call (cfg, bblock, call, sig, FALSE, ip, FALSE);
2651 }
2652
2653 static int
2654 mono_emit_rgctx_calli_spilled (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethodSignature *sig,
2655         MonoInst **args, MonoInst *addr, MonoInst *rgctx_arg, const guint8 *ip)
2656 {
2657         MonoCallInst *call = mono_emit_rgctx_calli (cfg, bblock, sig, args, addr, rgctx_arg, ip);
2658
2659         return mono_spill_call (cfg, bblock, call, sig, FALSE, ip, FALSE);
2660 }
2661
2662 static MonoCallInst*
2663 mono_emit_method_call_full (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *method, MonoMethodSignature *sig,
2664                        MonoInst **args, const guint8 *ip, MonoInst *this, gboolean to_end)
2665 {
2666         gboolean virtual = this != NULL;
2667         MonoCallInst *call;
2668
2669         call = mono_emit_call_args (cfg, bblock, sig, args, FALSE, virtual, ip, to_end);
2670
2671         if (this && sig->hasthis && 
2672             (method->klass->marshalbyref || method->klass == mono_defaults.object_class) && 
2673             !(method->flags & METHOD_ATTRIBUTE_VIRTUAL) && !MONO_CHECK_THIS (this)) {
2674                 call->method = mono_marshal_get_remoting_invoke_with_check (method);
2675         } else {
2676                 call->method = method;
2677         }
2678         call->inst.flags |= MONO_INST_HAS_METHOD;
2679         call->inst.inst_left = this;
2680
2681         if (call->method->klass->flags & TYPE_ATTRIBUTE_INTERFACE)
2682                 /* Needed by the code generated in inssel.brg */
2683                 mono_get_got_var (cfg);
2684
2685         return call;
2686 }
2687
2688 static MonoCallInst*
2689 mono_emit_method_call (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *method, MonoMethodSignature *sig,
2690                        MonoInst **args, const guint8 *ip, MonoInst *this)
2691 {
2692         return mono_emit_method_call_full (cfg, bblock, method, sig, args, ip, this, FALSE);
2693 }
2694
2695 inline static int
2696 mono_emit_method_call_spilled (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *method,  
2697                        MonoMethodSignature *signature, MonoInst **args, const guint8 *ip, MonoInst *this)
2698 {
2699         MonoCallInst *call = mono_emit_method_call (cfg, bblock, method, signature, args, ip, this);
2700
2701         return mono_spill_call (cfg, bblock, call, signature, method->string_ctor, ip, FALSE);
2702 }
2703
2704 inline static int
2705 mono_emit_method_call_spilled_full (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *method,  
2706                        MonoMethodSignature *signature, MonoInst **args, const guint8 *ip, MonoInst *this,
2707                        gboolean ret_object, gboolean to_end)
2708 {
2709         MonoCallInst *call = mono_emit_method_call_full (cfg, bblock, method, signature, args, ip, this, to_end);
2710
2711         return mono_spill_call (cfg, bblock, call, signature, ret_object, ip, to_end);
2712 }
2713
2714 inline static int
2715 mono_emit_native_call (MonoCompile *cfg, MonoBasicBlock *bblock, gconstpointer func, MonoMethodSignature *sig,
2716                        MonoInst **args, const guint8 *ip, gboolean ret_object, gboolean to_end)
2717 {
2718         MonoCallInst *call;
2719
2720         g_assert (sig);
2721
2722         call = mono_emit_call_args (cfg, bblock, sig, args, FALSE, FALSE, ip, to_end);
2723         call->fptr = func;
2724
2725         return mono_spill_call (cfg, bblock, call, sig, ret_object, ip, to_end);
2726 }
2727
2728 inline static int
2729 mono_emit_jit_icall (MonoCompile *cfg, MonoBasicBlock *bblock, gconstpointer func, MonoInst **args, const guint8 *ip)
2730 {
2731         MonoJitICallInfo *info = mono_find_jit_icall_by_addr (func);
2732         
2733         if (!info) {
2734                 g_warning ("unregistered JIT ICall");
2735                 g_assert_not_reached ();
2736         }
2737
2738         return mono_emit_native_call (cfg, bblock, mono_icall_get_wrapper (info), info->sig, args, ip, FALSE, FALSE);
2739 }
2740
2741 static MonoCallInst*
2742 mono_emit_rgctx_method_call (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *method, MonoMethodSignature *sig,
2743                 MonoInst **args, MonoInst *rgctx_arg, const guint8 *ip, MonoInst *this)
2744 {
2745         MonoCallInst *call = mono_emit_method_call_full (cfg, bblock, method, sig, args, ip, this, FALSE);
2746
2747         if (rgctx_arg) {
2748                 switch (call->inst.opcode) {
2749                 case OP_CALL: call->inst.opcode = OP_CALL_RGCTX; break;
2750                 case OP_VOIDCALL: call->inst.opcode = OP_VOIDCALL_RGCTX; break;
2751                 case OP_FCALL: call->inst.opcode = OP_FCALL_RGCTX; break;
2752                 case OP_LCALL: call->inst.opcode = OP_LCALL_RGCTX; break;
2753                 case OP_VCALL: call->inst.opcode = OP_VCALL_RGCTX; break;
2754                 default: g_assert_not_reached ();
2755                 }
2756
2757                 if (call->inst.opcode != OP_VCALL_RGCTX) {
2758                         g_assert (!call->inst.inst_left);
2759                         call->inst.inst_left = rgctx_arg;
2760                 } else {
2761                         g_assert (!call->inst.inst_right);
2762                         call->inst.inst_right = rgctx_arg;
2763                 }
2764         }
2765
2766         return call;
2767 }
2768
2769 inline static int
2770 mono_emit_rgctx_method_call_spilled (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *method,  
2771                 MonoMethodSignature *signature, MonoInst **args, MonoInst *rgctx_arg, const guint8 *ip,
2772                 MonoInst *this)
2773 {
2774         MonoCallInst *call = mono_emit_rgctx_method_call (cfg, bblock, method, signature, args, rgctx_arg, ip, this);
2775
2776         return mono_spill_call (cfg, bblock, call, signature, method->string_ctor, ip, FALSE);
2777 }
2778
2779 static void
2780 mono_emulate_opcode (MonoCompile *cfg, MonoInst *tree, MonoInst **iargs, MonoJitICallInfo *info)
2781 {
2782         MonoInst *ins, *temp = NULL, *store, *load;
2783         MonoInstList *head, *list;
2784         int nargs;
2785         MonoCallInst *call;
2786
2787         //g_print ("emulating: ");
2788         //mono_print_tree_nl (tree);
2789         MONO_INST_NEW_CALL (cfg, call, ret_type_to_call_opcode (info->sig->ret, FALSE, FALSE, cfg->generic_sharing_context));
2790         ins = (MonoInst*)call;
2791         MONO_INST_LIST_INIT (&ins->node);
2792         
2793         call->inst.cil_code = tree->cil_code;
2794         call->args = iargs;
2795         call->signature = info->sig;
2796
2797         call = mono_arch_call_opcode (cfg, cfg->cbb, call, FALSE);
2798
2799         if (!MONO_TYPE_IS_VOID (info->sig->ret)) {
2800                 temp = mono_compile_create_var (cfg, info->sig->ret, OP_LOCAL);
2801                 temp->flags |= MONO_INST_IS_TEMP;
2802                 NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
2803                 MONO_INST_LIST_INIT (&store->node);
2804                 /* FIXME: handle CEE_STIND_R4 */
2805                 store->cil_code = tree->cil_code;
2806         } else {
2807                 store = ins;
2808         }
2809
2810         nargs = info->sig->param_count + info->sig->hasthis;
2811
2812         if (nargs) {
2813                 MONO_INST_LIST_ADD_TAIL (&store->node,
2814                                         &call->out_args);
2815                 list = &call->out_args;
2816         } else {
2817                 list = &store->node;
2818         }
2819
2820         if (cfg->prev_ins) {
2821                 /* 
2822                  * This assumes that that in a tree, emulate_opcode is called for a
2823                  * node before it is called for its children. dec_foreach needs to
2824                  * take this into account.
2825                  */
2826                 head = &cfg->prev_ins->node;
2827         } else {
2828                 head = &cfg->cbb->ins_list;
2829         }
2830
2831         MONO_INST_LIST_SPLICE_INIT (list, head);
2832
2833         call->fptr = mono_icall_get_wrapper (info);
2834
2835         if (!MONO_TYPE_IS_VOID (info->sig->ret)) {
2836                 NEW_TEMPLOAD (cfg, load, temp->inst_c0);
2837                 *tree = *load;
2838         }
2839 }
2840
2841 /*
2842  * This entry point could be used later for arbitrary method
2843  * redirection.
2844  */
2845 inline static int
2846 mini_redirect_call (int *temp, MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *method,  
2847                        MonoMethodSignature *signature, MonoInst **args, const guint8 *ip, MonoInst *this)
2848 {
2849
2850         if (method->klass == mono_defaults.string_class) {
2851                 /* managed string allocation support */
2852                 if (strcmp (method->name, "InternalAllocateStr") == 0) {
2853                         MonoInst *iargs [2];
2854                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
2855                         MonoMethod *managed_alloc = mono_gc_get_managed_allocator (vtable, FALSE);
2856                         if (!managed_alloc)
2857                                 return FALSE;
2858                         NEW_VTABLECONST (cfg, iargs [0], vtable);
2859                         iargs [1] = args [0];
2860                         *temp = mono_emit_method_call_spilled (cfg, bblock, managed_alloc, mono_method_signature (managed_alloc), iargs, ip, this);
2861                         return TRUE;
2862                 }
2863         }
2864         return FALSE;
2865 }
2866
2867 static MonoMethodSignature *
2868 mono_get_array_new_va_signature (int arity)
2869 {
2870         static GHashTable *sighash = NULL;
2871         MonoMethodSignature *res;
2872         int i;
2873
2874         mono_jit_lock ();
2875         if (!sighash) {
2876                 sighash = g_hash_table_new (NULL, NULL);
2877         }
2878         else if ((res = g_hash_table_lookup (sighash, GINT_TO_POINTER (arity)))) {
2879                 mono_jit_unlock ();
2880                 return res;
2881         }
2882
2883         res = mono_metadata_signature_alloc (mono_defaults.corlib, arity + 1);
2884
2885         res->pinvoke = 1;
2886 #ifdef MONO_ARCH_VARARG_ICALLS
2887         /* Only set this only some archs since not all backends can handle varargs+pinvoke */
2888         res->call_convention = MONO_CALL_VARARG;
2889 #endif
2890
2891 #ifdef PLATFORM_WIN32
2892         res->call_convention = MONO_CALL_C;
2893 #endif
2894
2895         res->params [0] = &mono_defaults.int_class->byval_arg;  
2896         for (i = 0; i < arity; i++)
2897                 res->params [i + 1] = &mono_defaults.int_class->byval_arg;
2898
2899         res->ret = &mono_defaults.int_class->byval_arg;
2900
2901         g_hash_table_insert (sighash, GINT_TO_POINTER (arity), res);
2902         mono_jit_unlock ();
2903
2904         return res;
2905 }
2906
2907 #ifdef MONO_ARCH_SOFT_FLOAT
2908 static void
2909 handle_store_float (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *ptr, MonoInst *val, const unsigned char *ip)
2910 {
2911         MonoInst *iargs [2];
2912         iargs [0] = val;
2913         iargs [1] = ptr;
2914
2915         mono_emit_jit_icall (cfg, bblock, mono_fstore_r4, iargs, ip);
2916 }
2917
2918 static int
2919 handle_load_float (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *ptr, const unsigned char *ip)
2920 {
2921         MonoInst *iargs [1];
2922         iargs [0] = ptr;
2923
2924         return mono_emit_jit_icall (cfg, bblock, mono_fload_r4, iargs, ip);
2925 }
2926
2927 #define LDLOC_SOFT_FLOAT(cfg,ins,idx,ip) do {\
2928                 if (header->locals [(idx)]->type == MONO_TYPE_R4 && !header->locals [(idx)]->byref) {   \
2929                         int temp;       \
2930                         NEW_LOCLOADA (cfg, (ins), (idx));       \
2931                         temp = handle_load_float (cfg, bblock, (ins), (ip));    \
2932                         NEW_TEMPLOAD (cfg, (ins), temp);        \
2933                 }       \
2934         } while (0)
2935 #define STLOC_SOFT_FLOAT(cfg,ins,idx,ip) do {\
2936                 if (header->locals [(idx)]->type == MONO_TYPE_R4 && !header->locals [(idx)]->byref) {   \
2937                         int temp;       \
2938                         NEW_LOCLOADA (cfg, (ins), (idx));       \
2939                         handle_store_float (cfg, bblock, (ins), *sp, (ip));     \
2940                         MONO_INST_NEW (cfg, (ins), OP_NOP);     \
2941                 }       \
2942         } while (0)
2943 #define LDARG_SOFT_FLOAT(cfg,ins,idx,ip) do {\
2944                 if (param_types [(idx)]->type == MONO_TYPE_R4 && !param_types [(idx)]->byref) { \
2945                         int temp;       \
2946                         NEW_ARGLOADA (cfg, (ins), (idx));       \
2947                         temp = handle_load_float (cfg, bblock, (ins), (ip));    \
2948                         NEW_TEMPLOAD (cfg, (ins), temp);        \
2949                 }       \
2950         } while (0)
2951 #define STARG_SOFT_FLOAT(cfg,ins,idx,ip) do {\
2952                 if (param_types [(idx)]->type == MONO_TYPE_R4 && !param_types [(idx)]->byref) { \
2953                         int temp;       \
2954                         NEW_ARGLOADA (cfg, (ins), (idx));       \
2955                         handle_store_float (cfg, bblock, (ins), *sp, (ip));     \
2956                         MONO_INST_NEW (cfg, (ins), OP_NOP);     \
2957                 }       \
2958         } while (0)
2959 #else
2960 #define LDLOC_SOFT_FLOAT(cfg,ins,idx,ip)
2961 #define STLOC_SOFT_FLOAT(cfg,ins,idx,ip)
2962 #define LDARG_SOFT_FLOAT(cfg,ins,idx,ip)
2963 #define STARG_SOFT_FLOAT(cfg,ins,idx,ip)
2964 #endif
2965
2966 static MonoMethod*
2967 get_memcpy_method (void)
2968 {
2969         static MonoMethod *memcpy_method = NULL;
2970         if (!memcpy_method) {
2971                 memcpy_method = mono_class_get_method_from_name (mono_defaults.string_class, "memcpy", 3);
2972                 if (!memcpy_method)
2973                         g_error ("Old corlib found. Install a new one");
2974         }
2975         return memcpy_method;
2976 }
2977
2978 static void
2979 handle_stobj (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *dest, MonoInst *src, const unsigned char *ip, MonoClass *klass, gboolean to_end, gboolean native, gboolean write_barrier) {
2980         MonoInst *iargs [3];
2981         int n;
2982         guint32 align = 0;
2983         MonoMethod *memcpy_method;
2984
2985         g_assert (klass);
2986         /*
2987          * This check breaks with spilled vars... need to handle it during verification anyway.
2988          * g_assert (klass && klass == src->klass && klass == dest->klass);
2989          */
2990
2991         if (native)
2992                 n = mono_class_native_size (klass, &align);
2993         else
2994                 n = mono_class_value_size (klass, &align);
2995
2996 #if HAVE_WRITE_BARRIERS
2997         /* if native is true there should be no references in the struct */
2998         if (write_barrier && klass->has_references && !native) {
2999                 iargs [0] = dest;
3000                 iargs [1] = src;
3001                 NEW_PCONST (cfg, iargs [2], klass);
3002
3003                 mono_emit_jit_icall (cfg, bblock, mono_value_copy, iargs, ip);
3004                 return;
3005         }
3006 #endif
3007
3008         /* FIXME: add write barrier handling */
3009         if ((cfg->opt & MONO_OPT_INTRINS) && !to_end && n <= sizeof (gpointer) * 5) {
3010                 MonoInst *inst;
3011                 if (dest->opcode == OP_LDADDR) {
3012                         /* Keep liveness info correct */
3013                         NEW_DUMMY_STORE (cfg, inst, dest->inst_i0->inst_c0);
3014                         MONO_ADD_INS (bblock, inst);
3015                 }
3016                 NEW_MEMCPY (cfg, inst, dest, src, n, align);
3017                 MONO_ADD_INS (bblock, inst);
3018                 return;
3019         }
3020         iargs [0] = dest;
3021         iargs [1] = src;
3022         NEW_ICONST (cfg, iargs [2], n);
3023
3024         memcpy_method = get_memcpy_method ();
3025         mono_emit_method_call_spilled_full (cfg, bblock, memcpy_method, memcpy_method->signature, iargs, ip, NULL, FALSE, to_end);
3026 }
3027
3028 static MonoMethod*
3029 get_memset_method (void)
3030 {
3031         static MonoMethod *memset_method = NULL;
3032         if (!memset_method) {
3033                 memset_method = mono_class_get_method_from_name (mono_defaults.string_class, "memset", 3);
3034                 if (!memset_method)
3035                         g_error ("Old corlib found. Install a new one");
3036         }
3037         return memset_method;
3038 }
3039
3040 static void
3041 handle_initobj (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *dest, const guchar *ip, MonoClass *klass, MonoInst **stack_start, MonoInst **sp)
3042 {
3043         MonoInst *iargs [3];
3044         MonoInst *ins, *zero_int32;
3045         int n;
3046         guint32 align;
3047         MonoMethod *memset_method;
3048
3049         NEW_ICONST (cfg, zero_int32, 0);
3050
3051         mono_class_init (klass);
3052         n = mono_class_value_size (klass, &align);
3053         MONO_INST_NEW (cfg, ins, 0);
3054         ins->cil_code = ip;
3055         ins->inst_left = dest;
3056         ins->inst_right = zero_int32;
3057         if (n == 1) {
3058                 ins->opcode = CEE_STIND_I1;
3059                 MONO_ADD_INS (bblock, ins);
3060         } else if ((n == 2) && (align >= 2)) {
3061                 ins->opcode = CEE_STIND_I2;
3062                 MONO_ADD_INS (bblock, ins);
3063         } else if ((n == 2) && (align >= 4)) {
3064                 ins->opcode = CEE_STIND_I4;
3065                 MONO_ADD_INS (bblock, ins);
3066         } else if (n <= sizeof (gpointer) * 5) {
3067                 NEW_MEMSET (cfg, ins, dest, 0, n, align);
3068                 MONO_ADD_INS (bblock, ins);
3069         } else {
3070                 memset_method = get_memset_method ();
3071                 handle_loaded_temps (cfg, bblock, stack_start, sp);
3072                 iargs [0] = dest;
3073                 NEW_ICONST (cfg, iargs [1], 0);
3074                 NEW_ICONST (cfg, iargs [2], n);
3075                 mono_emit_method_call_spilled (cfg, bblock, memset_method, memset_method->signature, iargs, ip, NULL);
3076         }
3077 }
3078
3079 static int
3080 handle_alloc (MonoCompile *cfg, MonoBasicBlock *bblock, MonoClass *klass, gboolean for_box, const guchar *ip)
3081 {
3082         MonoInst *iargs [2];
3083         void *alloc_ftn;
3084
3085         if (cfg->opt & MONO_OPT_SHARED) {
3086                 NEW_DOMAINCONST (cfg, iargs [0]);
3087                 NEW_CLASSCONST (cfg, iargs [1], klass);
3088
3089                 alloc_ftn = mono_object_new;
3090         } else if (cfg->compile_aot && bblock->out_of_line && klass->type_token && klass->image == mono_defaults.corlib) {
3091                 /* This happens often in argument checking code, eg. throw new FooException... */
3092                 /* Avoid relocations by calling a helper function specialized to mscorlib */
3093                 NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (klass->type_token));
3094                 return mono_emit_jit_icall (cfg, bblock, mono_helper_newobj_mscorlib, iargs, ip);
3095         } else {
3096                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
3097                 MonoMethod *managed_alloc = mono_gc_get_managed_allocator (vtable, for_box);
3098                 gboolean pass_lw;
3099
3100                 if (managed_alloc) {
3101                         NEW_VTABLECONST (cfg, iargs [0], vtable);
3102                         return mono_emit_method_call_spilled (cfg, bblock, managed_alloc, mono_method_signature (managed_alloc), iargs, ip, NULL);
3103                 }
3104                 alloc_ftn = mono_class_get_allocation_ftn (vtable, for_box, &pass_lw);
3105                 if (pass_lw) {
3106                         guint32 lw = vtable->klass->instance_size;
3107                         lw = ((lw + (sizeof (gpointer) - 1)) & ~(sizeof (gpointer) - 1)) / sizeof (gpointer);
3108                         NEW_ICONST (cfg, iargs [0], lw);
3109                         NEW_VTABLECONST (cfg, iargs [1], vtable);
3110                 }
3111                 else
3112                         NEW_VTABLECONST (cfg, iargs [0], vtable);
3113         }
3114
3115         return mono_emit_jit_icall (cfg, bblock, alloc_ftn, iargs, ip);
3116 }
3117
3118 static int
3119 handle_alloc_from_inst (MonoCompile *cfg, MonoBasicBlock *bblock, MonoClass *klass, MonoInst *data_inst,
3120                 gboolean for_box, const guchar *ip)
3121 {
3122         MonoInst *iargs [2];
3123         MonoMethod *managed_alloc = NULL;
3124         void *alloc_ftn;
3125         /*
3126           FIXME: we cannot get managed_alloc here because we can't get
3127           the class's vtable (because it's not a closed class)
3128
3129         MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
3130         MonoMethod *managed_alloc = mono_gc_get_managed_allocator (vtable, for_box);
3131         */
3132
3133         if (cfg->opt & MONO_OPT_SHARED) {
3134                 NEW_DOMAINCONST (cfg, iargs [0]);
3135                 iargs [1] = data_inst;
3136                 alloc_ftn = mono_object_new;
3137         } else {
3138                 g_assert (!cfg->compile_aot);
3139
3140                 if (managed_alloc) {
3141                         iargs [0] = data_inst;
3142                         return mono_emit_method_call_spilled (cfg, bblock, managed_alloc,
3143                                 mono_method_signature (managed_alloc), iargs, ip, NULL);
3144                 }
3145
3146                 iargs [0] = data_inst;
3147                 alloc_ftn = mono_object_new_specific;
3148         }
3149
3150         return mono_emit_jit_icall (cfg, bblock, alloc_ftn, iargs, ip);
3151 }
3152
3153 static MonoInst*
3154 handle_box_copy (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *val, const guchar *ip, MonoClass *klass, int temp)
3155 {
3156         MonoInst *dest, *vtoffset, *add, *vstore;
3157
3158         NEW_TEMPLOAD (cfg, dest, temp);
3159         NEW_ICONST (cfg, vtoffset, sizeof (MonoObject));
3160         MONO_INST_NEW (cfg, add, OP_PADD);
3161         add->inst_left = dest;
3162         add->inst_right = vtoffset;
3163         add->cil_code = ip;
3164         add->klass = klass;
3165         MONO_INST_NEW (cfg, vstore, CEE_STIND_I);
3166         vstore->opcode = mini_type_to_stind (cfg, &klass->byval_arg);
3167         vstore->cil_code = ip;
3168         vstore->inst_left = add;
3169         vstore->inst_right = val;
3170
3171 #ifdef MONO_ARCH_SOFT_FLOAT
3172         if (vstore->opcode == CEE_STIND_R4) {
3173                 handle_store_float (cfg, bblock, add, val, ip);
3174         } else
3175 #endif
3176         if (vstore->opcode == CEE_STOBJ) {
3177                 handle_stobj (cfg, bblock, add, val, ip, klass, FALSE, FALSE, TRUE);
3178         } else
3179                 MONO_ADD_INS (bblock, vstore);
3180
3181         NEW_TEMPLOAD (cfg, dest, temp);
3182         return dest;
3183 }
3184
3185 static MonoInst *
3186 handle_box (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *val, const guchar *ip, MonoClass *klass)
3187 {
3188         MonoInst *dest;
3189         int temp;
3190
3191         if (mono_class_is_nullable (klass)) {
3192                 MonoMethod* method = mono_class_get_method_from_name (klass, "Box", 1);
3193                 temp = mono_emit_method_call_spilled (cfg, bblock, method, mono_method_signature (method), &val, ip, NULL);
3194                 NEW_TEMPLOAD (cfg, dest, temp);
3195                 return dest;
3196         }
3197
3198         temp = handle_alloc (cfg, bblock, klass, TRUE, ip);
3199
3200         return handle_box_copy (cfg, bblock, val, ip, klass, temp);
3201 }
3202
3203 static MonoInst *
3204 handle_box_from_inst (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *val, const guchar *ip,
3205                 MonoClass *klass, MonoInst *data_inst)
3206 {
3207         int temp;
3208
3209         g_assert (!mono_class_is_nullable (klass));
3210
3211         temp = handle_alloc_from_inst (cfg, bblock, klass, data_inst, TRUE, ip);
3212
3213         return handle_box_copy (cfg, bblock, val, ip, klass, temp);
3214 }
3215
3216 static MonoInst*
3217 handle_delegate_ctor (MonoCompile *cfg, MonoBasicBlock *bblock, MonoClass *klass, MonoInst *target, MonoMethod *method, unsigned char *ip)
3218 {
3219         gpointer *trampoline;
3220         MonoInst *obj, *ins, *store, *offset_ins, *method_ins, *tramp_ins;
3221         int temp;
3222
3223         temp = handle_alloc (cfg, bblock, klass, FALSE, ip);
3224
3225         /* Inline the contents of mono_delegate_ctor */
3226
3227         /* Set target field */
3228         /* Optimize away setting of NULL target */
3229         if (!(target->opcode == OP_PCONST && target->inst_p0 == 0)) {
3230                 NEW_TEMPLOAD (cfg, obj, temp);
3231                 NEW_ICONST (cfg, offset_ins, G_STRUCT_OFFSET (MonoDelegate, target));
3232                 MONO_INST_NEW (cfg, ins, OP_PADD);
3233                 ins->inst_left = obj;
3234                 ins->inst_right = offset_ins;
3235
3236                 MONO_INST_NEW (cfg, store, CEE_STIND_REF);
3237                 store->inst_left = ins;
3238                 store->inst_right = target;
3239                 mono_bblock_add_inst (bblock, store);
3240         }
3241
3242         /* Set method field */
3243         NEW_TEMPLOAD (cfg, obj, temp);
3244         NEW_ICONST (cfg, offset_ins, G_STRUCT_OFFSET (MonoDelegate, method));
3245         MONO_INST_NEW (cfg, ins, OP_PADD);
3246         ins->inst_left = obj;
3247         ins->inst_right = offset_ins;
3248
3249         NEW_METHODCONST (cfg, method_ins, method);
3250
3251         MONO_INST_NEW (cfg, store, CEE_STIND_I);
3252         store->inst_left = ins;
3253         store->inst_right = method_ins;
3254         mono_bblock_add_inst (bblock, store);
3255
3256         /* Set invoke_impl field */
3257         NEW_TEMPLOAD (cfg, obj, temp);
3258         NEW_ICONST (cfg, offset_ins, G_STRUCT_OFFSET (MonoDelegate, invoke_impl));
3259         MONO_INST_NEW (cfg, ins, OP_PADD);
3260         ins->inst_left = obj;
3261         ins->inst_right = offset_ins;
3262
3263         trampoline = mono_create_delegate_trampoline (klass);
3264         NEW_AOTCONST (cfg, tramp_ins, MONO_PATCH_INFO_ABS, trampoline);
3265
3266         MONO_INST_NEW (cfg, store, CEE_STIND_I);
3267         store->inst_left = ins;
3268         store->inst_right = tramp_ins;
3269         mono_bblock_add_inst (bblock, store);
3270
3271         /* All the checks which are in mono_delegate_ctor () are done by the delegate trampoline */
3272
3273         NEW_TEMPLOAD (cfg, obj, temp);
3274
3275         return obj;
3276 }
3277
3278 static int
3279 handle_array_new (MonoCompile *cfg, MonoBasicBlock *bblock, int rank, MonoInst **sp, unsigned char *ip)
3280 {
3281         MonoMethodSignature *esig;
3282         char icall_name [256];
3283         char *name;
3284         MonoJitICallInfo *info;
3285
3286         /* Need to register the icall so it gets an icall wrapper */
3287         sprintf (icall_name, "ves_array_new_va_%d", rank);
3288
3289         mono_jit_lock ();
3290         info = mono_find_jit_icall_by_name (icall_name);
3291         if (info == NULL) {
3292                 esig = mono_get_array_new_va_signature (rank);
3293                 name = g_strdup (icall_name);
3294                 info = mono_register_jit_icall (mono_array_new_va, name, esig, FALSE);
3295
3296                 g_hash_table_insert (jit_icall_name_hash, name, name);
3297         }
3298         mono_jit_unlock ();
3299
3300         cfg->flags |= MONO_CFG_HAS_VARARGS;
3301
3302         /* FIXME: This uses info->sig, but it should use the signature of the wrapper */
3303         return mono_emit_native_call (cfg, bblock, mono_icall_get_wrapper (info), info->sig, sp, ip, TRUE, FALSE);
3304 }
3305
3306 static void
3307 mono_emit_load_got_addr (MonoCompile *cfg)
3308 {
3309         MonoInst *load, *store, *dummy_use;
3310         MonoInst *get_got;
3311
3312         if (!cfg->got_var || cfg->got_var_allocated)
3313                 return;
3314
3315         MONO_INST_NEW (cfg, get_got, OP_LOAD_GOTADDR);
3316         NEW_TEMPSTORE (cfg, store, cfg->got_var->inst_c0, get_got);
3317
3318         /* Add it to the start of the first bblock */
3319         MONO_INST_LIST_ADD (&store->node, &cfg->bb_entry->ins_list);
3320
3321         cfg->got_var_allocated = TRUE;
3322
3323         /* 
3324          * Add a dummy use to keep the got_var alive, since real uses might
3325          * only be generated in the decompose or instruction selection phases.
3326          * Add it to end_bblock, so the variable's lifetime covers the whole
3327          * method.
3328          */
3329         NEW_TEMPLOAD (cfg, load, cfg->got_var->inst_c0);
3330         NEW_DUMMY_USE (cfg, dummy_use, load);
3331         MONO_ADD_INS (cfg->bb_exit, dummy_use);
3332 }
3333
3334 #define CODE_IS_STLOC(ip) (((ip) [0] >= CEE_STLOC_0 && (ip) [0] <= CEE_STLOC_3) || ((ip) [0] == CEE_STLOC_S))
3335
3336 static gboolean
3337 mini_class_is_system_array (MonoClass *klass)
3338 {
3339         if (klass->parent == mono_defaults.array_class)
3340                 return TRUE;
3341         else
3342                 return FALSE;
3343 }
3344
3345 static gboolean
3346 mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method)
3347 {
3348         MonoMethodHeader *header = mono_method_get_header (method);
3349         MonoMethodSignature *signature = mono_method_signature (method);
3350         MonoVTable *vtable;
3351         int i;
3352
3353         if (cfg->generic_sharing_context)
3354                 return FALSE;
3355
3356         if (method->inline_failure)
3357                 return FALSE;
3358
3359 #ifdef MONO_ARCH_HAVE_LMF_OPS
3360         if (((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
3361                  (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) &&
3362             !MONO_TYPE_ISSTRUCT (signature->ret) && !mini_class_is_system_array (method->klass))
3363                 return TRUE;
3364 #endif
3365
3366         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
3367             (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
3368             (method->iflags & METHOD_IMPL_ATTRIBUTE_NOINLINING) ||
3369             (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) ||
3370             (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
3371             (method->klass->marshalbyref) ||
3372             !header || header->num_clauses ||
3373             /* fixme: why cant we inline valuetype returns? */
3374             MONO_TYPE_ISSTRUCT (signature->ret))
3375                 return FALSE;
3376
3377 #ifdef MONO_ARCH_SOFT_FLOAT
3378         /* this complicates things, fix later */
3379         if (signature->ret->type == MONO_TYPE_R4)
3380                 return FALSE;
3381 #endif
3382         /* its not worth to inline methods with valuetype arguments?? */
3383         for (i = 0; i < signature->param_count; i++) {
3384                 if (MONO_TYPE_ISSTRUCT (signature->params [i])) {
3385                         return FALSE;
3386                 }
3387 #ifdef MONO_ARCH_SOFT_FLOAT
3388                 /* this complicates things, fix later */
3389                 if (!signature->params [i]->byref && signature->params [i]->type == MONO_TYPE_R4)
3390                         return FALSE;
3391 #endif
3392         }
3393
3394         /* also consider num_locals? */
3395         /* Do the size check early to avoid creating vtables */
3396         if (getenv ("MONO_INLINELIMIT")) {
3397                 if (header->code_size >= atoi (getenv ("MONO_INLINELIMIT"))) {
3398                         return FALSE;
3399                 }
3400         } else if (header->code_size >= INLINE_LENGTH_LIMIT)
3401                 return FALSE;
3402
3403         /*
3404          * if we can initialize the class of the method right away, we do,
3405          * otherwise we don't allow inlining if the class needs initialization,
3406          * since it would mean inserting a call to mono_runtime_class_init()
3407          * inside the inlined code
3408          */
3409         if (!(cfg->opt & MONO_OPT_SHARED)) {
3410                 if (method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) {
3411                         if (cfg->run_cctors && method->klass->has_cctor) {
3412                                 if (!method->klass->runtime_info)
3413                                         /* No vtable created yet */
3414                                         return FALSE;
3415                                 vtable = mono_class_vtable (cfg->domain, method->klass);
3416                                 if (!vtable)
3417                                         return FALSE;
3418                                 /* This makes so that inline cannot trigger */
3419                                 /* .cctors: too many apps depend on them */
3420                                 /* running with a specific order... */
3421                                 if (! vtable->initialized)
3422                                         return FALSE;
3423                                 mono_runtime_class_init (vtable);
3424                         }
3425                 } else if (mono_class_needs_cctor_run (method->klass, NULL)) {
3426                         if (!method->klass->runtime_info)
3427                                 /* No vtable created yet */
3428                                 return FALSE;
3429                         vtable = mono_class_vtable (cfg->domain, method->klass);
3430                         if (!vtable)
3431                                 return FALSE;
3432                         if (!vtable->initialized)
3433                                 return FALSE;
3434                 }
3435         } else {
3436                 /* 
3437                  * If we're compiling for shared code
3438                  * the cctor will need to be run at aot method load time, for example,
3439                  * or at the end of the compilation of the inlining method.
3440                  */
3441                 if (mono_class_needs_cctor_run (method->klass, NULL) && !((method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT)))
3442                         return FALSE;
3443         }
3444         //if (!MONO_TYPE_IS_VOID (signature->ret)) return FALSE;
3445
3446         /*
3447          * CAS - do not inline methods with declarative security
3448          * Note: this has to be before any possible return TRUE;
3449          */
3450         if (mono_method_has_declsec (method))
3451                 return FALSE;
3452
3453         return TRUE;
3454 }
3455
3456 static gboolean
3457 mini_field_access_needs_cctor_run (MonoCompile *cfg, MonoMethod *method, MonoVTable *vtable)
3458 {
3459         if (vtable->initialized && !cfg->compile_aot)
3460                 return FALSE;
3461
3462         if (vtable->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT)
3463                 return FALSE;
3464
3465         if (!mono_class_needs_cctor_run (vtable->klass, method))
3466                 return FALSE;
3467
3468         if (! (method->flags & METHOD_ATTRIBUTE_STATIC) && (vtable->klass == method->klass))
3469                 /* The initialization is already done before the method is called */
3470                 return FALSE;
3471
3472         return TRUE;
3473 }
3474
3475 static MonoInst*
3476 mini_get_ldelema_ins (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *cmethod, MonoInst **sp, unsigned char *ip, gboolean is_set)
3477 {
3478         int temp, rank;
3479         MonoInst *addr;
3480         MonoMethod *addr_method;
3481         int element_size;
3482
3483         rank = mono_method_signature (cmethod)->param_count - (is_set? 1: 0);
3484
3485         if (rank == 1) {
3486                 MONO_INST_NEW (cfg, addr, CEE_LDELEMA);
3487                 addr->inst_left = sp [0];
3488                 addr->inst_right = sp [1];
3489                 addr->type = STACK_MP;
3490                 addr->klass = cmethod->klass->element_class;
3491                 return addr;
3492         }
3493
3494         if (rank == 2 && (cfg->opt & MONO_OPT_INTRINS)) {
3495 #if defined(MONO_ARCH_EMULATE_MUL_DIV) && !defined(MONO_ARCH_NO_EMULATE_MUL)
3496                 /* OP_LDELEMA2D depends on OP_LMUL */
3497 #else
3498                 MonoInst *indexes;
3499                 NEW_GROUP (cfg, indexes, sp [1], sp [2]);
3500                 MONO_INST_NEW (cfg, addr, OP_LDELEMA2D);
3501                 addr->inst_left = sp [0];
3502                 addr->inst_right = indexes;
3503                 addr->type = STACK_MP;
3504                 addr->klass = cmethod->klass->element_class;
3505                 return addr;
3506 #endif
3507         }
3508
3509         element_size = mono_class_array_element_size (cmethod->klass->element_class);
3510         addr_method = mono_marshal_get_array_address (rank, element_size);
3511         temp = mono_emit_method_call_spilled (cfg, bblock, addr_method, addr_method->signature, sp, ip, NULL);
3512         NEW_TEMPLOAD (cfg, addr, temp);
3513         return addr;
3514
3515 }
3516
3517 static MonoJitICallInfo **emul_opcode_map = NULL;
3518
3519 MonoJitICallInfo *
3520 mono_find_jit_opcode_emulation (int opcode)
3521 {
3522         g_assert (opcode >= 0 && opcode <= OP_LAST);
3523         if  (emul_opcode_map)
3524                 return emul_opcode_map [opcode];
3525         else
3526                 return NULL;
3527 }
3528
3529 static int
3530 is_unsigned_regsize_type (MonoType *type)
3531 {
3532         switch (type->type) {
3533         case MONO_TYPE_U1:
3534         case MONO_TYPE_U2:
3535         case MONO_TYPE_U4:
3536 #if SIZEOF_VOID_P == 8
3537         /*case MONO_TYPE_U8: this requires different opcodes in inssel.brg */
3538 #endif
3539                 return TRUE;
3540         default:
3541                 return FALSE;
3542         }
3543 }
3544
3545 static MonoInst*
3546 mini_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
3547 {
3548         MonoInst *ins = NULL;
3549         
3550         static MonoClass *runtime_helpers_class = NULL;
3551         if (! runtime_helpers_class)
3552                 runtime_helpers_class = mono_class_from_name (mono_defaults.corlib,
3553                         "System.Runtime.CompilerServices", "RuntimeHelpers");
3554
3555         if (cmethod->klass == mono_defaults.string_class) {
3556                 if (strcmp (cmethod->name, "get_Chars") == 0) {
3557                         MONO_INST_NEW (cfg, ins, OP_GETCHR);
3558                         ins->inst_i0 = args [0];
3559                         ins->inst_i1 = args [1];
3560                         return ins;
3561                 } else if (strcmp (cmethod->name, "get_Length") == 0) {
3562                         MONO_INST_NEW (cfg, ins, OP_STRLEN);
3563                         ins->inst_i0 = args [0];
3564                         return ins;
3565                 } else if (strcmp (cmethod->name, "InternalSetChar") == 0) {
3566                         MonoInst *get_addr;
3567                         MONO_INST_NEW (cfg, get_addr, OP_STR_CHAR_ADDR);
3568                         get_addr->inst_i0 = args [0];
3569                         get_addr->inst_i1 = args [1];
3570                         MONO_INST_NEW (cfg, ins, CEE_STIND_I2);
3571                         ins->inst_i0 = get_addr;
3572                         ins->inst_i1 = args [2];
3573                         return ins;
3574                 } else 
3575                         return NULL;
3576         } else if (cmethod->klass == mono_defaults.object_class) {
3577                 if (strcmp (cmethod->name, "GetType") == 0) {
3578                         MONO_INST_NEW (cfg, ins, OP_GETTYPE);
3579                         ins->inst_i0 = args [0];
3580                         return ins;
3581                 /* The OP_GETHASHCODE rule depends on OP_MUL */
3582 #if !defined(MONO_ARCH_EMULATE_MUL_DIV) && !defined(HAVE_MOVING_COLLECTOR)
3583                 } else if (strcmp (cmethod->name, "InternalGetHashCode") == 0) {
3584                         MONO_INST_NEW (cfg, ins, OP_GETHASHCODE);
3585                         ins->inst_i0 = args [0];
3586                         return ins;
3587 #endif
3588                 } else if (strcmp (cmethod->name, ".ctor") == 0) {
3589                         MONO_INST_NEW (cfg, ins, OP_NOP);
3590                         return ins;
3591                 } else
3592                         return NULL;
3593         } else if (cmethod->klass == mono_defaults.array_class) {
3594                 if (cmethod->name [0] != 'g')
3595                         return NULL;
3596
3597                 if (strcmp (cmethod->name, "get_Rank") == 0) {
3598                         MONO_INST_NEW (cfg, ins, OP_ARRAY_RANK);
3599                         ins->inst_i0 = args [0];
3600                         return ins;
3601                 } else if (strcmp (cmethod->name, "get_Length") == 0) {
3602                         MONO_INST_NEW (cfg, ins, CEE_LDLEN);
3603                         ins->inst_i0 = args [0];
3604                         return ins;
3605                 } else
3606                         return NULL;
3607         } else if (cmethod->klass == runtime_helpers_class) {
3608                 if (strcmp (cmethod->name, "get_OffsetToStringData") == 0) {
3609                         NEW_ICONST (cfg, ins, G_STRUCT_OFFSET (MonoString, chars));
3610                         return ins;
3611                 } else
3612                         return NULL;
3613         } else if (cmethod->klass == mono_defaults.thread_class) {
3614                 if (strcmp (cmethod->name, "get_CurrentThread") == 0 && (ins = mono_arch_get_thread_intrinsic (cfg)))
3615                         return ins;
3616                 if (strcmp (cmethod->name, "MemoryBarrier") == 0) {
3617                         MONO_INST_NEW (cfg, ins, OP_MEMORY_BARRIER);
3618                         return ins;
3619                 }
3620         } else if (mini_class_is_system_array (cmethod->klass) &&
3621                         strcmp (cmethod->name, "GetGenericValueImpl") == 0) {
3622                 MonoInst *sp [2];
3623                 MonoInst *ldelem, *store, *load;
3624                 MonoClass *eklass = mono_class_from_mono_type (fsig->params [1]);
3625                 int n;
3626                 n = mini_type_to_stind (cfg, &eklass->byval_arg);
3627                 if (n == CEE_STOBJ)
3628                         return NULL;
3629                 sp [0] = args [0];
3630                 sp [1] = args [1];
3631                 NEW_LDELEMA (cfg, ldelem, sp, eklass);
3632                 ldelem->flags |= MONO_INST_NORANGECHECK;
3633                 MONO_INST_NEW (cfg, store, n);
3634                 MONO_INST_NEW (cfg, load, mini_type_to_ldind (cfg, &eklass->byval_arg));
3635                 type_to_eval_stack_type (cfg, &eklass->byval_arg, load);
3636                 load->inst_left = ldelem;
3637                 store->inst_left = args [2];
3638                 store->inst_right = load;
3639                 return store;
3640         } else if (cmethod->klass == mono_defaults.math_class) {
3641                 if (strcmp (cmethod->name, "Min") == 0) {
3642                         if (is_unsigned_regsize_type (fsig->params [0])) {
3643                                 MONO_INST_NEW (cfg, ins, OP_MIN);
3644                                 ins->inst_i0 = args [0];
3645                                 ins->inst_i1 = args [1];
3646                                 return ins;
3647                         }
3648                 } else if (strcmp (cmethod->name, "Max") == 0) {
3649                         if (is_unsigned_regsize_type (fsig->params [0])) {
3650                                 MONO_INST_NEW (cfg, ins, OP_MAX);
3651                                 ins->inst_i0 = args [0];
3652                                 ins->inst_i1 = args [1];
3653                                 return ins;
3654                         }
3655                 }
3656         } else if (cmethod->klass->image == mono_defaults.corlib &&
3657                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
3658                            (strcmp (cmethod->klass->name, "Interlocked") == 0)) {
3659                 ins = NULL;
3660
3661 #if SIZEOF_VOID_P == 8
3662                 if (strcmp (cmethod->name, "Read") == 0 && (fsig->params [0]->type == MONO_TYPE_I8)) {
3663                         /* 64 bit reads are already atomic */
3664                         MONO_INST_NEW (cfg, ins, CEE_LDIND_I8);
3665                         ins->inst_i0 = args [0];
3666                 }
3667 #endif
3668
3669 #ifdef MONO_ARCH_HAVE_ATOMIC_ADD
3670                 if (strcmp (cmethod->name, "Increment") == 0) {
3671                         MonoInst *ins_iconst;
3672                         guint32 opcode;
3673
3674                         if (fsig->params [0]->type == MONO_TYPE_I4)
3675                                 opcode = OP_ATOMIC_ADD_NEW_I4;
3676                         else if (fsig->params [0]->type == MONO_TYPE_I8)
3677                                 opcode = OP_ATOMIC_ADD_NEW_I8;
3678                         else
3679                                 g_assert_not_reached ();
3680
3681 #if SIZEOF_VOID_P == 4
3682                         if (opcode == OP_ATOMIC_ADD_NEW_I8)
3683                                 return NULL;
3684 #endif
3685
3686                         MONO_INST_NEW (cfg, ins, opcode);
3687                         MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
3688                         ins_iconst->inst_c0 = 1;
3689
3690                         ins->inst_i0 = args [0];
3691                         ins->inst_i1 = ins_iconst;
3692                 } else if (strcmp (cmethod->name, "Decrement") == 0) {
3693                         MonoInst *ins_iconst;
3694                         guint32 opcode;
3695
3696                         if (fsig->params [0]->type == MONO_TYPE_I4)
3697                                 opcode = OP_ATOMIC_ADD_NEW_I4;
3698                         else if (fsig->params [0]->type == MONO_TYPE_I8)
3699                                 opcode = OP_ATOMIC_ADD_NEW_I8;
3700                         else
3701                                 g_assert_not_reached ();
3702
3703 #if SIZEOF_VOID_P == 4
3704                         if (opcode == OP_ATOMIC_ADD_NEW_I8)
3705                                 return NULL;
3706 #endif
3707
3708                         MONO_INST_NEW (cfg, ins, opcode);
3709                         MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
3710                         ins_iconst->inst_c0 = -1;
3711
3712                         ins->inst_i0 = args [0];
3713                         ins->inst_i1 = ins_iconst;
3714                 } else if (strcmp (cmethod->name, "Add") == 0) {
3715                         guint32 opcode;
3716
3717                         if (fsig->params [0]->type == MONO_TYPE_I4)
3718                                 opcode = OP_ATOMIC_ADD_NEW_I4;
3719                         else if (fsig->params [0]->type == MONO_TYPE_I8)
3720                                 opcode = OP_ATOMIC_ADD_NEW_I8;
3721                         else
3722                                 g_assert_not_reached ();
3723
3724 #if SIZEOF_VOID_P == 4
3725                         if (opcode == OP_ATOMIC_ADD_NEW_I8)
3726                                 return NULL;
3727 #endif
3728                         
3729                         MONO_INST_NEW (cfg, ins, opcode);
3730
3731                         ins->inst_i0 = args [0];
3732                         ins->inst_i1 = args [1];
3733                 }
3734 #endif /* MONO_ARCH_HAVE_ATOMIC_ADD */
3735
3736 #ifdef MONO_ARCH_HAVE_ATOMIC_EXCHANGE
3737                 if (strcmp (cmethod->name, "Exchange") == 0) {
3738                         guint32 opcode;
3739
3740                         if (fsig->params [0]->type == MONO_TYPE_I4)
3741                                 opcode = OP_ATOMIC_EXCHANGE_I4;
3742 #if SIZEOF_VOID_P == 8
3743                         else if ((fsig->params [0]->type == MONO_TYPE_I8) ||
3744                                          (fsig->params [0]->type == MONO_TYPE_I) ||
3745                                          (fsig->params [0]->type == MONO_TYPE_OBJECT))
3746                                 opcode = OP_ATOMIC_EXCHANGE_I8;
3747 #else
3748                         else if ((fsig->params [0]->type == MONO_TYPE_I) ||
3749                                          (fsig->params [0]->type == MONO_TYPE_OBJECT))
3750                                 opcode = OP_ATOMIC_EXCHANGE_I4;
3751 #endif
3752                         else
3753                                 return NULL;
3754
3755 #if SIZEOF_VOID_P == 4
3756                         if (opcode == OP_ATOMIC_EXCHANGE_I8)
3757                                 return NULL;
3758 #endif
3759
3760                         MONO_INST_NEW (cfg, ins, opcode);
3761
3762                         ins->inst_i0 = args [0];
3763                         ins->inst_i1 = args [1];
3764                 }
3765 #endif /* MONO_ARCH_HAVE_ATOMIC_EXCHANGE */
3766
3767 #ifdef MONO_ARCH_HAVE_ATOMIC_CAS_IMM
3768                 /* 
3769                  * Can't implement CompareExchange methods this way since they have
3770                  * three arguments. We can implement one of the common cases, where the new
3771                  * value is a constant.
3772                  */
3773                 if ((strcmp (cmethod->name, "CompareExchange") == 0)) {
3774                         if (fsig->params [1]->type == MONO_TYPE_I4 && args [2]->opcode == OP_ICONST) {
3775                                 MONO_INST_NEW (cfg, ins, OP_ATOMIC_CAS_IMM_I4);
3776                                 ins->inst_i0 = args [0];
3777                                 ins->inst_i1 = args [1];
3778                                 ins->backend.data = GINT_TO_POINTER (args [2]->inst_c0);
3779                         }
3780                         /* The I8 case is hard to detect, since the arg might be a conv.i8 (iconst) tree */
3781                 }
3782 #endif /* MONO_ARCH_HAVE_ATOMIC_CAS_IMM */
3783
3784                 if (ins)
3785                         return ins;
3786         } else if (cmethod->klass->image == mono_defaults.corlib) {
3787                 if (cmethod->name [0] == 'B' && strcmp (cmethod->name, "Break") == 0
3788                                 && strcmp (cmethod->klass->name, "Debugger") == 0) {
3789                         MONO_INST_NEW (cfg, ins, OP_BREAK);
3790                         return ins;
3791                 }
3792                 if (cmethod->name [0] == 'g' && strcmp (cmethod->name, "get_IsRunningOnWindows") == 0
3793                                 && strcmp (cmethod->klass->name, "Environment") == 0) {
3794 #ifdef PLATFORM_WIN32
3795                         NEW_ICONST (cfg, ins, 1);
3796 #else
3797                         NEW_ICONST (cfg, ins, 0);
3798 #endif
3799                         return ins;
3800                 }
3801         }
3802
3803         return mono_arch_get_inst_for_method (cfg, cmethod, fsig, args);
3804 }
3805
3806 static void
3807 mono_save_args (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethodSignature *sig, MonoInst **sp, MonoInst **args)
3808 {
3809         MonoInst *store, *temp;
3810         int i;
3811
3812         g_assert (!MONO_TYPE_ISSTRUCT (sig->ret));
3813
3814         if (!sig->hasthis && sig->param_count == 0) 
3815                 return;
3816
3817         if (sig->hasthis) {
3818                 if (sp [0]->opcode == OP_ICONST) {
3819                         *args++ = sp [0];
3820                 } else {
3821                         temp = mono_compile_create_var (cfg, type_from_stack_type (*sp), OP_LOCAL);
3822                         *args++ = temp;
3823                         NEW_TEMPSTORE (cfg, store, temp->inst_c0, *sp);
3824                         /* FIXME: handle CEE_STIND_R4 */
3825                         store->cil_code = sp [0]->cil_code;
3826                         MONO_ADD_INS (bblock, store);
3827                 }
3828                 sp++;
3829         }
3830
3831         for (i = 0; i < sig->param_count; ++i) {
3832                 if (sp [0]->opcode == OP_ICONST) {
3833                         *args++ = sp [0];
3834                 } else {
3835                         temp = mono_compile_create_var (cfg, sig->params [i], OP_LOCAL);
3836                         *args++ = temp;
3837                         NEW_TEMPSTORE (cfg, store, temp->inst_c0, *sp);
3838                         store->cil_code = sp [0]->cil_code;
3839                         /* FIXME: handle CEE_STIND_R4 */
3840                         if (store->opcode == CEE_STOBJ) {
3841                                 NEW_TEMPLOADA (cfg, store, temp->inst_c0);
3842                                 handle_stobj (cfg, bblock, store, *sp, sp [0]->cil_code, temp->klass, FALSE, FALSE, FALSE);
3843 #ifdef MONO_ARCH_SOFT_FLOAT
3844                         } else if (store->opcode == CEE_STIND_R4) {
3845                                 NEW_TEMPLOADA (cfg, store, temp->inst_c0);
3846                                 handle_store_float (cfg, bblock, store, *sp, sp [0]->cil_code);
3847 #endif
3848                         } else {
3849                                 MONO_ADD_INS (bblock, store);
3850                         } 
3851                 }
3852                 sp++;
3853         }
3854 }
3855 #define MONO_INLINE_CALLED_LIMITED_METHODS 0
3856 #define MONO_INLINE_CALLER_LIMITED_METHODS 0
3857
3858 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
3859 static char*
3860 mono_inline_called_method_name_limit = NULL;
3861 static gboolean check_inline_called_method_name_limit (MonoMethod *called_method) {
3862         char *called_method_name = mono_method_full_name (called_method, TRUE);
3863         int strncmp_result;
3864         
3865         if (mono_inline_called_method_name_limit == NULL) {
3866                 char *limit_string = getenv ("MONO_INLINE_CALLED_METHOD_NAME_LIMIT");
3867                 if (limit_string != NULL) {
3868                         mono_inline_called_method_name_limit = limit_string;
3869                 } else {
3870                         mono_inline_called_method_name_limit = (char *) "";
3871                 }
3872         }
3873         
3874         strncmp_result = strncmp (called_method_name, mono_inline_called_method_name_limit, strlen (mono_inline_called_method_name_limit));
3875         g_free (called_method_name);
3876         
3877         //return (strncmp_result <= 0);
3878         return (strncmp_result == 0);
3879 }
3880 #endif
3881
3882 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
3883 static char*
3884 mono_inline_caller_method_name_limit = NULL;
3885 static gboolean check_inline_caller_method_name_limit (MonoMethod *caller_method) {
3886         char *caller_method_name = mono_method_full_name (caller_method, TRUE);
3887         int strncmp_result;
3888         
3889         if (mono_inline_caller_method_name_limit == NULL) {
3890                 char *limit_string = getenv ("MONO_INLINE_CALLER_METHOD_NAME_LIMIT");
3891                 if (limit_string != NULL) {
3892                         mono_inline_caller_method_name_limit = limit_string;
3893                 } else {
3894                         mono_inline_caller_method_name_limit = (char *) "";
3895                 }
3896         }
3897         
3898         strncmp_result = strncmp (caller_method_name, mono_inline_caller_method_name_limit, strlen (mono_inline_caller_method_name_limit));
3899         g_free (caller_method_name);
3900         
3901         //return (strncmp_result <= 0);
3902         return (strncmp_result == 0);
3903 }
3904 #endif
3905
3906 static int
3907 inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoBasicBlock *bblock, MonoInst **sp,
3908                 guchar *ip, guint real_offset, GList *dont_inline, MonoBasicBlock **last_b, gboolean inline_allways)
3909 {
3910         MonoInst *ins, *rvar = NULL;
3911         MonoMethodHeader *cheader;
3912         MonoBasicBlock *ebblock, *sbblock;
3913         int i, costs, new_locals_offset;
3914         MonoMethod *prev_inlined_method;
3915         MonoBasicBlock **prev_cil_offset_to_bb;
3916         unsigned char* prev_cil_start;
3917         guint32 prev_cil_offset_to_bb_len;
3918
3919         g_assert (cfg->exception_type == MONO_EXCEPTION_NONE);
3920
3921 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
3922         if ((! inline_allways) && ! check_inline_called_method_name_limit (cmethod))
3923                 return 0;
3924 #endif
3925 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
3926         if ((! inline_allways) && ! check_inline_caller_method_name_limit (cfg->method))
3927                 return 0;
3928 #endif
3929
3930         if (bblock->out_of_line && !inline_allways)
3931                 return 0;
3932
3933         if (cfg->verbose_level > 2)
3934                 g_print ("INLINE START %p %s -> %s\n", cmethod,  mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
3935
3936         if (!cmethod->inline_info) {
3937                 mono_jit_stats.inlineable_methods++;
3938                 cmethod->inline_info = 1;
3939         }
3940         /* allocate space to store the return value */
3941         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
3942                 rvar =  mono_compile_create_var (cfg, fsig->ret, OP_LOCAL);
3943         }
3944
3945         /* allocate local variables */
3946         cheader = mono_method_get_header (cmethod);
3947         new_locals_offset = cfg->num_varinfo;
3948         for (i = 0; i < cheader->num_locals; ++i)
3949                 mono_compile_create_var (cfg, cheader->locals [i], OP_LOCAL);
3950
3951         /* allocate starte and end blocks */
3952         NEW_BBLOCK (cfg, sbblock);
3953         sbblock->block_num = cfg->num_bblocks++;
3954         sbblock->real_offset = real_offset;
3955
3956         NEW_BBLOCK (cfg, ebblock);
3957         ebblock->block_num = cfg->num_bblocks++;
3958         ebblock->real_offset = real_offset;
3959
3960         prev_inlined_method = cfg->inlined_method;
3961         cfg->inlined_method = cmethod;
3962         prev_cil_offset_to_bb = cfg->cil_offset_to_bb;
3963         prev_cil_offset_to_bb_len = cfg->cil_offset_to_bb_len;
3964         prev_cil_start = cfg->cil_start;
3965
3966         costs = mono_method_to_ir (cfg, cmethod, sbblock, ebblock, new_locals_offset, rvar, dont_inline, sp, real_offset, *ip == CEE_CALLVIRT);
3967
3968         cfg->inlined_method = prev_inlined_method;
3969         cfg->cil_offset_to_bb = prev_cil_offset_to_bb;
3970         cfg->cil_offset_to_bb_len = prev_cil_offset_to_bb_len;
3971         cfg->cil_start = prev_cil_start;
3972
3973         if ((costs >= 0 && costs < 60) || inline_allways) {
3974                 if (cfg->verbose_level > 2)
3975                         g_print ("INLINE END %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
3976                 
3977                 mono_jit_stats.inlined_methods++;
3978
3979                 /* always add some code to avoid block split failures */
3980                 MONO_INST_NEW (cfg, ins, OP_NOP);
3981                 MONO_ADD_INS (bblock, ins);
3982                 ins->cil_code = ip;
3983
3984                 bblock->next_bb = sbblock;
3985                 link_bblock (cfg, bblock, sbblock);
3986
3987                 if (rvar) {
3988                         NEW_TEMPLOAD (cfg, ins, rvar->inst_c0);
3989 #ifdef MONO_ARCH_SOFT_FLOAT
3990                         if (ins->opcode == CEE_LDIND_R4) {
3991                                 int temp;
3992                                 NEW_TEMPLOADA (cfg, ins, rvar->inst_c0);
3993                                 temp = handle_load_float (cfg, bblock, ins, ip);
3994                                 NEW_TEMPLOAD (cfg, ins, temp);
3995                         }
3996 #endif
3997                         *sp++ = ins;
3998                 }
3999                 *last_b = ebblock;
4000                 return costs + 1;
4001         } else {
4002                 if (cfg->verbose_level > 2)
4003                         g_print ("INLINE ABORTED %s\n", mono_method_full_name (cmethod, TRUE));
4004                 cfg->exception_type = MONO_EXCEPTION_NONE;
4005                 mono_loader_clear_error ();
4006                 cmethod->inline_failure = TRUE;
4007         }
4008         return 0;
4009 }
4010
4011 /*
4012  * Some of these comments may well be out-of-date.
4013  * Design decisions: we do a single pass over the IL code (and we do bblock 
4014  * splitting/merging in the few cases when it's required: a back jump to an IL
4015  * address that was not already seen as bblock starting point).
4016  * Code is validated as we go (full verification is still better left to metadata/verify.c).
4017  * Complex operations are decomposed in simpler ones right away. We need to let the 
4018  * arch-specific code peek and poke inside this process somehow (except when the 
4019  * optimizations can take advantage of the full semantic info of coarse opcodes).
4020  * All the opcodes of the form opcode.s are 'normalized' to opcode.
4021  * MonoInst->opcode initially is the IL opcode or some simplification of that 
4022  * (OP_LOAD, OP_STORE). The arch-specific code may rearrange it to an arch-specific 
4023  * opcode with value bigger than OP_LAST.
4024  * At this point the IR can be handed over to an interpreter, a dumb code generator
4025  * or to the optimizing code generator that will translate it to SSA form.
4026  *
4027  * Profiling directed optimizations.
4028  * We may compile by default with few or no optimizations and instrument the code
4029  * or the user may indicate what methods to optimize the most either in a config file
4030  * or through repeated runs where the compiler applies offline the optimizations to 
4031  * each method and then decides if it was worth it.
4032  *
4033  */
4034
4035 #define CHECK_TYPE(ins) if (!(ins)->type) UNVERIFIED
4036 #define CHECK_STACK(num) if ((sp - stack_start) < (num)) UNVERIFIED
4037 #define CHECK_STACK_OVF(num) if (((sp - stack_start) + (num)) > header->max_stack) UNVERIFIED
4038 #define CHECK_ARG(num) if ((unsigned)(num) >= (unsigned)num_args) UNVERIFIED
4039 #define CHECK_LOCAL(num) if ((unsigned)(num) >= (unsigned)header->num_locals) UNVERIFIED
4040 #define CHECK_OPSIZE(size) if (ip + size > end) UNVERIFIED
4041 #define CHECK_UNVERIFIABLE(cfg) if (cfg->unverifiable) UNVERIFIED
4042 #define CHECK_TYPELOAD(klass) if (!(klass) || (klass)->exception_type) {cfg->exception_ptr = klass; goto load_error;}
4043
4044 /* offset from br.s -> br like opcodes */
4045 #define BIG_BRANCH_OFFSET 13
4046
4047 static inline gboolean
4048 ip_in_bb (MonoCompile *cfg, MonoBasicBlock *bb, const guint8* ip)
4049 {
4050         MonoBasicBlock *b = cfg->cil_offset_to_bb [ip - cfg->cil_start];
4051         
4052         return b == NULL || b == bb;
4053 }
4054
4055 static int
4056 get_basic_blocks (MonoCompile *cfg, MonoMethodHeader* header, guint real_offset, unsigned char *start, unsigned char *end, unsigned char **pos)
4057 {
4058         unsigned char *ip = start;
4059         unsigned char *target;
4060         int i;
4061         guint cli_addr;
4062         MonoBasicBlock *bblock;
4063         const MonoOpcode *opcode;
4064
4065         while (ip < end) {
4066                 cli_addr = ip - start;
4067                 i = mono_opcode_value ((const guint8 **)&ip, end);
4068                 if (i < 0)
4069                         UNVERIFIED;
4070                 opcode = &mono_opcodes [i];
4071                 switch (opcode->argument) {
4072                 case MonoInlineNone:
4073                         ip++; 
4074                         break;
4075                 case MonoInlineString:
4076                 case MonoInlineType:
4077                 case MonoInlineField:
4078                 case MonoInlineMethod:
4079                 case MonoInlineTok:
4080                 case MonoInlineSig:
4081                 case MonoShortInlineR:
4082                 case MonoInlineI:
4083                         ip += 5;
4084                         break;
4085                 case MonoInlineVar:
4086                         ip += 3;
4087                         break;
4088                 case MonoShortInlineVar:
4089                 case MonoShortInlineI:
4090                         ip += 2;
4091                         break;
4092                 case MonoShortInlineBrTarget:
4093                         target = start + cli_addr + 2 + (signed char)ip [1];
4094                         GET_BBLOCK (cfg, bblock, target);
4095                         ip += 2;
4096                         if (ip < end)
4097                                 GET_BBLOCK (cfg, bblock, ip);
4098                         break;
4099                 case MonoInlineBrTarget:
4100                         target = start + cli_addr + 5 + (gint32)read32 (ip + 1);
4101                         GET_BBLOCK (cfg, bblock, target);
4102                         ip += 5;
4103                         if (ip < end)
4104                                 GET_BBLOCK (cfg, bblock, ip);
4105                         break;
4106                 case MonoInlineSwitch: {
4107                         guint32 n = read32 (ip + 1);
4108                         guint32 j;
4109                         ip += 5;
4110                         cli_addr += 5 + 4 * n;
4111                         target = start + cli_addr;
4112                         GET_BBLOCK (cfg, bblock, target);
4113                         
4114                         for (j = 0; j < n; ++j) {
4115                                 target = start + cli_addr + (gint32)read32 (ip);
4116                                 GET_BBLOCK (cfg, bblock, target);
4117                                 ip += 4;
4118                         }
4119                         break;
4120                 }
4121                 case MonoInlineR:
4122                 case MonoInlineI8:
4123                         ip += 9;
4124                         break;
4125                 default:
4126                         g_assert_not_reached ();
4127                 }
4128
4129                 if (i == CEE_THROW) {
4130                         unsigned char *bb_start = ip - 1;
4131                         
4132                         /* Find the start of the bblock containing the throw */
4133                         bblock = NULL;
4134                         while ((bb_start >= start) && !bblock) {
4135                                 bblock = cfg->cil_offset_to_bb [(bb_start) - start];
4136                                 bb_start --;
4137                         }
4138                         if (bblock)
4139                                 bblock->out_of_line = 1;
4140                 }
4141         }
4142         return 0;
4143 unverified:
4144         *pos = ip;
4145         return 1;
4146 }
4147
4148 static MonoInst*
4149 emit_tree (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *ins, const guint8* ip_next)
4150 {
4151         MonoInst *store, *temp, *load;
4152         
4153         if (ip_in_bb (cfg, bblock, ip_next) &&
4154                 (CODE_IS_STLOC (ip_next) || *ip_next == CEE_RET))
4155                         return ins;
4156         
4157         temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
4158         temp->flags |= MONO_INST_IS_TEMP;
4159         NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
4160         /* FIXME: handle CEE_STIND_R4 */
4161         store->cil_code = ins->cil_code;
4162         MONO_ADD_INS (bblock, store);
4163         NEW_TEMPLOAD (cfg, load, temp->inst_c0);
4164         load->cil_code = ins->cil_code;
4165         return load;
4166 }
4167
4168 static inline MonoMethod *
4169 mini_get_method_allow_open (MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
4170 {
4171         MonoMethod *method;
4172
4173         if (m->wrapper_type != MONO_WRAPPER_NONE)
4174                 return mono_method_get_wrapper_data (m, token);
4175
4176         method = mono_get_method_full (m->klass->image, token, klass, context);
4177
4178         return method;
4179 }
4180
4181 static inline MonoMethod *
4182 mini_get_method (MonoCompile *cfg, MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
4183 {
4184         MonoMethod *method = mini_get_method_allow_open (m, token, klass, context);
4185
4186         if (method && cfg && !cfg->generic_sharing_context && mono_class_is_open_constructed_type (&method->klass->byval_arg))
4187                 return NULL;
4188
4189         return method;
4190 }
4191
4192 static inline MonoClass*
4193 mini_get_class (MonoMethod *method, guint32 token, MonoGenericContext *context)
4194 {
4195         MonoClass *klass;
4196
4197         if (method->wrapper_type != MONO_WRAPPER_NONE)
4198                 klass = mono_method_get_wrapper_data (method, token);
4199         else
4200                 klass = mono_class_get_full (method->klass->image, token, context);
4201         if (klass)
4202                 mono_class_init (klass);
4203         return klass;
4204 }
4205
4206 /*
4207  * Returns TRUE if the JIT should abort inlining because "callee"
4208  * is influenced by security attributes.
4209  */
4210 static
4211 gboolean check_linkdemand (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee, MonoBasicBlock *bblock, unsigned char *ip)
4212 {
4213         guint32 result;
4214         
4215         if ((cfg->method != caller) && mono_method_has_declsec (callee)) {
4216                 return TRUE;
4217         }
4218         
4219         result = mono_declsec_linkdemand (cfg->domain, caller, callee);
4220         if (result == MONO_JIT_SECURITY_OK)
4221                 return FALSE;
4222
4223         if (result == MONO_JIT_LINKDEMAND_ECMA) {
4224                 /* Generate code to throw a SecurityException before the actual call/link */
4225                 MonoSecurityManager *secman = mono_security_manager_get_methods ();
4226                 MonoInst *args [2];
4227
4228                 NEW_ICONST (cfg, args [0], 4);
4229                 NEW_METHODCONST (cfg, args [1], caller);
4230                 mono_emit_method_call_spilled (cfg, bblock, secman->linkdemandsecurityexception, mono_method_signature (secman->linkdemandsecurityexception), args, ip, NULL);
4231         } else if (cfg->exception_type == MONO_EXCEPTION_NONE) {
4232                  /* don't hide previous results */
4233                 cfg->exception_type = MONO_EXCEPTION_SECURITY_LINKDEMAND;
4234                 cfg->exception_data = result;
4235                 return TRUE;
4236         }
4237         
4238         return FALSE;
4239 }
4240
4241 static MonoMethod*
4242 method_access_exception (void)
4243 {
4244         static MonoMethod *method = NULL;
4245
4246         if (!method) {
4247                 MonoSecurityManager *secman = mono_security_manager_get_methods ();
4248                 method = mono_class_get_method_from_name (secman->securitymanager,
4249                                                           "MethodAccessException", 2);
4250         }
4251         g_assert (method);
4252         return method;
4253 }
4254
4255 static void
4256 emit_throw_method_access_exception (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee,
4257                                     MonoBasicBlock *bblock, unsigned char *ip)
4258 {
4259         MonoMethod *thrower = method_access_exception ();
4260         MonoInst *args [2];
4261
4262         NEW_METHODCONST (cfg, args [0], caller);
4263         NEW_METHODCONST (cfg, args [1], callee);
4264         mono_emit_method_call_spilled (cfg, bblock, thrower,
4265                 mono_method_signature (thrower), args, ip, NULL);
4266 }
4267
4268 static MonoMethod*
4269 verification_exception (void)
4270 {
4271         static MonoMethod *method = NULL;
4272
4273         if (!method) {
4274                 MonoSecurityManager *secman = mono_security_manager_get_methods ();
4275                 method = mono_class_get_method_from_name (secman->securitymanager,
4276                                                           "VerificationException", 0);
4277         }
4278         g_assert (method);
4279         return method;
4280 }
4281
4282 static void
4283 emit_throw_verification_exception (MonoCompile *cfg, MonoBasicBlock *bblock, unsigned char *ip)
4284 {
4285         MonoMethod *thrower = verification_exception ();
4286
4287         mono_emit_method_call_spilled (cfg, bblock, thrower,
4288                 mono_method_signature (thrower),
4289                 NULL, ip, NULL);
4290 }
4291
4292 static void
4293 ensure_method_is_allowed_to_call_method (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee,
4294                                          MonoBasicBlock *bblock, unsigned char *ip)
4295 {
4296         MonoSecurityCoreCLRLevel caller_level = mono_security_core_clr_method_level (caller, TRUE);
4297         MonoSecurityCoreCLRLevel callee_level = mono_security_core_clr_method_level (callee, TRUE);
4298         gboolean is_safe = TRUE;
4299
4300         if (!(caller_level >= callee_level ||
4301                         caller_level == MONO_SECURITY_CORE_CLR_SAFE_CRITICAL ||
4302                         callee_level == MONO_SECURITY_CORE_CLR_SAFE_CRITICAL)) {
4303                 is_safe = FALSE;
4304         }
4305
4306         if (!is_safe)
4307                 emit_throw_method_access_exception (cfg, caller, callee, bblock, ip);
4308 }
4309
4310 static gboolean
4311 method_is_safe (MonoMethod *method)
4312 {
4313         /*
4314         if (strcmp (method->name, "unsafeMethod") == 0)
4315                 return FALSE;
4316         */
4317         return TRUE;
4318 }
4319
4320 /*
4321  * Check that the IL instructions at ip are the array initialization
4322  * sequence and return the pointer to the data and the size.
4323  */
4324 static const char*
4325 initialize_array_data (MonoMethod *method, gboolean aot, unsigned char *ip, MonoInst *newarr, int *out_size)
4326 {
4327         /*
4328          * newarr[System.Int32]
4329          * dup
4330          * ldtoken field valuetype ...
4331          * call void class [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype [mscorlib]System.RuntimeFieldHandle)
4332          */
4333         if (ip [0] == CEE_DUP && ip [1] == CEE_LDTOKEN && ip [5] == 0x4 && ip [6] == CEE_CALL) {
4334                 MonoClass *klass = newarr->inst_newa_class;
4335                 guint32 field_token = read32 (ip + 2);
4336                 guint32 field_index = field_token & 0xffffff;
4337                 guint32 token = read32 (ip + 7);
4338                 guint32 rva;
4339                 const char *data_ptr;
4340                 int size = 0;
4341                 MonoMethod *cmethod;
4342                 MonoClass *dummy_class;
4343                 MonoClassField *field = mono_field_from_token (method->klass->image, field_token, &dummy_class, NULL);
4344                 int dummy_align;
4345
4346                 if (!field)
4347                         return NULL;
4348
4349                 if (newarr->inst_newa_len->opcode != OP_ICONST)
4350                         return NULL;
4351                 cmethod = mini_get_method (NULL, method, token, NULL, NULL);
4352                 if (!cmethod)
4353                         return NULL;
4354                 if (strcmp (cmethod->name, "InitializeArray") || strcmp (cmethod->klass->name, "RuntimeHelpers") || cmethod->klass->image != mono_defaults.corlib)
4355                         return NULL;
4356                 switch (mono_type_get_underlying_type (&klass->byval_arg)->type) {
4357                 case MONO_TYPE_BOOLEAN:
4358                 case MONO_TYPE_I1:
4359                 case MONO_TYPE_U1:
4360                         size = 1; break;
4361                 /* we need to swap on big endian, so punt. Should we handle R4 and R8 as well? */
4362 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
4363                 case MONO_TYPE_CHAR:
4364                 case MONO_TYPE_I2:
4365                 case MONO_TYPE_U2:
4366                         size = 2; break;
4367                 case MONO_TYPE_I4:
4368                 case MONO_TYPE_U4:
4369                 case MONO_TYPE_R4:
4370                         size = 4; break;
4371                 case MONO_TYPE_R8:
4372 #ifdef ARM_FPU_FPA
4373                         return NULL; /* stupid ARM FP swapped format */
4374 #endif
4375                 case MONO_TYPE_I8:
4376                 case MONO_TYPE_U8:
4377                         size = 8; break;
4378 #endif
4379                 default:
4380                         return NULL;
4381                 }
4382                 size *= newarr->inst_newa_len->inst_c0;
4383                 if (size > mono_type_size (field->type, &dummy_align))
4384                     return NULL;
4385                 *out_size = size;
4386                 /*g_print ("optimized in %s: size: %d, numelems: %d\n", method->name, size, newarr->inst_newa_len->inst_c0);*/
4387                 field_index = read32 (ip + 2) & 0xffffff;
4388                 mono_metadata_field_info (method->klass->image, field_index - 1, NULL, &rva, NULL);
4389                 data_ptr = mono_image_rva_map (method->klass->image, rva);
4390                 /*g_print ("field: 0x%08x, rva: %d, rva_ptr: %p\n", read32 (ip + 2), rva, data_ptr);*/
4391                 /* for aot code we do the lookup on load */
4392                 if (aot && data_ptr)
4393                         return GUINT_TO_POINTER (rva);
4394                 return data_ptr;
4395         }
4396         return NULL;
4397 }
4398
4399 static void
4400 set_exception_type_from_invalid_il (MonoCompile *cfg, MonoMethod *method, unsigned char *ip)
4401 {
4402         char *method_fname = mono_method_full_name (method, TRUE);
4403         char *method_code;
4404
4405         if (mono_method_get_header (method)->code_size == 0)
4406                 method_code = g_strdup ("method body is empty.");
4407         else
4408                 method_code = mono_disasm_code_one (NULL, method, ip, NULL);
4409         cfg->exception_type = MONO_EXCEPTION_INVALID_PROGRAM;
4410         cfg->exception_message = g_strdup_printf ("Invalid IL code in %s: %s\n", method_fname, method_code);
4411         g_free (method_fname);
4412         g_free (method_code);
4413 }
4414
4415 static MonoInst*
4416 get_runtime_generic_context (MonoCompile *cfg, MonoMethod *method, MonoInst *this, unsigned char *ip)
4417 {
4418         g_assert (!method->klass->valuetype);
4419
4420         if (method->flags & METHOD_ATTRIBUTE_STATIC) {
4421                 MonoInst *vtable_loc, *vtable_var;
4422
4423                 vtable_loc = mono_get_vtable_var (cfg);
4424                 NEW_TEMPLOAD (cfg, vtable_var, vtable_loc->inst_c0);
4425
4426                 return vtable_var;
4427         } else {
4428                 MonoInst *vtable;
4429
4430                 MONO_INST_NEW (cfg, vtable, CEE_LDIND_I);
4431                 vtable->inst_left = this;
4432                 vtable->type = STACK_PTR;
4433
4434                 return vtable;
4435         }
4436 }
4437
4438 static gpointer
4439 create_rgctx_lazy_fetch_trampoline (guint32 offset)
4440 {
4441         static gboolean inited = FALSE;
4442         static int num_trampolines = 0;
4443
4444         gpointer tramp, ptr;
4445
4446         mono_jit_lock ();
4447         if (rgctx_lazy_fetch_trampoline_hash)
4448                 tramp = g_hash_table_lookup (rgctx_lazy_fetch_trampoline_hash, GUINT_TO_POINTER (offset));
4449         else
4450                 tramp = NULL;
4451         mono_jit_unlock ();
4452         if (tramp)
4453                 return tramp;
4454
4455         tramp = mono_arch_create_rgctx_lazy_fetch_trampoline (offset);
4456         ptr = mono_create_ftnptr (mono_get_root_domain (), tramp);
4457
4458         mono_jit_lock ();
4459         if (!rgctx_lazy_fetch_trampoline_hash)
4460                 rgctx_lazy_fetch_trampoline_hash = g_hash_table_new (NULL, NULL);
4461         g_hash_table_insert (rgctx_lazy_fetch_trampoline_hash, GUINT_TO_POINTER (offset), ptr);
4462         mono_jit_unlock ();
4463
4464         if (!inited) {
4465                 mono_counters_register ("RGCTX num lazy fetch trampolines",
4466                                 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_trampolines);
4467                 inited = TRUE;
4468         }
4469         num_trampolines++;
4470
4471         return ptr;
4472 }
4473
4474 /*
4475  * Generates rgc->other_infos [index].XXX if index is non-negative, or
4476  * rgc->extra_other_infos [-index + 1] if index is negative.  XXX is
4477  * specified by rgctx_type;
4478  */
4479 static MonoInst*
4480 get_runtime_generic_context_other_table_ptr (MonoCompile *cfg, MonoBasicBlock *bblock,
4481         MonoInst *rgc_ptr, int slot, const unsigned char *ip)
4482 {
4483         MonoMethodSignature *sig = helper_sig_rgctx_lazy_fetch_trampoline;
4484         guint8 *tramp = create_rgctx_lazy_fetch_trampoline (slot);
4485         int temp;
4486         MonoInst *field;
4487
4488         temp = mono_emit_native_call (cfg, bblock, tramp, sig, &rgc_ptr, ip, FALSE, FALSE);
4489
4490         NEW_TEMPLOAD (cfg, field, temp);
4491
4492         return field;
4493 }
4494
4495 static MonoInst*
4496 get_runtime_generic_context_other_ptr (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *bblock,
4497         MonoInst *rgc_ptr, guint32 token, int token_source, int rgctx_type, unsigned char *ip, int index)
4498 {
4499         MonoInst *args [6];
4500         int temp;
4501         MonoInst *result;
4502
4503         g_assert (method->wrapper_type == MONO_WRAPPER_NONE);
4504
4505         NEW_CLASSCONST (cfg, args [0], method->klass);
4506         args [1] = rgc_ptr;
4507         NEW_ICONST (cfg, args [2], token);
4508         NEW_ICONST (cfg, args [3], token_source);
4509         NEW_ICONST (cfg, args [4], rgctx_type);
4510         NEW_ICONST (cfg, args [5], index);
4511
4512         temp = mono_emit_jit_icall (cfg, bblock, mono_helper_get_rgctx_other_ptr, args, ip);
4513         NEW_TEMPLOAD (cfg, result, temp);
4514
4515         return result;
4516 }
4517
4518 static MonoInst*
4519 get_runtime_generic_context_ptr (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *bblock,
4520         MonoClass *klass, guint32 type_token, int token_source, MonoGenericContext *generic_context, MonoInst *rgctx,
4521         int rgctx_type, unsigned char *ip)
4522 {
4523         int arg_num = -1;
4524         int relation = mono_class_generic_class_relation (klass, rgctx_type, method->klass, generic_context, &arg_num);
4525
4526         switch (relation) {
4527         case MINI_GENERIC_CLASS_RELATION_OTHER_TABLE:
4528                 return get_runtime_generic_context_other_table_ptr (cfg, bblock, rgctx, arg_num, ip);
4529         case MINI_GENERIC_CLASS_RELATION_OTHER:
4530                 return get_runtime_generic_context_other_ptr (cfg, method, bblock, rgctx,
4531                         type_token, token_source, rgctx_type, ip, arg_num);
4532         default:
4533                 g_assert_not_reached ();
4534                 return NULL;
4535         }
4536 }
4537
4538 static MonoInst*
4539 get_runtime_generic_context_method (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *bblock,
4540         MonoMethod *cmethod, MonoGenericContext *generic_context, MonoInst *rgctx, int rgctx_type, const unsigned char *ip)
4541 {
4542         int arg_num = mono_class_lookup_or_register_other_info (method->klass, cmethod, rgctx_type, generic_context);
4543
4544         return get_runtime_generic_context_other_table_ptr (cfg, bblock, rgctx, arg_num, ip);
4545 }
4546
4547 static MonoInst*
4548 get_runtime_generic_context_field (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *bblock,
4549         MonoClassField *field, MonoGenericContext *generic_context, MonoInst *rgctx, int rgctx_type,
4550         const unsigned char *ip)
4551 {
4552         int arg_num = mono_class_lookup_or_register_other_info (method->klass, field, rgctx_type, generic_context);
4553
4554         return get_runtime_generic_context_other_table_ptr (cfg, bblock, rgctx, arg_num, ip);
4555 }
4556
4557 static gboolean
4558 generic_class_is_reference_type (MonoCompile *cfg, MonoClass *klass)
4559 {
4560         MonoType *type;
4561
4562         if (cfg->generic_sharing_context)
4563                 type = mini_get_basic_type_from_generic (cfg->generic_sharing_context, &klass->byval_arg);
4564         else
4565                 type = &klass->byval_arg;
4566         return MONO_TYPE_IS_REFERENCE (type);
4567 }
4568
4569 /**
4570  * Handles unbox of a Nullable<T>, returning a temp variable where the
4571  * result is stored.  If a rgctx is passed, then shared generic code
4572  * is generated.
4573  */
4574 static int
4575 handle_unbox_nullable (MonoCompile* cfg, MonoMethod *caller_method, MonoBasicBlock* bblock, MonoInst* val,
4576         guchar *ip, MonoClass* klass, MonoGenericContext *generic_context, MonoInst *rgctx)
4577 {
4578         MonoMethod* method = mono_class_get_method_from_name (klass, "Unbox", 1);
4579         MonoMethodSignature *signature = mono_method_signature (method);
4580
4581         if (rgctx) {
4582                 MonoInst *addr = get_runtime_generic_context_method (cfg, caller_method, bblock, method,
4583                         generic_context, rgctx, MONO_RGCTX_INFO_GENERIC_METHOD_CODE, ip);
4584
4585                 return mono_emit_rgctx_calli_spilled (cfg, bblock, signature, &val, addr, NULL, ip);
4586         } else {
4587                 return mono_emit_method_call_spilled (cfg, bblock, method, signature, &val, ip, NULL);
4588         }
4589 }
4590
4591 static MonoInst*
4592 handle_box_nullable_from_inst (MonoCompile *cfg, MonoMethod *caller_method, int context_used, MonoBasicBlock *bblock,
4593         MonoInst *val, const guchar *ip, MonoClass *klass, MonoGenericContext *generic_context, MonoInst *rgctx)
4594 {
4595         MonoMethod* method = mono_class_get_method_from_name (klass, "Box", 1);
4596         MonoInst *dest, *method_addr;
4597         int temp;
4598
4599         g_assert (mono_class_is_nullable (klass));
4600
4601         method_addr = get_runtime_generic_context_method (cfg, caller_method, bblock, method,
4602                         generic_context, rgctx, MONO_RGCTX_INFO_GENERIC_METHOD_CODE, ip);
4603         temp = mono_emit_rgctx_calli_spilled (cfg, bblock, mono_method_signature (method), &val,
4604                         method_addr, NULL, ip);
4605         NEW_TEMPLOAD (cfg, dest, temp);
4606         return dest;
4607 }
4608
4609 static MonoObject*
4610 mono_object_castclass (MonoObject *obj, MonoClass *klass)
4611 {
4612         if (!obj)
4613                 return NULL;
4614
4615         if (mono_object_isinst (obj, klass))
4616                 return obj;
4617
4618         mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
4619                                         "System", "InvalidCastException"));
4620
4621         return NULL;
4622 }
4623
4624 static int
4625 emit_castclass (MonoClass *klass, guint32 token, gboolean shared_access, gboolean inst_is_castclass, MonoCompile *cfg,
4626                 MonoMethod *method, MonoInst **arg_array, MonoType **param_types, GList *dont_inline,
4627                 unsigned char *end, MonoMethodHeader *header, MonoGenericContext *generic_context,
4628                 MonoBasicBlock **_bblock, unsigned char **_ip, MonoInst ***_sp, int *_inline_costs, guint *_real_offset)
4629 {
4630         MonoBasicBlock *bblock = *_bblock;
4631         unsigned char *ip = *_ip;
4632         MonoInst **sp = *_sp;
4633         int inline_costs = *_inline_costs;
4634         guint real_offset = *_real_offset;
4635         int return_value = 0;
4636
4637         if (shared_access) {
4638                 MonoInst *this = NULL, *rgctx;
4639                 MonoInst *args [2];
4640                 int temp;
4641
4642                 g_assert (!method->klass->valuetype);
4643
4644                 /* obj */
4645                 args [0] = *sp;
4646
4647                 /* klass */
4648                 if (!(method->flags & METHOD_ATTRIBUTE_STATIC))
4649                         NEW_ARGLOAD (cfg, this, 0);
4650                 rgctx = get_runtime_generic_context (cfg, method, this, ip);
4651                 args [1] = get_runtime_generic_context_ptr (cfg, method, bblock, klass,
4652                                 token, MINI_TOKEN_SOURCE_CLASS, generic_context, rgctx, MONO_RGCTX_INFO_KLASS, ip);
4653
4654                 temp = mono_emit_jit_icall (cfg, bblock, mono_object_castclass, args, ip);
4655                 NEW_TEMPLOAD (cfg, *sp, temp);
4656
4657                 sp++;
4658                 ip += 5;
4659                 inline_costs += 2;
4660         } else if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4661
4662                 MonoMethod *mono_castclass;
4663                 MonoInst *iargs [1];
4664                 MonoBasicBlock *ebblock;
4665                 int costs;
4666                 int temp;
4667
4668                 mono_castclass = mono_marshal_get_castclass (klass);
4669                 iargs [0] = sp [0];
4670
4671                 costs = inline_method (cfg, mono_castclass, mono_method_signature (mono_castclass), bblock,
4672                                 iargs, ip, real_offset, dont_inline, &ebblock, TRUE);
4673
4674                 g_assert (costs > 0);
4675
4676                 ip += 5;
4677                 real_offset += 5;
4678
4679                 GET_BBLOCK (cfg, bblock, ip);
4680                 ebblock->next_bb = bblock;
4681                 link_bblock (cfg, ebblock, bblock);
4682
4683                 temp = iargs [0]->inst_i0->inst_c0;
4684                 NEW_TEMPLOAD (cfg, *sp, temp);
4685
4686                 sp++;
4687                 bblock = ebblock;
4688                 inline_costs += costs;
4689         } else {
4690                 MonoInst *ins;
4691
4692                 /* Needed by the code generated in inssel.brg */
4693                 mono_get_got_var (cfg);
4694
4695                 MONO_INST_NEW (cfg, ins, CEE_CASTCLASS);
4696                 ins->type = STACK_OBJ;
4697                 ins->inst_left = *sp;
4698                 ins->klass = klass;
4699                 ins->inst_newa_class = klass;
4700                 if (inst_is_castclass)
4701                         ins->backend.record_cast_details = debug_options.better_cast_details;
4702                 if (inst_is_castclass)
4703                         *sp++ = emit_tree (cfg, bblock, ins, ip + 5);
4704                 else
4705                         *sp++ = ins;
4706                 ip += 5;
4707         }
4708
4709 do_return:
4710         *_bblock = bblock;
4711         *_ip = ip;
4712         *_sp = sp;
4713         *_inline_costs = inline_costs;
4714         *_real_offset = real_offset;
4715         return return_value;
4716 unverified:
4717         return_value = -1;
4718         goto do_return;
4719 }
4720
4721 static gboolean
4722 mini_assembly_can_skip_verification (MonoDomain *domain, MonoMethod *method)
4723 {
4724         MonoAssembly *assembly = method->klass->image->assembly;
4725         if (method->wrapper_type != MONO_WRAPPER_NONE)
4726                 return FALSE;
4727         if (assembly->in_gac || assembly->image == mono_defaults.corlib)
4728                 return FALSE;
4729         if (mono_security_get_mode () != MONO_SECURITY_MODE_NONE)
4730                 return FALSE;
4731         return mono_assembly_has_skip_verification (assembly);
4732 }
4733
4734 /*
4735  * mini_method_verify:
4736  * 
4737  * Verify the method using the new verfier.
4738  * 
4739  * Returns true if the method is invalid. 
4740  */
4741 static gboolean
4742 mini_method_verify (MonoCompile *cfg, MonoMethod *method)
4743 {
4744         GSList *tmp, *res;
4745         gboolean is_fulltrust;
4746         MonoLoaderError *error;
4747
4748         if (method->verification_success)
4749                 return FALSE;
4750
4751         is_fulltrust = mono_verifier_is_method_full_trust (method);
4752
4753         if (!mono_verifier_is_enabled_for_method (method))
4754                 return FALSE;
4755
4756         res = mono_method_verify_with_current_settings (method, cfg->skip_visibility);
4757
4758         if ((error = mono_loader_get_last_error ())) {
4759                 cfg->exception_type = error->exception_type;
4760                 if (res)
4761                         mono_free_verify_list (res);
4762                 return TRUE;
4763         }
4764
4765         if (res) { 
4766                 for (tmp = res; tmp; tmp = tmp->next) {
4767                         MonoVerifyInfoExtended *info = (MonoVerifyInfoExtended *)tmp->data;
4768                         if (info->info.status == MONO_VERIFY_ERROR) {
4769                                 cfg->exception_type = info->exception_type;
4770                                 cfg->exception_message = g_strdup (info->info.message);
4771                                 mono_free_verify_list (res);
4772                                 return TRUE;
4773                         }
4774                         if (info->info.status == MONO_VERIFY_NOT_VERIFIABLE && !is_fulltrust) {
4775                                 cfg->exception_type = info->exception_type;
4776                                 cfg->exception_message = g_strdup (info->info.message);
4777                                 mono_free_verify_list (res);
4778                                 return TRUE;
4779                         }
4780                 }
4781                 mono_free_verify_list (res);
4782         }
4783         method->verification_success = 1;
4784         return FALSE;
4785 }
4786
4787 /*
4788  * mono_method_to_ir: translates IL into basic blocks containing trees
4789  */
4790 static int
4791 mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock, 
4792                    int locals_offset, MonoInst *return_var, GList *dont_inline, MonoInst **inline_args, 
4793                    guint inline_offset, gboolean is_virtual_call)
4794 {
4795         MonoInst *zero_int32, *zero_int64, *zero_ptr, *zero_obj, *zero_r8;
4796         MonoInst *ins, **sp, **stack_start;
4797         MonoBasicBlock *bblock, *tblock = NULL, *init_localsbb = NULL;
4798         MonoMethod *cmethod, *method_definition;
4799         MonoInst **arg_array;
4800         MonoMethodHeader *header;
4801         MonoImage *image;
4802         guint32 token, ins_flag;
4803         MonoClass *klass;
4804         MonoClass *constrained_call = NULL;
4805         unsigned char *ip, *end, *target, *err_pos;
4806         static double r8_0 = 0.0;
4807         MonoMethodSignature *sig;
4808         MonoGenericContext *generic_context = NULL;
4809         MonoGenericContainer *generic_container = NULL;
4810         MonoType **param_types;
4811         GList *bb_recheck = NULL, *tmp;
4812         int i, n, start_new_bblock, ialign;
4813         int num_calls = 0, inline_costs = 0;
4814         int breakpoint_id = 0;
4815         guint32 align;
4816         guint real_offset, num_args;
4817         MonoBoolean security, pinvoke;
4818         MonoSecurityManager* secman = NULL;
4819         MonoDeclSecurityActions actions;
4820         GSList *class_inits = NULL;
4821         gboolean dont_verify, dont_verify_stloc, readonly = FALSE;
4822
4823         /* serialization and xdomain stuff may need access to private fields and methods */
4824         dont_verify = method->klass->image->assembly->corlib_internal? TRUE: FALSE;
4825         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE;
4826         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH;
4827         dont_verify |= method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE; /* bug #77896 */
4828         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP;
4829         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP_INVOKE;
4830
4831         /* turn off visibility checks for smcs */
4832         dont_verify |= mono_security_get_mode () == MONO_SECURITY_MODE_SMCS_HACK;
4833
4834         /* still some type unsafety issues in marshal wrappers... (unknown is PtrToStructure) */
4835         dont_verify_stloc = method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE;
4836         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_UNKNOWN;
4837         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED;
4838
4839         image = method->klass->image;
4840         header = mono_method_get_header (method);
4841         generic_container = mono_method_get_generic_container (method);
4842         sig = mono_method_signature (method);
4843         num_args = sig->hasthis + sig->param_count;
4844         ip = (unsigned char*)header->code;
4845         cfg->cil_start = ip;
4846         end = ip + header->code_size;
4847         mono_jit_stats.cil_code_size += header->code_size;
4848
4849         method_definition = method;
4850         while (method_definition->is_inflated) {
4851                 MonoMethodInflated *imethod = (MonoMethodInflated *) method_definition;
4852                 method_definition = imethod->declaring;
4853         }
4854
4855         /* SkipVerification is not allowed if core-clr is enabled */
4856         if (!dont_verify && mini_assembly_can_skip_verification (cfg->domain, method)) {
4857                 dont_verify = TRUE;
4858                 dont_verify_stloc = TRUE;
4859         }
4860
4861         if (!dont_verify && mini_method_verify (cfg, method_definition))
4862                 goto exception_exit;
4863
4864         if (sig->is_inflated)
4865                 generic_context = mono_method_get_context (method);
4866         else if (generic_container)
4867                 generic_context = &generic_container->context;
4868
4869         if (!cfg->generic_sharing_context)
4870                 g_assert (!sig->has_type_parameters);
4871
4872         if (cfg->method == method)
4873                 real_offset = 0;
4874         else
4875                 real_offset = inline_offset;
4876
4877         cfg->cil_offset_to_bb = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoBasicBlock*) * header->code_size);
4878         cfg->cil_offset_to_bb_len = header->code_size;
4879
4880         if (cfg->verbose_level > 2)
4881                 g_print ("method to IR %s\n", mono_method_full_name (method, TRUE));
4882
4883         dont_inline = g_list_prepend (dont_inline, method);
4884         if (cfg->method == method) {
4885
4886                 if (cfg->prof_options & MONO_PROFILE_INS_COVERAGE)
4887                         cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, header->code_size);
4888
4889                 /* ENTRY BLOCK */
4890                 NEW_BBLOCK (cfg, start_bblock);
4891                 cfg->bb_entry = start_bblock;
4892                 start_bblock->cil_code = NULL;
4893                 start_bblock->cil_length = 0;
4894                 start_bblock->block_num = cfg->num_bblocks++;
4895
4896                 /* EXIT BLOCK */
4897                 NEW_BBLOCK (cfg, end_bblock);
4898                 cfg->bb_exit = end_bblock;
4899                 end_bblock->cil_code = NULL;
4900                 end_bblock->cil_length = 0;
4901                 end_bblock->block_num = cfg->num_bblocks++;
4902                 g_assert (cfg->num_bblocks == 2);
4903
4904                 arg_array = alloca (sizeof (MonoInst *) * num_args);
4905                 for (i = num_args - 1; i >= 0; i--)
4906                         arg_array [i] = cfg->varinfo [i];
4907
4908                 if (header->num_clauses) {
4909                         cfg->spvars = g_hash_table_new (NULL, NULL);
4910                         cfg->exvars = g_hash_table_new (NULL, NULL);
4911                 }
4912                 /* handle exception clauses */
4913                 for (i = 0; i < header->num_clauses; ++i) {
4914                         MonoBasicBlock *try_bb;
4915                         MonoExceptionClause *clause = &header->clauses [i];
4916
4917                         GET_BBLOCK (cfg, try_bb, ip + clause->try_offset);
4918                         try_bb->real_offset = clause->try_offset;
4919                         GET_BBLOCK (cfg, tblock, ip + clause->handler_offset);
4920                         tblock->real_offset = clause->handler_offset;
4921                         tblock->flags |= BB_EXCEPTION_HANDLER;
4922
4923                         link_bblock (cfg, try_bb, tblock);
4924
4925                         if (*(ip + clause->handler_offset) == CEE_POP)
4926                                 tblock->flags |= BB_EXCEPTION_DEAD_OBJ;
4927
4928                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY ||
4929                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER ||
4930                             clause->flags == MONO_EXCEPTION_CLAUSE_FAULT) {
4931                                 MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
4932                                 MONO_ADD_INS (tblock, ins);
4933
4934                                 /* todo: is a fault block unsafe to optimize? */
4935                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
4936                                         tblock->flags |= BB_EXCEPTION_UNSAFE;
4937                         }
4938
4939
4940                         /*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);
4941                           while (p < end) {
4942                           g_print ("%s", mono_disasm_code_one (NULL, method, p, &p));
4943                           }*/
4944                         /* catch and filter blocks get the exception object on the stack */
4945                         if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE ||
4946                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
4947                                 MonoInst *load, *dummy_use;
4948
4949                                 /* mostly like handle_stack_args (), but just sets the input args */
4950                                 /* g_print ("handling clause at IL_%04x\n", clause->handler_offset); */
4951                                 tblock->in_scount = 1;
4952                                 tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
4953                                 tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
4954
4955                                 /* 
4956                                  * Add a dummy use for the exvar so its liveness info will be
4957                                  * correct.
4958                                  */
4959                                 NEW_TEMPLOAD (cfg, load, tblock->in_stack [0]->inst_c0);
4960                                 NEW_DUMMY_USE (cfg, dummy_use, load);
4961                                 MONO_ADD_INS (tblock, dummy_use);
4962                                 
4963                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
4964                                         GET_BBLOCK (cfg, tblock, ip + clause->data.filter_offset);
4965                                         tblock->real_offset = clause->data.filter_offset;
4966                                         tblock->in_scount = 1;
4967                                         tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
4968                                         /* The filter block shares the exvar with the handler block */
4969                                         tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
4970                                         MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
4971                                         MONO_ADD_INS (tblock, ins);
4972                                 }
4973                         }
4974
4975                         if (clause->flags != MONO_EXCEPTION_CLAUSE_FILTER &&
4976                                         clause->data.catch_class &&
4977                                         cfg->generic_sharing_context &&
4978                                         mono_class_check_context_used (clause->data.catch_class)) {
4979                                 /*
4980                                  * In shared generic code with catch
4981                                  * clauses containing type variables
4982                                  * the exception handling code has to
4983                                  * be able to get to the rgctx.
4984                                  * Therefore we have to make sure that
4985                                  * the rgctx argument (for static
4986                                  * methods) or the "this" argument
4987                                  * (for non-static methods) are live.
4988                                  */
4989                                 if (method->flags & METHOD_ATTRIBUTE_STATIC) {
4990                                         mono_get_vtable_var (cfg);
4991                                 } else {
4992                                         MonoInst *this, *dummy_use;
4993                                         MonoType *this_type;
4994
4995                                         if (method->klass->valuetype)
4996                                                 this_type = &method->klass->this_arg;
4997                                         else
4998                                                 this_type = &method->klass->byval_arg;
4999
5000                                         if (arg_array [0]->opcode == OP_ICONST) {
5001                                                 this = arg_array [0];
5002                                         } else {
5003                                                 this = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));
5004                                                 this->ssa_op = MONO_SSA_LOAD;
5005                                                 this->inst_i0 = arg_array [0];
5006                                                 this->opcode = mini_type_to_ldind ((cfg), this->inst_i0->inst_vtype);
5007                                                 type_to_eval_stack_type ((cfg), this_type, this);
5008                                                 this->klass = this->inst_i0->klass;
5009                                         }
5010
5011                                         NEW_DUMMY_USE (cfg, dummy_use, this);
5012                                         MONO_ADD_INS (tblock, dummy_use);
5013                                 }
5014                         }
5015                 }
5016         } else {
5017                 arg_array = alloca (sizeof (MonoInst *) * num_args);
5018                 mono_save_args (cfg, start_bblock, sig, inline_args, arg_array);
5019         }
5020
5021         /* FIRST CODE BLOCK */
5022         NEW_BBLOCK (cfg, bblock);
5023         bblock->cil_code = ip;
5024
5025         ADD_BBLOCK (cfg, bblock);
5026
5027         if (cfg->method == method) {
5028                 breakpoint_id = mono_debugger_method_has_breakpoint (method);
5029                 if (breakpoint_id && (mono_debug_format != MONO_DEBUG_FORMAT_DEBUGGER)) {
5030                         MONO_INST_NEW (cfg, ins, OP_BREAK);
5031                         MONO_ADD_INS (bblock, ins);
5032                 }
5033         }
5034
5035         if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS)
5036                 secman = mono_security_manager_get_methods ();
5037
5038         security = (secman && mono_method_has_declsec (method));
5039         /* at this point having security doesn't mean we have any code to generate */
5040         if (security && (cfg->method == method)) {
5041                 /* Only Demand, NonCasDemand and DemandChoice requires code generation.
5042                  * And we do not want to enter the next section (with allocation) if we
5043                  * have nothing to generate */
5044                 security = mono_declsec_get_demands (method, &actions);
5045         }
5046
5047         /* we must Demand SecurityPermission.Unmanaged before P/Invoking */
5048         pinvoke = (secman && (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE));
5049         if (pinvoke) {
5050                 MonoMethod *wrapped = mono_marshal_method_from_wrapper (method);
5051                 if (wrapped && (wrapped->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
5052                         MonoCustomAttrInfo* custom = mono_custom_attrs_from_method (wrapped);
5053
5054                         /* unless the method or it's class has the [SuppressUnmanagedCodeSecurity] attribute */
5055                         if (custom && mono_custom_attrs_has_attr (custom, secman->suppressunmanagedcodesecurity)) {
5056                                 pinvoke = FALSE;
5057                         }
5058                         if (custom)
5059                                 mono_custom_attrs_free (custom);
5060
5061                         if (pinvoke) {
5062                                 custom = mono_custom_attrs_from_class (wrapped->klass);
5063                                 if (custom && mono_custom_attrs_has_attr (custom, secman->suppressunmanagedcodesecurity)) {
5064                                         pinvoke = FALSE;
5065                                 }
5066                                 if (custom)
5067                                         mono_custom_attrs_free (custom);
5068                         }
5069                 } else {
5070                         /* not a P/Invoke after all */
5071                         pinvoke = FALSE;
5072                 }
5073         }
5074         
5075         if ((header->init_locals || (cfg->method == method && (cfg->opt & MONO_OPT_SHARED))) || cfg->compile_aot || security || pinvoke) {
5076                 /* we use a separate basic block for the initialization code */
5077                 NEW_BBLOCK (cfg, init_localsbb);
5078                 cfg->bb_init = init_localsbb;
5079                 init_localsbb->real_offset = real_offset;
5080                 start_bblock->next_bb = init_localsbb;
5081                 init_localsbb->next_bb = bblock;
5082                 link_bblock (cfg, start_bblock, init_localsbb);
5083                 link_bblock (cfg, init_localsbb, bblock);
5084                 init_localsbb->block_num = cfg->num_bblocks++;
5085         } else {
5086                 start_bblock->next_bb = bblock;
5087                 link_bblock (cfg, start_bblock, bblock);
5088         }
5089
5090         /* at this point we know, if security is TRUE, that some code needs to be generated */
5091         if (security && (cfg->method == method)) {
5092                 MonoInst *args [2];
5093
5094                 mono_jit_stats.cas_demand_generation++;
5095
5096                 if (actions.demand.blob) {
5097                         /* Add code for SecurityAction.Demand */
5098                         NEW_DECLSECCONST (cfg, args[0], image, actions.demand);
5099                         NEW_ICONST (cfg, args [1], actions.demand.size);
5100                         /* Calls static void SecurityManager.InternalDemand (byte* permissions, int size); */
5101                         mono_emit_method_call_spilled (cfg, init_localsbb, secman->demand, mono_method_signature (secman->demand), args, ip, NULL);
5102                 }
5103                 if (actions.noncasdemand.blob) {
5104                         /* CLR 1.x uses a .noncasdemand (but 2.x doesn't) */
5105                         /* For Mono we re-route non-CAS Demand to Demand (as the managed code must deal with it anyway) */
5106                         NEW_DECLSECCONST (cfg, args[0], image, actions.noncasdemand);
5107                         NEW_ICONST (cfg, args [1], actions.noncasdemand.size);
5108                         /* Calls static void SecurityManager.InternalDemand (byte* permissions, int size); */
5109                         mono_emit_method_call_spilled (cfg, init_localsbb, secman->demand, mono_method_signature (secman->demand), args, ip, NULL);
5110                 }
5111                 if (actions.demandchoice.blob) {
5112                         /* New in 2.0, Demand must succeed for one of the permissions (i.e. not all) */
5113                         NEW_DECLSECCONST (cfg, args[0], image, actions.demandchoice);
5114                         NEW_ICONST (cfg, args [1], actions.demandchoice.size);
5115                         /* Calls static void SecurityManager.InternalDemandChoice (byte* permissions, int size); */
5116                         mono_emit_method_call_spilled (cfg, init_localsbb, secman->demandchoice, mono_method_signature (secman->demandchoice), args, ip, NULL);
5117                 }
5118         }
5119
5120         /* we must Demand SecurityPermission.Unmanaged before p/invoking */
5121         if (pinvoke) {
5122                 mono_emit_method_call_spilled (cfg, init_localsbb, secman->demandunmanaged, mono_method_signature (secman->demandunmanaged), NULL, ip, NULL);
5123         }
5124
5125         if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR) {
5126                 if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
5127                         MonoMethod *wrapped = mono_marshal_method_from_wrapper (method);
5128                         if (wrapped && (wrapped->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
5129                                 if (!(method->klass && method->klass->image &&
5130                                                 mono_security_core_clr_is_platform_image (method->klass->image))) {
5131                                         emit_throw_method_access_exception (cfg, method, wrapped, bblock, ip);
5132                                 }
5133                         }
5134                 }
5135                 if (!method_is_safe (method))
5136                         emit_throw_verification_exception (cfg, bblock, ip);
5137         }
5138
5139         if (header->code_size == 0)
5140                 UNVERIFIED;
5141
5142         if (get_basic_blocks (cfg, header, real_offset, ip, end, &err_pos)) {
5143                 ip = err_pos;
5144                 UNVERIFIED;
5145         }
5146
5147         if (cfg->method == method)
5148                 mono_debug_init_method (cfg, bblock, breakpoint_id);
5149
5150         param_types = mono_mempool_alloc (cfg->mempool, sizeof (MonoType*) * num_args);
5151         if (sig->hasthis)
5152                 param_types [0] = method->klass->valuetype?&method->klass->this_arg:&method->klass->byval_arg;
5153         for (n = 0; n < sig->param_count; ++n)
5154                 param_types [n + sig->hasthis] = sig->params [n];
5155         for (n = 0; n < header->num_locals; ++n) {
5156                 if (header->locals [n]->type == MONO_TYPE_VOID && !header->locals [n]->byref)
5157                         UNVERIFIED;
5158         }
5159         class_inits = NULL;
5160
5161         /* do this somewhere outside - not here */
5162         NEW_ICONST (cfg, zero_int32, 0);
5163         NEW_ICONST (cfg, zero_int64, 0);
5164         zero_int64->type = STACK_I8;
5165         NEW_PCONST (cfg, zero_ptr, 0);
5166         NEW_PCONST (cfg, zero_obj, 0);
5167         zero_obj->type = STACK_OBJ;
5168
5169         MONO_INST_NEW (cfg, zero_r8, OP_R8CONST);
5170         zero_r8->type = STACK_R8;
5171         zero_r8->inst_p0 = &r8_0;
5172
5173         /* add a check for this != NULL to inlined methods */
5174         if (is_virtual_call) {
5175                 MONO_INST_NEW (cfg, ins, OP_CHECK_THIS);
5176                 NEW_ARGLOAD (cfg, ins->inst_left, 0);
5177                 ins->cil_code = ip;
5178                 MONO_ADD_INS (bblock, ins);
5179         }
5180
5181         /* we use a spare stack slot in SWITCH and NEWOBJ and others */
5182         stack_start = sp = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (header->max_stack + 1));
5183
5184         ins_flag = 0;
5185         start_new_bblock = 0;
5186         while (ip < end) {
5187
5188                 if (cfg->method == method)
5189                         real_offset = ip - header->code;
5190                 else
5191                         real_offset = inline_offset;
5192                 cfg->ip = ip;
5193
5194                 if (start_new_bblock) {
5195                         bblock->cil_length = ip - bblock->cil_code;
5196                         if (start_new_bblock == 2) {
5197                                 g_assert (ip == tblock->cil_code);
5198                         } else {
5199                                 GET_BBLOCK (cfg, tblock, ip);
5200                         }
5201                         bblock->next_bb = tblock;
5202                         bblock = tblock;
5203                         start_new_bblock = 0;
5204                         for (i = 0; i < bblock->in_scount; ++i) {
5205                                 if (cfg->verbose_level > 3)
5206                                         g_print ("loading %d from temp %d\n", i, (int)bblock->in_stack [i]->inst_c0);                                           
5207                                 NEW_TEMPLOAD (cfg, ins, bblock->in_stack [i]->inst_c0);
5208                                 *sp++ = ins;
5209                         }
5210                         g_slist_free (class_inits);
5211                         class_inits = NULL;
5212                 } else {
5213                         if ((tblock = cfg->cil_offset_to_bb [ip - cfg->cil_start]) && (tblock != bblock)) {
5214                                 link_bblock (cfg, bblock, tblock);
5215                                 if (sp != stack_start) {
5216                                         handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
5217                                         sp = stack_start;
5218                                         CHECK_UNVERIFIABLE (cfg);
5219                                 }
5220                                 bblock->next_bb = tblock;
5221                                 bblock = tblock;
5222                                 for (i = 0; i < bblock->in_scount; ++i) {
5223                                         if (cfg->verbose_level > 3)
5224                                                 g_print ("loading %d from temp %d\n", i, (int)bblock->in_stack [i]->inst_c0);                                           
5225                                         NEW_TEMPLOAD (cfg, ins, bblock->in_stack [i]->inst_c0);
5226                                         *sp++ = ins;
5227                                 }
5228                                 g_slist_free (class_inits);
5229                                 class_inits = NULL;
5230                         }
5231                 }
5232
5233                 bblock->real_offset = real_offset;
5234
5235                 if ((cfg->method == method) && cfg->coverage_info) {
5236                         MonoInst *store, *one;
5237                         guint32 cil_offset = ip - header->code;
5238                         cfg->coverage_info->data [cil_offset].cil_code = ip;
5239
5240                         /* TODO: Use an increment here */
5241                         NEW_ICONST (cfg, one, 1);
5242                         one->cil_code = ip;
5243
5244                         NEW_PCONST (cfg, ins, &(cfg->coverage_info->data [cil_offset].count));
5245                         ins->cil_code = ip;
5246
5247                         MONO_INST_NEW (cfg, store, CEE_STIND_I);
5248                         store->inst_left = ins;
5249                         store->inst_right = one;
5250
5251                         MONO_ADD_INS (bblock, store);
5252                 }
5253
5254                 if (cfg->verbose_level > 3)
5255                         g_print ("converting (in B%d: stack: %d) %s", bblock->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
5256
5257                 switch (*ip) {
5258                 case CEE_NOP:
5259                         MONO_INST_NEW (cfg, ins, OP_NOP);
5260                         ip++;
5261                         MONO_ADD_INS (bblock, ins);
5262                         break;
5263                 case CEE_BREAK:
5264                         MONO_INST_NEW (cfg, ins, OP_BREAK);
5265                         ip++;
5266                         MONO_ADD_INS (bblock, ins);
5267                         break;
5268                 case CEE_LDARG_0:
5269                 case CEE_LDARG_1:
5270                 case CEE_LDARG_2:
5271                 case CEE_LDARG_3:
5272                         CHECK_STACK_OVF (1);
5273                         n = (*ip)-CEE_LDARG_0;
5274                         CHECK_ARG (n);
5275                         NEW_ARGLOAD (cfg, ins, n);
5276                         LDARG_SOFT_FLOAT (cfg, ins, n, ip);
5277                         ip++;
5278                         *sp++ = ins;
5279                         break;
5280                 case CEE_LDLOC_0:
5281                 case CEE_LDLOC_1:
5282                 case CEE_LDLOC_2:
5283                 case CEE_LDLOC_3:
5284                         CHECK_STACK_OVF (1);
5285                         n = (*ip)-CEE_LDLOC_0;
5286                         CHECK_LOCAL (n);
5287                         NEW_LOCLOAD (cfg, ins, n);
5288                         LDLOC_SOFT_FLOAT (cfg, ins, n, ip);
5289                         ip++;
5290                         *sp++ = ins;
5291                         break;
5292                 case CEE_STLOC_0:
5293                 case CEE_STLOC_1:
5294                 case CEE_STLOC_2:
5295                 case CEE_STLOC_3:
5296                         CHECK_STACK (1);
5297                         n = (*ip)-CEE_STLOC_0;
5298                         CHECK_LOCAL (n);
5299                         --sp;
5300                         handle_loaded_temps (cfg, bblock, stack_start, sp);
5301                         NEW_LOCSTORE (cfg, ins, n, *sp);
5302                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
5303                                 UNVERIFIED;
5304                         STLOC_SOFT_FLOAT (cfg, ins, n, ip);
5305                         if (ins->opcode == CEE_STOBJ) {
5306                                 NEW_LOCLOADA (cfg, ins, n);
5307                                 handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE, FALSE);
5308                         } else
5309                                 MONO_ADD_INS (bblock, ins);
5310                         ++ip;
5311                         inline_costs += 1;
5312                         break;
5313                 case CEE_LDARG_S:
5314                         CHECK_OPSIZE (2);
5315                         CHECK_STACK_OVF (1);
5316                         CHECK_ARG (ip [1]);
5317                         NEW_ARGLOAD (cfg, ins, ip [1]);
5318                         LDARG_SOFT_FLOAT (cfg, ins, ip [1], ip);
5319                         *sp++ = ins;
5320                         ip += 2;
5321                         break;
5322                 case CEE_LDARGA_S:
5323                         CHECK_OPSIZE (2);
5324                         CHECK_STACK_OVF (1);
5325                         CHECK_ARG (ip [1]);
5326                         NEW_ARGLOADA (cfg, ins, ip [1]);
5327                         *sp++ = ins;
5328                         ip += 2;
5329                         break;
5330                 case CEE_STARG_S:
5331                         CHECK_OPSIZE (2);
5332                         CHECK_STACK (1);
5333                         --sp;
5334                         CHECK_ARG (ip [1]);
5335                         NEW_ARGSTORE (cfg, ins, ip [1], *sp);
5336                         handle_loaded_temps (cfg, bblock, stack_start, sp);
5337                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [ip [1]], *sp))
5338                                 UNVERIFIED;
5339                         STARG_SOFT_FLOAT (cfg, ins, ip [1], ip);
5340                         if (ins->opcode == CEE_STOBJ) {
5341                                 NEW_ARGLOADA (cfg, ins, ip [1]);
5342                                 handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE, FALSE);
5343                         } else
5344                                 MONO_ADD_INS (bblock, ins);
5345                         ip += 2;
5346                         break;
5347                 case CEE_LDLOC_S:
5348                         CHECK_OPSIZE (2);
5349                         CHECK_STACK_OVF (1);
5350                         CHECK_LOCAL (ip [1]);
5351                         NEW_LOCLOAD (cfg, ins, ip [1]);
5352                         LDLOC_SOFT_FLOAT (cfg, ins, ip [1], ip);
5353                         *sp++ = ins;
5354                         ip += 2;
5355                         break;
5356                 case CEE_LDLOCA_S:
5357                         CHECK_OPSIZE (2);
5358                         CHECK_STACK_OVF (1);
5359                         CHECK_LOCAL (ip [1]);
5360                         NEW_LOCLOADA (cfg, ins, ip [1]);
5361                         *sp++ = ins;
5362                         ip += 2;
5363                         break;
5364                 case CEE_STLOC_S:
5365                         CHECK_OPSIZE (2);
5366                         CHECK_STACK (1);
5367                         --sp;
5368                         handle_loaded_temps (cfg, bblock, stack_start, sp);
5369                         CHECK_LOCAL (ip [1]);
5370                         NEW_LOCSTORE (cfg, ins, ip [1], *sp);
5371                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [ip [1]], *sp))
5372                                 UNVERIFIED;
5373                         STLOC_SOFT_FLOAT (cfg, ins, ip [1], ip);
5374                         if (ins->opcode == CEE_STOBJ) {
5375                                 NEW_LOCLOADA (cfg, ins, ip [1]);
5376                                 handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE, FALSE);
5377                         } else
5378                                 MONO_ADD_INS (bblock, ins);
5379                         ip += 2;
5380                         inline_costs += 1;
5381                         break;
5382                 case CEE_LDNULL:
5383                         CHECK_STACK_OVF (1);
5384                         NEW_PCONST (cfg, ins, NULL);
5385                         ins->type = STACK_OBJ;
5386                         ++ip;
5387                         *sp++ = ins;
5388                         break;
5389                 case CEE_LDC_I4_M1:
5390                         CHECK_STACK_OVF (1);
5391                         NEW_ICONST (cfg, ins, -1);
5392                         ++ip;
5393                         *sp++ = ins;
5394                         break;
5395                 case CEE_LDC_I4_0:
5396                 case CEE_LDC_I4_1:
5397                 case CEE_LDC_I4_2:
5398                 case CEE_LDC_I4_3:
5399                 case CEE_LDC_I4_4:
5400                 case CEE_LDC_I4_5:
5401                 case CEE_LDC_I4_6:
5402                 case CEE_LDC_I4_7:
5403                 case CEE_LDC_I4_8:
5404                         CHECK_STACK_OVF (1);
5405                         NEW_ICONST (cfg, ins, (*ip) - CEE_LDC_I4_0);
5406                         ++ip;
5407                         *sp++ = ins;
5408                         break;
5409                 case CEE_LDC_I4_S:
5410                         CHECK_OPSIZE (2);
5411                         CHECK_STACK_OVF (1);
5412                         ++ip;
5413                         NEW_ICONST (cfg, ins, *((signed char*)ip));
5414                         ++ip;
5415                         *sp++ = ins;
5416                         break;
5417                 case CEE_LDC_I4:
5418                         CHECK_OPSIZE (5);
5419                         CHECK_STACK_OVF (1);
5420                         NEW_ICONST (cfg, ins, (gint32)read32 (ip + 1));
5421                         ip += 5;
5422                         *sp++ = ins;
5423                         break;
5424                 case CEE_LDC_I8:
5425                         CHECK_OPSIZE (9);
5426                         CHECK_STACK_OVF (1);
5427                         MONO_INST_NEW (cfg, ins, OP_I8CONST);
5428                         ins->type = STACK_I8;
5429                         ++ip;
5430                         ins->inst_l = (gint64)read64 (ip);
5431                         ip += 8;
5432                         *sp++ = ins;
5433                         break;
5434                 case CEE_LDC_R4: {
5435                         float *f;
5436                         /* we should really allocate this only late in the compilation process */
5437                         mono_domain_lock (cfg->domain);
5438                         f = mono_mempool_alloc (cfg->domain->mp, sizeof (float));
5439                         mono_domain_unlock (cfg->domain);
5440                         CHECK_OPSIZE (5);
5441                         CHECK_STACK_OVF (1);
5442                         MONO_INST_NEW (cfg, ins, OP_R4CONST);
5443                         ins->type = STACK_R8;
5444                         ++ip;
5445                         readr4 (ip, f);
5446                         ins->inst_p0 = f;
5447
5448                         ip += 4;
5449                         *sp++ = ins;                    
5450                         break;
5451                 }
5452                 case CEE_LDC_R8: {
5453                         double *d;
5454                         mono_domain_lock (cfg->domain);
5455                         d = mono_mempool_alloc (cfg->domain->mp, sizeof (double));
5456                         mono_domain_unlock (cfg->domain);
5457                         CHECK_OPSIZE (9);
5458                         CHECK_STACK_OVF (1);
5459                         MONO_INST_NEW (cfg, ins, OP_R8CONST);
5460                         ins->type = STACK_R8;
5461                         ++ip;
5462                         readr8 (ip, d);
5463                         ins->inst_p0 = d;
5464
5465                         ip += 8;
5466                         *sp++ = ins;                    
5467                         break;
5468                 }
5469                 case CEE_DUP: {
5470                         MonoInst *temp, *store;
5471                         CHECK_STACK (1);
5472                         CHECK_STACK_OVF (1);
5473                         sp--;
5474                         ins = *sp;
5475                 
5476                         /* 
5477                          * small optimization: if the loaded value was from a local already,
5478                          * just load it twice.
5479                          */
5480                         if (ins->ssa_op == MONO_SSA_LOAD && 
5481                             (ins->inst_i0->opcode == OP_LOCAL || ins->inst_i0->opcode == OP_ARG)) {
5482                                 sp++;
5483                                 MONO_INST_NEW (cfg, temp, 0);
5484                                 *temp = *ins;
5485                                 *sp++ = temp;
5486                         } else {
5487                                 temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
5488                                 temp->flags |= MONO_INST_IS_TEMP;
5489                                 NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
5490                                 /* FIXME: handle CEE_STIND_R4 */
5491                                 if (store->opcode == CEE_STOBJ) {
5492                                         NEW_TEMPLOADA (cfg, store, temp->inst_c0);
5493                                         handle_stobj (cfg, bblock, store, sp [0], sp [0]->cil_code, store->klass, TRUE, FALSE, FALSE);
5494                                 } else {
5495                                         MONO_ADD_INS (bblock, store);
5496                                 }
5497                                 NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
5498                                 *sp++ = ins;
5499                                 NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
5500                                 *sp++ = ins;
5501                         }
5502                         ++ip;
5503                         inline_costs += 2;
5504                         break;
5505                 }
5506                 case CEE_POP:
5507                         CHECK_STACK (1);
5508                         MONO_INST_NEW (cfg, ins, CEE_POP);
5509                         MONO_ADD_INS (bblock, ins);
5510                         ip++;
5511                         --sp;
5512                         ins->inst_i0 = *sp;
5513                         break;
5514                 case CEE_JMP:
5515                         CHECK_OPSIZE (5);
5516                         if (stack_start != sp)
5517                                 UNVERIFIED;
5518                         MONO_INST_NEW (cfg, ins, OP_JMP);
5519                         token = read32 (ip + 1);
5520                         /* FIXME: check the signature matches */
5521                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
5522
5523                         if (!cmethod)
5524                                 goto load_error;
5525
5526                         if (cfg->generic_sharing_context && mono_method_check_context_used (cmethod))
5527                                 GENERIC_SHARING_FAILURE (CEE_JMP);
5528
5529                         if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS) {
5530                                 if (check_linkdemand (cfg, method, cmethod, bblock, ip))
5531                                         INLINE_FAILURE;
5532                                 CHECK_CFG_EXCEPTION;
5533                         }
5534
5535                         ins->inst_p0 = cmethod;
5536                         MONO_ADD_INS (bblock, ins);
5537                         ip += 5;
5538                         start_new_bblock = 1;
5539                         break;
5540                 case CEE_CALLI:
5541                 case CEE_CALL:
5542                 case CEE_CALLVIRT: {
5543                         MonoInst *addr = NULL;
5544                         MonoMethodSignature *fsig = NULL;
5545                         int temp, array_rank = 0;
5546                         int virtual = *ip == CEE_CALLVIRT;
5547                         gboolean no_spill;
5548                         int context_used = 0;
5549                         gboolean pass_vtable = FALSE;
5550                         MonoInst *vtable_arg = NULL;
5551
5552                         CHECK_OPSIZE (5);
5553                         token = read32 (ip + 1);
5554
5555                         if (*ip == CEE_CALLI) {
5556                                 cmethod = NULL;
5557                                 CHECK_STACK (1);
5558                                 --sp;
5559                                 addr = *sp;
5560                                 if (method->wrapper_type != MONO_WRAPPER_NONE)
5561                                         fsig = (MonoMethodSignature *)mono_method_get_wrapper_data (method, token);
5562                                 else
5563                                         fsig = mono_metadata_parse_signature (image, token);
5564
5565                                 n = fsig->param_count + fsig->hasthis;
5566                         } else {
5567                                 MonoMethod *cil_method;
5568                                 
5569                                 if (method->wrapper_type != MONO_WRAPPER_NONE) {
5570                                         cmethod =  (MonoMethod *)mono_method_get_wrapper_data (method, token);
5571                                         cil_method = cmethod;
5572                                 } else if (constrained_call) {
5573                                         cmethod = mono_get_method_constrained (image, token, constrained_call, generic_context, &cil_method);
5574                                         cil_method = cmethod;
5575                                 } else {
5576                                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
5577                                         cil_method = cmethod;
5578                                 }
5579
5580                                 if (!cmethod)
5581                                         goto load_error;
5582                                 if (!dont_verify && !cfg->skip_visibility) {
5583                                         MonoMethod *target_method = cil_method;
5584                                         if (method->is_inflated) {
5585                                                 target_method = mini_get_method_allow_open (method, token, NULL, &(mono_method_get_generic_container (method_definition)->context));
5586                                         }
5587                                         if (!mono_method_can_access_method (method_definition, target_method) &&
5588                                                 !mono_method_can_access_method (method, cil_method))
5589                                                 METHOD_ACCESS_FAILURE;
5590                                 }
5591
5592                                 if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR)
5593                                         ensure_method_is_allowed_to_call_method (cfg, method, cil_method, bblock, ip);
5594
5595                                 if (!virtual && (cmethod->flags & METHOD_ATTRIBUTE_ABSTRACT))
5596                                         /* MS.NET seems to silently convert this to a callvirt */
5597                                         virtual = 1;
5598
5599                                 if (!cmethod->klass->inited){
5600                                         if (!mono_class_init (cmethod->klass))
5601                                                 goto load_error;
5602                                 }
5603
5604                                 if (mono_method_signature (cmethod)->pinvoke) {
5605                                         MonoMethod *wrapper = mono_marshal_get_native_wrapper (cmethod, check_for_pending_exc);
5606                                         fsig = mono_method_signature (wrapper);
5607                                 } else if (constrained_call) {
5608                                         fsig = mono_method_signature (cmethod);
5609                                 } else {
5610                                         fsig = mono_method_get_signature_full (cmethod, image, token, generic_context);
5611                                 }
5612
5613                                 mono_save_token_info (cfg, image, token, cmethod);
5614
5615                                 n = fsig->param_count + fsig->hasthis;
5616
5617                                 if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS) {
5618                                         if (check_linkdemand (cfg, method, cmethod, bblock, ip))
5619                                                 INLINE_FAILURE;
5620                                         CHECK_CFG_EXCEPTION;
5621                                 }
5622
5623                                 if (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL &&
5624                                     mini_class_is_system_array (cmethod->klass)) {
5625                                         array_rank = cmethod->klass->rank;
5626                                 }
5627
5628                                 if (cmethod->string_ctor)
5629                                         g_assert_not_reached ();
5630
5631                         }
5632
5633                         if (!cfg->generic_sharing_context && cmethod && cmethod->klass->generic_container)
5634                                 UNVERIFIED;
5635
5636                         CHECK_STACK (n);
5637
5638                         //g_assert (!virtual || fsig->hasthis);
5639
5640                         sp -= n;
5641
5642                         if (constrained_call) {
5643                                 /*
5644                                  * We have the `constrained.' prefix opcode.
5645                                  */
5646                                 if (constrained_call->valuetype && !cmethod->klass->valuetype) {
5647                                         MonoInst *load;
5648                                         /*
5649                                          * The type parameter is instantiated as a valuetype,
5650                                          * but that type doesn't override the method we're
5651                                          * calling, so we need to box `this'.
5652                                          * sp [0] is a pointer to the data: we need the value
5653                                          * in handle_box (), so load it here.
5654                                          */
5655                                         MONO_INST_NEW (cfg, load, mini_type_to_ldind (cfg, &constrained_call->byval_arg));
5656                                         type_to_eval_stack_type (cfg, &constrained_call->byval_arg, load);
5657                                         load->inst_left = sp [0];
5658                                         sp [0] = handle_box (cfg, bblock, load, ip, constrained_call);
5659                                 } else if (!constrained_call->valuetype) {
5660                                         MonoInst *ins;
5661
5662                                         /*
5663                                          * The type parameter is instantiated as a reference
5664                                          * type.  We have a managed pointer on the stack, so
5665                                          * we need to dereference it here.
5666                                          */
5667
5668                                         MONO_INST_NEW (cfg, ins, CEE_LDIND_REF);
5669                                         ins->inst_i0 = sp [0];
5670                                         ins->type = STACK_OBJ;
5671                                         ins->klass = mono_class_from_mono_type (&constrained_call->byval_arg);
5672                                         sp [0] = ins;
5673                                 } else if (cmethod->klass->valuetype)
5674                                         virtual = 0;
5675                                 constrained_call = NULL;
5676                         }
5677
5678                         if (*ip != CEE_CALLI && check_call_signature (cfg, fsig, sp))
5679                                 UNVERIFIED;
5680
5681                         if (cmethod && (cmethod->flags & METHOD_ATTRIBUTE_STATIC) &&
5682                                         (cmethod->klass->generic_class || cmethod->klass->generic_container)) {
5683                                 gboolean sharing_enabled = mono_class_generic_sharing_enabled (cmethod->klass);
5684                                 MonoGenericContext *context = mini_class_get_context (cmethod->klass);
5685                                 gboolean context_sharable = mono_generic_context_is_sharable (context, TRUE);
5686
5687                                 /*
5688                                  * Pass vtable iff target method might
5689                                  * be shared, which means that sharing
5690                                  * is enabled for its class and its
5691                                  * context is sharable (and it's not a
5692                                  * generic method).
5693                                  */
5694                                 if (sharing_enabled && context_sharable &&
5695                                                 !mini_method_get_context (cmethod)->method_inst)
5696                                         pass_vtable = TRUE;
5697                         }
5698
5699                         if (cfg->generic_sharing_context && cmethod) {
5700                                 MonoGenericContext *cmethod_context = mono_method_get_context (cmethod);
5701
5702                                 context_used = mono_method_check_context_used (cmethod);
5703
5704                                 if (context_used & MONO_GENERIC_CONTEXT_USED_METHOD)
5705                                         GENERIC_SHARING_FAILURE (*ip);
5706
5707                                 if (context_used &&
5708                                                 ((cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) ||
5709                                                 (cmethod_context && cmethod_context->method_inst && cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))) {
5710                                         GENERIC_SHARING_FAILURE (*ip);
5711                                 }
5712                         }
5713
5714                         if (pass_vtable) {
5715                                 if (context_used) {
5716                                         MonoInst *rgctx;
5717
5718                                         GET_RGCTX (rgctx);
5719                                         vtable_arg = get_runtime_generic_context_ptr (cfg, method, bblock, cmethod->klass,
5720                                                 token, MINI_TOKEN_SOURCE_METHOD, generic_context,
5721                                                 rgctx, MONO_RGCTX_INFO_VTABLE, ip);
5722                                 } else {
5723                                         MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
5724                                         
5725                                         CHECK_TYPELOAD (cmethod->klass);
5726                                         NEW_VTABLECONST (cfg, vtable_arg, vtable);
5727                                 }
5728                         }
5729
5730                         if (cmethod && virtual && 
5731                             (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) && 
5732                             !((cmethod->flags & METHOD_ATTRIBUTE_FINAL) && 
5733                               cmethod->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK) &&
5734                             mono_method_signature (cmethod)->generic_param_count) {
5735                                 MonoInst *this_temp, *this_arg_temp, *store;
5736                                 MonoInst *iargs [4];
5737
5738                                 g_assert (mono_method_signature (cmethod)->is_inflated);
5739                                 /* Prevent inlining of methods that contain indirect calls */
5740                                 INLINE_FAILURE;
5741
5742                                 this_temp = mono_compile_create_var (cfg, type_from_stack_type (sp [0]), OP_LOCAL);
5743                                 NEW_TEMPSTORE (cfg, store, this_temp->inst_c0, sp [0]);
5744                                 MONO_ADD_INS (bblock, store);
5745
5746                                 /* FIXME: This should be a managed pointer */
5747                                 this_arg_temp = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
5748
5749                                 /* Because of the PCONST below */
5750                                 cfg->disable_aot = TRUE;
5751                                 NEW_TEMPLOAD (cfg, iargs [0], this_temp->inst_c0);
5752                                 NEW_METHODCONST (cfg, iargs [1], cmethod);
5753                                 NEW_PCONST (cfg, iargs [2], mono_method_get_context (cmethod));
5754                                 NEW_TEMPLOADA (cfg, iargs [3], this_arg_temp->inst_c0);
5755                                 temp = mono_emit_jit_icall (cfg, bblock, mono_helper_compile_generic_method, iargs, ip);
5756
5757                                 NEW_TEMPLOAD (cfg, addr, temp);
5758                                 NEW_TEMPLOAD (cfg, sp [0], this_arg_temp->inst_c0);
5759
5760                                 if ((temp = mono_emit_calli_spilled (cfg, bblock, fsig, sp, addr, ip)) != -1) {
5761                                         NEW_TEMPLOAD (cfg, *sp, temp);
5762                                         sp++;
5763                                 }
5764
5765                                 ip += 5;
5766                                 ins_flag = 0;
5767                                 break;
5768                         }
5769
5770                         /* FIXME: runtime generic context pointer for jumps? */
5771                         if ((ins_flag & MONO_INST_TAILCALL) && !cfg->generic_sharing_context && !vtable_arg && cmethod && (*ip == CEE_CALL) &&
5772                                  (mono_metadata_signature_equal (mono_method_signature (method), mono_method_signature (cmethod)))) {
5773                                 int i;
5774
5775                                 GENERIC_SHARING_FAILURE (*ip);
5776
5777                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
5778                                 INLINE_FAILURE;
5779                                 /* FIXME: This assumes the two methods has the same number and type of arguments */
5780                                 /*
5781                                  * We implement tail calls by storing the actual arguments into the 
5782                                  * argument variables, then emitting a OP_JMP. Since the actual arguments
5783                                  * can refer to the arg variables, we have to spill them.
5784                                  */
5785                                 handle_loaded_temps (cfg, bblock, sp, sp + n);
5786                                 for (i = 0; i < n; ++i) {
5787                                         /* Prevent argument from being register allocated */
5788                                         arg_array [i]->flags |= MONO_INST_VOLATILE;
5789
5790                                         /* Check if argument is the same */
5791                                         /* 
5792                                          * FIXME: This loses liveness info, so it can only be done if the
5793                                          * argument is not register allocated.
5794                                          */
5795                                         NEW_ARGLOAD (cfg, ins, i);
5796                                         if ((ins->opcode == sp [i]->opcode) && (ins->inst_i0 == sp [i]->inst_i0))
5797                                                 continue;
5798
5799                                         NEW_ARGSTORE (cfg, ins, i, sp [i]);
5800                                         /* FIXME: handle CEE_STIND_R4 */
5801                                         if (ins->opcode == CEE_STOBJ) {
5802                                                 NEW_ARGLOADA (cfg, ins, i);
5803                                                 handle_stobj (cfg, bblock, ins, sp [i], sp [i]->cil_code, ins->klass, FALSE, FALSE, FALSE);
5804                                         }
5805                                         else
5806                                                 MONO_ADD_INS (bblock, ins);
5807                                 }
5808                                 MONO_INST_NEW (cfg, ins, OP_JMP);
5809                                 ins->inst_p0 = cmethod;
5810                                 ins->inst_p1 = arg_array [0];
5811                                 MONO_ADD_INS (bblock, ins);
5812                                 link_bblock (cfg, bblock, end_bblock);                  
5813                                 start_new_bblock = 1;
5814                                 /* skip CEE_RET as well */
5815                                 ip += 6;
5816                                 ins_flag = 0;
5817                                 break;
5818                         }
5819                         if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_get_inst_for_method (cfg, cmethod, fsig, sp))) {
5820                                 if (MONO_TYPE_IS_VOID (fsig->ret)) {
5821                                         MONO_ADD_INS (bblock, ins);
5822                                 } else {
5823                                         type_to_eval_stack_type (cfg, fsig->ret, ins);
5824                                         *sp = ins;
5825                                         sp++;
5826                                 }
5827
5828                                 ip += 5;
5829                                 ins_flag = 0;
5830                                 break;
5831                         }
5832
5833                         handle_loaded_temps (cfg, bblock, stack_start, sp);
5834
5835                         if ((cfg->opt & MONO_OPT_INLINE) && cmethod &&
5836                             (!virtual || !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) || (cmethod->flags & METHOD_ATTRIBUTE_FINAL)) && 
5837                             mono_method_check_inlining (cfg, cmethod) &&
5838                                  !g_list_find (dont_inline, cmethod)) {
5839                                 int costs;
5840                                 MonoBasicBlock *ebblock;
5841                                 gboolean allways = FALSE;
5842
5843                                 if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
5844                                         (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
5845                                         /* Prevent inlining of methods that call wrappers */
5846                                         INLINE_FAILURE;
5847                                         cmethod = mono_marshal_get_native_wrapper (cmethod, check_for_pending_exc);
5848                                         allways = TRUE;
5849                                 }
5850
5851                                 if ((costs = inline_method (cfg, cmethod, fsig, bblock, sp, ip, real_offset, dont_inline, &ebblock, allways))) {
5852                                         ip += 5;
5853                                         real_offset += 5;
5854
5855                                         GET_BBLOCK (cfg, bblock, ip);
5856                                         ebblock->next_bb = bblock;
5857                                         link_bblock (cfg, ebblock, bblock);
5858
5859                                         if (!MONO_TYPE_IS_VOID (fsig->ret))
5860                                                 sp++;
5861
5862                                         /* indicates start of a new block, and triggers a load of all 
5863                                            stack arguments at bb boundarie */
5864                                         bblock = ebblock;
5865
5866                                         inline_costs += costs;
5867                                         ins_flag = 0;
5868                                         break;
5869                                 }
5870                         }
5871                         
5872                         inline_costs += 10 * num_calls++;
5873
5874                         /* tail recursion elimination */
5875                         if ((cfg->opt & MONO_OPT_TAILC) && *ip == CEE_CALL && cmethod == method && ip [5] == CEE_RET &&
5876                                         !vtable_arg) {
5877                                 gboolean has_vtargs = FALSE;
5878                                 int i;
5879                                 
5880                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
5881                                 INLINE_FAILURE;
5882                                 /* keep it simple */
5883                                 for (i =  fsig->param_count - 1; i >= 0; i--) {
5884                                         if (MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->params [i])) 
5885                                                 has_vtargs = TRUE;
5886                                 }
5887
5888                                 if (!has_vtargs) {
5889                                         for (i = 0; i < n; ++i) {
5890                                                 /* FIXME: handle CEE_STIND_R4 */
5891                                                 NEW_ARGSTORE (cfg, ins, i, sp [i]);
5892                                                 MONO_ADD_INS (bblock, ins);
5893                                         }
5894                                         MONO_INST_NEW (cfg, ins, OP_BR);
5895                                         MONO_ADD_INS (bblock, ins);
5896                                         tblock = start_bblock->out_bb [0];
5897                                         link_bblock (cfg, bblock, tblock);
5898                                         ins->inst_target_bb = tblock;
5899                                         start_new_bblock = 1;
5900
5901                                         /* skip the CEE_RET, too */
5902                                         if (ip_in_bb (cfg, bblock, ip + 5))
5903                                                 ip += 6;
5904                                         else
5905                                                 ip += 5;
5906                                         ins_flag = 0;
5907                                         break;
5908                                 }
5909                         }
5910
5911                         if (ip_in_bb (cfg, bblock, ip + 5) 
5912                                 && (!MONO_TYPE_ISSTRUCT (fsig->ret))
5913                                 && (!MONO_TYPE_IS_VOID (fsig->ret) || (cmethod && cmethod->string_ctor))
5914                                 && (CODE_IS_STLOC (ip + 5) || ip [5] == CEE_POP || ip [5] == CEE_RET))
5915                                 /* No need to spill */
5916                                 no_spill = TRUE;
5917                         else
5918                                 no_spill = FALSE;
5919
5920                         if (context_used &&
5921                                         (cmethod->klass->valuetype ||
5922                                         (cmethod->is_inflated && mono_method_get_context (cmethod)->method_inst) ||
5923                                         ((cmethod->flags & METHOD_ATTRIBUTE_STATIC) &&
5924                                                 mono_class_generic_sharing_enabled (cmethod->klass)) ||
5925                                         (!mono_method_is_generic_sharable_impl (cmethod) &&
5926                                                 (!virtual || cmethod->flags & METHOD_ATTRIBUTE_FINAL ||
5927                                                 !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))))) {
5928                                 MonoInst *this = NULL, *rgctx;
5929
5930                                 INLINE_FAILURE;
5931
5932                                 g_assert (cfg->generic_sharing_context && cmethod);
5933                                 g_assert (addr == NULL);
5934
5935                                 /*
5936                                  * We are compiling a call to a
5937                                  * generic method from shared code,
5938                                  * which means that we have to look up
5939                                  * the method in the rgctx and do an
5940                                  * indirect call.
5941                                  */
5942
5943                                 GENERIC_SHARING_FAILURE_IF_VALUETYPE_METHOD (*ip);
5944
5945                                 if (!(method->flags & METHOD_ATTRIBUTE_STATIC))
5946                                         NEW_ARGLOAD (cfg, this, 0);
5947                                 rgctx = get_runtime_generic_context (cfg, method, this, ip);
5948                                 addr = get_runtime_generic_context_method (cfg, method, bblock, cmethod,
5949                                                 generic_context, rgctx, MONO_RGCTX_INFO_GENERIC_METHOD_CODE, ip);
5950                         }
5951
5952                         if (addr) {
5953                                 if (*ip == CEE_CALL) {
5954                                         g_assert (context_used);
5955                                 } else if (*ip == CEE_CALLI) {
5956                                         g_assert (!vtable_arg);
5957                                 } else {
5958                                         g_assert (cmethod->flags & METHOD_ATTRIBUTE_FINAL ||
5959                                                         !(cmethod->flags & METHOD_ATTRIBUTE_FINAL));
5960                                 }
5961
5962                                 /* Prevent inlining of methods with indirect calls */
5963                                 INLINE_FAILURE;
5964                                 if (no_spill) {
5965                                         ins = (MonoInst*)mono_emit_rgctx_calli (cfg, bblock, fsig, sp, addr, vtable_arg, ip);
5966                                         *sp++ = ins;                                    
5967                                 } else {
5968                                         temp = mono_emit_rgctx_calli_spilled (cfg, bblock, fsig, sp, addr, vtable_arg, ip);
5969                                         if (temp != -1) {
5970                                                 NEW_TEMPLOAD (cfg, *sp, temp);
5971                                                 sp++;
5972                                         }
5973                                 }                       
5974                         } else if (array_rank) {
5975                                 MonoInst *addr;
5976
5977                                 if (strcmp (cmethod->name, "Set") == 0) { /* array Set */ 
5978                                         if (sp [fsig->param_count]->type == STACK_OBJ) {
5979                                                 MonoInst *iargs [2];
5980                                                 MonoInst *array, *to_store, *store;
5981
5982                                                 handle_loaded_temps (cfg, bblock, stack_start, sp);
5983                                                 
5984                                                 array = mono_compile_create_var (cfg, type_from_stack_type (sp [0]), OP_LOCAL);
5985                                                 NEW_TEMPSTORE (cfg, store, array->inst_c0, sp [0]);
5986                                                 MONO_ADD_INS (bblock, store);
5987                                                 NEW_TEMPLOAD (cfg, iargs [0], array->inst_c0);
5988
5989                                                 to_store = mono_compile_create_var (cfg, type_from_stack_type (sp [fsig->param_count]), OP_LOCAL);
5990                                                 NEW_TEMPSTORE (cfg, store, to_store->inst_c0, sp [fsig->param_count]);
5991                                                 /* FIXME: handle CEE_STIND_R4 */
5992                                                 MONO_ADD_INS (bblock, store);
5993                                                 NEW_TEMPLOAD (cfg, iargs [1], to_store->inst_c0);
5994
5995                                                 /*
5996                                                  * We first save the args for the call so that the args are copied to the stack
5997                                                  * and a new instruction tree for them is created. If we don't do this,
5998                                                  * the same MonoInst is added to two different trees and this is not 
5999                                                  * allowed by burg.
6000                                                  */
6001                                                 mono_emit_jit_icall (cfg, bblock, mono_helper_stelem_ref_check, iargs, ip);
6002
6003                                                 NEW_TEMPLOAD (cfg, sp [0], array->inst_c0);
6004                                                 NEW_TEMPLOAD (cfg, sp [fsig->param_count], to_store->inst_c0);
6005                                         }
6006
6007                                         addr = mini_get_ldelema_ins (cfg, bblock, cmethod, sp, ip, TRUE);
6008                                         NEW_INDSTORE (cfg, ins, addr, sp [fsig->param_count], fsig->params [fsig->param_count - 1]);
6009                                         /* FIXME: handle CEE_STIND_R4 */
6010                                         if (ins->opcode == CEE_STOBJ) {
6011                                                 handle_stobj (cfg, bblock, addr, sp [fsig->param_count], ip, mono_class_from_mono_type (fsig->params [fsig->param_count-1]), FALSE, FALSE, TRUE);
6012                                         } else {
6013                                                 MONO_ADD_INS (bblock, ins);
6014                                         }
6015
6016                                 } else if (strcmp (cmethod->name, "Get") == 0) { /* array Get */
6017                                         addr = mini_get_ldelema_ins (cfg, bblock, cmethod, sp, ip, FALSE);
6018                                         NEW_INDLOAD (cfg, ins, addr, fsig->ret);
6019
6020                                         *sp++ = ins;
6021                                 } else if (strcmp (cmethod->name, "Address") == 0) { /* array Address */
6022                                         if (!cmethod->klass->element_class->valuetype && !readonly) {
6023                                                 MonoInst* check;
6024                                                 //* Needed by the code generated in inssel.brg * /
6025                                                 mono_get_got_var (cfg);
6026
6027                                                 MONO_INST_NEW (cfg, check, OP_CHECK_ARRAY_TYPE);
6028                                                 check->klass = cmethod->klass;
6029                                                 check->inst_left = sp [0];
6030                                                 check->type = STACK_OBJ;
6031                                                 sp [0] = check;
6032                                         }
6033
6034                                         readonly = FALSE;
6035                                         addr = mini_get_ldelema_ins (cfg, bblock, cmethod, sp, ip, FALSE);
6036                                         *sp++ = addr;
6037                                 } else {
6038                                         g_assert_not_reached ();
6039                                 }
6040
6041                         } else {
6042                                 /* Prevent inlining of methods which call other methods */
6043                                 INLINE_FAILURE;
6044                                 if (mini_redirect_call (&temp, cfg, bblock, cmethod, fsig, sp, ip, virtual ? sp [0] : NULL)) {
6045                                         if (temp != -1) {
6046                                                 NEW_TEMPLOAD (cfg, *sp, temp);
6047                                                 sp++;
6048                                         }
6049                                 } else if (no_spill) {
6050                                         ins = (MonoInst*)mono_emit_rgctx_method_call (cfg, bblock, cmethod, fsig, sp,
6051                                                         vtable_arg, ip, virtual ? sp [0] : NULL);
6052                                         *sp++ = ins;
6053                                 } else {
6054                                         if ((temp = mono_emit_rgctx_method_call_spilled (cfg, bblock, cmethod, fsig, sp,
6055                                                         vtable_arg, ip, virtual ? sp [0] : NULL)) != -1) {
6056                                                 MonoInst *load;
6057                                                 NEW_TEMPLOAD (cfg, load, temp);
6058
6059 #ifdef MONO_ARCH_SOFT_FLOAT
6060                                                 if (load->opcode == CEE_LDIND_R4) {
6061                                                         NEW_TEMPLOADA (cfg, load, temp);
6062                                                         temp = handle_load_float (cfg, bblock, load, ip);
6063                                                         NEW_TEMPLOAD (cfg, load, temp);
6064                                                 }
6065 #endif
6066                                                 *sp++ = load;
6067                                         }
6068                                 }
6069                         }
6070
6071                         ip += 5;
6072                         ins_flag = 0;
6073                         break;
6074                 }
6075                 case CEE_RET:
6076                         if (cfg->method != method) {
6077                                 /* return from inlined method */
6078                                 if (return_var) {
6079                                         MonoInst *store;
6080                                         CHECK_STACK (1);
6081                                         --sp;
6082                                         //g_assert (returnvar != -1);
6083                                         NEW_TEMPSTORE (cfg, store, return_var->inst_c0, *sp);
6084                                         store->cil_code = sp [0]->cil_code;
6085                                         /* FIXME: handle CEE_STIND_R4 */
6086                                         if (store->opcode == CEE_STOBJ) {
6087                                                 g_assert_not_reached ();
6088                                                 NEW_TEMPLOADA (cfg, store, return_var->inst_c0);
6089                                                 /* FIXME: it is possible some optimization will pass the a heap pointer for the struct address, so we'll need the write barrier */
6090                                                 handle_stobj (cfg, bblock, store, *sp, sp [0]->cil_code, return_var->klass, FALSE, FALSE, FALSE);
6091 #ifdef MONO_ARCH_SOFT_FLOAT
6092                                         } else if (store->opcode == CEE_STIND_R4) {
6093                                                 NEW_TEMPLOADA (cfg, store, return_var->inst_c0);
6094                                                 handle_store_float (cfg, bblock, store, *sp, sp [0]->cil_code);
6095 #endif
6096                                         } else
6097                                                 MONO_ADD_INS (bblock, store);
6098                                 } 
6099                         } else {
6100                                 if (cfg->ret) {
6101                                         g_assert (!return_var);
6102                                         CHECK_STACK (1);
6103                                         --sp;
6104                                         MONO_INST_NEW (cfg, ins, OP_NOP);
6105                                         ins->opcode = mini_type_to_stind (cfg, mono_method_signature (method)->ret);
6106                                         if (ins->opcode == CEE_STOBJ) {
6107                                                 NEW_RETLOADA (cfg, ins);
6108                                                 /* FIXME: it is possible some optimization will pass the a heap pointer for the struct address, so we'll need the write barrier */
6109                                                 handle_stobj (cfg, bblock, ins, *sp, ip, cfg->ret->klass, FALSE, FALSE, FALSE);
6110                                         } else {
6111                                                 ins->opcode = OP_SETRET;
6112                                                 ins->inst_i0 = *sp;;
6113                                                 ins->inst_i1 = NULL;
6114                                                 MONO_ADD_INS (bblock, ins);
6115                                         }
6116                                 }
6117                         }
6118                         if (sp != stack_start)
6119                                 UNVERIFIED;
6120                         MONO_INST_NEW (cfg, ins, OP_BR);
6121                         ip++;
6122                         ins->inst_target_bb = end_bblock;
6123                         MONO_ADD_INS (bblock, ins);
6124                         link_bblock (cfg, bblock, end_bblock);
6125                         start_new_bblock = 1;
6126                         break;
6127                 case CEE_BR_S:
6128                         CHECK_OPSIZE (2);
6129                         MONO_INST_NEW (cfg, ins, OP_BR);
6130                         ip++;
6131                         MONO_ADD_INS (bblock, ins);
6132                         target = ip + 1 + (signed char)(*ip);
6133                         ++ip;
6134                         GET_BBLOCK (cfg, tblock, target);
6135                         link_bblock (cfg, bblock, tblock);
6136                         CHECK_BBLOCK (target, ip, tblock);
6137                         ins->inst_target_bb = tblock;
6138                         if (sp != stack_start) {
6139                                 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
6140                                 sp = stack_start;
6141                                 CHECK_UNVERIFIABLE (cfg);
6142                         }
6143                         start_new_bblock = 1;
6144                         inline_costs += BRANCH_COST;
6145                         break;
6146                 case CEE_BRFALSE_S:
6147                 case CEE_BRTRUE_S:
6148                         CHECK_OPSIZE (2);
6149                         CHECK_STACK (1);
6150                         if (sp [-1]->type == STACK_VTYPE || sp [-1]->type == STACK_R8)
6151                                 UNVERIFIED;
6152                         MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
6153                         ip++;
6154                         target = ip + 1 + *(signed char*)ip;
6155                         ip++;
6156                         ADD_UNCOND (ins->opcode == CEE_BRTRUE);
6157                         if (sp != stack_start) {
6158                                 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
6159                                 sp = stack_start;
6160                                 CHECK_UNVERIFIABLE (cfg);
6161                         }
6162                         inline_costs += BRANCH_COST;
6163                         break;
6164                 case CEE_BEQ_S:
6165                 case CEE_BGE_S:
6166                 case CEE_BGT_S:
6167                 case CEE_BLE_S:
6168                 case CEE_BLT_S:
6169                 case CEE_BNE_UN_S:
6170                 case CEE_BGE_UN_S:
6171                 case CEE_BGT_UN_S:
6172                 case CEE_BLE_UN_S:
6173                 case CEE_BLT_UN_S:
6174                         CHECK_OPSIZE (2);
6175                         CHECK_STACK (2);
6176                         MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
6177                         ip++;
6178                         target = ip + 1 + *(signed char*)ip;
6179                         ip++;
6180 #ifdef MONO_ARCH_SOFT_FLOAT
6181                         if (sp [-1]->type == STACK_R8 || sp [-2]->type == STACK_R8) {
6182                                 ins->opcode = condbr_to_fp_br (ins->opcode);
6183                                 sp -= 2;
6184                                 ins->inst_left = sp [0];
6185                                 ins->inst_right = sp [1];
6186                                 ins->type = STACK_I4;
6187                                 *sp++ = emit_tree (cfg, bblock, ins, ins->cil_code);
6188                                 MONO_INST_NEW (cfg, ins, CEE_BRTRUE);
6189                                 ADD_UNCOND (TRUE);
6190                         } else {
6191                                 ADD_BINCOND (NULL);
6192                         }
6193 #else
6194                         ADD_BINCOND (NULL);
6195 #endif
6196                         if (sp != stack_start) {
6197                                 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
6198                                 sp = stack_start;
6199                                 CHECK_UNVERIFIABLE (cfg);
6200                         }
6201                         inline_costs += BRANCH_COST;
6202                         break;
6203                 case CEE_BR:
6204                         CHECK_OPSIZE (5);
6205                         MONO_INST_NEW (cfg, ins, OP_BR);
6206                         ip++;
6207                         MONO_ADD_INS (bblock, ins);
6208                         target = ip + 4 + (gint32)read32(ip);
6209                         ip += 4;
6210                         GET_BBLOCK (cfg, tblock, target);
6211                         link_bblock (cfg, bblock, tblock);
6212                         CHECK_BBLOCK (target, ip, tblock);
6213                         ins->inst_target_bb = tblock;
6214                         if (sp != stack_start) {
6215                                 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
6216                                 sp = stack_start;
6217                                 CHECK_UNVERIFIABLE (cfg);
6218                         }
6219                         start_new_bblock = 1;
6220                         inline_costs += BRANCH_COST;
6221                         break;
6222                 case CEE_BRFALSE:
6223                 case CEE_BRTRUE:
6224                         CHECK_OPSIZE (5);
6225                         CHECK_STACK (1);
6226                         if (sp [-1]->type == STACK_VTYPE || sp [-1]->type == STACK_R8)
6227                                 UNVERIFIED;
6228                         MONO_INST_NEW (cfg, ins, *ip);
6229                         ip++;
6230                         target = ip + 4 + (gint32)read32(ip);
6231                         ip += 4;
6232                         ADD_UNCOND(ins->opcode == CEE_BRTRUE);
6233                         if (sp != stack_start) {
6234                                 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
6235                                 sp = stack_start;
6236                                 CHECK_UNVERIFIABLE (cfg);
6237                         }
6238                         inline_costs += BRANCH_COST;
6239                         break;
6240                 case CEE_BEQ:
6241                 case CEE_BGE:
6242                 case CEE_BGT:
6243                 case CEE_BLE:
6244                 case CEE_BLT:
6245                 case CEE_BNE_UN:
6246                 case CEE_BGE_UN:
6247                 case CEE_BGT_UN:
6248                 case CEE_BLE_UN:
6249                 case CEE_BLT_UN:
6250                         CHECK_OPSIZE (5);
6251                         CHECK_STACK (2);
6252                         MONO_INST_NEW (cfg, ins, *ip);
6253                         ip++;
6254                         target = ip + 4 + (gint32)read32(ip);
6255                         ip += 4;
6256 #ifdef MONO_ARCH_SOFT_FLOAT
6257                         if (sp [-1]->type == STACK_R8 || sp [-2]->type == STACK_R8) {
6258                                 ins->opcode = condbr_to_fp_br (ins->opcode);
6259                                 sp -= 2;
6260                                 ins->inst_left = sp [0];
6261                                 ins->inst_right = sp [1];
6262                                 ins->type = STACK_I4;
6263                                 *sp++ = emit_tree (cfg, bblock, ins, ins->cil_code);
6264                                 MONO_INST_NEW (cfg, ins, CEE_BRTRUE);
6265                                 ADD_UNCOND (TRUE);
6266                         } else {
6267                                 ADD_BINCOND (NULL);
6268                         }
6269 #else
6270                         ADD_BINCOND (NULL);
6271 #endif
6272                         if (sp != stack_start) {
6273                                 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
6274                                 sp = stack_start;
6275                                 CHECK_UNVERIFIABLE (cfg);
6276                         }
6277                         inline_costs += BRANCH_COST;
6278                         break;
6279                 case CEE_SWITCH:
6280                         CHECK_OPSIZE (5);
6281                         CHECK_STACK (1);
6282                         n = read32 (ip + 1);
6283                         MONO_INST_NEW (cfg, ins, OP_SWITCH);
6284                         --sp;
6285                         ins->inst_left = *sp;
6286                         if ((ins->inst_left->type != STACK_I4) && (ins->inst_left->type != STACK_PTR)) 
6287                                 UNVERIFIED;
6288                         ip += 5;
6289                         CHECK_OPSIZE (n * sizeof (guint32));
6290                         target = ip + n * sizeof (guint32);
6291                         MONO_ADD_INS (bblock, ins);
6292                         GET_BBLOCK (cfg, tblock, target);
6293                         link_bblock (cfg, bblock, tblock);
6294                         ins->klass = GUINT_TO_POINTER (n);
6295                         ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * (n + 1));
6296                         ins->inst_many_bb [n] = tblock;
6297
6298                         for (i = 0; i < n; ++i) {
6299                                 GET_BBLOCK (cfg, tblock, target + (gint32)read32(ip));
6300                                 link_bblock (cfg, bblock, tblock);
6301                                 ins->inst_many_bb [i] = tblock;
6302                                 ip += 4;
6303                         }
6304                         if (sp != stack_start) {
6305                                 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
6306                                 sp = stack_start;
6307                                 CHECK_UNVERIFIABLE (cfg);
6308                         }
6309                         /* Needed by the code generated in inssel.brg */
6310                         mono_get_got_var (cfg);
6311                         inline_costs += (BRANCH_COST * 2);
6312                         break;
6313                 case CEE_LDIND_I1:
6314                 case CEE_LDIND_U1:
6315                 case CEE_LDIND_I2:
6316                 case CEE_LDIND_U2:
6317                 case CEE_LDIND_I4:
6318                 case CEE_LDIND_U4:
6319                 case CEE_LDIND_I8:
6320                 case CEE_LDIND_I:
6321                 case CEE_LDIND_R4:
6322                 case CEE_LDIND_R8:
6323                 case CEE_LDIND_REF:
6324                         CHECK_STACK (1);
6325                         MONO_INST_NEW (cfg, ins, *ip);
6326                         --sp;
6327                         ins->inst_i0 = *sp;
6328                         *sp++ = ins;
6329                         ins->type = ldind_type [*ip - CEE_LDIND_I1];
6330                         ins->flags |= ins_flag;
6331                         ins_flag = 0;
6332                         if (ins->type == STACK_OBJ)
6333                                 ins->klass = mono_defaults.object_class;
6334 #ifdef MONO_ARCH_SOFT_FLOAT
6335                         if (*ip == CEE_LDIND_R4) {
6336                                 int temp;
6337                                 --sp;
6338                                 temp = handle_load_float (cfg, bblock, ins->inst_i0, ip);
6339                                 NEW_TEMPLOAD (cfg, *sp, temp);
6340                                 sp++;
6341                         }
6342 #endif
6343                         ++ip;
6344                         break;
6345                 case CEE_STIND_REF:
6346                 case CEE_STIND_I1:
6347                 case CEE_STIND_I2:
6348                 case CEE_STIND_I4:
6349                 case CEE_STIND_I8:
6350                 case CEE_STIND_R4:
6351                 case CEE_STIND_R8:
6352                         CHECK_STACK (2);
6353 #ifdef MONO_ARCH_SOFT_FLOAT
6354                         if (*ip == CEE_STIND_R4) {
6355                                 sp -= 2;
6356                                 handle_store_float (cfg, bblock, sp [0], sp [1], ip);
6357                                 ip++;
6358                                 break;
6359                         }
6360 #endif
6361 #if HAVE_WRITE_BARRIERS
6362                         if (*ip == CEE_STIND_REF && method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER && !((sp [-1]->opcode == OP_PCONST) && (sp [-1]->inst_p0 == 0))) {
6363                                 /* insert call to write barrier */
6364                                 MonoMethod *write_barrier = mono_marshal_get_write_barrier ();
6365                                 sp -= 2;
6366                                 mono_emit_method_call_spilled (cfg, bblock, write_barrier, mono_method_signature (write_barrier), sp, ip, NULL);
6367                                 ip++;
6368                                 break;
6369                         }
6370 #endif
6371                         MONO_INST_NEW (cfg, ins, *ip);
6372                         ip++;
6373                         sp -= 2;
6374                         handle_loaded_temps (cfg, bblock, stack_start, sp);
6375                         MONO_ADD_INS (bblock, ins);
6376                         ins->inst_i0 = sp [0];
6377                         ins->inst_i1 = sp [1];
6378                         ins->flags |= ins_flag;
6379                         ins_flag = 0;
6380                         inline_costs += 1;
6381                         break;
6382                 case CEE_MUL:
6383                         CHECK_STACK (2);
6384                         ADD_BINOP (*ip);
6385
6386 #ifdef MONO_ARCH_NO_EMULATE_MUL_IMM
6387                         /* FIXME: This breaks with ssapre (mono -O=ssapre loader.exe) */
6388                         if ((ins->inst_right->opcode == OP_ICONST) && !(cfg->opt & MONO_OPT_SSAPRE)) {
6389                                 switch (ins->opcode) {
6390                                 case CEE_MUL:
6391                                         ins->opcode = OP_IMUL_IMM;
6392                                         ins->inst_imm = ins->inst_right->inst_c0;
6393                                         break;
6394                                 case OP_LMUL:
6395                                         ins->opcode = OP_LMUL_IMM;
6396                                         ins->inst_imm = ins->inst_right->inst_c0;
6397                                         break;
6398                                 default:
6399                                         g_assert_not_reached ();
6400                                 }
6401                         }
6402 #endif
6403
6404                         if (mono_find_jit_opcode_emulation (ins->opcode)) {
6405                                 --sp;
6406                                 *sp++ = emit_tree (cfg, bblock, ins, ip + 1);
6407                         }
6408                         ip++;
6409                         break;
6410                 case CEE_ADD:
6411                 case CEE_SUB:
6412                 case CEE_DIV:
6413                 case CEE_DIV_UN:
6414                 case CEE_REM:
6415                 case CEE_REM_UN:
6416                 case CEE_AND:
6417                 case CEE_OR:
6418                 case CEE_XOR:
6419                 case CEE_SHL:
6420                 case CEE_SHR:
6421                 case CEE_SHR_UN:
6422                         CHECK_STACK (2);
6423                         ADD_BINOP (*ip);
6424                         /* special case that gives a nice speedup and happens to workaorund a ppc jit but (for the release)
6425                          * later apply the speedup to the left shift as well
6426                          * See BUG# 57957.
6427                          */
6428                         if ((ins->opcode == OP_LSHR_UN) && (ins->type == STACK_I8) 
6429                                         && (ins->inst_right->opcode == OP_ICONST) && (ins->inst_right->inst_c0 == 32)) {
6430                                 ins->opcode = OP_LONG_SHRUN_32;
6431                                 /*g_print ("applied long shr speedup to %s\n", cfg->method->name);*/
6432                                 ip++;
6433                                 break;
6434                         }
6435                         if (mono_find_jit_opcode_emulation (ins->opcode)) {
6436                                 --sp;
6437                                 *sp++ = emit_tree (cfg, bblock, ins, ip + 1);
6438                         }
6439                         ip++;
6440                         break;
6441                 case CEE_NEG:
6442                 case CEE_NOT:
6443                 case CEE_CONV_I1:
6444                 case CEE_CONV_I2:
6445                 case CEE_CONV_I4:
6446                 case CEE_CONV_R4:
6447                 case CEE_CONV_R8:
6448                 case CEE_CONV_U4:
6449                 case CEE_CONV_I8:
6450                 case CEE_CONV_U8:
6451                 case CEE_CONV_OVF_I8:
6452                 case CEE_CONV_OVF_U8:
6453                 case CEE_CONV_R_UN:
6454                         CHECK_STACK (1);
6455                         ADD_UNOP (*ip);
6456                         if (mono_find_jit_opcode_emulation (ins->opcode)) {
6457                                 --sp;
6458                                 *sp++ = emit_tree (cfg, bblock, ins, ip + 1);
6459                         }
6460                         ip++;                   
6461                         break;
6462                 case CEE_CONV_OVF_I4:
6463                 case CEE_CONV_OVF_I1:
6464                 case CEE_CONV_OVF_I2:
6465                 case CEE_CONV_OVF_I:
6466                 case CEE_CONV_OVF_U:
6467                         CHECK_STACK (1);
6468
6469                         if (sp [-1]->type == STACK_R8) {
6470                                 ADD_UNOP (CEE_CONV_OVF_I8);
6471                                 ADD_UNOP (*ip);
6472                         } else {
6473                                 ADD_UNOP (*ip);
6474                         }
6475
6476                         ip++;
6477                         break;
6478                 case CEE_CONV_OVF_U1:
6479                 case CEE_CONV_OVF_U2:
6480                 case CEE_CONV_OVF_U4:
6481                         CHECK_STACK (1);
6482
6483                         if (sp [-1]->type == STACK_R8) {
6484                                 ADD_UNOP (CEE_CONV_OVF_U8);
6485                                 ADD_UNOP (*ip);
6486                         } else {
6487                                 ADD_UNOP (*ip);
6488                         }
6489
6490                         ip++;
6491                         break;
6492                 case CEE_CONV_OVF_I1_UN:
6493                 case CEE_CONV_OVF_I2_UN:
6494                 case CEE_CONV_OVF_I4_UN:
6495                 case CEE_CONV_OVF_I8_UN:
6496                 case CEE_CONV_OVF_U1_UN:
6497                 case CEE_CONV_OVF_U2_UN:
6498                 case CEE_CONV_OVF_U4_UN:
6499                 case CEE_CONV_OVF_U8_UN:
6500                 case CEE_CONV_OVF_I_UN:
6501                 case CEE_CONV_OVF_U_UN:
6502                         CHECK_STACK (1);
6503                         ADD_UNOP (*ip);
6504                         ip++;
6505                         break;
6506                 case CEE_CPOBJ:
6507                         CHECK_OPSIZE (5);
6508                         CHECK_STACK (2);
6509                         token = read32 (ip + 1);
6510                         klass = mini_get_class (method, token, generic_context);
6511                         CHECK_TYPELOAD (klass);
6512                         sp -= 2;
6513                         if (generic_class_is_reference_type (cfg, klass)) {
6514                                 MonoInst *store, *load;
6515                                 MONO_INST_NEW (cfg, load, CEE_LDIND_REF);
6516                                 load->inst_i0 = sp [1];
6517                                 load->type = STACK_OBJ;
6518                                 load->klass = klass;
6519                                 load->flags |= ins_flag;
6520                                 MONO_INST_NEW (cfg, store, CEE_STIND_REF);
6521                                 handle_loaded_temps (cfg, bblock, stack_start, sp);
6522                                 MONO_ADD_INS (bblock, store);
6523                                 store->inst_i0 = sp [0];
6524                                 store->inst_i1 = load;
6525                                 store->flags |= ins_flag;
6526                         } else {
6527                                 guint32 align;
6528
6529                                 n = mono_class_value_size (klass, &align);
6530                                 if ((cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 5) {
6531                                         MonoInst *copy;
6532                                         NEW_MEMCPY (cfg, copy, sp [0], sp [1], n, align);
6533                                         MONO_ADD_INS (bblock, copy);
6534                                 } else {
6535                                         MonoMethod *memcpy_method = get_memcpy_method ();
6536                                         MonoInst *iargs [3];
6537                                         iargs [0] = sp [0];
6538                                         iargs [1] = sp [1];
6539                                         NEW_ICONST (cfg, iargs [2], n);
6540
6541                                         mono_emit_method_call_spilled (cfg, bblock, memcpy_method, memcpy_method->signature, iargs, ip, NULL);
6542                                 }
6543                         }
6544                         ins_flag = 0;
6545                         ip += 5;
6546                         break;
6547                 case CEE_LDOBJ: {
6548                         MonoInst *iargs [3];
6549                         int loc_index = -1;
6550                         int stloc_len = 0;
6551                         guint32 align;
6552
6553                         CHECK_OPSIZE (5);
6554                         CHECK_STACK (1);
6555                         --sp;
6556                         token = read32 (ip + 1);
6557                         klass = mini_get_class (method, token, generic_context);
6558                         CHECK_TYPELOAD (klass);
6559                         if (generic_class_is_reference_type (cfg, klass)) {
6560                                 MONO_INST_NEW (cfg, ins, CEE_LDIND_REF);
6561                                 ins->inst_i0 = sp [0];
6562                                 ins->type = STACK_OBJ;
6563                                 ins->klass = klass;
6564                                 ins->flags |= ins_flag;
6565                                 ins_flag = 0;
6566                                 *sp++ = ins;
6567                                 ip += 5;
6568                                 break;
6569                         }
6570
6571                         /* Optimize the common ldobj+stloc combination */
6572                         switch (ip [5]) {
6573                         case CEE_STLOC_S:
6574                                 loc_index = ip [6];
6575                                 stloc_len = 2;
6576                                 break;
6577                         case CEE_STLOC_0:
6578                         case CEE_STLOC_1:
6579                         case CEE_STLOC_2:
6580                         case CEE_STLOC_3:
6581                                 loc_index = ip [5] - CEE_STLOC_0;
6582                                 stloc_len = 1;
6583                                 break;
6584                         default:
6585                                 break;
6586                         }
6587
6588                         if ((loc_index != -1) && ip_in_bb (cfg, bblock, ip + 5)) {
6589                                 CHECK_LOCAL (loc_index);
6590                                 NEW_LOCSTORE (cfg, ins, loc_index, *sp);
6591
6592                                 /* FIXME: handle CEE_STIND_R4 */
6593                                 if (ins->opcode == CEE_STOBJ) {
6594                                         handle_loaded_temps (cfg, bblock, stack_start, sp);
6595                                         g_assert (ins->opcode == CEE_STOBJ);
6596                                         NEW_LOCLOADA (cfg, ins, loc_index);
6597                                         handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE, FALSE);
6598                                         ip += 5;
6599                                         ip += stloc_len;
6600                                         break;
6601                                 }
6602                         }
6603
6604                         n = mono_class_value_size (klass, &align);
6605                         ins = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
6606                         NEW_TEMPLOADA (cfg, iargs [0], ins->inst_c0);
6607                         if ((cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 5) {
6608                                 MonoInst *copy;
6609                                 NEW_MEMCPY (cfg, copy, iargs [0], *sp, n, align);
6610                                 MONO_ADD_INS (bblock, copy);
6611                         } else {
6612                                 MonoMethod *memcpy_method = get_memcpy_method ();
6613                                 iargs [1] = *sp;
6614                                 NEW_ICONST (cfg, iargs [2], n);
6615
6616                                 mono_emit_method_call_spilled (cfg, bblock, memcpy_method, memcpy_method->signature, iargs, ip, NULL);
6617                         }
6618                         NEW_TEMPLOAD (cfg, *sp, ins->inst_c0);
6619                         ++sp;
6620                         ip += 5;
6621                         ins_flag = 0;
6622                         inline_costs += 1;
6623                         break;
6624                 }
6625                 case CEE_LDSTR:
6626                         CHECK_STACK_OVF (1);
6627                         CHECK_OPSIZE (5);
6628                         n = read32 (ip + 1);
6629
6630                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
6631                                 /* FIXME: moving GC */
6632                                 NEW_PCONST (cfg, ins, mono_method_get_wrapper_data (method, n));
6633                                 ins->type = STACK_OBJ;
6634                                 ins->klass = mono_defaults.string_class;
6635                                 *sp = ins;
6636                         }
6637                         else if (method->wrapper_type != MONO_WRAPPER_NONE) {
6638                                 int temp;
6639                                 MonoInst *iargs [1];
6640
6641                                 NEW_PCONST (cfg, iargs [0], mono_method_get_wrapper_data (method, n));                          
6642                                 temp = mono_emit_jit_icall (cfg, bblock, mono_string_new_wrapper, iargs, ip);
6643                                 NEW_TEMPLOAD (cfg, *sp, temp);
6644
6645                         } else {
6646
6647                                 if (cfg->opt & MONO_OPT_SHARED) {
6648                                         int temp;
6649                                         MonoInst *iargs [3];
6650                                         MonoInst* domain_var;
6651                                         
6652                                         if (cfg->compile_aot) {
6653                                                 /* FIXME: bug when inlining methods from different assemblies (n is a token valid just in one). */
6654                                                 cfg->ldstr_list = g_list_prepend (cfg->ldstr_list, GINT_TO_POINTER (n));
6655                                         }
6656                                         /* avoid depending on undefined C behavior in sequence points */
6657                                         domain_var = mono_get_domainvar (cfg);
6658                                         NEW_TEMPLOAD (cfg, iargs [0], domain_var->inst_c0);
6659                                         NEW_IMAGECONST (cfg, iargs [1], image);
6660                                         NEW_ICONST (cfg, iargs [2], mono_metadata_token_index (n));
6661                                         temp = mono_emit_jit_icall (cfg, bblock, mono_ldstr, iargs, ip);
6662                                         NEW_TEMPLOAD (cfg, *sp, temp);
6663                                         mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
6664                                 } else {
6665                                         if (bblock->out_of_line) {
6666                                                 MonoInst *iargs [2];
6667                                                 int temp;
6668
6669                                                 if (cfg->method->klass->image == mono_defaults.corlib) {
6670                                                         /* 
6671                                                          * Avoid relocations and save some code size by using a 
6672                                                          * version of helper_ldstr specialized to mscorlib.
6673                                                          */
6674                                                         NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (n));
6675                                                         temp = mono_emit_jit_icall (cfg, bblock, mono_helper_ldstr_mscorlib, iargs, ip);
6676                                                 } else {
6677                                                         /* Avoid creating the string object */
6678                                                         NEW_IMAGECONST (cfg, iargs [0], image);
6679                                                         NEW_ICONST (cfg, iargs [1], mono_metadata_token_index (n));
6680                                                         temp = mono_emit_jit_icall (cfg, bblock, mono_helper_ldstr, iargs, ip);
6681                                                 }
6682                                                 NEW_TEMPLOAD (cfg, *sp, temp);
6683                                         } 
6684                                         else
6685                                         if (cfg->compile_aot) {
6686                                                 NEW_LDSTRCONST (cfg, ins, image, n);
6687                                                 *sp = ins;
6688                                         } 
6689                                         else {
6690                                                 NEW_PCONST (cfg, ins, NULL);
6691                                                 ins->type = STACK_OBJ;
6692                                                 ins->inst_p0 = mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
6693                                                 ins->klass = mono_defaults.string_class;
6694                                                 *sp = ins;
6695                                         }
6696                                 }
6697                         }
6698
6699                         sp++;
6700                         ip += 5;
6701                         break;
6702                 case CEE_NEWOBJ: {
6703                         MonoInst *iargs [2];
6704                         MonoMethodSignature *fsig;
6705                         int temp;
6706                         gboolean generic_shared = FALSE;
6707
6708                         CHECK_OPSIZE (5);
6709                         token = read32 (ip + 1);
6710                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
6711                         if (!cmethod)
6712                                 goto load_error;
6713                         fsig = mono_method_get_signature (cmethod, image, token);
6714
6715                         mono_save_token_info (cfg, image, token, cmethod);
6716
6717                         if (!mono_class_init (cmethod->klass))
6718                                 goto load_error;
6719
6720                         if (cfg->generic_sharing_context) {
6721                                 int context_used = mono_method_check_context_used (cmethod);
6722
6723                                 if (context_used & MONO_GENERIC_CONTEXT_USED_METHOD)
6724                                         GENERIC_SHARING_FAILURE (CEE_NEWOBJ);
6725
6726                                 if (context_used)
6727                                         generic_shared = TRUE;
6728                         }
6729
6730                         if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS) {
6731                                 if (check_linkdemand (cfg, method, cmethod, bblock, ip))
6732                                         INLINE_FAILURE;
6733                                 CHECK_CFG_EXCEPTION;
6734                         } else if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR) {
6735                                 ensure_method_is_allowed_to_call_method (cfg, method, cmethod, bblock, ip);
6736                         }
6737
6738                         n = fsig->param_count;
6739                         CHECK_STACK (n);
6740  
6741                         /* 
6742                          * Generate smaller code for the common newobj <exception> instruction in
6743                          * argument checking code.
6744                          */
6745                         if (bblock->out_of_line && cmethod->klass->image == mono_defaults.corlib && n <= 2 && 
6746                                 ((n < 1) || (!fsig->params [0]->byref && fsig->params [0]->type == MONO_TYPE_STRING)) && 
6747                                 ((n < 2) || (!fsig->params [1]->byref && fsig->params [1]->type == MONO_TYPE_STRING))) {
6748                                 MonoInst *iargs [3];
6749                                 int temp;
6750                                 
6751                                 sp -= n;
6752
6753                                 NEW_ICONST (cfg, iargs [0], cmethod->klass->type_token);
6754                                 switch (n) {
6755                                 case 0:
6756                                         temp = mono_emit_jit_icall (cfg, bblock, mono_create_corlib_exception_0, iargs, ip);
6757                                         break;
6758                                 case 1:
6759                                         iargs [1] = sp [0];
6760                                         temp = mono_emit_jit_icall (cfg, bblock, mono_create_corlib_exception_1, iargs, ip);
6761                                         break;
6762                                 case 2:
6763                                         iargs [1] = sp [0];
6764                                         iargs [2] = sp [1];
6765                                         temp = mono_emit_jit_icall (cfg, bblock, mono_create_corlib_exception_2, iargs, ip);
6766                                         break;
6767                                 default:
6768                                         g_assert_not_reached ();
6769                                 }
6770                                 NEW_TEMPLOAD (cfg, ins, temp);
6771                                 *sp ++ = ins;
6772
6773                                 ip += 5;
6774                                 inline_costs += 5;
6775                                 break;
6776                         }
6777
6778                         /* move the args to allow room for 'this' in the first position */
6779                         while (n--) {
6780                                 --sp;
6781                                 sp [1] = sp [0];
6782                         }
6783
6784                         handle_loaded_temps (cfg, bblock, stack_start, sp);
6785
6786                         if (mini_class_is_system_array (cmethod->klass)) {
6787                                 g_assert (!generic_shared);
6788
6789                                 NEW_METHODCONST (cfg, *sp, cmethod);
6790                                 temp = handle_array_new (cfg, bblock, fsig->param_count, sp, ip);
6791                         } else if (cmethod->string_ctor) {
6792                                 g_assert (!generic_shared);
6793
6794                                 /* we simply pass a null pointer */
6795                                 NEW_PCONST (cfg, *sp, NULL); 
6796                                 /* now call the string ctor */
6797                                 temp = mono_emit_method_call_spilled (cfg, bblock, cmethod, fsig, sp, ip, NULL);
6798                         } else {
6799                                 MonoInst* callvirt_this_arg = NULL;
6800                                 
6801                                 if (cmethod->klass->valuetype) {
6802                                         iargs [0] = mono_compile_create_var (cfg, &cmethod->klass->byval_arg, OP_LOCAL);
6803                                         temp = iargs [0]->inst_c0;
6804
6805                                         NEW_TEMPLOADA (cfg, *sp, temp);
6806
6807                                         handle_initobj (cfg, bblock, *sp, NULL, cmethod->klass, stack_start, sp);
6808
6809                                         NEW_TEMPLOADA (cfg, *sp, temp);
6810
6811                                         /* 
6812                                          * The code generated by mini_emit_virtual_call () expects
6813                                          * iargs [0] to be a boxed instance, but luckily the vcall
6814                                          * will be transformed into a normal call there.
6815                                          */
6816                                 } else if (generic_shared) {
6817                                         MonoInst *rgctx, *data;
6818                                         int rgctx_info;
6819
6820                                         GET_RGCTX (rgctx);
6821                                         if (cfg->opt & MONO_OPT_SHARED)
6822                                                 rgctx_info = MONO_RGCTX_INFO_KLASS;
6823                                         else
6824                                                 rgctx_info = MONO_RGCTX_INFO_VTABLE;
6825                                         data = get_runtime_generic_context_ptr (cfg, method, bblock, cmethod->klass,
6826                                                 token, MINI_TOKEN_SOURCE_METHOD, generic_context,
6827                                                 rgctx, rgctx_info, ip);
6828
6829                                         temp = handle_alloc_from_inst (cfg, bblock, cmethod->klass, data, FALSE, ip);
6830                                         NEW_TEMPLOAD (cfg, *sp, temp);
6831                                 } else {
6832                                         MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
6833
6834                                         CHECK_TYPELOAD (cmethod->klass);
6835                                         if (mini_field_access_needs_cctor_run (cfg, method, vtable) && !(g_slist_find (class_inits, vtable))) {
6836                                                 guint8 *tramp = mono_create_class_init_trampoline (vtable);
6837                                                 mono_emit_native_call (cfg, bblock, tramp, 
6838                                                                                            helper_sig_class_init_trampoline,
6839                                                                                            NULL, ip, FALSE, FALSE);
6840                                                 if (cfg->verbose_level > 2)
6841                                                         g_print ("class %s.%s needs init call for ctor\n", cmethod->klass->name_space, cmethod->klass->name);
6842                                                 class_inits = g_slist_prepend (class_inits, vtable);
6843                                         }
6844                                         temp = handle_alloc (cfg, bblock, cmethod->klass, FALSE, ip);
6845                                         NEW_TEMPLOAD (cfg, *sp, temp);
6846                                 }
6847
6848                                 /* Avoid virtual calls to ctors if possible */
6849                                 if (cmethod->klass->marshalbyref)
6850                                         callvirt_this_arg = sp [0];
6851                                 
6852                                 if ((cfg->opt & MONO_OPT_INLINE) && cmethod && !generic_shared &&
6853                                     mono_method_check_inlining (cfg, cmethod) &&
6854                                     !mono_class_is_subclass_of (cmethod->klass, mono_defaults.exception_class, FALSE) &&
6855                                     !g_list_find (dont_inline, cmethod)) {
6856                                         int costs;
6857                                         MonoBasicBlock *ebblock;
6858                                         if ((costs = inline_method (cfg, cmethod, fsig, bblock, sp, ip, real_offset, dont_inline, &ebblock, FALSE))) {
6859
6860                                                 ip += 5;
6861                                                 real_offset += 5;
6862                                                 
6863                                                 GET_BBLOCK (cfg, bblock, ip);
6864                                                 ebblock->next_bb = bblock;
6865                                                 link_bblock (cfg, ebblock, bblock);
6866
6867                                                 NEW_TEMPLOAD (cfg, *sp, temp);
6868                                                 sp++;
6869
6870                                                 /* indicates start of a new block, and triggers a load 
6871                                                    of all stack arguments at bb boundarie */
6872                                                 bblock = ebblock;
6873
6874                                                 inline_costs += costs;
6875                                                 break;
6876                                                 
6877                                         } else {
6878                                                 /* Prevent inlining of methods which call other methods */
6879                                                 INLINE_FAILURE;
6880                                                 mono_emit_method_call_spilled (cfg, bblock, cmethod, fsig, sp, ip, callvirt_this_arg);
6881                                         }
6882                                 } else if (generic_shared &&
6883                                                 (cmethod->klass->valuetype ||
6884                                                 !mono_method_is_generic_sharable_impl (cmethod))) {
6885                                         MonoInst *this = NULL, *rgctx, *cmethod_addr;
6886
6887                                         g_assert (!callvirt_this_arg);
6888
6889                                         GENERIC_SHARING_FAILURE_IF_VALUETYPE_METHOD (*ip);
6890
6891                                         if (!(method->flags & METHOD_ATTRIBUTE_STATIC))
6892                                                 NEW_ARGLOAD (cfg, this, 0);
6893                                         rgctx = get_runtime_generic_context (cfg, method, this, ip);
6894                                         cmethod_addr = get_runtime_generic_context_method (cfg, method, bblock, cmethod,
6895                                                         generic_context, rgctx, MONO_RGCTX_INFO_GENERIC_METHOD_CODE, ip);
6896
6897                                         mono_emit_calli_spilled (cfg, bblock, fsig, sp, cmethod_addr, ip);
6898                                 } else {
6899                                         /* Prevent inlining of methods which call other methods */
6900                                         INLINE_FAILURE;
6901                                         /* now call the actual ctor */
6902                                         mono_emit_method_call_spilled (cfg, bblock, cmethod, fsig, sp, ip, callvirt_this_arg);
6903                                 }
6904                         }
6905
6906                         NEW_TEMPLOAD (cfg, *sp, temp);
6907                         sp++;
6908                         
6909                         ip += 5;
6910                         inline_costs += 5;
6911                         break;
6912                 }
6913                 case CEE_ISINST: {
6914                         gboolean shared_access = FALSE;
6915
6916                         CHECK_STACK (1);
6917                         --sp;
6918                         CHECK_OPSIZE (5);
6919                         token = read32 (ip + 1);
6920                         klass = mini_get_class (method, token, generic_context);
6921                         CHECK_TYPELOAD (klass);
6922                         if (sp [0]->type != STACK_OBJ)
6923                                 UNVERIFIED;
6924
6925                         if (cfg->generic_sharing_context) {
6926                                 int context_used = mono_class_check_context_used (klass);
6927
6928                                 if (context_used & MONO_GENERIC_CONTEXT_USED_METHOD)
6929                                         GENERIC_SHARING_FAILURE (CEE_ISINST);
6930
6931                                 if (context_used)
6932                                         shared_access = TRUE;
6933                         }
6934
6935                         /* Needed by the code generated in inssel.brg */
6936                         if (!shared_access)
6937                                 mono_get_got_var (cfg);
6938
6939                         if (shared_access) {
6940                                 MonoInst *this = NULL, *rgctx;
6941                                 MonoInst *args [2];
6942                                 int temp;
6943
6944                                 GENERIC_SHARING_FAILURE_IF_VALUETYPE_METHOD (*ip);
6945
6946                                 /* obj */
6947                                 args [0] = *sp;
6948
6949                                 /* klass */
6950                                 if (!(method->flags & METHOD_ATTRIBUTE_STATIC))
6951                                         NEW_ARGLOAD (cfg, this, 0);
6952                                 rgctx = get_runtime_generic_context (cfg, method, this, ip);
6953                                 args [1] = get_runtime_generic_context_ptr (cfg, method, bblock, klass,
6954                                         token, MINI_TOKEN_SOURCE_CLASS, generic_context, rgctx, MONO_RGCTX_INFO_KLASS, ip);
6955
6956                                 temp = mono_emit_jit_icall (cfg, bblock, mono_object_isinst, args, ip);
6957                                 NEW_TEMPLOAD (cfg, *sp, temp);
6958
6959                                 sp++;
6960                                 ip += 5;
6961                                 inline_costs += 2;
6962                         } else if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
6963                         
6964                                 MonoMethod *mono_isinst;
6965                                 MonoInst *iargs [1];
6966                                 MonoBasicBlock *ebblock;
6967                                 int costs;
6968                                 int temp;
6969                                 
6970                                 mono_isinst = mono_marshal_get_isinst (klass); 
6971                                 iargs [0] = sp [0];
6972                                 
6973                                 costs = inline_method (cfg, mono_isinst, mono_method_signature (mono_isinst), bblock, 
6974                                                        iargs, ip, real_offset, dont_inline, &ebblock, TRUE);
6975                         
6976                                 g_assert (costs > 0);
6977                                 
6978                                 ip += 5;
6979                                 real_offset += 5;
6980                         
6981                                 GET_BBLOCK (cfg, bblock, ip);
6982                                 ebblock->next_bb = bblock;
6983                                 link_bblock (cfg, ebblock, bblock);
6984
6985                                 temp = iargs [0]->inst_i0->inst_c0;
6986                                 NEW_TEMPLOAD (cfg, *sp, temp);
6987                                 
6988                                 sp++;
6989                                 bblock = ebblock;
6990                                 inline_costs += costs;
6991                         } else {
6992                                 MONO_INST_NEW (cfg, ins, *ip);
6993                                 ins->type = STACK_OBJ;
6994                                 ins->inst_left = *sp;
6995                                 ins->inst_newa_class = klass;
6996                                 ins->klass = klass;
6997                                 *sp++ = emit_tree (cfg, bblock, ins, ip + 5);
6998                                 ip += 5;
6999                         }
7000                         break;
7001                 }
7002                 case CEE_UNBOX_ANY: {
7003                         MonoInst *add, *vtoffset;
7004                         MonoInst *iargs [3];
7005                         guint32 align;
7006                         int context_used = 0;
7007
7008                         CHECK_STACK (1);
7009                         --sp;
7010                         CHECK_OPSIZE (5);
7011                         token = read32 (ip + 1);
7012                         klass = mini_get_class (method, token, generic_context);
7013                         CHECK_TYPELOAD (klass);
7014
7015                         if (cfg->generic_sharing_context) {
7016                                 context_used = mono_class_check_context_used (klass);
7017
7018                                 if (context_used & MONO_GENERIC_CONTEXT_USED_METHOD)
7019                                         GENERIC_SHARING_FAILURE (CEE_UNBOX_ANY);
7020                         }
7021
7022                         if (generic_class_is_reference_type (cfg, klass)) {
7023                                 if (context_used)
7024                                         GENERIC_SHARING_FAILURE_IF_VALUETYPE_METHOD (CEE_UNBOX_ANY);
7025                                 switch (emit_castclass (klass, token, context_used, FALSE,
7026                                                 cfg, method, arg_array, param_types, dont_inline, end, header,
7027                                                 generic_context, &bblock, &ip, &sp, &inline_costs, &real_offset)) {
7028                                 case 0: break;
7029                                 case -1: goto unverified;
7030                                 default: g_assert_not_reached ();
7031                                 }
7032                                 break;
7033                         }
7034
7035                         if (mono_class_is_nullable (klass)) {
7036                                 int v;
7037                                 MonoInst *rgctx = NULL;
7038
7039                                 if (context_used) {
7040                                         MonoInst *this = NULL;
7041
7042                                         if (!(method->flags & METHOD_ATTRIBUTE_STATIC))
7043                                                 NEW_ARGLOAD (cfg, this, 0);
7044                                         rgctx = get_runtime_generic_context (cfg, method, this, ip);
7045                                 }
7046
7047                                 v = handle_unbox_nullable (cfg, method, bblock, *sp, ip, klass, generic_context, rgctx);
7048                                 NEW_TEMPLOAD (cfg, *sp, v);
7049                                 sp ++;
7050                                 ip += 5;
7051                                 break;
7052                         }
7053
7054                         /* Needed by the code generated in inssel.brg */
7055                         mono_get_got_var (cfg);
7056
7057                         if (context_used) {
7058                                 MonoInst *this = NULL, *rgctx;
7059                                 MonoInst *element_class;
7060
7061                                 GENERIC_SHARING_FAILURE_IF_VALUETYPE_METHOD (CEE_UNBOX_ANY);
7062
7063                                 /* This assertion is from the
7064                                    unboxcast insn */
7065                                 g_assert (klass->rank == 0);
7066
7067                                 if (!(method->flags & METHOD_ATTRIBUTE_STATIC))
7068                                         NEW_ARGLOAD (cfg, this, 0);
7069                                 rgctx = get_runtime_generic_context (cfg, method, this, ip);
7070                                 /* FIXME: Passing token here is
7071                                    technically not correct, because we
7072                                    don't use klass but
7073                                    klass->element_class.  Since it's
7074                                    only used by code for debugging the
7075                                    extensible runtime generic context
7076                                    it's not a big deal.  To be correct
7077                                    we'd have to invent a new token
7078                                    source. */
7079                                 element_class = get_runtime_generic_context_ptr (cfg, method, bblock,
7080                                         klass->element_class, token, MINI_TOKEN_SOURCE_CLASS,
7081                                         generic_context, rgctx, MONO_RGCTX_INFO_KLASS, ip);
7082
7083                                 MONO_INST_NEW (cfg, ins, OP_UNBOXCAST_REG);
7084                                 ins->type = STACK_OBJ;
7085                                 ins->inst_left = *sp;
7086                                 ins->inst_right = element_class;
7087                                 ins->klass = klass;
7088                         } else {
7089                                 MONO_INST_NEW (cfg, ins, OP_UNBOXCAST);
7090                                 ins->type = STACK_OBJ;
7091                                 ins->inst_left = *sp;
7092                                 ins->klass = klass;
7093                                 ins->inst_newa_class = klass;
7094                         }
7095
7096                         MONO_INST_NEW (cfg, add, OP_PADD);
7097                         NEW_ICONST (cfg, vtoffset, sizeof (MonoObject));
7098                         add->inst_left = ins;
7099                         add->inst_right = vtoffset;
7100                         add->type = STACK_MP;
7101                         add->klass = mono_defaults.object_class;
7102                         *sp = add;
7103                         ip += 5;
7104                         /* LDOBJ impl */
7105                         n = mono_class_value_size (klass, &align);
7106                         ins = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
7107                         NEW_TEMPLOADA (cfg, iargs [0], ins->inst_c0);
7108                         if ((cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 5) {
7109                                 MonoInst *copy;
7110                                 NEW_MEMCPY (cfg, copy, iargs [0], *sp, n, align);
7111                                 MONO_ADD_INS (bblock, copy);
7112                         } else {
7113                                 MonoMethod *memcpy_method = get_memcpy_method ();
7114                                 iargs [1] = *sp;
7115                                 NEW_ICONST (cfg, iargs [2], n);
7116
7117                                 mono_emit_method_call_spilled (cfg, bblock, memcpy_method, memcpy_method->signature, iargs, ip, NULL);
7118                         }
7119                         NEW_TEMPLOAD (cfg, *sp, ins->inst_c0);
7120                         ++sp;
7121                         inline_costs += 2;
7122                         break;
7123                 }
7124                 case CEE_UNBOX: {
7125                         MonoInst *add, *vtoffset;
7126
7127                         CHECK_STACK (1);
7128                         --sp;
7129                         CHECK_OPSIZE (5);
7130                         token = read32 (ip + 1);
7131                         klass = mini_get_class (method, token, generic_context);
7132                         CHECK_TYPELOAD (klass);
7133
7134                         if (cfg->generic_sharing_context && mono_class_check_context_used (klass))
7135                                 GENERIC_SHARING_FAILURE (CEE_UNBOX);
7136
7137                         if (mono_class_is_nullable (klass)) {
7138                                 int v = handle_unbox_nullable (cfg, method, bblock, *sp, ip, klass, generic_context, NULL);
7139                                 NEW_TEMPLOAD (cfg, *sp, v);
7140                                 sp ++;
7141                                 ip += 5;
7142                                 break;
7143                         }
7144
7145                         /* Needed by the code generated in inssel.brg */
7146                         mono_get_got_var (cfg);
7147
7148                         MONO_INST_NEW (cfg, ins, OP_UNBOXCAST);
7149                         ins->type = STACK_OBJ;
7150                         ins->inst_left = *sp;
7151                         ins->klass = klass;
7152                         ins->inst_newa_class = klass;
7153
7154                         MONO_INST_NEW (cfg, add, OP_PADD);
7155                         NEW_ICONST (cfg, vtoffset, sizeof (MonoObject));
7156                         add->inst_left = ins;
7157                         add->inst_right = vtoffset;
7158                         add->type = STACK_MP;
7159                         add->klass = klass;
7160                         *sp++ = add;
7161                         ip += 5;
7162                         inline_costs += 2;
7163                         break;
7164                 }
7165                 case CEE_CASTCLASS: {
7166                         gboolean shared_access = FALSE;
7167
7168                         CHECK_STACK (1);
7169                         --sp;
7170                         CHECK_OPSIZE (5);
7171                         token = read32 (ip + 1);
7172                         klass = mini_get_class (method, token, generic_context);
7173                         CHECK_TYPELOAD (klass);
7174                         if (sp [0]->type != STACK_OBJ)
7175                                 UNVERIFIED;
7176
7177                         if (cfg->generic_sharing_context) {
7178                                 int context_used = mono_class_check_context_used (klass);
7179
7180                                 if (context_used & MONO_GENERIC_CONTEXT_USED_METHOD)
7181                                         GENERIC_SHARING_FAILURE (CEE_CASTCLASS);
7182
7183                                 if (context_used) {
7184                                         shared_access = TRUE;
7185                                         GENERIC_SHARING_FAILURE_IF_VALUETYPE_METHOD (*ip);
7186                                 }
7187                         }
7188
7189                         switch (emit_castclass (klass, token, shared_access, TRUE,
7190                                         cfg, method, arg_array, param_types, dont_inline, end, header,
7191                                         generic_context, &bblock, &ip, &sp, &inline_costs, &real_offset)) {
7192                         case 0: break;
7193                         case -1: goto unverified;
7194                         default: g_assert_not_reached ();
7195                         }
7196                         break;
7197                 }
7198                 case CEE_THROW:
7199                         CHECK_STACK (1);
7200                         MONO_INST_NEW (cfg, ins, OP_THROW);
7201                         --sp;
7202                         ins->inst_left = *sp;
7203                         ip++;
7204                         bblock->out_of_line = TRUE;
7205                         MONO_ADD_INS (bblock, ins);
7206                         MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
7207                         ins->cil_code = ip - 1;
7208                         MONO_ADD_INS (bblock, ins);
7209                         sp = stack_start;
7210                         
7211                         link_bblock (cfg, bblock, end_bblock);
7212                         start_new_bblock = 1;
7213                         break;
7214                 case CEE_LDFLD:
7215                 case CEE_LDFLDA:
7216                 case CEE_STFLD: {
7217                         MonoInst *offset_ins;
7218                         MonoClassField *field;
7219                         MonoBasicBlock *ebblock;
7220                         int costs;
7221                         guint foffset;
7222
7223                         if (*ip == CEE_STFLD) {
7224                                 CHECK_STACK (2);
7225                                 sp -= 2;
7226                         } else {
7227                                 CHECK_STACK (1);
7228                                 --sp;
7229                         }
7230                         if (sp [0]->type == STACK_I4 || sp [0]->type == STACK_I8 || sp [0]->type == STACK_R8)
7231                                 UNVERIFIED;
7232                         if (*ip != CEE_LDFLD && sp [0]->type == STACK_VTYPE)
7233                                 UNVERIFIED;
7234                         CHECK_OPSIZE (5);
7235                         token = read32 (ip + 1);
7236                         if (method->wrapper_type != MONO_WRAPPER_NONE) {
7237                                 field = mono_method_get_wrapper_data (method, token);
7238                                 klass = field->parent;
7239                         } else {
7240                                 field = mono_field_from_token (image, token, &klass, generic_context);
7241                         }
7242                         if (!field)
7243                                 goto load_error;
7244                         mono_class_init (klass);
7245                         if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_field (method, field))
7246                                 FIELD_ACCESS_FAILURE;
7247
7248                         foffset = klass->valuetype? field->offset - sizeof (MonoObject): field->offset;
7249                         /* FIXME: mark instructions for use in SSA */
7250                         if (*ip == CEE_STFLD) {
7251                                 if (target_type_is_incompatible (cfg, field->type, sp [1]))
7252                                         UNVERIFIED;
7253                                 if ((klass->marshalbyref && !MONO_CHECK_THIS (sp [0])) || klass->contextbound || klass == mono_defaults.marshalbyrefobject_class) {
7254                                         MonoMethod *stfld_wrapper = mono_marshal_get_stfld_wrapper (field->type); 
7255                                         MonoInst *iargs [5];
7256
7257                                         iargs [0] = sp [0];
7258                                         NEW_CLASSCONST (cfg, iargs [1], klass);
7259                                         NEW_FIELDCONST (cfg, iargs [2], field);
7260                                         NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : 
7261                                                     field->offset);
7262                                         iargs [4] = sp [1];
7263
7264                                         if (cfg->opt & MONO_OPT_INLINE) {
7265                                                 costs = inline_method (cfg, stfld_wrapper, mono_method_signature (stfld_wrapper), bblock, 
7266                                                                 iargs, ip, real_offset, dont_inline, &ebblock, TRUE);
7267                                                 g_assert (costs > 0);
7268                                                       
7269                                                 ip += 5;
7270                                                 real_offset += 5;
7271
7272                                                 GET_BBLOCK (cfg, bblock, ip);
7273                                                 ebblock->next_bb = bblock;
7274                                                 link_bblock (cfg, ebblock, bblock);
7275
7276                                                 /* indicates start of a new block, and triggers a load 
7277                                                    of all stack arguments at bb boundarie */
7278                                                 bblock = ebblock;
7279
7280                                                 inline_costs += costs;
7281                                                 break;
7282                                         } else {
7283                                                 mono_emit_method_call_spilled (cfg, bblock, stfld_wrapper, mono_method_signature (stfld_wrapper), iargs, ip, NULL);
7284                                         }
7285 #if HAVE_WRITE_BARRIERS
7286                                 } else if (mini_type_to_stind (cfg, field->type) == CEE_STIND_REF && !(sp [1]->opcode == OP_PCONST && sp [1]->inst_c0 == 0)) {
7287                                         /* insert call to write barrier */
7288                                         MonoMethod *write_barrier = mono_marshal_get_write_barrier ();
7289                                         MonoInst *iargs [2];
7290                                         NEW_ICONST (cfg, offset_ins, foffset);
7291                                         MONO_INST_NEW (cfg, ins, OP_PADD);
7292                                         ins->inst_left = *sp;
7293                                         ins->inst_right = offset_ins;
7294                                         ins->type = STACK_MP;
7295                                         ins->klass = mono_defaults.object_class;
7296                                         iargs [0] = ins;
7297                                         iargs [1] = sp [1];
7298                                         mono_emit_method_call_spilled (cfg, bblock, write_barrier, mono_method_signature (write_barrier), iargs, ip, NULL);
7299 #endif
7300 #ifdef MONO_ARCH_SOFT_FLOAT
7301                                 } else if (mini_type_to_stind (cfg, field->type) == CEE_STIND_R4) {
7302                                         NEW_ICONST (cfg, offset_ins, foffset);
7303                                         MONO_INST_NEW (cfg, ins, OP_PADD);
7304                                         ins->inst_left = *sp;
7305                                         ins->inst_right = offset_ins;
7306                                         ins->type = STACK_MP;
7307                                         ins->klass = mono_defaults.object_class;
7308                                         handle_store_float (cfg, bblock, ins, sp [1], ip);
7309 #endif
7310                                 } else {
7311                                         MonoInst *store;
7312                                         NEW_ICONST (cfg, offset_ins, foffset);
7313                                         MONO_INST_NEW (cfg, ins, OP_PADD);
7314                                         ins->inst_left = *sp;
7315                                         ins->inst_right = offset_ins;
7316                                         ins->type = STACK_MP;
7317
7318                                         MONO_INST_NEW (cfg, store, mini_type_to_stind (cfg, field->type));
7319                                         store->inst_left = ins;
7320                                         store->inst_right = sp [1];
7321                                         handle_loaded_temps (cfg, bblock, stack_start, sp);
7322                                         store->flags |= ins_flag;
7323                                         ins_flag = 0;
7324                                         if (store->opcode == CEE_STOBJ) {
7325                                                 handle_stobj (cfg, bblock, ins, sp [1], ip, 
7326                                                               mono_class_from_mono_type (field->type), FALSE, FALSE, TRUE);
7327                                         } else
7328                                                 MONO_ADD_INS (bblock, store);
7329                                 }
7330                         } else {
7331                                 if ((klass->marshalbyref && !MONO_CHECK_THIS (sp [0])) || klass->contextbound || klass == mono_defaults.marshalbyrefobject_class) {
7332                                         MonoMethod *wrapper = (*ip == CEE_LDFLDA) ? mono_marshal_get_ldflda_wrapper (field->type) : mono_marshal_get_ldfld_wrapper (field->type); 
7333                                         MonoInst *iargs [4];
7334                                         int temp;
7335                                         
7336                                         iargs [0] = sp [0];
7337                                         NEW_CLASSCONST (cfg, iargs [1], klass);
7338                                         NEW_FIELDCONST (cfg, iargs [2], field);
7339                                         NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset);
7340                                         if ((cfg->opt & MONO_OPT_INLINE) && !MONO_TYPE_ISSTRUCT (mono_method_signature (wrapper)->ret)) {
7341                                                 costs = inline_method (cfg, wrapper, mono_method_signature (wrapper), bblock, 
7342                                                                 iargs, ip, real_offset, dont_inline, &ebblock, TRUE);
7343                                                 g_assert (costs > 0);
7344                                                       
7345                                                 ip += 5;
7346                                                 real_offset += 5;
7347
7348                                                 GET_BBLOCK (cfg, bblock, ip);
7349                                                 ebblock->next_bb = bblock;
7350                                                 link_bblock (cfg, ebblock, bblock);
7351
7352                                                 temp = iargs [0]->inst_i0->inst_c0;
7353
7354                                                 NEW_TEMPLOAD (cfg, *sp, temp);
7355                                                 sp++;
7356
7357                                                 /* indicates start of a new block, and triggers a load of
7358                                                    all stack arguments at bb boundarie */
7359                                                 bblock = ebblock;
7360                                                 
7361                                                 inline_costs += costs;
7362                                                 break;
7363                                         } else {
7364                                                 temp = mono_emit_method_call_spilled (cfg, bblock, wrapper, mono_method_signature (wrapper), iargs, ip, NULL);
7365                                                 NEW_TEMPLOAD (cfg, *sp, temp);
7366                                                 sp++;
7367                                         }
7368                                 } else {
7369                                         NEW_ICONST (cfg, offset_ins, foffset);
7370                                         MONO_INST_NEW (cfg, ins, OP_PADD);
7371                                         ins->inst_left = *sp;
7372                                         ins->inst_right = offset_ins;
7373                                         ins->type = STACK_MP;
7374
7375                                         if (*ip == CEE_LDFLDA) {
7376                                                 ins->klass = mono_class_from_mono_type (field->type);
7377                                                 *sp++ = ins;
7378                                         } else {
7379                                                 MonoInst *load;
7380                                                 MONO_INST_NEW (cfg, load, mini_type_to_ldind (cfg, field->type));
7381                                                 type_to_eval_stack_type (cfg, field->type, load);
7382                                                 load->inst_left = ins;
7383                                                 load->flags |= ins_flag;
7384                                                 ins_flag = 0;
7385 #ifdef MONO_ARCH_SOFT_FLOAT
7386                                                 if (mini_type_to_ldind (cfg, field->type) == CEE_LDIND_R4) {
7387                                                         int temp;
7388                                                         temp = handle_load_float (cfg, bblock, ins, ip);
7389                                                         NEW_TEMPLOAD (cfg, *sp, temp);
7390                                                         sp++;
7391                                                 } else
7392 #endif
7393                                                 *sp++ = load;
7394                                         }
7395                                 }
7396                         }
7397                         ip += 5;
7398                         break;
7399                 }
7400                 case CEE_LDSFLD:
7401                 case CEE_LDSFLDA:
7402                 case CEE_STSFLD: {
7403                         MonoClassField *field;
7404                         gpointer addr = NULL;
7405                         gboolean shared_access = FALSE;
7406                         int relation = 0;
7407
7408                         CHECK_OPSIZE (5);
7409                         token = read32 (ip + 1);
7410                         if (method->wrapper_type != MONO_WRAPPER_NONE) {
7411                                 field = mono_method_get_wrapper_data (method, token);
7412                                 klass = field->parent;
7413                         }
7414                         else
7415                                 field = mono_field_from_token (image, token, &klass, generic_context);
7416                         if (!field)
7417                                 goto load_error;
7418                         mono_class_init (klass);
7419                         if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_field (method, field))
7420                                 FIELD_ACCESS_FAILURE;
7421
7422                         /*
7423                          * We can only support shared generic static
7424                          * field access on architectures where the
7425                          * trampoline code has been extended to handle
7426                          * the generic class init.
7427                          */
7428 #ifndef MONO_ARCH_VTABLE_REG
7429                         GENERIC_SHARING_FAILURE (*ip);
7430 #endif
7431
7432                         if (cfg->generic_sharing_context) {
7433                                 int context_used = mono_class_check_context_used (klass);
7434
7435                                 if (context_used & MONO_GENERIC_CONTEXT_USED_METHOD ||
7436                                                 klass->valuetype)
7437                                         GENERIC_SHARING_FAILURE (*ip);
7438
7439                                 if (context_used) {
7440                                         relation = mono_class_generic_class_relation (klass, MONO_RGCTX_INFO_VTABLE,
7441                                                 method->klass, generic_context, NULL);
7442                                         shared_access = TRUE;
7443                                 }
7444                         }
7445
7446                         g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
7447
7448                         if ((*ip) == CEE_STSFLD)
7449                                 handle_loaded_temps (cfg, bblock, stack_start, sp);
7450
7451                         /* The special_static_fields field is init'd in mono_class_vtable, so it needs
7452                          * to be called here.
7453                          */
7454                         if (!(cfg->opt & MONO_OPT_SHARED)) {
7455                                 mono_class_vtable (cfg->domain, klass);
7456                                 CHECK_TYPELOAD (klass);
7457                         }
7458                         mono_domain_lock (cfg->domain);
7459                         if (cfg->domain->special_static_fields)
7460                                 addr = g_hash_table_lookup (cfg->domain->special_static_fields, field);
7461                         mono_domain_unlock (cfg->domain);
7462
7463                         if ((cfg->opt & MONO_OPT_SHARED) || (cfg->compile_aot && addr)) {
7464                                 int temp;
7465                                 MonoInst *iargs [2];
7466                                 MonoInst *domain_var;
7467
7468                                 g_assert (field->parent);
7469                                 /* avoid depending on undefined C behavior in sequence points */
7470                                 domain_var = mono_get_domainvar (cfg);
7471                                 NEW_TEMPLOAD (cfg, iargs [0], domain_var->inst_c0);
7472                                 if (shared_access) {
7473                                         MonoInst *rgctx;
7474
7475                                         GET_RGCTX (rgctx);
7476                                         iargs [1] = get_runtime_generic_context_field (cfg, method, bblock, field,
7477                                                         generic_context, rgctx, MONO_RGCTX_INFO_CLASS_FIELD, ip);
7478                                 } else {
7479                                         NEW_FIELDCONST (cfg, iargs [1], field);
7480                                 }
7481                                 temp = mono_emit_jit_icall (cfg, bblock, mono_class_static_field_address, iargs, ip);
7482                                 NEW_TEMPLOAD (cfg, ins, temp);
7483                         } else if (shared_access) {
7484                                 MonoInst *this, *rgctx, *static_data;
7485
7486                                 GENERIC_SHARING_FAILURE_IF_VALUETYPE_METHOD (*ip);
7487
7488                                 /*
7489                                 g_print ("sharing static field access in %s.%s.%s - depth %d offset %d\n",
7490                                         method->klass->name_space, method->klass->name, method->name,
7491                                         depth, field->offset);
7492                                 */
7493
7494                                 if (mono_class_needs_cctor_run (klass, method)) {
7495                                         MonoMethodSignature *sig = helper_sig_generic_class_init_trampoline;
7496                                         MonoCallInst *call;
7497                                         MonoInst *vtable, *rgctx;
7498
7499                                         if (!(method->flags & METHOD_ATTRIBUTE_STATIC))
7500                                                 NEW_ARGLOAD (cfg, this, 0);
7501                                         else
7502                                                 this = NULL;
7503
7504                                         rgctx = get_runtime_generic_context (cfg, method, this, ip);
7505                                         vtable = get_runtime_generic_context_ptr (cfg, method, bblock, klass,
7506                                                         token, MINI_TOKEN_SOURCE_FIELD, generic_context,
7507                                                         rgctx, MONO_RGCTX_INFO_VTABLE, ip);
7508
7509                                         call = mono_emit_call_args (cfg, bblock, sig, NULL, FALSE, FALSE, ip, FALSE);
7510                                         call->inst.opcode = OP_TRAMPCALL_VTABLE;
7511                                         call->fptr = mono_get_trampoline_code (MONO_TRAMPOLINE_GENERIC_CLASS_INIT);
7512
7513                                         call->inst.inst_left = vtable;
7514
7515                                         mono_spill_call (cfg, bblock, call, sig, FALSE, ip, FALSE);
7516                                 }
7517
7518                                 /*
7519                                  * The pointer we're computing here is
7520                                  *
7521                                  *   super_info.static_data + field->offset
7522                                  */
7523
7524                                 if (!(method->flags & METHOD_ATTRIBUTE_STATIC))
7525                                         NEW_ARGLOAD (cfg, this, 0);
7526                                 else
7527                                         this = NULL;
7528                                 rgctx = get_runtime_generic_context (cfg, method, this, ip);
7529                                 static_data = get_runtime_generic_context_ptr (cfg, method, bblock, klass,
7530                                         token, MINI_TOKEN_SOURCE_FIELD, generic_context,
7531                                         rgctx, MONO_RGCTX_INFO_STATIC_DATA, ip);
7532
7533                                 if (field->offset == 0) {
7534                                         ins = static_data;
7535                                 } else {
7536                                         MonoInst *field_offset;
7537
7538                                         NEW_ICONST (cfg, field_offset, field->offset);
7539
7540                                         MONO_INST_NEW (cfg, ins, OP_PADD);
7541                                         ins->inst_left = static_data;
7542                                         ins->inst_right = field_offset;
7543                                         ins->type = STACK_PTR;
7544                                         ins->klass = klass;
7545                                 }
7546                         } else {
7547                                 MonoVTable *vtable;
7548
7549                                 vtable = mono_class_vtable (cfg->domain, klass);
7550                                 CHECK_TYPELOAD (klass);
7551                                 if (!addr) {
7552                                         if (mini_field_access_needs_cctor_run (cfg, method, vtable) && !(g_slist_find (class_inits, vtable))) {
7553                                                 guint8 *tramp = mono_create_class_init_trampoline (vtable);
7554                                                 mono_emit_native_call (cfg, bblock, tramp, 
7555                                                                                            helper_sig_class_init_trampoline,
7556                                                                                            NULL, ip, FALSE, FALSE);
7557                                                 if (cfg->verbose_level > 2)
7558                                                         g_print ("class %s.%s needs init call for %s\n", klass->name_space, klass->name, field->name);
7559                                                 class_inits = g_slist_prepend (class_inits, vtable);
7560                                         } else {
7561                                                 if (cfg->run_cctors) {
7562                                                         /* This makes so that inline cannot trigger */
7563                                                         /* .cctors: too many apps depend on them */
7564                                                         /* running with a specific order... */
7565                                                         if (! vtable->initialized)
7566                                                                 INLINE_FAILURE;
7567                                                         mono_runtime_class_init (vtable);
7568                                                 }
7569                                         }
7570                                         addr = (char*)vtable->data + field->offset;
7571
7572                                         if (cfg->compile_aot)
7573                                                 NEW_SFLDACONST (cfg, ins, field);
7574                                         else
7575                                                 NEW_PCONST (cfg, ins, addr);
7576                                 } else {
7577                                         /* 
7578                                          * insert call to mono_threads_get_static_data (GPOINTER_TO_UINT (addr)) 
7579                                          * This could be later optimized to do just a couple of
7580                                          * memory dereferences with constant offsets.
7581                                          */
7582                                         int temp;
7583                                         MonoInst *iargs [1];
7584                                         NEW_ICONST (cfg, iargs [0], GPOINTER_TO_UINT (addr));
7585                                         temp = mono_emit_jit_icall (cfg, bblock, mono_get_special_static_data, iargs, ip);
7586                                         NEW_TEMPLOAD (cfg, ins, temp);
7587                                 }
7588                         }
7589
7590                         /* FIXME: mark instructions for use in SSA */
7591                         if (*ip == CEE_LDSFLDA) {
7592                                 ins->klass = mono_class_from_mono_type (field->type);
7593                                 *sp++ = ins;
7594                         } else if (*ip == CEE_STSFLD) {
7595                                 MonoInst *store;
7596                                 CHECK_STACK (1);
7597                                 sp--;
7598                                 MONO_INST_NEW (cfg, store, mini_type_to_stind (cfg, field->type));
7599                                 store->inst_left = ins;
7600                                 store->inst_right = sp [0];
7601                                 store->flags |= ins_flag;
7602                                 ins_flag = 0;
7603
7604 #ifdef MONO_ARCH_SOFT_FLOAT
7605                                 if (store->opcode == CEE_STIND_R4)
7606                                         handle_store_float (cfg, bblock, ins, sp [0], ip);
7607                                 else
7608 #endif
7609                                 if (store->opcode == CEE_STOBJ) {
7610                                         handle_stobj (cfg, bblock, ins, sp [0], ip, mono_class_from_mono_type (field->type), FALSE, FALSE, FALSE);
7611                                 } else
7612                                         MONO_ADD_INS (bblock, store);
7613                         } else {
7614                                 gboolean is_const = FALSE;
7615                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
7616
7617                                 CHECK_TYPELOAD (klass);
7618                                 if (!shared_access && !((cfg->opt & MONO_OPT_SHARED) || cfg->compile_aot) && 
7619                                     vtable->initialized && (field->type->attrs & FIELD_ATTRIBUTE_INIT_ONLY)) {
7620                                         gpointer addr = (char*)vtable->data + field->offset;
7621                                         int ro_type = field->type->type;
7622                                         if (ro_type == MONO_TYPE_VALUETYPE && field->type->data.klass->enumtype) {
7623                                                 ro_type = field->type->data.klass->enum_basetype->type;
7624                                         }
7625                                         /* g_print ("RO-FIELD %s.%s:%s\n", klass->name_space, klass->name, field->name);*/
7626                                         is_const = TRUE;
7627                                         switch (ro_type) {
7628                                         case MONO_TYPE_BOOLEAN:
7629                                         case MONO_TYPE_U1:
7630                                                 NEW_ICONST (cfg, *sp, *((guint8 *)addr));
7631                                                 sp++;
7632                                                 break;
7633                                         case MONO_TYPE_I1:
7634                                                 NEW_ICONST (cfg, *sp, *((gint8 *)addr));
7635                                                 sp++;
7636                                                 break;                                          
7637                                         case MONO_TYPE_CHAR:
7638                                         case MONO_TYPE_U2:
7639                                                 NEW_ICONST (cfg, *sp, *((guint16 *)addr));
7640                                                 sp++;
7641                                                 break;
7642                                         case MONO_TYPE_I2:
7643                                                 NEW_ICONST (cfg, *sp, *((gint16 *)addr));
7644                                                 sp++;
7645                                                 break;
7646                                                 break;
7647                                         case MONO_TYPE_I4:
7648                                                 NEW_ICONST (cfg, *sp, *((gint32 *)addr));
7649                                                 sp++;
7650                                                 break;                                          
7651                                         case MONO_TYPE_U4:
7652                                                 NEW_ICONST (cfg, *sp, *((guint32 *)addr));
7653                                                 sp++;
7654                                                 break;
7655 #ifndef HAVE_MOVING_COLLECTOR
7656                                         case MONO_TYPE_I:
7657                                         case MONO_TYPE_U:
7658                                         case MONO_TYPE_STRING:
7659                                         case MONO_TYPE_OBJECT:
7660                                         case MONO_TYPE_CLASS:
7661                                         case MONO_TYPE_SZARRAY:
7662                                         case MONO_TYPE_PTR:
7663                                         case MONO_TYPE_FNPTR:
7664                                         case MONO_TYPE_ARRAY:
7665                                                 NEW_PCONST (cfg, *sp, *((gpointer *)addr));
7666                                                 type_to_eval_stack_type (cfg, field->type, *sp);
7667                                                 sp++;
7668                                                 break;
7669 #endif
7670                                         case MONO_TYPE_I8:
7671                                         case MONO_TYPE_U8:
7672                                                 MONO_INST_NEW (cfg, *sp, OP_I8CONST);
7673                                                 sp [0]->type = STACK_I8;
7674                                                 sp [0]->inst_l = *((gint64 *)addr);
7675                                                 sp++;
7676                                                 break;
7677                                         case MONO_TYPE_R4:
7678                                         case MONO_TYPE_R8:
7679                                         case MONO_TYPE_VALUETYPE:
7680                                         default:
7681                                                 is_const = FALSE;
7682                                                 break;
7683                                         }
7684                                 }
7685
7686                                 if (!is_const) {
7687                                         MonoInst *load;
7688                                         CHECK_STACK_OVF (1);
7689                                         MONO_INST_NEW (cfg, load, mini_type_to_ldind (cfg, field->type));
7690                                         type_to_eval_stack_type (cfg, field->type, load);
7691                                         load->inst_left = ins;
7692                                         load->flags |= ins_flag;
7693 #ifdef MONO_ARCH_SOFT_FLOAT
7694                                         if (load->opcode == CEE_LDIND_R4) {
7695                                                 int temp;
7696                                                 temp = handle_load_float (cfg, bblock, ins, ip);
7697                                                 NEW_TEMPLOAD (cfg, load, temp);
7698                                         }
7699 #endif
7700                                         *sp++ = load;
7701                                         ins_flag = 0;
7702                                 }
7703                         }
7704                         ip += 5;
7705                         break;
7706                 }
7707                 case CEE_STOBJ:
7708                         CHECK_STACK (2);
7709                         sp -= 2;
7710                         CHECK_OPSIZE (5);
7711                         token = read32 (ip + 1);
7712                         klass = mini_get_class (method, token, generic_context);
7713                         CHECK_TYPELOAD (klass);
7714                         n = mini_type_to_stind (cfg, &klass->byval_arg);
7715                         /* FIXME: handle CEE_STIND_R4 */
7716                         if (n == CEE_STOBJ) {
7717                                 handle_stobj (cfg, bblock, sp [0], sp [1], ip, klass, FALSE, FALSE, TRUE);
7718                         } else {
7719                                 /* FIXME: should check item at sp [1] is compatible with the type of the store. */
7720                                 MonoInst *store;
7721                                 MONO_INST_NEW (cfg, store, n);
7722                                 store->inst_left = sp [0];
7723                                 store->inst_right = sp [1];
7724                                 store->flags |= ins_flag;
7725                                 MONO_ADD_INS (bblock, store);
7726                         }
7727                         ins_flag = 0;
7728                         ip += 5;
7729                         inline_costs += 1;
7730                         break;
7731                 case CEE_BOX: {
7732                         MonoInst *val;
7733                         int context_used = 0;
7734
7735                         CHECK_STACK (1);
7736                         --sp;
7737                         val = *sp;
7738                         CHECK_OPSIZE (5);
7739                         token = read32 (ip + 1);
7740                         klass = mini_get_class (method, token, generic_context);
7741                         CHECK_TYPELOAD (klass);
7742
7743                         if (cfg->generic_sharing_context) {
7744                                 context_used = mono_class_check_context_used (klass);
7745
7746                                 if (context_used & MONO_GENERIC_CONTEXT_USED_METHOD)
7747                                         GENERIC_SHARING_FAILURE (*ip);
7748                         }
7749
7750                         if (generic_class_is_reference_type (cfg, klass)) {
7751                                 *sp++ = val;
7752                                 ip += 5;
7753                                 break;
7754                         }
7755                         if (klass == mono_defaults.void_class)
7756                                 UNVERIFIED;
7757                         if (target_type_is_incompatible (cfg, &klass->byval_arg, *sp))
7758                                 UNVERIFIED;
7759                         /* frequent check in generic code: box (struct), brtrue */
7760                         if (!mono_class_is_nullable (klass) &&
7761                             ip + 5 < end && ip_in_bb (cfg, bblock, ip + 5) && (ip [5] == CEE_BRTRUE || ip [5] == CEE_BRTRUE_S)) {
7762                                 /*g_print ("box-brtrue opt at 0x%04x in %s\n", real_offset, method->name);*/
7763                                 MONO_INST_NEW (cfg, ins, CEE_POP);
7764                                 MONO_ADD_INS (bblock, ins);
7765                                 ins->inst_i0 = *sp;
7766                                 ip += 5;
7767                                 cfg->ip = ip;
7768                                 MONO_INST_NEW (cfg, ins, OP_BR);
7769                                 MONO_ADD_INS (bblock, ins);
7770                                 if (*ip == CEE_BRTRUE_S) {
7771                                         CHECK_OPSIZE (2);
7772                                         ip++;
7773                                         target = ip + 1 + (signed char)(*ip);
7774                                         ip++;
7775                                 } else {
7776                                         CHECK_OPSIZE (5);
7777                                         ip++;
7778                                         target = ip + 4 + (gint)(read32 (ip));
7779                                         ip += 4;
7780                                 }
7781                                 GET_BBLOCK (cfg, tblock, target);
7782                                 link_bblock (cfg, bblock, tblock);
7783                                 CHECK_BBLOCK (target, ip, tblock);
7784                                 ins->inst_target_bb = tblock;
7785                                 GET_BBLOCK (cfg, tblock, ip);
7786                                 link_bblock (cfg, bblock, tblock);
7787                                 if (sp != stack_start) {
7788                                         handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
7789                                         sp = stack_start;
7790                                         CHECK_UNVERIFIABLE (cfg);
7791                                 }
7792                                 start_new_bblock = 1;
7793                                 break;
7794                         }
7795                         if (context_used) {
7796                                 MonoInst *rgctx;
7797
7798                                 if (mono_class_is_nullable (klass)) {
7799                                         GET_RGCTX (rgctx);
7800                                         *sp++ = handle_box_nullable_from_inst (cfg, method, context_used, bblock, val,
7801                                                         ip, klass, generic_context, rgctx);
7802                                 } else {
7803                                         MonoInst *data;
7804                                         int rgctx_info;
7805
7806                                         GET_RGCTX (rgctx);
7807                                         if (cfg->opt & MONO_OPT_SHARED)
7808                                                 rgctx_info = MONO_RGCTX_INFO_KLASS;
7809                                         else
7810                                                 rgctx_info = MONO_RGCTX_INFO_VTABLE;
7811                                         data = get_runtime_generic_context_ptr (cfg, method, bblock, klass,
7812                                                         token, MINI_TOKEN_SOURCE_CLASS, generic_context,
7813                                                         rgctx, rgctx_info, ip);
7814
7815                                         *sp++ = handle_box_from_inst (cfg, bblock, val, ip, klass, data);
7816                                 }
7817                         } else {
7818                                 *sp++ = handle_box (cfg, bblock, val, ip, klass);
7819                         }
7820                         ip += 5;
7821                         inline_costs += 1;
7822                         break;
7823                 }
7824                 case CEE_NEWARR: {
7825                         gboolean shared_access = FALSE;
7826
7827                         CHECK_STACK (1);
7828                         --sp;
7829
7830                         CHECK_OPSIZE (5);
7831                         token = read32 (ip + 1);
7832
7833                         /* allocate the domainvar - becaus this is used in decompose_foreach */
7834                         if (cfg->opt & MONO_OPT_SHARED) {
7835                                 mono_get_domainvar (cfg);
7836                                 /* LAME-IR: Mark it as used since otherwise it will be optimized away */
7837                                 cfg->domainvar->flags |= MONO_INST_VOLATILE;
7838                         }
7839
7840                         /* Ditto */
7841                         mono_get_got_var (cfg);
7842
7843                         klass = mini_get_class (method, token, generic_context);
7844                         CHECK_TYPELOAD (klass);
7845
7846                         if (cfg->generic_sharing_context) {
7847                                 int context_used = mono_class_check_context_used (klass);
7848
7849                                 if (context_used & MONO_GENERIC_CONTEXT_USED_METHOD || klass->valuetype)
7850                                         GENERIC_SHARING_FAILURE (CEE_NEWARR);
7851
7852                                 if (context_used)
7853                                         shared_access = TRUE;
7854                         }
7855
7856                         if (shared_access) {
7857                                 MonoInst *this = NULL, *rgctx;
7858                                 MonoInst *args [3];
7859                                 int temp;
7860
7861                                 GENERIC_SHARING_FAILURE_IF_VALUETYPE_METHOD (*ip);
7862
7863                                 /* domain */
7864                                 NEW_DOMAINCONST (cfg, args [0]);
7865
7866                                 /* klass */
7867                                 if (!(method->flags & METHOD_ATTRIBUTE_STATIC))
7868                                         NEW_ARGLOAD (cfg, this, 0);
7869                                 rgctx = get_runtime_generic_context (cfg, method, this, ip);
7870                                 args [1] = get_runtime_generic_context_ptr (cfg, method, bblock, klass,
7871                                         token, MINI_TOKEN_SOURCE_CLASS, generic_context, rgctx, MONO_RGCTX_INFO_KLASS, ip);
7872
7873                                 /* array len */
7874                                 args [2] = *sp;
7875
7876                                 temp = mono_emit_jit_icall (cfg, bblock, mono_array_new, args, ip);
7877                                 NEW_TEMPLOAD (cfg, ins, temp);
7878                         } else {
7879                                 MONO_INST_NEW (cfg, ins, *ip);
7880                                 ins->inst_newa_class = klass;
7881                                 ins->inst_newa_len = *sp;
7882                                 ins->type = STACK_OBJ;
7883                                 ins->klass = mono_array_class_get (klass, 1);
7884                         }
7885
7886                         ip += 5;
7887                         *sp++ = ins;
7888                         /* 
7889                          * we store the object so calls to create the array are not interleaved
7890                          * with the arguments of other calls.
7891                          */
7892                         if (1) {
7893                                 MonoInst *store, *temp, *load;
7894                                 const char *data_ptr;
7895                                 int data_size = 0;
7896                                 --sp;
7897                                 temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
7898                                 NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
7899                                 store->cil_code = ins->cil_code;
7900                                 MONO_ADD_INS (bblock, store);
7901                                 /* 
7902                                  * we inline/optimize the initialization sequence if possible.
7903                                  * we should also allocate the array as not cleared, since we spend as much time clearing to 0 as initializing
7904                                  * for small sizes open code the memcpy
7905                                  * ensure the rva field is big enough
7906                                  */
7907                                 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))) {
7908                                         MonoMethod *memcpy_method = get_memcpy_method ();
7909                                         MonoInst *data_offset, *add;
7910                                         MonoInst *iargs [3];
7911                                         NEW_ICONST (cfg, iargs [2], data_size);
7912                                         NEW_TEMPLOAD (cfg, load, temp->inst_c0);
7913                                         load->cil_code = ins->cil_code;
7914                                         NEW_ICONST (cfg, data_offset, G_STRUCT_OFFSET (MonoArray, vector));
7915                                         MONO_INST_NEW (cfg, add, OP_PADD);
7916                                         add->inst_left = load;
7917                                         add->inst_right = data_offset;
7918                                         iargs [0] = add;
7919                                         if (cfg->compile_aot) {
7920                                                 NEW_AOTCONST_TOKEN (cfg, iargs [1], MONO_PATCH_INFO_RVA, method->klass->image, GPOINTER_TO_UINT(data_ptr), STACK_PTR, NULL);
7921                                         } else {
7922                                                 NEW_PCONST (cfg, iargs [1], (char*)data_ptr);
7923                                         }
7924                                         mono_emit_method_call_spilled (cfg, bblock, memcpy_method, memcpy_method->signature, iargs, ip, NULL);
7925                                         ip += 11;
7926                                 }
7927                                 NEW_TEMPLOAD (cfg, load, temp->inst_c0);
7928                                 load->cil_code = ins->cil_code;
7929                                 *sp++ = load;
7930                         }
7931                         inline_costs += 1;
7932                         break;
7933                 }
7934                 case CEE_LDLEN:
7935                         CHECK_STACK (1);
7936                         --sp;
7937                         if (sp [0]->type != STACK_OBJ)
7938                                 UNVERIFIED;
7939                         MONO_INST_NEW (cfg, ins, *ip);
7940                         ip++;
7941                         ins->inst_left = *sp;
7942                         ins->type = STACK_PTR;
7943                         *sp++ = ins;
7944                         break;
7945                 case CEE_LDELEMA:
7946                         CHECK_STACK (2);
7947                         sp -= 2;
7948                         CHECK_OPSIZE (5);
7949                         if (sp [0]->type != STACK_OBJ)
7950                                 UNVERIFIED;
7951
7952                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
7953                         CHECK_TYPELOAD (klass);
7954                         /* we need to make sure that this array is exactly the type it needs
7955                          * to be for correctness. the wrappers are lax with their usage
7956                          * so we need to ignore them here
7957                          */
7958                         if (!klass->valuetype && method->wrapper_type == MONO_WRAPPER_NONE && !readonly) {
7959                                 MonoInst* check;
7960
7961                                 /* Needed by the code generated in inssel.brg */
7962                                 mono_get_got_var (cfg);
7963
7964                                 MONO_INST_NEW (cfg, check, OP_CHECK_ARRAY_TYPE);
7965                                 check->klass = mono_array_class_get (klass, 1);
7966                                 check->inst_left = sp [0];
7967                                 check->type = STACK_OBJ;
7968                                 sp [0] = check;
7969                         }
7970                         
7971                         readonly = FALSE;
7972                         mono_class_init (klass);
7973                         NEW_LDELEMA (cfg, ins, sp, klass);
7974                         *sp++ = ins;
7975                         ip += 5;
7976                         break;
7977                 case CEE_LDELEM_ANY: {
7978                         MonoInst *load;
7979                         CHECK_STACK (2);
7980                         sp -= 2;
7981                         if (sp [0]->type != STACK_OBJ)
7982                                 UNVERIFIED;
7983                         CHECK_OPSIZE (5);
7984                         token = read32 (ip + 1);
7985                         klass = mini_get_class (method, token, generic_context);
7986                         CHECK_TYPELOAD (klass);
7987                         mono_class_init (klass);
7988                         NEW_LDELEMA (cfg, load, sp, klass);
7989                         MONO_INST_NEW (cfg, ins, mini_type_to_ldind (cfg, &klass->byval_arg));
7990                         ins->inst_left = load;
7991                         *sp++ = ins;
7992                         type_to_eval_stack_type (cfg, &klass->byval_arg, ins);
7993                         ip += 5;
7994                         break;
7995                 }
7996                 case CEE_LDELEM_I1:
7997                 case CEE_LDELEM_U1:
7998                 case CEE_LDELEM_I2:
7999                 case CEE_LDELEM_U2:
8000                 case CEE_LDELEM_I4:
8001                 case CEE_LDELEM_U4:
8002                 case CEE_LDELEM_I8:
8003                 case CEE_LDELEM_I:
8004                 case CEE_LDELEM_R4:
8005                 case CEE_LDELEM_R8:
8006                 case CEE_LDELEM_REF: {
8007                         MonoInst *load;
8008                         /*
8009                          * translate to:
8010                          * ldind.x (ldelema (array, index))
8011                          * ldelema does the bounds check
8012                          */
8013                         CHECK_STACK (2);
8014                         sp -= 2;
8015                         if (sp [0]->type != STACK_OBJ)
8016                                 UNVERIFIED;
8017                         klass = array_access_to_klass (*ip, sp [0]);
8018                         NEW_LDELEMA (cfg, load, sp, klass);
8019 #ifdef MONO_ARCH_SOFT_FLOAT
8020                         if (*ip == CEE_LDELEM_R4) {
8021                                 int temp;
8022                                 temp = handle_load_float (cfg, bblock, load, ip);
8023                                 NEW_TEMPLOAD (cfg, *sp, temp);
8024                                 sp++;
8025                                 ++ip;
8026                                 break;
8027                         }
8028 #endif
8029                         MONO_INST_NEW (cfg, ins, ldelem_to_ldind [*ip - CEE_LDELEM_I1]);
8030                         ins->inst_left = load;
8031                         *sp++ = ins;
8032                         ins->type = ldind_type [ins->opcode - CEE_LDIND_I1];
8033                         ins->klass = klass;
8034                         ++ip;
8035                         break;
8036                 }
8037                 case CEE_STELEM_I:
8038                 case CEE_STELEM_I1:
8039                 case CEE_STELEM_I2:
8040                 case CEE_STELEM_I4:
8041                 case CEE_STELEM_I8:
8042                 case CEE_STELEM_R4:
8043                 case CEE_STELEM_R8: {
8044                         MonoInst *load;
8045                         /*
8046                          * translate to:
8047                          * stind.x (ldelema (array, index), val)
8048                          * ldelema does the bounds check
8049                          */
8050                         CHECK_STACK (3);
8051                         sp -= 3;
8052                         if (sp [0]->type != STACK_OBJ)
8053                                 UNVERIFIED;
8054                         klass = array_access_to_klass (*ip, sp [0]);
8055                         NEW_LDELEMA (cfg, load, sp, klass);
8056 #ifdef MONO_ARCH_SOFT_FLOAT
8057                         if (*ip == CEE_STELEM_R4) {
8058                                 handle_store_float (cfg, bblock, load, sp [2], ip);
8059                                 ip++;
8060                                 break;
8061                         }
8062 #endif
8063                         MONO_INST_NEW (cfg, ins, stelem_to_stind [*ip - CEE_STELEM_I]);
8064                         ins->inst_left = load;
8065                         ins->inst_right = sp [2];
8066                         ++ip;
8067                         handle_loaded_temps (cfg, bblock, stack_start, sp);
8068                         MONO_ADD_INS (bblock, ins);
8069                         inline_costs += 1;
8070                         break;
8071                 }
8072                 case CEE_STELEM_ANY: {
8073                         MonoInst *load;
8074                         /*
8075                          * translate to:
8076                          * stind.x (ldelema (array, index), val)
8077                          * ldelema does the bounds check
8078                          */
8079                         CHECK_STACK (3);
8080                         sp -= 3;
8081                         if (sp [0]->type != STACK_OBJ)
8082                                 UNVERIFIED;
8083                         CHECK_OPSIZE (5);
8084                         token = read32 (ip + 1);
8085                         klass = mini_get_class (method, token, generic_context);
8086                         CHECK_TYPELOAD (klass);
8087                         mono_class_init (klass);
8088                         if (generic_class_is_reference_type (cfg, klass)) {
8089                                 /* storing a NULL doesn't need any of the complex checks in stelemref */
8090                                 if (sp [2]->opcode == OP_PCONST && sp [2]->inst_p0 == NULL) {
8091                                         MonoInst *load;
8092                                         NEW_LDELEMA (cfg, load, sp, mono_defaults.object_class);
8093                                         MONO_INST_NEW (cfg, ins, stelem_to_stind [*ip - CEE_STELEM_I]);
8094                                         ins->inst_left = load;
8095                                         ins->inst_right = sp [2];
8096                                         MONO_ADD_INS (bblock, ins);
8097                                 } else {
8098                                         MonoMethod* helper = mono_marshal_get_stelemref ();
8099                                         MonoInst *iargs [3];
8100                                         handle_loaded_temps (cfg, bblock, stack_start, sp);
8101
8102                                         iargs [2] = sp [2];
8103                                         iargs [1] = sp [1];
8104                                         iargs [0] = sp [0];
8105
8106                                         mono_emit_method_call_spilled (cfg, bblock, helper, mono_method_signature (helper), iargs, ip, NULL);
8107                                 }
8108                         } else {
8109                                 NEW_LDELEMA (cfg, load, sp, klass);
8110
8111                                 n = mini_type_to_stind (cfg, &klass->byval_arg);
8112                                 /* FIXME: CEE_STIND_R4 */
8113                                 if (n == CEE_STOBJ)
8114                                         handle_stobj (cfg, bblock, load, sp [2], ip, klass, FALSE, FALSE, TRUE);
8115                                 else {
8116                                         MONO_INST_NEW (cfg, ins, n);
8117                                         ins->inst_left = load;
8118                                         ins->inst_right = sp [2];
8119                                         handle_loaded_temps (cfg, bblock, stack_start, sp);
8120                                         MONO_ADD_INS (bblock, ins);
8121                                 }
8122                         }
8123                         ip += 5;
8124                         inline_costs += 1;
8125                         break;
8126                 }
8127                 case CEE_STELEM_REF: {
8128                         MonoInst *iargs [3];
8129                         MonoMethod* helper = mono_marshal_get_stelemref ();
8130
8131                         CHECK_STACK (3);
8132                         sp -= 3;
8133                         if (sp [0]->type != STACK_OBJ)
8134                                 UNVERIFIED;
8135                         if (sp [2]->type != STACK_OBJ)
8136                                 UNVERIFIED;
8137
8138                         handle_loaded_temps (cfg, bblock, stack_start, sp);
8139
8140                         /* storing a NULL doesn't need any of the complex checks in stelemref */
8141                         if (sp [2]->opcode == OP_PCONST && sp [2]->inst_p0 == NULL) {
8142                                 MonoInst *load;
8143                                 NEW_LDELEMA (cfg, load, sp, mono_defaults.object_class);
8144                                 MONO_INST_NEW (cfg, ins, stelem_to_stind [*ip - CEE_STELEM_I]);
8145                                 ins->inst_left = load;
8146                                 ins->inst_right = sp [2];
8147                                 MONO_ADD_INS (bblock, ins);
8148                         } else {
8149                                 iargs [2] = sp [2];
8150                                 iargs [1] = sp [1];
8151                                 iargs [0] = sp [0];
8152                         
8153                                 mono_emit_method_call_spilled (cfg, bblock, helper, mono_method_signature (helper), iargs, ip, NULL);
8154                                 inline_costs += 1;
8155                         }
8156
8157                         ++ip;
8158                         break;
8159                 }
8160                 case CEE_CKFINITE: {
8161                         MonoInst *store, *temp;
8162                         CHECK_STACK (1);
8163
8164                         /* this instr. can throw exceptions as side effect,
8165                          * so we cant eliminate dead code which contains CKFINITE opdodes.
8166                          * Spilling to memory makes sure that we always perform
8167                          * this check */
8168
8169                         
8170                         MONO_INST_NEW (cfg, ins, OP_CKFINITE);
8171                         ins->inst_left = sp [-1];
8172                         temp = mono_compile_create_var (cfg, &mono_defaults.double_class->byval_arg, OP_LOCAL);
8173
8174                         NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
8175                         MONO_ADD_INS (bblock, store);
8176
8177                         NEW_TEMPLOAD (cfg, sp [-1], temp->inst_c0);
8178                        
8179                         ++ip;
8180                         break;
8181                 }
8182                 case CEE_REFANYVAL: {
8183                         int context_used = 0;
8184
8185                         CHECK_STACK (1);
8186                         --sp;
8187                         CHECK_OPSIZE (5);
8188                         token = read32 (ip + 1);
8189                         klass = mono_class_get_full (image, token, generic_context);
8190                         CHECK_TYPELOAD (klass);
8191                         mono_class_init (klass);
8192
8193                         if (cfg->generic_sharing_context) {
8194                                 context_used = mono_class_check_context_used (klass);
8195                                 if (context_used && cfg->compile_aot)
8196                                         GENERIC_SHARING_FAILURE (*ip);
8197                         }
8198
8199                         if (context_used) {
8200                                 MonoInst *rgctx;
8201
8202                                 MONO_INST_NEW (cfg, ins, OP_REFANYVAL_REG);
8203                                 ins->type = STACK_MP;
8204                                 ins->inst_left = *sp;
8205                                 ins->klass = klass;
8206
8207                                 GET_RGCTX (rgctx);
8208                                 ins->inst_right = get_runtime_generic_context_ptr (cfg, method,
8209                                                 bblock, klass,
8210                                                 token, MINI_TOKEN_SOURCE_CLASS, generic_context,
8211                                                 rgctx, MONO_RGCTX_INFO_KLASS, ip);
8212                         } else {
8213                                 MONO_INST_NEW (cfg, ins, *ip);
8214                                 ins->type = STACK_MP;
8215                                 ins->inst_left = *sp;
8216                                 ins->klass = klass;
8217                                 ins->inst_newa_class = klass;
8218                         }
8219                         ip += 5;
8220                         *sp++ = ins;
8221                         break;
8222                 }
8223                 case CEE_MKREFANY: {
8224                         MonoInst *loc;
8225                         int context_used = 0;
8226
8227                         CHECK_STACK (1);
8228                         --sp;
8229                         CHECK_OPSIZE (5);
8230                         token = read32 (ip + 1);
8231                         klass = mono_class_get_full (image, token, generic_context);
8232                         CHECK_TYPELOAD (klass);
8233                         mono_class_init (klass);
8234
8235                         if (cfg->generic_sharing_context) {
8236                                 context_used = mono_class_check_context_used (klass);
8237                                 if (context_used && cfg->compile_aot)
8238                                         GENERIC_SHARING_FAILURE (CEE_MKREFANY);
8239                         }
8240
8241                         loc = mono_compile_create_var (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL);
8242                         if (context_used) {
8243                                 MonoInst *rgctx, *klass_type, *klass_klass, *loc_load;
8244
8245                                 GET_RGCTX (rgctx);
8246                                 klass_klass = get_runtime_generic_context_ptr (cfg, method, bblock, klass,
8247                                                 token, MINI_TOKEN_SOURCE_CLASS, generic_context,
8248                                                 rgctx, MONO_RGCTX_INFO_KLASS, ip);
8249                                 GET_RGCTX (rgctx);
8250                                 klass_type = get_runtime_generic_context_ptr (cfg, method, bblock, klass,
8251                                                 token, MINI_TOKEN_SOURCE_CLASS, generic_context,
8252                                                 rgctx, MONO_RGCTX_INFO_TYPE, ip);
8253
8254                                 NEW_TEMPLOADA (cfg, loc_load, loc->inst_c0);
8255
8256                                 MONO_INST_NEW (cfg, ins, OP_MKREFANY_REGS);
8257                                 NEW_GROUP (cfg, ins->inst_left, klass_type, klass_klass);
8258                                 NEW_GROUP (cfg, ins->inst_right, *sp, loc_load);
8259                         } else {
8260                                 MonoInst *klassconst;
8261
8262                                 NEW_PCONST (cfg, klassconst, klass);
8263
8264                                 MONO_INST_NEW (cfg, ins, *ip);
8265                                 NEW_TEMPLOADA (cfg, ins->inst_right, loc->inst_c0);
8266                                 NEW_GROUP (cfg, ins->inst_left, *sp, klassconst);
8267                         }
8268
8269                         MONO_ADD_INS (bblock, ins);
8270
8271                         NEW_TEMPLOAD (cfg, *sp, loc->inst_c0);
8272                         ++sp;
8273                         ip += 5;
8274                         break;
8275                 }
8276                 case CEE_LDTOKEN: {
8277                         gpointer handle;
8278                         MonoClass *handle_class;
8279                         int context_used = 0;
8280
8281                         CHECK_STACK_OVF (1);
8282
8283                         CHECK_OPSIZE (5);
8284                         n = read32 (ip + 1);
8285
8286                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
8287                                 handle = mono_method_get_wrapper_data (method, n);
8288                                 handle_class = mono_method_get_wrapper_data (method, n + 1);
8289                                 if (handle_class == mono_defaults.typehandle_class)
8290                                         handle = &((MonoClass*)handle)->byval_arg;
8291                         }
8292                         else {
8293                                 handle = mono_ldtoken (image, n, &handle_class, generic_context);
8294                         }
8295                         if (!handle)
8296                                 goto load_error;
8297                         mono_class_init (handle_class);
8298
8299                         if (cfg->generic_sharing_context) {
8300                                 if (handle_class == mono_defaults.typehandle_class) {
8301                                         /* If we get a MONO_TYPE_CLASS
8302                                            then we need to provide the
8303                                            open type, not an
8304                                            instantiation of it. */
8305                                         if (mono_type_get_type (handle) == MONO_TYPE_CLASS)
8306                                                 context_used = 0;
8307                                         else
8308                                                 context_used = mono_class_check_context_used (mono_class_from_mono_type (handle));
8309                                 } else if (handle_class == mono_defaults.fieldhandle_class)
8310                                         context_used = mono_class_check_context_used (((MonoClassField*)handle)->parent);
8311                                 else if (handle_class == mono_defaults.methodhandle_class)
8312                                         context_used = mono_method_check_context_used (handle);
8313                                 else
8314                                         g_assert_not_reached ();
8315
8316                                 if (context_used & MONO_GENERIC_CONTEXT_USED_METHOD)
8317                                         GENERIC_SHARING_FAILURE (CEE_LDTOKEN);
8318                         }
8319
8320                         if (cfg->opt & MONO_OPT_SHARED) {
8321                                 int temp;
8322                                 MonoInst *res, *store, *addr, *vtvar, *iargs [3];
8323
8324                                 vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL); 
8325
8326                                 NEW_IMAGECONST (cfg, iargs [0], image);
8327                                 NEW_ICONST (cfg, iargs [1], n);
8328                                 if (cfg->generic_sharing_context) {
8329                                         MonoInst *rgctx;
8330
8331                                         GET_RGCTX (rgctx);
8332                                         iargs [2] = get_runtime_generic_context_method (cfg, method, bblock, method,
8333                                                         generic_context, rgctx, MONO_RGCTX_INFO_METHOD, ip);
8334                                         temp = mono_emit_jit_icall (cfg, bblock, mono_ldtoken_wrapper_generic_shared,
8335                                                         iargs, ip);
8336                                 } else {
8337                                         NEW_PCONST (cfg, iargs [2], generic_context);
8338                                         temp = mono_emit_jit_icall (cfg, bblock, mono_ldtoken_wrapper, iargs, ip);
8339                                 }
8340                                 NEW_TEMPLOAD (cfg, res, temp);
8341                                 NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
8342                                 NEW_INDSTORE (cfg, store, addr, res, &mono_defaults.int_class->byval_arg);
8343                                 MONO_ADD_INS (bblock, store);
8344                                 NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
8345                         } else {
8346                                 if ((ip + 10 < end) && ip_in_bb (cfg, bblock, ip + 5) &&
8347                                         handle_class == mono_defaults.typehandle_class &&
8348                                         ((ip [5] == CEE_CALL) || (ip [5] == CEE_CALLVIRT)) && 
8349                                         (cmethod = mini_get_method (cfg, method, read32 (ip + 6), NULL, generic_context)) &&
8350                                         (cmethod->klass == mono_defaults.monotype_class->parent) &&
8351                                         (strcmp (cmethod->name, "GetTypeFromHandle") == 0)) {
8352                                         MonoClass *tclass = mono_class_from_mono_type (handle);
8353                                         mono_class_init (tclass);
8354                                         if (context_used) {
8355                                                 MonoInst *this, *rgctx;
8356
8357                                                 g_assert (!cfg->compile_aot);
8358                                                 if (!(method->flags & METHOD_ATTRIBUTE_STATIC))
8359                                                         NEW_ARGLOAD (cfg, this, 0);
8360                                                 rgctx = get_runtime_generic_context (cfg, method, this, ip);
8361                                                 ins = get_runtime_generic_context_ptr (cfg, method, bblock, tclass,
8362                                                         token, MINI_TOKEN_SOURCE_CLASS, generic_context,
8363                                                         rgctx, MONO_RGCTX_INFO_REFLECTION_TYPE, ip);
8364                                         } else if (cfg->compile_aot) {
8365                                                 NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, image, n);
8366                                         } else {
8367                                                 NEW_PCONST (cfg, ins, mono_type_get_object (cfg->domain, handle));
8368                                         }
8369                                         ins->type = STACK_OBJ;
8370                                         ins->klass = cmethod->klass;
8371                                         ip += 5;
8372                                 } else {
8373                                         MonoInst *store, *addr, *vtvar;
8374
8375                                         GENERIC_SHARING_FAILURE (CEE_LDTOKEN);
8376
8377                                         if (cfg->compile_aot)
8378                                                 NEW_LDTOKENCONST (cfg, ins, image, n);
8379                                         else
8380                                                 NEW_PCONST (cfg, ins, handle);
8381                                         vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL);
8382                                         NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
8383                                         NEW_INDSTORE (cfg, store, addr, ins, &mono_defaults.int_class->byval_arg);
8384                                         MONO_ADD_INS (bblock, store);
8385                                         NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
8386                                 }
8387                         }
8388
8389                         *sp++ = ins;
8390                         ip += 5;
8391                         break;
8392                 }
8393                 case CEE_CONV_U2:
8394                 case CEE_CONV_U1:
8395                 case CEE_CONV_I:
8396                         CHECK_STACK (1);
8397                         ADD_UNOP (*ip);
8398                         ip++;
8399                         break;
8400                 case CEE_ADD_OVF:
8401                 case CEE_ADD_OVF_UN:
8402                 case CEE_MUL_OVF:
8403                 case CEE_MUL_OVF_UN:
8404                 case CEE_SUB_OVF:
8405                 case CEE_SUB_OVF_UN:
8406                         CHECK_STACK (2);
8407                         ADD_BINOP (*ip);
8408                         if (mono_find_jit_opcode_emulation (ins->opcode)) {
8409                                 --sp;
8410                                 *sp++ = emit_tree (cfg, bblock, ins, ip + 1);
8411                         }
8412                         ip++;
8413                         break;
8414                 case CEE_ENDFINALLY:
8415                         MONO_INST_NEW (cfg, ins, OP_ENDFINALLY);
8416                         MONO_ADD_INS (bblock, ins);
8417                         ip++;
8418                         start_new_bblock = 1;
8419
8420                         /*
8421                          * Control will leave the method so empty the stack, otherwise
8422                          * the next basic block will start with a nonempty stack.
8423                          */
8424                         while (sp != stack_start) {
8425                                 MONO_INST_NEW (cfg, ins, CEE_POP);
8426                                 sp--;
8427                                 ins->inst_i0 = *sp;
8428                                 MONO_ADD_INS (bblock, ins);
8429                         }
8430                         break;
8431                 case CEE_LEAVE:
8432                 case CEE_LEAVE_S: {
8433                         GList *handlers;
8434
8435                         if (*ip == CEE_LEAVE) {
8436                                 CHECK_OPSIZE (5);
8437                                 target = ip + 5 + (gint32)read32(ip + 1);
8438                         } else {
8439                                 CHECK_OPSIZE (2);
8440                                 target = ip + 2 + (signed char)(ip [1]);
8441                         }
8442
8443                         /* empty the stack */
8444                         while (sp != stack_start) {
8445                                 MONO_INST_NEW (cfg, ins, CEE_POP);
8446                                 sp--;
8447                                 ins->inst_i0 = *sp;
8448                                 MONO_ADD_INS (bblock, ins);
8449                         }
8450
8451                         /* 
8452                          * If this leave statement is in a catch block, check for a
8453                          * pending exception, and rethrow it if necessary.
8454                          */
8455                         for (i = 0; i < header->num_clauses; ++i) {
8456                                 MonoExceptionClause *clause = &header->clauses [i];
8457
8458                                 /* 
8459                                  * Use <= in the final comparison to handle clauses with multiple
8460                                  * leave statements, like in bug #78024.
8461                                  * The ordering of the exception clauses guarantees that we find the
8462                                  * innermost clause.
8463                                  */
8464                                 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)) {
8465                                         int temp;
8466                                         MonoInst *load;
8467
8468                                         NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, clause->handler_offset)->inst_c0);
8469
8470                                         temp = mono_emit_jit_icall (cfg, bblock, mono_thread_get_undeniable_exception, NULL, ip);
8471                                         NEW_TEMPLOAD (cfg, *sp, temp);
8472                                 
8473                                         MONO_INST_NEW (cfg, ins, OP_THROW_OR_NULL);
8474                                         ins->inst_left = *sp;
8475                                         ins->inst_right = load;
8476                                         MONO_ADD_INS (bblock, ins);
8477                                 }
8478                         }
8479
8480                         if ((handlers = mono_find_final_block (cfg, ip, target, MONO_EXCEPTION_CLAUSE_FINALLY))) {
8481                                 GList *tmp;
8482                                 for (tmp = handlers; tmp; tmp = tmp->next) {
8483                                         tblock = tmp->data;
8484                                         link_bblock (cfg, bblock, tblock);
8485                                         MONO_INST_NEW (cfg, ins, OP_CALL_HANDLER);
8486                                         ins->inst_target_bb = tblock;
8487                                         MONO_ADD_INS (bblock, ins);
8488                                 }
8489                                 g_list_free (handlers);
8490                         } 
8491
8492                         MONO_INST_NEW (cfg, ins, OP_BR);
8493                         MONO_ADD_INS (bblock, ins);
8494                         GET_BBLOCK (cfg, tblock, target);
8495                         link_bblock (cfg, bblock, tblock);
8496                         CHECK_BBLOCK (target, ip, tblock);
8497                         ins->inst_target_bb = tblock;
8498                         start_new_bblock = 1;
8499
8500                         if (*ip == CEE_LEAVE)
8501                                 ip += 5;
8502                         else
8503                                 ip += 2;
8504
8505                         break;
8506                 }
8507                 case CEE_STIND_I:
8508                         CHECK_STACK (2);
8509                         MONO_INST_NEW (cfg, ins, *ip);
8510                         sp -= 2;
8511                         handle_loaded_temps (cfg, bblock, stack_start, sp);
8512                         MONO_ADD_INS (bblock, ins);
8513                         ip++;
8514                         ins->inst_i0 = sp [0];
8515                         ins->inst_i1 = sp [1];
8516                         inline_costs += 1;
8517                         break;
8518                 case CEE_CONV_U:
8519                         CHECK_STACK (1);
8520                         ADD_UNOP (*ip);
8521                         ip++;
8522                         break;
8523                 /* trampoline mono specific opcodes */
8524                 case MONO_CUSTOM_PREFIX: {
8525
8526                         g_assert (method->wrapper_type != MONO_WRAPPER_NONE);
8527
8528                         CHECK_OPSIZE (2);
8529                         switch (ip [1]) {
8530
8531                         case CEE_MONO_ICALL: {
8532                                 int temp;
8533                                 gpointer func;
8534                                 MonoJitICallInfo *info;
8535
8536                                 token = read32 (ip + 2);
8537                                 func = mono_method_get_wrapper_data (method, token);
8538                                 info = mono_find_jit_icall_by_addr (func);
8539                                 if (info == NULL){
8540                                         g_error ("An attempt has been made to perform an icall to address %p, "
8541                                                  "but the address has not been registered as an icall\n", info);
8542                                         g_assert_not_reached ();
8543                                 }
8544
8545                                 CHECK_STACK (info->sig->param_count);
8546                                 sp -= info->sig->param_count;
8547
8548                                 temp = mono_emit_jit_icall (cfg, bblock, info->func, sp, ip);
8549                                 if (!MONO_TYPE_IS_VOID (info->sig->ret)) {
8550                                         NEW_TEMPLOAD (cfg, *sp, temp);
8551                                         sp++;
8552                                 }
8553
8554                                 ip += 6;
8555                                 inline_costs += 10 * num_calls++;
8556
8557                                 break;
8558                         }
8559                         case CEE_MONO_LDPTR: {
8560                                 gpointer ptr;
8561
8562                                 CHECK_STACK_OVF (1);
8563                                 CHECK_OPSIZE (6);
8564                                 token = read32 (ip + 2);
8565
8566                                 ptr = mono_method_get_wrapper_data (method, token);
8567                                 if (cfg->compile_aot && cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
8568                                         MonoMethod *wrapped = mono_marshal_method_from_wrapper (cfg->method);
8569
8570                                         if (wrapped && ptr != NULL && mono_lookup_internal_call (wrapped) == ptr) {
8571                                                 NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_ICALL_ADDR, wrapped);
8572                                                 *sp++ = ins;
8573                                                 ip += 6;
8574                                                 break;
8575                                         }
8576                                 }
8577                                 NEW_PCONST (cfg, ins, ptr);
8578                                 *sp++ = ins;
8579                                 ip += 6;
8580                                 inline_costs += 10 * num_calls++;
8581                                 /* Can't embed random pointers into AOT code */
8582                                 cfg->disable_aot = 1;
8583                                 break;
8584                         }
8585                         case CEE_MONO_VTADDR:
8586                                 CHECK_STACK (1);
8587                                 --sp;
8588                                 MONO_INST_NEW (cfg, ins, OP_VTADDR);
8589                                 ins->type = STACK_MP;
8590                                 ins->inst_left = *sp;
8591                                 *sp++ = ins;
8592                                 ip += 2;
8593                                 break;
8594                         case CEE_MONO_NEWOBJ: {
8595                                 MonoInst *iargs [2];
8596                                 int temp;
8597                                 CHECK_STACK_OVF (1);
8598                                 CHECK_OPSIZE (6);
8599                                 token = read32 (ip + 2);
8600                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
8601                                 mono_class_init (klass);
8602                                 NEW_DOMAINCONST (cfg, iargs [0]);
8603                                 NEW_CLASSCONST (cfg, iargs [1], klass);
8604                                 temp = mono_emit_jit_icall (cfg, bblock, mono_object_new, iargs, ip);
8605                                 NEW_TEMPLOAD (cfg, *sp, temp);
8606                                 sp++;
8607                                 ip += 6;
8608                                 inline_costs += 10 * num_calls++;
8609                                 break;
8610                         }
8611                         case CEE_MONO_OBJADDR:
8612                                 CHECK_STACK (1);
8613                                 --sp;
8614                                 MONO_INST_NEW (cfg, ins, OP_OBJADDR);
8615                                 ins->type = STACK_MP;
8616                                 ins->inst_left = *sp;
8617                                 *sp++ = ins;
8618                                 ip += 2;
8619                                 break;
8620                         case CEE_MONO_LDNATIVEOBJ:
8621                                 CHECK_STACK (1);
8622                                 CHECK_OPSIZE (6);
8623                                 token = read32 (ip + 2);
8624                                 klass = mono_method_get_wrapper_data (method, token);
8625                                 g_assert (klass->valuetype);
8626                                 mono_class_init (klass);
8627                                 NEW_INDLOAD (cfg, ins, sp [-1], &klass->byval_arg);
8628                                 sp [-1] = ins;
8629                                 ip += 6;
8630                                 break;
8631                         case CEE_MONO_RETOBJ:
8632                                 g_assert (cfg->ret);
8633                                 g_assert (mono_method_signature (method)->pinvoke); 
8634                                 CHECK_STACK (1);
8635                                 --sp;
8636                                 
8637                                 CHECK_OPSIZE (6);
8638                                 token = read32 (ip + 2);    
8639                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
8640
8641                                 NEW_RETLOADA (cfg, ins);
8642                                 handle_stobj (cfg, bblock, ins, *sp, ip, klass, FALSE, TRUE, FALSE);
8643                                 
8644                                 if (sp != stack_start)
8645                                         UNVERIFIED;
8646                                 
8647                                 MONO_INST_NEW (cfg, ins, OP_BR);
8648                                 ins->inst_target_bb = end_bblock;
8649                                 MONO_ADD_INS (bblock, ins);
8650                                 link_bblock (cfg, bblock, end_bblock);
8651                                 start_new_bblock = 1;
8652                                 ip += 6;
8653                                 break;
8654                         case CEE_MONO_CISINST:
8655                         case CEE_MONO_CCASTCLASS: {
8656                                 int token;
8657                                 CHECK_STACK (1);
8658                                 --sp;
8659                                 CHECK_OPSIZE (6);
8660                                 token = read32 (ip + 2);
8661                                 /* Needed by the code generated in inssel.brg */
8662                                 mono_get_got_var (cfg);
8663                 
8664                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
8665                                 MONO_INST_NEW (cfg, ins, (ip [1] == CEE_MONO_CISINST) ? OP_CISINST : OP_CCASTCLASS);
8666                                 ins->type = STACK_I4;
8667                                 ins->inst_left = *sp;
8668                                 ins->inst_newa_class = klass;
8669                                 *sp++ = emit_tree (cfg, bblock, ins, ip + 6);
8670                                 ip += 6;
8671                                 break;
8672                         }
8673                         case CEE_MONO_SAVE_LMF:
8674                         case CEE_MONO_RESTORE_LMF:
8675 #ifdef MONO_ARCH_HAVE_LMF_OPS
8676                                 MONO_INST_NEW (cfg, ins, (ip [1] == CEE_MONO_SAVE_LMF) ? OP_SAVE_LMF : OP_RESTORE_LMF);
8677                                 MONO_ADD_INS (bblock, ins);
8678                                 cfg->need_lmf_area = TRUE;
8679 #endif
8680                                 ip += 2;
8681                                 break;
8682                         case CEE_MONO_CLASSCONST:
8683                                 CHECK_STACK_OVF (1);
8684                                 CHECK_OPSIZE (6);
8685                                 token = read32 (ip + 2);
8686                                 NEW_CLASSCONST (cfg, ins, mono_method_get_wrapper_data (method, token));
8687                                 *sp++ = ins;
8688                                 ip += 6;
8689                                 inline_costs += 10 * num_calls++;
8690                                 break;
8691                         case CEE_MONO_NOT_TAKEN:
8692                                 bblock->out_of_line = TRUE;
8693                                 ip += 2;
8694                                 break;
8695                         case CEE_MONO_TLS:
8696                                 CHECK_STACK_OVF (1);
8697                                 CHECK_OPSIZE (6);
8698                                 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
8699                                 ins->inst_offset = (gint32)read32 (ip + 2);
8700                                 ins->type = STACK_PTR;
8701                                 *sp++ = ins;
8702                                 ip += 6;
8703                                 break;
8704                         default:
8705                                 g_error ("opcode 0x%02x 0x%02x not handled", MONO_CUSTOM_PREFIX, ip [1]);
8706                                 break;
8707                         }
8708                         break;
8709                 }
8710                 case CEE_PREFIX1: {
8711                         CHECK_OPSIZE (2);
8712                         switch (ip [1]) {
8713                         case CEE_ARGLIST: {
8714                                 /* somewhat similar to LDTOKEN */
8715                                 MonoInst *addr, *vtvar;
8716                                 CHECK_STACK_OVF (1);
8717                                 vtvar = mono_compile_create_var (cfg, &mono_defaults.argumenthandle_class->byval_arg, OP_LOCAL); 
8718
8719                                 NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
8720                                 MONO_INST_NEW (cfg, ins, OP_ARGLIST);
8721                                 ins->inst_left = addr;
8722                                 MONO_ADD_INS (bblock, ins);
8723                                 NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
8724                                 *sp++ = ins;
8725                                 ip += 2;
8726                                 break;
8727                         }
8728                         case CEE_CEQ:
8729                         case CEE_CGT:
8730                         case CEE_CGT_UN:
8731                         case CEE_CLT:
8732                         case CEE_CLT_UN: {
8733                                 MonoInst *cmp;
8734                                 CHECK_STACK (2);
8735                                 /*
8736                                  * The following transforms:
8737                                  *    CEE_CEQ    into OP_CEQ
8738                                  *    CEE_CGT    into OP_CGT
8739                                  *    CEE_CGT_UN into OP_CGT_UN
8740                                  *    CEE_CLT    into OP_CLT
8741                                  *    CEE_CLT_UN into OP_CLT_UN
8742                                  */
8743                                 MONO_INST_NEW (cfg, cmp, (OP_CEQ - CEE_CEQ) + ip [1]);
8744                                 
8745                                 MONO_INST_NEW (cfg, ins, cmp->opcode);
8746                                 sp -= 2;
8747                                 cmp->inst_i0 = sp [0];
8748                                 cmp->inst_i1 = sp [1];
8749                                 type_from_op (cmp);
8750                                 CHECK_TYPE (cmp);
8751                                 ins->type = STACK_I4;
8752                                 ins->inst_i0 = cmp;
8753 #if MONO_ARCH_SOFT_FLOAT
8754                                 if (sp [0]->type == STACK_R8) {
8755                                         cmp->type = STACK_I4;
8756                                         *sp++ = emit_tree (cfg, bblock, cmp, ip + 2);
8757                                         ip += 2;
8758                                         break;
8759                                 }
8760 #endif
8761                                 if ((sp [0]->type == STACK_I8) || ((sizeof (gpointer) == 8) && ((sp [0]->type == STACK_PTR) || (sp [0]->type == STACK_OBJ) || (sp [0]->type == STACK_MP))))
8762                                         cmp->opcode = OP_LCOMPARE;
8763                                 else
8764                                         cmp->opcode = OP_COMPARE;
8765                                 *sp++ = ins;
8766                                 /* spill it to reduce the expression complexity
8767                                  * and workaround bug 54209 
8768                                  */
8769                                 if (cmp->inst_left->type == STACK_I8) {
8770                                         --sp;
8771                                         *sp++ = emit_tree (cfg, bblock, ins, ip + 2);
8772                                 }
8773                                 ip += 2;
8774                                 break;
8775                         }
8776                         case CEE_LDFTN: {
8777                                 MonoInst *argconst;
8778                                 MonoMethod *cil_method, *ctor_method;
8779                                 int temp;
8780                                 gboolean is_shared;
8781
8782                                 CHECK_STACK_OVF (1);
8783                                 CHECK_OPSIZE (6);
8784                                 n = read32 (ip + 2);
8785                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
8786                                 if (!cmethod)
8787                                         goto load_error;
8788                                 mono_class_init (cmethod->klass);
8789
8790                                 if (cfg->generic_sharing_context && mono_method_check_context_used (cmethod))
8791                                         GENERIC_SHARING_FAILURE (CEE_LDFTN);
8792
8793                                 is_shared = (cmethod->flags & METHOD_ATTRIBUTE_STATIC) &&
8794                                         (cmethod->klass->generic_class || cmethod->klass->generic_container) &&
8795                                         mono_class_generic_sharing_enabled (cmethod->klass);
8796
8797                                 cil_method = cmethod;
8798                                 if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_method (method, cmethod))
8799                                         METHOD_ACCESS_FAILURE;
8800                                 if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS) {
8801                                         if (check_linkdemand (cfg, method, cmethod, bblock, ip))
8802                                                 INLINE_FAILURE;
8803                                         CHECK_CFG_EXCEPTION;
8804                                 } else if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR) {
8805                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod, bblock, ip);
8806                                 }
8807
8808                                 /* 
8809                                  * Optimize the common case of ldftn+delegate creation
8810                                  */
8811 #if defined(MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE) && !defined(HAVE_WRITE_BARRIERS)
8812                                 /* FIXME: SGEN support */
8813                                 /* FIXME: handle shared static generic methods */
8814                                 if (!is_shared && (sp > stack_start) && (ip + 6 + 5 < end) && ip_in_bb (cfg, bblock, ip + 6) && (ip [6] == CEE_NEWOBJ) && (ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context)) && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
8815                                         MonoInst *target_ins;
8816
8817                                         ip += 6;
8818                                         if (cfg->verbose_level > 3)
8819                                                 g_print ("converting (in B%d: stack: %d) %s", bblock->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
8820                                         target_ins = sp [-1];
8821                                         sp --;
8822                                         *sp = handle_delegate_ctor (cfg, bblock, ctor_method->klass, target_ins, cmethod, ip);
8823                                         ip += 5;                                        
8824                                         sp ++;
8825                                         break;
8826                                 }
8827 #endif
8828
8829                                 handle_loaded_temps (cfg, bblock, stack_start, sp);
8830
8831                                 if (is_shared)
8832                                         NEW_METHODCONST (cfg, argconst, mono_marshal_get_static_rgctx_invoke (cmethod));
8833                                 else
8834                                         NEW_METHODCONST (cfg, argconst, cmethod);
8835                                 if (method->wrapper_type != MONO_WRAPPER_SYNCHRONIZED)
8836                                         temp = mono_emit_jit_icall (cfg, bblock, mono_ldftn, &argconst, ip);
8837                                 else
8838                                         temp = mono_emit_jit_icall (cfg, bblock, mono_ldftn_nosync, &argconst, ip);
8839                                 NEW_TEMPLOAD (cfg, *sp, temp);
8840                                 sp ++;
8841                                 
8842                                 ip += 6;
8843                                 inline_costs += 10 * num_calls++;
8844                                 break;
8845                         }
8846                         case CEE_LDVIRTFTN: {
8847                                 MonoInst *args [2];
8848                                 int temp;
8849
8850                                 CHECK_STACK (1);
8851                                 CHECK_OPSIZE (6);
8852                                 n = read32 (ip + 2);
8853                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
8854                                 if (!cmethod)
8855                                         goto load_error;
8856                                 mono_class_init (cmethod->klass);
8857
8858                                 if (cfg->generic_sharing_context && mono_method_check_context_used (cmethod))
8859                                         GENERIC_SHARING_FAILURE (CEE_LDVIRTFTN);
8860
8861                                 if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS) {
8862                                         if (check_linkdemand (cfg, method, cmethod, bblock, ip))
8863                                                 INLINE_FAILURE;
8864                                         CHECK_CFG_EXCEPTION;
8865                                 } else if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR) {
8866                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod, bblock, ip);
8867                                 }
8868
8869                                 handle_loaded_temps (cfg, bblock, stack_start, sp);
8870
8871                                 --sp;
8872                                 args [0] = *sp;
8873                                 NEW_METHODCONST (cfg, args [1], cmethod);
8874                                 temp = mono_emit_jit_icall (cfg, bblock, mono_ldvirtfn, args, ip);
8875                                 NEW_TEMPLOAD (cfg, *sp, temp);
8876                                 sp ++;
8877
8878                                 ip += 6;
8879                                 inline_costs += 10 * num_calls++;
8880                                 break;
8881                         }
8882                         case CEE_LDARG:
8883                                 CHECK_STACK_OVF (1);
8884                                 CHECK_OPSIZE (4);
8885                                 n = read16 (ip + 2);
8886                                 CHECK_ARG (n);
8887                                 NEW_ARGLOAD (cfg, ins, n);
8888                                 LDARG_SOFT_FLOAT (cfg, ins, n, ip);
8889                                 *sp++ = ins;
8890                                 ip += 4;
8891                                 break;
8892                         case CEE_LDARGA:
8893                                 CHECK_STACK_OVF (1);
8894                                 CHECK_OPSIZE (4);
8895                                 n = read16 (ip + 2);
8896                                 CHECK_ARG (n);
8897                                 NEW_ARGLOADA (cfg, ins, n);
8898                                 *sp++ = ins;
8899                                 ip += 4;
8900                                 break;
8901                         case CEE_STARG:
8902                                 CHECK_STACK (1);
8903                                 --sp;
8904                                 handle_loaded_temps (cfg, bblock, stack_start, sp);
8905                                 CHECK_OPSIZE (4);
8906                                 n = read16 (ip + 2);
8907                                 CHECK_ARG (n);
8908                                 NEW_ARGSTORE (cfg, ins, n, *sp);
8909                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [n], *sp))
8910                                         UNVERIFIED;
8911                                 STARG_SOFT_FLOAT (cfg, ins, n, ip);
8912                                 if (ins->opcode == CEE_STOBJ) {
8913                                         NEW_ARGLOADA (cfg, ins, n);
8914                                         handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE, FALSE);
8915                                 } else
8916                                         MONO_ADD_INS (bblock, ins);
8917                                 ip += 4;
8918                                 break;
8919                         case CEE_LDLOC:
8920                                 CHECK_STACK_OVF (1);
8921                                 CHECK_OPSIZE (4);
8922                                 n = read16 (ip + 2);
8923                                 CHECK_LOCAL (n);
8924                                 NEW_LOCLOAD (cfg, ins, n);
8925                                 LDLOC_SOFT_FLOAT (cfg, ins, n, ip);
8926                                 *sp++ = ins;
8927                                 ip += 4;
8928                                 break;
8929                         case CEE_LDLOCA:
8930                                 CHECK_STACK_OVF (1);
8931                                 CHECK_OPSIZE (4);
8932                                 n = read16 (ip + 2);
8933                                 CHECK_LOCAL (n);
8934                                 NEW_LOCLOADA (cfg, ins, n);
8935                                 *sp++ = ins;
8936                                 ip += 4;
8937                                 break;
8938                         case CEE_STLOC:
8939                                 CHECK_STACK (1);
8940                                 --sp;
8941                                 CHECK_OPSIZE (4);
8942                                 n = read16 (ip + 2);
8943                                 CHECK_LOCAL (n);
8944                                 handle_loaded_temps (cfg, bblock, stack_start, sp);
8945                                 NEW_LOCSTORE (cfg, ins, n, *sp);
8946                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
8947                                         UNVERIFIED;
8948                                 STLOC_SOFT_FLOAT (cfg, ins, n, ip);
8949                                 if (ins->opcode == CEE_STOBJ) {
8950                                         NEW_LOCLOADA (cfg, ins, n);
8951                                         handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE, FALSE);
8952                                 } else
8953                                         MONO_ADD_INS (bblock, ins);
8954                                 ip += 4;
8955                                 inline_costs += 1;
8956                                 break;
8957                         case CEE_LOCALLOC:
8958                                 CHECK_STACK (1);
8959                                 --sp;
8960                                 if (sp != stack_start) 
8961                                         UNVERIFIED;
8962                                 if (cfg->method != method) 
8963                                         /* 
8964                                          * Inlining this into a loop in a parent could lead to 
8965                                          * stack overflows which is different behavior than the
8966                                          * non-inlined case, thus disable inlining in this case.
8967                                          */
8968                                         goto inline_failure;
8969                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
8970                                 ins->inst_left = *sp;
8971                                 ins->type = STACK_PTR;
8972
8973                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
8974                                 if (header->init_locals)
8975                                         ins->flags |= MONO_INST_INIT;
8976
8977                                 *sp++ = ins;
8978                                 ip += 2;
8979                                 /* FIXME: set init flag if locals init is set in this method */
8980                                 break;
8981                         case CEE_ENDFILTER: {
8982                                 MonoExceptionClause *clause, *nearest;
8983                                 int cc, nearest_num;
8984
8985                                 CHECK_STACK (1);
8986                                 --sp;
8987                                 if ((sp != stack_start) || (sp [0]->type != STACK_I4)) 
8988                                         UNVERIFIED;
8989                                 MONO_INST_NEW (cfg, ins, OP_ENDFILTER);
8990                                 ins->inst_left = *sp;
8991                                 MONO_ADD_INS (bblock, ins);
8992                                 start_new_bblock = 1;
8993                                 ip += 2;
8994
8995                                 nearest = NULL;
8996                                 nearest_num = 0;
8997                                 for (cc = 0; cc < header->num_clauses; ++cc) {
8998                                         clause = &header->clauses [cc];
8999                                         if ((clause->flags & MONO_EXCEPTION_CLAUSE_FILTER) &&
9000                                                 ((ip - header->code) > clause->data.filter_offset && (ip - header->code) <= clause->handler_offset) &&
9001                                             (!nearest || (clause->data.filter_offset < nearest->data.filter_offset))) {
9002                                                 nearest = clause;
9003                                                 nearest_num = cc;
9004                                         }
9005                                 }
9006                                 g_assert (nearest);
9007                                 if ((ip - header->code) != nearest->handler_offset)
9008                                         UNVERIFIED;
9009
9010                                 break;
9011                         }
9012                         case CEE_UNALIGNED_:
9013                                 ins_flag |= MONO_INST_UNALIGNED;
9014                                 /* FIXME: record alignment? we can assume 1 for now */
9015                                 CHECK_OPSIZE (3);
9016                                 ip += 3;
9017                                 break;
9018                         case CEE_VOLATILE_:
9019                                 ins_flag |= MONO_INST_VOLATILE;
9020                                 ip += 2;
9021                                 break;
9022                         case CEE_TAIL_:
9023                                 ins_flag   |= MONO_INST_TAILCALL;
9024                                 cfg->flags |= MONO_CFG_HAS_TAIL;
9025                                 /* Can't inline tail calls at this time */
9026                                 inline_costs += 100000;
9027                                 ip += 2;
9028                                 break;
9029                         case CEE_INITOBJ:
9030                                 CHECK_STACK (1);
9031                                 --sp;
9032                                 CHECK_OPSIZE (6);
9033                                 token = read32 (ip + 2);
9034                                 klass = mini_get_class (method, token, generic_context);
9035                                 CHECK_TYPELOAD (klass);
9036
9037                                 if (generic_class_is_reference_type (cfg, klass)) {
9038                                         MonoInst *store, *load;
9039                                         NEW_PCONST (cfg, load, NULL);
9040                                         load->type = STACK_OBJ;
9041                                         load->klass = klass;
9042                                         MONO_INST_NEW (cfg, store, CEE_STIND_REF);
9043                                         handle_loaded_temps (cfg, bblock, stack_start, sp);
9044                                         MONO_ADD_INS (bblock, store);
9045                                         store->inst_i0 = sp [0];
9046                                         store->inst_i1 = load;
9047                                 } else {
9048                                         GENERIC_SHARING_FAILURE (CEE_INITOBJ);
9049                                         handle_initobj (cfg, bblock, *sp, NULL, klass, stack_start, sp);
9050                                 }
9051                                 ip += 6;
9052                                 inline_costs += 1;
9053                                 break;
9054                         case CEE_CONSTRAINED_:
9055                                 /* FIXME: implement */
9056                                 CHECK_OPSIZE (6);
9057                                 token = read32 (ip + 2);
9058                                 constrained_call = mono_class_get_full (image, token, generic_context);
9059                                 CHECK_TYPELOAD (constrained_call);
9060                                 ip += 6;
9061                                 break;
9062                         case CEE_CPBLK:
9063                         case CEE_INITBLK: {
9064                                 MonoInst *iargs [3];
9065                                 CHECK_STACK (3);
9066                                 sp -= 3;
9067                                 if ((cfg->opt & MONO_OPT_INTRINS) && (ip [1] == CEE_CPBLK) && (sp [2]->opcode == OP_ICONST) && ((n = sp [2]->inst_c0) <= sizeof (gpointer) * 5)) {
9068                                         MonoInst *copy;
9069                                         NEW_MEMCPY (cfg, copy, sp [0], sp [1], n, 0);
9070                                         MONO_ADD_INS (bblock, copy);
9071                                         ip += 2;
9072                                         break;
9073                                 }
9074                                 iargs [0] = sp [0];
9075                                 iargs [1] = sp [1];
9076                                 iargs [2] = sp [2];
9077                                 handle_loaded_temps (cfg, bblock, stack_start, sp);
9078                                 if (ip [1] == CEE_CPBLK) {
9079                                         MonoMethod *memcpy_method = get_memcpy_method ();
9080                                         mono_emit_method_call_spilled (cfg, bblock, memcpy_method, memcpy_method->signature, iargs, ip, NULL);
9081                                 } else {
9082                                         MonoMethod *memset_method = get_memset_method ();
9083                                         mono_emit_method_call_spilled (cfg, bblock, memset_method, memset_method->signature, iargs, ip, NULL);
9084                                 }
9085                                 ip += 2;
9086                                 inline_costs += 1;
9087                                 break;
9088                         }
9089                         case CEE_NO_:
9090                                 CHECK_OPSIZE (3);
9091                                 if (ip [2] & 0x1)
9092                                         ins_flag |= MONO_INST_NOTYPECHECK;
9093                                 if (ip [2] & 0x2)
9094                                         ins_flag |= MONO_INST_NORANGECHECK;
9095                                 /* we ignore the no-nullcheck for now since we
9096                                  * really do it explicitly only when doing callvirt->call
9097                                  */
9098                                 ip += 3;
9099                                 break;
9100                         case CEE_RETHROW: {
9101                                 MonoInst *load;
9102                                 int handler_offset = -1;
9103
9104                                 for (i = 0; i < header->num_clauses; ++i) {
9105                                         MonoExceptionClause *clause = &header->clauses [i];
9106                                         if (MONO_OFFSET_IN_HANDLER (clause, ip - header->code) && !(clause->flags & MONO_EXCEPTION_CLAUSE_FINALLY))
9107                                                 handler_offset = clause->handler_offset;
9108                                 }
9109
9110                                 bblock->flags |= BB_EXCEPTION_UNSAFE;
9111
9112                                 g_assert (handler_offset != -1);
9113
9114                                 NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, handler_offset)->inst_c0);
9115                                 MONO_INST_NEW (cfg, ins, OP_RETHROW);
9116                                 ins->inst_left = load;
9117                                 MONO_ADD_INS (bblock, ins);
9118                                 sp = stack_start;
9119                                 link_bblock (cfg, bblock, end_bblock);
9120                                 start_new_bblock = 1;
9121                                 ip += 2;
9122                                 break;
9123                         }
9124                         case CEE_SIZEOF:
9125                                 GENERIC_SHARING_FAILURE (CEE_SIZEOF);
9126
9127                                 CHECK_STACK_OVF (1);
9128                                 CHECK_OPSIZE (6);
9129                                 token = read32 (ip + 2);
9130                                 /* FIXXME: handle generics. */
9131                                 if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC) {
9132                                         MonoType *type = mono_type_create_from_typespec (image, token);
9133                                         token = mono_type_size (type, &ialign);
9134                                 } else {
9135                                         MonoClass *klass = mono_class_get_full (image, token, generic_context);
9136                                         CHECK_TYPELOAD (klass);
9137                                         mono_class_init (klass);
9138                                         token = mono_class_value_size (klass, &align);
9139                                 }
9140                                 NEW_ICONST (cfg, ins, token);
9141                                 *sp++= ins;
9142                                 ip += 6;
9143                                 break;
9144                         case CEE_REFANYTYPE:
9145                                 CHECK_STACK (1);
9146                                 MONO_INST_NEW (cfg, ins, OP_REFANYTYPE);
9147                                 --sp;
9148                                 ins->type = STACK_MP;
9149                                 ins->inst_left = *sp;
9150                                 ins->type = STACK_VTYPE;
9151                                 ins->klass = mono_defaults.typehandle_class;
9152                                 ip += 2;
9153                                 *sp++ = ins;
9154                                 break;
9155                         case CEE_READONLY_:
9156                                 readonly = TRUE;
9157                                 ip += 2;
9158                                 break;
9159                         default:
9160                                 g_error ("opcode 0xfe 0x%02x not handled", ip [1]);
9161                         }
9162                         break;
9163                 }
9164                 default:
9165                         g_error ("opcode 0x%02x not handled", *ip);
9166                 }
9167         }
9168         if (start_new_bblock != 1)
9169                 UNVERIFIED;
9170
9171         bblock->cil_length = ip - bblock->cil_code;
9172         bblock->next_bb = end_bblock;
9173
9174         if (cfg->method == method && cfg->domainvar) {
9175                 MonoInst *store;
9176                 MonoInst *get_domain;
9177                 
9178                 if (! (get_domain = mono_arch_get_domain_intrinsic (cfg))) {
9179                         MonoCallInst *call;
9180                         
9181                         MONO_INST_NEW_CALL (cfg, call, OP_CALL);
9182                         call->signature = helper_sig_domain_get;
9183                         call->inst.type = STACK_PTR;
9184                         call->fptr = mono_domain_get;
9185                         get_domain = (MonoInst*)call;
9186                 }
9187                 
9188                 NEW_TEMPSTORE (cfg, store, cfg->domainvar->inst_c0, get_domain);
9189                 MONO_ADD_INS (init_localsbb, store);
9190         }
9191
9192         if (cfg->method == method && cfg->got_var)
9193                 mono_emit_load_got_addr (cfg);
9194
9195         if (header->init_locals) {
9196                 MonoInst *store;
9197                 cfg->ip = header->code;
9198                 for (i = 0; i < header->num_locals; ++i) {
9199                         MonoType *ptype = header->locals [i];
9200                         int t = ptype->type;
9201                         if (t == MONO_TYPE_VALUETYPE && ptype->data.klass->enumtype)
9202                                 t = ptype->data.klass->enum_basetype->type;
9203                         if (ptype->byref) {
9204                                 NEW_PCONST (cfg, ins, NULL);
9205                                 NEW_LOCSTORE (cfg, store, i, ins);
9206                                 MONO_ADD_INS (init_localsbb, store);
9207                         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
9208                                 NEW_ICONST (cfg, ins, 0);
9209                                 NEW_LOCSTORE (cfg, store, i, ins);
9210                                 MONO_ADD_INS (init_localsbb, store);
9211                         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
9212                                 MONO_INST_NEW (cfg, ins, OP_I8CONST);
9213                                 ins->type = STACK_I8;
9214                                 ins->inst_l = 0;
9215                                 NEW_LOCSTORE (cfg, store, i, ins);
9216                                 MONO_ADD_INS (init_localsbb, store);
9217                         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
9218 #ifdef MONO_ARCH_SOFT_FLOAT
9219                                 /* FIXME: handle init of R4 */
9220 #else
9221                                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
9222                                 ins->type = STACK_R8;
9223                                 ins->inst_p0 = (void*)&r8_0;
9224                                 NEW_LOCSTORE (cfg, store, i, ins);
9225                                 MONO_ADD_INS (init_localsbb, store);
9226 #endif
9227                         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
9228                                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (ptype))) {
9229                                 NEW_LOCLOADA (cfg, ins, i);
9230                                 handle_initobj (cfg, init_localsbb, ins, NULL, mono_class_from_mono_type (ptype), NULL, NULL);
9231                         } else {
9232                                 NEW_PCONST (cfg, ins, NULL);
9233                                 NEW_LOCSTORE (cfg, store, i, ins);
9234                                 MONO_ADD_INS (init_localsbb, store);
9235                         }
9236                 }
9237         }
9238
9239         cfg->ip = NULL;
9240
9241         /* resolve backward branches in the middle of an existing basic block */
9242         for (tmp = bb_recheck; tmp; tmp = tmp->next) {
9243                 bblock = tmp->data;
9244                 /*g_print ("need recheck in %s at IL_%04x\n", method->name, bblock->cil_code - header->code);*/
9245                 tblock = find_previous (cfg->cil_offset_to_bb, header->code_size, start_bblock, bblock->cil_code);
9246                 if (tblock != start_bblock) {
9247                         int l;
9248                         split_bblock (cfg, tblock, bblock);
9249                         l = bblock->cil_code - header->code;
9250                         bblock->cil_length = tblock->cil_length - l;
9251                         tblock->cil_length = l;
9252                 } else {
9253                         g_print ("recheck failed.\n");
9254                 }
9255         }
9256
9257         if (cfg->method == method) {
9258                 MonoBasicBlock *bb;
9259                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
9260                         bb->region = mono_find_block_region (cfg, bb->real_offset);
9261                         if (cfg->spvars)
9262                                 mono_create_spvar_for_region (cfg, bb->region);
9263                         if (cfg->verbose_level > 2)
9264                                 g_print ("REGION BB%d IL_%04x ID_%08X\n", bb->block_num, bb->real_offset, bb->region);
9265                 }
9266         }
9267
9268         g_slist_free (class_inits);
9269         dont_inline = g_list_remove (dont_inline, method);
9270
9271         if (inline_costs < 0) {
9272                 char *mname;
9273
9274                 /* Method is too large */
9275                 mname = mono_method_full_name (method, TRUE);
9276                 cfg->exception_type = MONO_EXCEPTION_INVALID_PROGRAM;
9277                 cfg->exception_message = g_strdup_printf ("Method %s is too complex.", mname);
9278                 g_free (mname);
9279                 return -1;
9280         }
9281
9282         return inline_costs;
9283
9284  exception_exit:
9285         g_assert (cfg->exception_type != MONO_EXCEPTION_NONE);
9286         g_slist_free (class_inits);
9287         dont_inline = g_list_remove (dont_inline, method);
9288         return -1;
9289
9290  inline_failure:
9291         g_slist_free (class_inits);
9292         dont_inline = g_list_remove (dont_inline, method);
9293         return -1;
9294
9295  load_error:
9296         g_slist_free (class_inits);
9297         dont_inline = g_list_remove (dont_inline, method);
9298         cfg->exception_type = MONO_EXCEPTION_TYPE_LOAD;
9299         return -1;
9300
9301  unverified:
9302         g_slist_free (class_inits);
9303         dont_inline = g_list_remove (dont_inline, method);
9304         set_exception_type_from_invalid_il (cfg, method, ip);
9305         return -1;
9306 }
9307
9308 void
9309 mono_print_tree (MonoInst *tree) {
9310         int arity;
9311
9312         if (!tree)
9313                 return;
9314
9315         arity = mono_burg_arity [tree->opcode];
9316
9317         printf (" %s%s", arity?"(":"",  mono_inst_name (tree->opcode));
9318
9319         switch (tree->opcode) {
9320         case OP_ICONST:
9321                 printf ("[%d]", (int)tree->inst_c0);
9322                 break;
9323         case OP_I8CONST:
9324                 printf ("[%lld]", (long long)tree->inst_l);
9325                 break;
9326         case OP_R8CONST:
9327                 printf ("[%f]", *(double*)tree->inst_p0);
9328                 break;
9329         case OP_R4CONST:
9330                 printf ("[%f]", *(float*)tree->inst_p0);
9331                 break;
9332         case OP_ARG:
9333         case OP_LOCAL:
9334                 printf ("[%d]", (int)tree->inst_c0);
9335                 break;
9336         case OP_REGOFFSET:
9337                 if (tree->inst_offset < 0)
9338                         printf ("[-0x%x(%s)]", (int)(-tree->inst_offset), mono_arch_regname (tree->inst_basereg));
9339                 else
9340                         printf ("[0x%x(%s)]", (int)(tree->inst_offset), mono_arch_regname (tree->inst_basereg));
9341                 break;
9342         case OP_REGVAR:
9343                 printf ("[%s]", mono_arch_regname (tree->dreg));
9344                 break;
9345         case CEE_NEWARR:
9346                 printf ("[%s]",  tree->inst_newa_class->name);
9347                 mono_print_tree (tree->inst_newa_len);
9348                 break;
9349         case OP_CALL:
9350         case OP_CALLVIRT:
9351         case OP_FCALL:
9352         case OP_FCALLVIRT:
9353         case OP_LCALL:
9354         case OP_LCALLVIRT:
9355         case OP_VCALL:
9356         case OP_VCALLVIRT:
9357         case OP_VOIDCALL:
9358         case OP_VOIDCALLVIRT:
9359         case OP_TRAMPCALL_VTABLE: {
9360                 MonoCallInst *call = (MonoCallInst*)tree;
9361                 if (call->method)
9362                         printf ("[%s]", call->method->name);
9363                 else if (call->fptr) {
9364                         MonoJitICallInfo *info = mono_find_jit_icall_by_addr (call->fptr);
9365                         if (info)
9366                                 printf ("[%s]", info->name);
9367                 }
9368                 break;
9369         }
9370         case OP_PHI: {
9371                 int i;
9372                 printf ("[%d (", (int)tree->inst_c0);
9373                 for (i = 0; i < tree->inst_phi_args [0]; i++) {
9374                         if (i)
9375                                 printf (", ");
9376                         printf ("%d", tree->inst_phi_args [i + 1]);
9377                 }
9378                 printf (")]");
9379                 break;
9380         }
9381         case OP_RENAME:
9382         case OP_RETARG:
9383         case OP_NOP:
9384         case OP_JMP:
9385         case OP_BREAK:
9386                 break;
9387         case OP_LOAD_MEMBASE:
9388         case OP_LOADI4_MEMBASE:
9389         case OP_LOADU4_MEMBASE:
9390         case OP_LOADU1_MEMBASE:
9391         case OP_LOADI1_MEMBASE:
9392         case OP_LOADU2_MEMBASE:
9393         case OP_LOADI2_MEMBASE:
9394                 printf ("[%s] <- [%s + 0x%x]", mono_arch_regname (tree->dreg), mono_arch_regname (tree->inst_basereg), (int)tree->inst_offset);
9395                 break;
9396         case OP_BR:
9397         case OP_CALL_HANDLER:
9398                 printf ("[B%d]", tree->inst_target_bb->block_num);
9399                 break;
9400         case OP_SWITCH:
9401         case CEE_ISINST:
9402         case CEE_CASTCLASS:
9403         case OP_OUTARG:
9404         case OP_CALL_REG:
9405         case OP_FCALL_REG:
9406         case OP_LCALL_REG:
9407         case OP_VCALL_REG:
9408         case OP_VOIDCALL_REG:
9409                 mono_print_tree (tree->inst_left);
9410                 break;
9411         case CEE_BNE_UN:
9412         case CEE_BEQ:
9413         case CEE_BLT:
9414         case CEE_BLT_UN:
9415         case CEE_BGT:
9416         case CEE_BGT_UN:
9417         case CEE_BGE:
9418         case CEE_BGE_UN:
9419         case CEE_BLE:
9420         case CEE_BLE_UN:
9421                 printf ("[B%dB%d]", tree->inst_true_bb->block_num, tree->inst_false_bb->block_num);
9422                 mono_print_tree (tree->inst_left);
9423                 break;
9424         default:
9425                 if (!mono_arch_print_tree(tree, arity)) {
9426                         if (arity) {
9427                                 mono_print_tree (tree->inst_left);
9428                                 if (arity > 1)
9429                                         mono_print_tree (tree->inst_right);
9430                         }
9431                 }
9432                 break;
9433         }
9434
9435         if (arity)
9436                 printf (")");
9437 }
9438
9439 void
9440 mono_print_tree_nl (MonoInst *tree)
9441 {
9442         mono_print_tree (tree);
9443         printf ("\n");
9444 }
9445
9446 static void
9447 create_helper_signature (void)
9448 {
9449         helper_sig_domain_get = mono_create_icall_signature ("ptr");
9450         helper_sig_class_init_trampoline = mono_create_icall_signature ("void");
9451         helper_sig_generic_class_init_trampoline = mono_create_icall_signature ("void");
9452         helper_sig_rgctx_lazy_fetch_trampoline = mono_create_icall_signature ("ptr ptr");
9453 }
9454
9455 gconstpointer
9456 mono_icall_get_wrapper (MonoJitICallInfo* callinfo)
9457 {
9458         char *name;
9459         MonoMethod *wrapper;
9460         gconstpointer trampoline;
9461         MonoDomain *domain = mono_get_root_domain ();
9462         
9463         if (callinfo->wrapper) {
9464                 return callinfo->wrapper;
9465         }
9466
9467         if (callinfo->trampoline)
9468                 return callinfo->trampoline;
9469
9470         /* 
9471          * We use the lock on the root domain instead of the JIT lock to protect 
9472          * callinfo->trampoline, since we do a lot of stuff inside the critical section.
9473          */
9474         mono_domain_lock (domain);
9475
9476         if (callinfo->trampoline) {
9477                 mono_domain_unlock (domain);
9478                 return callinfo->trampoline;
9479         }
9480
9481         name = g_strdup_printf ("__icall_wrapper_%s", callinfo->name);
9482         wrapper = mono_marshal_get_icall_wrapper (callinfo->sig, name, callinfo->func, check_for_pending_exc);
9483         g_free (name);
9484
9485         trampoline = mono_create_ftnptr (domain, mono_create_jit_trampoline_in_domain (domain, wrapper));
9486         mono_register_jit_icall_wrapper (callinfo, trampoline);
9487
9488         callinfo->trampoline = trampoline;
9489
9490         mono_domain_unlock (domain);
9491         
9492         return callinfo->trampoline;
9493 }
9494
9495 static void
9496 mono_dynamic_code_hash_insert (MonoDomain *domain, MonoMethod *method, MonoJitDynamicMethodInfo *ji)
9497 {
9498         if (!domain->dynamic_code_hash)
9499                 domain->dynamic_code_hash = g_hash_table_new (NULL, NULL);
9500         g_hash_table_insert (domain->dynamic_code_hash, method, ji);
9501 }
9502
9503 static MonoJitDynamicMethodInfo*
9504 mono_dynamic_code_hash_lookup (MonoDomain *domain, MonoMethod *method)
9505 {
9506         MonoJitDynamicMethodInfo *res;
9507
9508         if (domain->dynamic_code_hash)
9509                 res = g_hash_table_lookup (domain->dynamic_code_hash, method);
9510         else
9511                 res = NULL;
9512         return res;
9513 }
9514
9515 typedef struct {
9516         MonoClass *vtype;
9517         GList *active;
9518         GSList *slots;
9519 } StackSlotInfo;
9520
9521 static inline GSList*
9522 g_slist_prepend_mempool (MonoMemPool *mp, GSList   *list,
9523                                                  gpointer  data)
9524 {
9525   GSList *new_list;
9526
9527   new_list = mono_mempool_alloc (mp, sizeof (GSList));
9528   new_list->data = data;
9529   new_list->next = list;
9530
9531   return new_list;
9532 }
9533
9534 /*
9535  *  mono_allocate_stack_slots_full:
9536  *
9537  *  Allocate stack slots for all non register allocated variables using a
9538  * linear scan algorithm.
9539  * Returns: an array of stack offsets.
9540  * STACK_SIZE is set to the amount of stack space needed.
9541  * STACK_ALIGN is set to the alignment needed by the locals area.
9542  */
9543 gint32*
9544 mono_allocate_stack_slots_full (MonoCompile *cfg, gboolean backward, guint32 *stack_size, guint32 *stack_align)
9545 {
9546         int i, slot, offset, size;
9547         guint32 align;
9548         MonoMethodVar *vmv;
9549         MonoInst *inst;
9550         gint32 *offsets;
9551         GList *vars = NULL, *l;
9552         StackSlotInfo *scalar_stack_slots, *vtype_stack_slots, *slot_info;
9553         MonoType *t;
9554         int nvtypes;
9555
9556         scalar_stack_slots = mono_mempool_alloc0 (cfg->mempool, sizeof (StackSlotInfo) * MONO_TYPE_PINNED);
9557         vtype_stack_slots = NULL;
9558         nvtypes = 0;
9559
9560         offsets = mono_mempool_alloc (cfg->mempool, sizeof (gint32) * cfg->num_varinfo);
9561         for (i = 0; i < cfg->num_varinfo; ++i)
9562                 offsets [i] = -1;
9563
9564         for (i = cfg->locals_start; i < cfg->num_varinfo; i++) {
9565                 inst = cfg->varinfo [i];
9566                 vmv = MONO_VARINFO (cfg, i);
9567
9568                 if ((inst->flags & MONO_INST_IS_DEAD) || inst->opcode == OP_REGVAR || inst->opcode == OP_REGOFFSET)
9569                         continue;
9570
9571                 vars = g_list_prepend (vars, vmv);
9572         }
9573
9574         vars = mono_varlist_sort (cfg, vars, 0);
9575         offset = 0;
9576         *stack_align = 0;
9577         for (l = vars; l; l = l->next) {
9578                 vmv = l->data;
9579                 inst = cfg->varinfo [vmv->idx];
9580
9581                 /* inst->backend.is_pinvoke indicates native sized value types, this is used by the
9582                 * pinvoke wrappers when they call functions returning structures */
9583                 if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->inst_vtype->type != MONO_TYPE_TYPEDBYREF)
9584                         size = mono_class_native_size (inst->inst_vtype->data.klass, &align);
9585                 else {
9586                         int ialign;
9587
9588                         size = mono_type_size (inst->inst_vtype, &ialign);
9589                         align = ialign;
9590                 }
9591
9592                 t = mono_type_get_underlying_type (inst->inst_vtype);
9593                 if (t->byref) {
9594                         slot_info = &scalar_stack_slots [MONO_TYPE_I];
9595                 } else {
9596                         switch (t->type) {
9597                         case MONO_TYPE_GENERICINST:
9598                                 if (!mono_type_generic_inst_is_valuetype (t)) {
9599                                         slot_info = &scalar_stack_slots [t->type];
9600                                         break;
9601                                 }
9602                                 /* Fall through */
9603                         case MONO_TYPE_VALUETYPE:
9604                                 if (!vtype_stack_slots)
9605                                         vtype_stack_slots = mono_mempool_alloc0 (cfg->mempool, sizeof (StackSlotInfo) * 256);
9606                                 for (i = 0; i < nvtypes; ++i)
9607                                         if (t->data.klass == vtype_stack_slots [i].vtype)
9608                                                 break;
9609                                 if (i < nvtypes)
9610                                         slot_info = &vtype_stack_slots [i];
9611                                 else {
9612                                         g_assert (nvtypes < 256);
9613                                         vtype_stack_slots [nvtypes].vtype = t->data.klass;
9614                                         slot_info = &vtype_stack_slots [nvtypes];
9615                                         nvtypes ++;
9616                                 }
9617                                 break;
9618                         case MONO_TYPE_CLASS:
9619                         case MONO_TYPE_OBJECT:
9620                         case MONO_TYPE_ARRAY:
9621                         case MONO_TYPE_SZARRAY:
9622                         case MONO_TYPE_STRING:
9623                         case MONO_TYPE_PTR:
9624                         case MONO_TYPE_I:
9625                         case MONO_TYPE_U:
9626 #if SIZEOF_VOID_P == 4
9627                         case MONO_TYPE_I4:
9628 #else
9629                         case MONO_TYPE_I8:
9630 #endif
9631                                 /* Share non-float stack slots of the same size */
9632                                 slot_info = &scalar_stack_slots [MONO_TYPE_CLASS];
9633                                 break;
9634                         default:
9635                                 slot_info = &scalar_stack_slots [t->type];
9636                         }
9637                 }
9638
9639                 slot = 0xffffff;
9640                 if (cfg->comp_done & MONO_COMP_LIVENESS) {
9641                         //printf ("START  %2d %08x %08x\n",  vmv->idx, vmv->range.first_use.abs_pos, vmv->range.last_use.abs_pos);
9642                         
9643                         /* expire old intervals in active */
9644                         while (slot_info->active) {
9645                                 MonoMethodVar *amv = (MonoMethodVar *)slot_info->active->data;
9646
9647                                 if (amv->range.last_use.abs_pos > vmv->range.first_use.abs_pos)
9648                                         break;
9649
9650                                 //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);
9651
9652                                 slot_info->active = g_list_delete_link (slot_info->active, slot_info->active);
9653                                 slot_info->slots = g_slist_prepend_mempool (cfg->mempool, slot_info->slots, GINT_TO_POINTER (offsets [amv->idx]));
9654                         }
9655
9656                         /* 
9657                          * This also handles the case when the variable is used in an
9658                          * exception region, as liveness info is not computed there.
9659                          */
9660                         /* 
9661                          * FIXME: All valuetypes are marked as INDIRECT because of LDADDR
9662                          * opcodes.
9663                          */
9664                         if (! (inst->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT))) {
9665                                 if (slot_info->slots) {
9666                                         slot = GPOINTER_TO_INT (slot_info->slots->data);
9667
9668                                         slot_info->slots = slot_info->slots->next;
9669                                 }
9670
9671                                 slot_info->active = mono_varlist_insert_sorted (cfg, slot_info->active, vmv, TRUE);
9672                         }
9673                 }
9674
9675                 {
9676                         static int count = 0;
9677                         count ++;
9678
9679                         /*
9680                         if (count == atoi (getenv ("COUNT")))
9681                                 printf ("LAST: %s\n", mono_method_full_name (cfg->method, TRUE));
9682                         if (count > atoi (getenv ("COUNT")))
9683                                 slot = 0xffffff;
9684                         else {
9685                                 mono_print_tree_nl (inst);
9686                                 }
9687                         */
9688                 }
9689
9690                 if (cfg->disable_reuse_stack_slots)
9691                         slot = 0xffffff;
9692
9693                 if (slot == 0xffffff) {
9694                         /*
9695                          * Allways allocate valuetypes to sizeof (gpointer) to allow more
9696                          * efficient copying (and to work around the fact that OP_MEMCPY
9697                          * and OP_MEMSET ignores alignment).
9698                          */
9699                         if (MONO_TYPE_ISSTRUCT (t))
9700                                 align = sizeof (gpointer);
9701
9702                         if (backward) {
9703                                 offset += size;
9704                                 offset += align - 1;
9705                                 offset &= ~(align - 1);
9706                                 slot = offset;
9707                         }
9708                         else {
9709                                 offset += align - 1;
9710                                 offset &= ~(align - 1);
9711                                 slot = offset;
9712                                 offset += size;
9713                         }
9714
9715                         if (*stack_align == 0)
9716                                 *stack_align = align;
9717                 }
9718
9719                 offsets [vmv->idx] = slot;
9720         }
9721         g_list_free (vars);
9722         for (i = 0; i < MONO_TYPE_PINNED; ++i) {
9723                 if (scalar_stack_slots [i].active)
9724                         g_list_free (scalar_stack_slots [i].active);
9725         }
9726         for (i = 0; i < nvtypes; ++i) {
9727                 if (vtype_stack_slots [i].active)
9728                         g_list_free (vtype_stack_slots [i].active);
9729         }
9730
9731         mono_jit_stats.locals_stack_size += offset;
9732
9733         *stack_size = offset;
9734         return offsets;
9735 }
9736
9737 gint32*
9738 mono_allocate_stack_slots (MonoCompile *m, guint32 *stack_size, guint32 *stack_align)
9739 {
9740         return mono_allocate_stack_slots_full (m, TRUE, stack_size, stack_align);
9741 }
9742
9743 void
9744 mono_register_opcode_emulation (int opcode, const char *name, const char *sigstr, gpointer func, gboolean no_throw)
9745 {
9746         MonoJitICallInfo *info;
9747         MonoMethodSignature *sig = mono_create_icall_signature (sigstr);
9748
9749         if (!emul_opcode_map)
9750                 emul_opcode_map = g_new0 (MonoJitICallInfo*, OP_LAST + 1);
9751
9752         g_assert (!sig->hasthis);
9753         g_assert (sig->param_count < 3);
9754
9755         info = mono_register_jit_icall (func, name, sig, no_throw);
9756
9757         emul_opcode_map [opcode] = info;
9758 }
9759
9760 static void
9761 register_icall (gpointer func, const char *name, const char *sigstr, gboolean save)
9762 {
9763         MonoMethodSignature *sig;
9764
9765         if (sigstr)
9766                 sig = mono_create_icall_signature (sigstr);
9767         else
9768                 sig = NULL;
9769
9770         mono_register_jit_icall (func, name, sig, save);
9771 }
9772
9773 static void
9774 decompose_foreach (MonoInst *tree, gpointer data) 
9775 {
9776         static MonoJitICallInfo *newarr_info = NULL;
9777         static MonoJitICallInfo *newarr_specific_info = NULL;
9778         MonoJitICallInfo *info;
9779         int i;
9780
9781         switch (tree->opcode) {
9782         case CEE_NEWARR: {
9783                 MonoCompile *cfg = data;
9784                 MonoInst *iargs [3];
9785
9786                 if (!newarr_info) {
9787                         newarr_info = mono_find_jit_icall_by_addr (mono_array_new);
9788                         g_assert (newarr_info);
9789                         newarr_specific_info = mono_find_jit_icall_by_addr (mono_array_new_specific);
9790                         g_assert (newarr_specific_info);
9791                 }
9792
9793                 if (cfg->opt & MONO_OPT_SHARED) {
9794                         NEW_DOMAINCONST (cfg, iargs [0]);
9795                         NEW_CLASSCONST (cfg, iargs [1], tree->inst_newa_class);
9796                         iargs [2] = tree->inst_newa_len;
9797
9798                         info = newarr_info;
9799                 }
9800                 else {
9801                         MonoVTable *vtable = mono_class_vtable (cfg->domain, mono_array_class_get (tree->inst_newa_class, 1));
9802
9803                         g_assert (vtable);
9804                         NEW_VTABLECONST (cfg, iargs [0], vtable);
9805                         iargs [1] = tree->inst_newa_len;
9806
9807                         info = newarr_specific_info;
9808                 }
9809
9810                 mono_emulate_opcode (cfg, tree, iargs, info);
9811
9812                 /* Need to decompose arguments after the the opcode is decomposed */
9813                 for (i = 0; i < info->sig->param_count; ++i)
9814                         dec_foreach (iargs [i], cfg);
9815                 break;
9816         }
9817 #ifdef MONO_ARCH_SOFT_FLOAT
9818         case OP_FBEQ:
9819         case OP_FBGE:
9820         case OP_FBGT:
9821         case OP_FBLE:
9822         case OP_FBLT:
9823         case OP_FBNE_UN:
9824         case OP_FBGE_UN:
9825         case OP_FBGT_UN:
9826         case OP_FBLE_UN:
9827         case OP_FBLT_UN: {
9828                 if ((info = mono_find_jit_opcode_emulation (tree->opcode))) {
9829                         MonoCompile *cfg = data;
9830                         MonoInst *iargs [2];
9831                 
9832                         iargs [0] = tree->inst_i0;
9833                         iargs [1] = tree->inst_i1;
9834                 
9835                         mono_emulate_opcode (cfg, tree, iargs, info);
9836
9837                         dec_foreach (iargs [0], cfg);
9838                         dec_foreach (iargs [1], cfg);
9839                         break;
9840                 } else {
9841                         g_assert_not_reached ();
9842                 }
9843                 break;
9844         }
9845         case OP_FCEQ:
9846         case OP_FCGT:
9847         case OP_FCGT_UN:
9848         case OP_FCLT:
9849         case OP_FCLT_UN: {
9850                 if ((info = mono_find_jit_opcode_emulation (tree->opcode))) {
9851                         MonoCompile *cfg = data;
9852                         MonoInst *iargs [2];
9853
9854                         /* the args are in the compare opcode ... */
9855                         iargs [0] = tree->inst_i0;
9856                         iargs [1] = tree->inst_i1;
9857                 
9858                         mono_emulate_opcode (cfg, tree, iargs, info);
9859
9860                         dec_foreach (iargs [0], cfg);
9861                         dec_foreach (iargs [1], cfg);
9862                         break;
9863                 } else {
9864                         g_assert_not_reached ();
9865                 }
9866                 break;
9867         }
9868 #endif
9869
9870         default:
9871                 break;
9872         }
9873 }
9874
9875 void
9876 mono_inst_foreach (MonoInst *tree, MonoInstFunc func, gpointer data) {
9877
9878         switch (mono_burg_arity [tree->opcode]) {
9879         case 0: break;
9880         case 1: 
9881                 mono_inst_foreach (tree->inst_left, func, data);
9882                 break;
9883         case 2: 
9884                 mono_inst_foreach (tree->inst_left, func, data);
9885                 mono_inst_foreach (tree->inst_right, func, data);
9886                 break;
9887         default:
9888                 g_assert_not_reached ();
9889         }
9890         func (tree, data);
9891 }
9892
9893 G_GNUC_UNUSED
9894 static void
9895 mono_print_bb_code (MonoBasicBlock *bb)
9896 {
9897         MonoInst *c;
9898
9899         MONO_BB_FOR_EACH_INS (bb, c) {
9900                 mono_print_tree (c);
9901                 g_print ("\n");
9902         }
9903 }
9904
9905 static void
9906 print_dfn (MonoCompile *cfg) {
9907         int i, j;
9908         char *code;
9909         MonoBasicBlock *bb;
9910
9911         g_print ("IR code for method %s\n", mono_method_full_name (cfg->method, TRUE));
9912
9913         for (i = 0; i < cfg->num_bblocks; ++i) {
9914                 MonoInst *c;
9915
9916                 bb = cfg->bblocks [i];
9917                 /*if (bb->cil_code) {
9918                         char* code1, *code2;
9919                         code1 = mono_disasm_code_one (NULL, cfg->method, bb->cil_code, NULL);
9920                         if (bb->last_ins->cil_code)
9921                                 code2 = mono_disasm_code_one (NULL, cfg->method, bb->last_ins->cil_code, NULL);
9922                         else
9923                                 code2 = g_strdup ("");
9924
9925                         code1 [strlen (code1) - 1] = 0;
9926                         code = g_strdup_printf ("%s -> %s", code1, code2);
9927                         g_free (code1);
9928                         g_free (code2);
9929                 } else*/
9930                         code = g_strdup ("\n");
9931                 g_print ("\nBB%d DFN%d (len: %d): %s", bb->block_num, i, bb->cil_length, code);
9932                 MONO_BB_FOR_EACH_INS (bb, c) {
9933                         mono_print_tree (c);
9934                         g_print ("\n");
9935                 }
9936
9937                 g_print ("\tprev:");
9938                 for (j = 0; j < bb->in_count; ++j) {
9939                         g_print (" BB%d", bb->in_bb [j]->block_num);
9940                 }
9941                 g_print ("\t\tsucc:");
9942                 for (j = 0; j < bb->out_count; ++j) {
9943                         g_print (" BB%d", bb->out_bb [j]->block_num);
9944                 }
9945                 g_print ("\n\tidom: BB%d\n", bb->idom? bb->idom->block_num: -1);
9946
9947                 if (bb->idom)
9948                         g_assert (mono_bitset_test_fast (bb->dominators, bb->idom->dfn));
9949
9950                 if (bb->dominators)
9951                         mono_blockset_print (cfg, bb->dominators, "\tdominators", bb->idom? bb->idom->dfn: -1);
9952                 if (bb->dfrontier)
9953                         mono_blockset_print (cfg, bb->dfrontier, "\tdfrontier", -1);
9954                 g_free (code);
9955         }
9956
9957         g_print ("\n");
9958 }
9959
9960 void
9961 mono_bblock_add_inst (MonoBasicBlock *bb, MonoInst *inst)
9962 {
9963         MONO_ADD_INS (bb, inst);
9964 }
9965
9966 void
9967 mono_destroy_compile (MonoCompile *cfg)
9968 {
9969         //mono_mempool_stats (cfg->mempool);
9970         mono_free_loop_info (cfg);
9971         if (cfg->rs)
9972                 mono_regstate_free (cfg->rs);
9973         if (cfg->spvars)
9974                 g_hash_table_destroy (cfg->spvars);
9975         if (cfg->exvars)
9976                 g_hash_table_destroy (cfg->exvars);
9977         mono_mempool_destroy (cfg->mempool);
9978         g_list_free (cfg->ldstr_list);
9979         g_hash_table_destroy (cfg->token_info_hash);
9980
9981         g_free (cfg->varinfo);
9982         g_free (cfg->vars);
9983         g_free (cfg->exception_message);
9984         g_free (cfg);
9985 }
9986
9987 #ifdef HAVE_KW_THREAD
9988 static __thread gpointer mono_lmf_addr MONO_TLS_FAST;
9989 #ifdef MONO_ARCH_ENABLE_MONO_LMF_VAR
9990 /* 
9991  * When this is defined, the current lmf is stored in this tls variable instead of in 
9992  * jit_tls->lmf.
9993  */
9994 static __thread gpointer mono_lmf MONO_TLS_FAST;
9995 #endif
9996 #endif
9997
9998 guint32
9999 mono_get_jit_tls_key (void)
10000 {
10001         return mono_jit_tls_id;
10002 }
10003
10004 gint32
10005 mono_get_jit_tls_offset (void)
10006 {
10007 #ifdef HAVE_KW_THREAD
10008         int offset;
10009         MONO_THREAD_VAR_OFFSET (mono_jit_tls, offset);
10010         return offset;
10011 #else
10012         return -1;
10013 #endif
10014 }
10015
10016 gint32
10017 mono_get_lmf_tls_offset (void)
10018 {
10019 #if defined(HAVE_KW_THREAD) && defined(MONO_ARCH_ENABLE_MONO_LMF_VAR)
10020         int offset;
10021         MONO_THREAD_VAR_OFFSET(mono_lmf,offset);
10022         return offset;
10023 #else
10024         return -1;
10025 #endif
10026 }
10027
10028 gint32
10029 mono_get_lmf_addr_tls_offset (void)
10030 {
10031         int offset;
10032         MONO_THREAD_VAR_OFFSET(mono_lmf_addr,offset);
10033         return offset;
10034 }
10035
10036 MonoLMF *
10037 mono_get_lmf (void)
10038 {
10039 #if defined(HAVE_KW_THREAD) && defined(MONO_ARCH_ENABLE_MONO_LMF_VAR)
10040         return mono_lmf;
10041 #else
10042         MonoJitTlsData *jit_tls;
10043
10044         if ((jit_tls = TlsGetValue (mono_jit_tls_id)))
10045                 return jit_tls->lmf;
10046
10047         g_assert_not_reached ();
10048         return NULL;
10049 #endif
10050 }
10051
10052 MonoLMF **
10053 mono_get_lmf_addr (void)
10054 {
10055 #ifdef HAVE_KW_THREAD
10056         return mono_lmf_addr;
10057 #else
10058         MonoJitTlsData *jit_tls;
10059
10060         if ((jit_tls = TlsGetValue (mono_jit_tls_id)))
10061                 return &jit_tls->lmf;
10062
10063         g_assert_not_reached ();
10064         return NULL;
10065 #endif
10066 }
10067
10068 /* Called by native->managed wrappers */
10069 void
10070 mono_jit_thread_attach (MonoDomain *domain)
10071 {
10072 #ifdef HAVE_KW_THREAD
10073         if (!mono_lmf_addr) {
10074                 mono_thread_attach (domain);
10075         }
10076 #else
10077         if (!TlsGetValue (mono_jit_tls_id))
10078                 mono_thread_attach (domain);
10079 #endif
10080         if (mono_domain_get () != domain)
10081                 mono_domain_set (domain, TRUE);
10082 }       
10083
10084 /**
10085  * mono_thread_abort:
10086  * @obj: exception object
10087  *
10088  * abort the thread, print exception information and stack trace
10089  */
10090 static void
10091 mono_thread_abort (MonoObject *obj)
10092 {
10093         /* MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id); */
10094         
10095         /* handle_remove should be eventually called for this thread, too
10096         g_free (jit_tls);*/
10097
10098         if ((mono_runtime_unhandled_exception_policy_get () == MONO_UNHANLED_POLICY_LEGACY) ||
10099                         (obj->vtable->klass == mono_defaults.threadabortexception_class)) {
10100                 mono_thread_exit ();
10101         } else {
10102                 exit (mono_environment_exitcode_get ());
10103         }
10104 }
10105
10106 static void*
10107 setup_jit_tls_data (gpointer stack_start, gpointer abort_func)
10108 {
10109         MonoJitTlsData *jit_tls;
10110         MonoLMF *lmf;
10111
10112         jit_tls = TlsGetValue (mono_jit_tls_id);
10113         if (jit_tls)
10114                 return jit_tls;
10115
10116         jit_tls = g_new0 (MonoJitTlsData, 1);
10117
10118         TlsSetValue (mono_jit_tls_id, jit_tls);
10119
10120 #ifdef HAVE_KW_THREAD
10121         mono_jit_tls = jit_tls;
10122 #endif
10123
10124         jit_tls->abort_func = abort_func;
10125         jit_tls->end_of_stack = stack_start;
10126
10127         lmf = g_new0 (MonoLMF, 1);
10128 #ifdef MONO_ARCH_INIT_TOP_LMF_ENTRY
10129         MONO_ARCH_INIT_TOP_LMF_ENTRY (lmf);
10130 #else
10131         lmf->ebp = -1;
10132 #endif
10133
10134         jit_tls->first_lmf = lmf;
10135
10136 #if defined(HAVE_KW_THREAD) && defined(MONO_ARCH_ENABLE_MONO_LMF_VAR)
10137         /* jit_tls->lmf is unused */
10138         mono_lmf = lmf;
10139         mono_lmf_addr = &mono_lmf;
10140 #else
10141 #if defined(HAVE_KW_THREAD)
10142         mono_lmf_addr = &jit_tls->lmf;  
10143 #endif
10144
10145         jit_tls->lmf = lmf;
10146 #endif
10147
10148         mono_arch_setup_jit_tls_data (jit_tls);
10149         mono_setup_altstack (jit_tls);
10150
10151         return jit_tls;
10152 }
10153
10154 static void
10155 mono_thread_start_cb (gsize tid, gpointer stack_start, gpointer func)
10156 {
10157         MonoThread *thread;
10158         void *jit_tls = setup_jit_tls_data (stack_start, mono_thread_abort);
10159         thread = mono_thread_current ();
10160         mono_debugger_thread_created (tid, thread, jit_tls);
10161         if (thread)
10162                 thread->jit_data = jit_tls;
10163 }
10164
10165 void (*mono_thread_attach_aborted_cb ) (MonoObject *obj) = NULL;
10166
10167 static void
10168 mono_thread_abort_dummy (MonoObject *obj)
10169 {
10170   if (mono_thread_attach_aborted_cb)
10171     mono_thread_attach_aborted_cb (obj);
10172   else
10173     mono_thread_abort (obj);
10174 }
10175
10176 static void
10177 mono_thread_attach_cb (gsize tid, gpointer stack_start)
10178 {
10179         MonoThread *thread;
10180         void *jit_tls = setup_jit_tls_data (stack_start, mono_thread_abort_dummy);
10181         thread = mono_thread_current ();
10182         mono_debugger_thread_created (tid, thread, (MonoJitTlsData *) jit_tls);
10183         if (thread)
10184                 thread->jit_data = jit_tls;
10185         if (mono_profiler_get_events () & MONO_PROFILE_STATISTICAL)
10186                 setup_stat_profiler ();
10187 }
10188
10189 static void
10190 mini_thread_cleanup (MonoThread *thread)
10191 {
10192         MonoJitTlsData *jit_tls = thread->jit_data;
10193
10194         if (jit_tls) {
10195                 mono_debugger_thread_cleanup (jit_tls);
10196                 mono_arch_free_jit_tls_data (jit_tls);
10197
10198                 mono_free_altstack (jit_tls);
10199                 g_free (jit_tls->first_lmf);
10200                 g_free (jit_tls);
10201                 thread->jit_data = NULL;
10202                 TlsSetValue (mono_jit_tls_id, NULL);
10203         }
10204 }
10205
10206 static MonoInst*
10207 mono_create_tls_get (MonoCompile *cfg, int offset)
10208 {
10209 #ifdef MONO_ARCH_HAVE_TLS_GET
10210         MonoInst* ins;
10211         
10212         if (offset == -1)
10213                 return NULL;
10214         
10215         MONO_INST_NEW (cfg, ins, OP_TLS_GET);
10216         ins->dreg = mono_regstate_next_int (cfg->rs);
10217         ins->inst_offset = offset;
10218         return ins;
10219 #else
10220         return NULL;
10221 #endif
10222 }
10223
10224 MonoInst*
10225 mono_get_jit_tls_intrinsic (MonoCompile *cfg)
10226 {
10227         return mono_create_tls_get (cfg, mono_get_jit_tls_offset ());
10228 }
10229
10230 void
10231 mono_add_patch_info (MonoCompile *cfg, int ip, MonoJumpInfoType type, gconstpointer target)
10232 {
10233         MonoJumpInfo *ji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo));
10234
10235         ji->ip.i = ip;
10236         ji->type = type;
10237         ji->data.target = target;
10238         ji->next = cfg->patch_info;
10239
10240         cfg->patch_info = ji;
10241 }
10242
10243 void
10244 mono_remove_patch_info (MonoCompile *cfg, int ip)
10245 {
10246         MonoJumpInfo **ji = &cfg->patch_info;
10247
10248         while (*ji) {
10249                 if ((*ji)->ip.i == ip)
10250                         *ji = (*ji)->next;
10251                 else
10252                         ji = &((*ji)->next);
10253         }
10254 }
10255
10256 /**
10257  * mono_patch_info_dup_mp:
10258  *
10259  * Make a copy of PATCH_INFO, allocating memory from the mempool MP.
10260  */
10261 MonoJumpInfo*
10262 mono_patch_info_dup_mp (MonoMemPool *mp, MonoJumpInfo *patch_info)
10263 {
10264         MonoJumpInfo *res = mono_mempool_alloc (mp, sizeof (MonoJumpInfo));
10265         memcpy (res, patch_info, sizeof (MonoJumpInfo));
10266
10267         switch (patch_info->type) {
10268         case MONO_PATCH_INFO_RVA:
10269         case MONO_PATCH_INFO_LDSTR:
10270         case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
10271         case MONO_PATCH_INFO_LDTOKEN:
10272         case MONO_PATCH_INFO_DECLSEC:
10273                 res->data.token = mono_mempool_alloc (mp, sizeof (MonoJumpInfoToken));
10274                 memcpy (res->data.token, patch_info->data.token, sizeof (MonoJumpInfoToken));
10275                 break;
10276         case MONO_PATCH_INFO_SWITCH:
10277                 res->data.table = mono_mempool_alloc (mp, sizeof (MonoJumpInfoBBTable));
10278                 memcpy (res->data.table, patch_info->data.table, sizeof (MonoJumpInfoBBTable));
10279                 break;
10280         default:
10281                 break;
10282         }
10283
10284         return res;
10285 }
10286
10287 guint
10288 mono_patch_info_hash (gconstpointer data)
10289 {
10290         const MonoJumpInfo *ji = (MonoJumpInfo*)data;
10291
10292         switch (ji->type) {
10293         case MONO_PATCH_INFO_RVA:
10294         case MONO_PATCH_INFO_LDSTR:
10295         case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
10296         case MONO_PATCH_INFO_LDTOKEN:
10297         case MONO_PATCH_INFO_DECLSEC:
10298                 return (ji->type << 8) | ji->data.token->token;
10299         case MONO_PATCH_INFO_VTABLE:
10300         case MONO_PATCH_INFO_CLASS:
10301         case MONO_PATCH_INFO_IID:
10302         case MONO_PATCH_INFO_ADJUSTED_IID:
10303                 return (ji->type << 8) | (gssize)ji->data.klass;
10304         case MONO_PATCH_INFO_FIELD:
10305         case MONO_PATCH_INFO_SFLDA:
10306                 return (ji->type << 8) | (gssize)ji->data.field;
10307         case MONO_PATCH_INFO_METHODCONST:
10308         case MONO_PATCH_INFO_METHOD:
10309         case MONO_PATCH_INFO_METHOD_JUMP:
10310                 return (ji->type << 8) | (gssize)ji->data.method;
10311         case MONO_PATCH_INFO_IMAGE:
10312                 return (ji->type << 8) | (gssize)ji->data.image;                
10313         default:
10314                 return (ji->type << 8);
10315         }
10316 }
10317
10318 /* 
10319  * mono_patch_info_equal:
10320  * 
10321  * This might fail to recognize equivalent patches, i.e. floats, so its only
10322  * usable in those cases where this is not a problem, i.e. sharing GOT slots
10323  * in AOT.
10324  */
10325 gint
10326 mono_patch_info_equal (gconstpointer ka, gconstpointer kb)
10327 {
10328         const MonoJumpInfo *ji1 = (MonoJumpInfo*)ka;
10329         const MonoJumpInfo *ji2 = (MonoJumpInfo*)kb;
10330
10331         if (ji1->type != ji2->type)
10332                 return 0;
10333
10334         switch (ji1->type) {
10335         case MONO_PATCH_INFO_RVA:
10336         case MONO_PATCH_INFO_LDSTR:
10337         case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
10338         case MONO_PATCH_INFO_LDTOKEN:
10339         case MONO_PATCH_INFO_DECLSEC:
10340                 if ((ji1->data.token->image != ji2->data.token->image) ||
10341                         (ji1->data.token->token != ji2->data.token->token))
10342                         return 0;
10343                 break;
10344         default:
10345                 if (ji1->data.name != ji2->data.name)
10346                         return 0;
10347                 break;
10348         }
10349
10350         return 1;
10351 }
10352
10353 gpointer
10354 mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *patch_info, gboolean run_cctors)
10355 {
10356         unsigned char *ip = patch_info->ip.i + code;
10357         gconstpointer target = NULL;
10358
10359         switch (patch_info->type) {
10360         case MONO_PATCH_INFO_BB:
10361                 target = patch_info->data.bb->native_offset + code;
10362                 break;
10363         case MONO_PATCH_INFO_ABS:
10364                 target = patch_info->data.target;
10365                 break;
10366         case MONO_PATCH_INFO_LABEL:
10367                 target = patch_info->data.inst->inst_c0 + code;
10368                 break;
10369         case MONO_PATCH_INFO_IP:
10370                 target = ip;
10371                 break;
10372         case MONO_PATCH_INFO_METHOD_REL:
10373                 target = code + patch_info->data.offset;
10374                 break;
10375         case MONO_PATCH_INFO_INTERNAL_METHOD: {
10376                 MonoJitICallInfo *mi = mono_find_jit_icall_by_name (patch_info->data.name);
10377                 if (!mi) {
10378                         g_warning ("unknown MONO_PATCH_INFO_INTERNAL_METHOD %s", patch_info->data.name);
10379                         g_assert_not_reached ();
10380                 }
10381                 target = mono_icall_get_wrapper (mi);
10382                 break;
10383         }
10384         case MONO_PATCH_INFO_METHOD_JUMP: {
10385                 GSList *list;
10386
10387                 /* get the trampoline to the method from the domain */
10388                 target = mono_create_jump_trampoline (domain, patch_info->data.method, TRUE);
10389                 if (!domain->jump_target_hash)
10390                         domain->jump_target_hash = g_hash_table_new (NULL, NULL);
10391                 list = g_hash_table_lookup (domain->jump_target_hash, patch_info->data.method);
10392                 list = g_slist_prepend (list, ip);
10393                 g_hash_table_insert (domain->jump_target_hash, patch_info->data.method, list);
10394                 break;
10395         }
10396         case MONO_PATCH_INFO_METHOD:
10397                 if (patch_info->data.method == method) {
10398                         target = code;
10399                 } else {
10400                         /* get the trampoline to the method from the domain */
10401                         if (method && method->wrapper_type == MONO_WRAPPER_STATIC_RGCTX_INVOKE)
10402                                 target = mono_ldftn_nosync (patch_info->data.method);
10403                         else
10404                                 target = mono_create_jit_trampoline (patch_info->data.method);
10405                 }
10406                 break;
10407         case MONO_PATCH_INFO_SWITCH: {
10408                 gpointer *jump_table;
10409                 int i;
10410
10411                 if (method && method->dynamic) {
10412                         jump_table = mono_code_manager_reserve (mono_dynamic_code_hash_lookup (domain, method)->code_mp, sizeof (gpointer) * patch_info->data.table->table_size);
10413                 } else {
10414                         mono_domain_lock (domain);
10415                         jump_table = mono_code_manager_reserve (domain->code_mp, sizeof (gpointer) * patch_info->data.table->table_size);
10416                         mono_domain_unlock (domain);
10417                 }
10418
10419                 for (i = 0; i < patch_info->data.table->table_size; i++) {
10420                         jump_table [i] = code + GPOINTER_TO_INT (patch_info->data.table->table [i]);
10421                 }
10422                 target = jump_table;
10423                 break;
10424         }
10425         case MONO_PATCH_INFO_METHODCONST:
10426         case MONO_PATCH_INFO_CLASS:
10427         case MONO_PATCH_INFO_IMAGE:
10428         case MONO_PATCH_INFO_FIELD:
10429                 target = patch_info->data.target;
10430                 break;
10431         case MONO_PATCH_INFO_IID:
10432                 mono_class_init (patch_info->data.klass);
10433                 target = GINT_TO_POINTER ((int)patch_info->data.klass->interface_id);
10434                 break;
10435         case MONO_PATCH_INFO_ADJUSTED_IID:
10436                 mono_class_init (patch_info->data.klass);
10437                 target = GINT_TO_POINTER ((int)(-((patch_info->data.klass->interface_id + 1) * SIZEOF_VOID_P)));
10438                 break;
10439         case MONO_PATCH_INFO_VTABLE:
10440                 target = mono_class_vtable (domain, patch_info->data.klass);
10441                 g_assert (target);
10442                 break;
10443         case MONO_PATCH_INFO_CLASS_INIT: {
10444                 MonoVTable *vtable = mono_class_vtable (domain, patch_info->data.klass);
10445
10446                 g_assert (vtable);
10447                 target = mono_create_class_init_trampoline (vtable);
10448                 break;
10449         }
10450         case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE:
10451                 target = mono_create_delegate_trampoline (patch_info->data.klass);
10452                 break;
10453         case MONO_PATCH_INFO_SFLDA: {
10454                 MonoVTable *vtable = mono_class_vtable (domain, patch_info->data.field->parent);
10455
10456                 g_assert (vtable);
10457                 if (!vtable->initialized && !(vtable->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) && (method && mono_class_needs_cctor_run (vtable->klass, method)))
10458                         /* Done by the generated code */
10459                         ;
10460                 else {
10461                         if (run_cctors)
10462                                 mono_runtime_class_init (vtable);
10463                 }
10464                 target = (char*)vtable->data + patch_info->data.field->offset;
10465                 break;
10466         }
10467         case MONO_PATCH_INFO_RVA:
10468                 target = mono_image_rva_map (patch_info->data.token->image, patch_info->data.token->token);
10469                 break;
10470         case MONO_PATCH_INFO_R4:
10471         case MONO_PATCH_INFO_R8:
10472                 target = patch_info->data.target;
10473                 break;
10474         case MONO_PATCH_INFO_EXC_NAME:
10475                 target = patch_info->data.name;
10476                 break;
10477         case MONO_PATCH_INFO_LDSTR:
10478                 target =
10479                         mono_ldstr (domain, patch_info->data.token->image, 
10480                                                 mono_metadata_token_index (patch_info->data.token->token));
10481                 break;
10482         case MONO_PATCH_INFO_TYPE_FROM_HANDLE: {
10483                 gpointer handle;
10484                 MonoClass *handle_class;
10485
10486                 handle = mono_ldtoken (patch_info->data.token->image, 
10487                                        patch_info->data.token->token, &handle_class, NULL);
10488                 mono_class_init (handle_class);
10489                 mono_class_init (mono_class_from_mono_type (handle));
10490
10491                 target =
10492                         mono_type_get_object (domain, handle);
10493                 break;
10494         }
10495         case MONO_PATCH_INFO_LDTOKEN: {
10496                 gpointer handle;
10497                 MonoClass *handle_class;
10498                 
10499                 handle = mono_ldtoken (patch_info->data.token->image,
10500                                        patch_info->data.token->token, &handle_class, NULL);
10501                 mono_class_init (handle_class);
10502                 
10503                 target = handle;
10504                 break;
10505         }
10506         case MONO_PATCH_INFO_DECLSEC:
10507                 target = (mono_metadata_blob_heap (patch_info->data.token->image, patch_info->data.token->token) + 2);
10508                 break;
10509         case MONO_PATCH_INFO_ICALL_ADDR:
10510                 target = mono_lookup_internal_call (patch_info->data.method);
10511                 break;
10512         case MONO_PATCH_INFO_BB_OVF:
10513         case MONO_PATCH_INFO_EXC_OVF:
10514         case MONO_PATCH_INFO_GOT_OFFSET:
10515         case MONO_PATCH_INFO_NONE:
10516                 break;
10517         default:
10518                 g_assert_not_reached ();
10519         }
10520
10521         return (gpointer)target;
10522 }
10523
10524 static void
10525 dec_foreach (MonoInst *tree, MonoCompile *cfg) {
10526         MonoJitICallInfo *info;
10527
10528         decompose_foreach (tree, cfg);
10529
10530         switch (mono_burg_arity [tree->opcode]) {
10531         case 0: break;
10532         case 1: 
10533                 dec_foreach (tree->inst_left, cfg);
10534
10535                 if ((info = mono_find_jit_opcode_emulation (tree->opcode))) {
10536                         MonoInst *iargs [2];
10537                 
10538                         iargs [0] = tree->inst_left;
10539
10540                         mono_emulate_opcode (cfg, tree, iargs, info);
10541                         return;
10542                 }
10543
10544                 break;
10545         case 2:
10546 #ifdef MONO_ARCH_BIGMUL_INTRINS
10547                 if (tree->opcode == OP_LMUL
10548                                 && (cfg->opt & MONO_OPT_INTRINS)
10549                                 && (tree->inst_left->opcode == CEE_CONV_I8 
10550                                         || tree->inst_left->opcode == CEE_CONV_U8)
10551                                 && tree->inst_left->inst_left->type == STACK_I4
10552                                 && (tree->inst_right->opcode == CEE_CONV_I8 
10553                                         || tree->inst_right->opcode == CEE_CONV_U8)
10554                                 && tree->inst_right->inst_left->type == STACK_I4
10555                                 && tree->inst_left->opcode == tree->inst_right->opcode) {
10556                         tree->opcode = (tree->inst_left->opcode == CEE_CONV_I8 ? OP_BIGMUL: OP_BIGMUL_UN);
10557                         tree->inst_left = tree->inst_left->inst_left;
10558                         tree->inst_right = tree->inst_right->inst_left;
10559                         dec_foreach (tree, cfg);
10560                 } else 
10561 #endif
10562                         if ((info = mono_find_jit_opcode_emulation (tree->opcode))) {
10563                         MonoInst *iargs [2];
10564                 
10565                         iargs [0] = tree->inst_i0;
10566                         iargs [1] = tree->inst_i1;
10567                 
10568                         mono_emulate_opcode (cfg, tree, iargs, info);
10569
10570                         dec_foreach (iargs [0], cfg);
10571                         dec_foreach (iargs [1], cfg);
10572                         return;
10573                 } else {
10574                         dec_foreach (tree->inst_left, cfg);
10575                         dec_foreach (tree->inst_right, cfg);
10576                 }
10577                 break;
10578         default:
10579                 g_assert_not_reached ();
10580         }
10581 }
10582
10583 static void
10584 decompose_pass (MonoCompile *cfg) {
10585         MonoBasicBlock *bb;
10586
10587         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
10588                 MonoInst *tree;
10589                 cfg->cbb = bb;
10590                 cfg->prev_ins = NULL;
10591                 MONO_BB_FOR_EACH_INS (cfg->cbb, tree) {
10592                         dec_foreach (tree, cfg);
10593                         cfg->prev_ins = tree;
10594                 }
10595         }
10596 }
10597
10598 static void
10599 nullify_basic_block (MonoBasicBlock *bb) 
10600 {
10601         bb->in_count = 0;
10602         bb->out_count = 0;
10603         bb->in_bb = NULL;
10604         bb->out_bb = NULL;
10605         bb->next_bb = NULL;
10606         MONO_INST_LIST_INIT (&bb->ins_list);
10607         bb->cil_code = NULL;
10608 }
10609
10610 static void 
10611 replace_out_block (MonoBasicBlock *bb, MonoBasicBlock *orig,  MonoBasicBlock *repl)
10612 {
10613         int i;
10614
10615         for (i = 0; i < bb->out_count; i++) {
10616                 MonoBasicBlock *ob = bb->out_bb [i];
10617                 if (ob == orig) {
10618                         if (!repl) {
10619                                 if (bb->out_count > 1) {
10620                                         bb->out_bb [i] = bb->out_bb [bb->out_count - 1];
10621                                 }
10622                                 bb->out_count--;
10623                         } else {
10624                                 bb->out_bb [i] = repl;
10625                         }
10626                 }
10627         }
10628 }
10629
10630 static void 
10631 replace_in_block (MonoBasicBlock *bb, MonoBasicBlock *orig, MonoBasicBlock *repl)
10632 {
10633         int i;
10634
10635         for (i = 0; i < bb->in_count; i++) {
10636                 MonoBasicBlock *ib = bb->in_bb [i];
10637                 if (ib == orig) {
10638                         if (!repl) {
10639                                 if (bb->in_count > 1) {
10640                                         bb->in_bb [i] = bb->in_bb [bb->in_count - 1];
10641                                 }
10642                                 bb->in_count--;
10643                         } else {
10644                                 bb->in_bb [i] = repl;
10645                         }
10646                 }
10647         }
10648 }
10649
10650 static void
10651 replace_out_block_in_code (MonoBasicBlock *bb, MonoBasicBlock *orig, MonoBasicBlock *repl) {
10652         MonoInst *inst;
10653         
10654         MONO_BB_FOR_EACH_INS (bb, inst) {
10655                 if (inst->opcode == OP_CALL_HANDLER) {
10656                         if (inst->inst_target_bb == orig)
10657                                 inst->inst_target_bb = repl;
10658                 }
10659         }
10660
10661         inst = mono_inst_list_last (&bb->ins_list);
10662         if (!inst)
10663                 return;
10664
10665         switch (inst->opcode) {
10666         case OP_BR:
10667                 if (inst->inst_target_bb == orig)
10668                         inst->inst_target_bb = repl;
10669                 break;
10670         case OP_SWITCH: {
10671                 int i;
10672                 int n = GPOINTER_TO_INT (inst->klass);
10673                 for (i = 0; i < n; i++ ) {
10674                         if (inst->inst_many_bb [i] == orig)
10675                                 inst->inst_many_bb [i] = repl;
10676                 }
10677                 break;
10678         }
10679         case CEE_BNE_UN:
10680         case CEE_BEQ:
10681         case CEE_BLT:
10682         case CEE_BLT_UN:
10683         case CEE_BGT:
10684         case CEE_BGT_UN:
10685         case CEE_BGE:
10686         case CEE_BGE_UN:
10687         case CEE_BLE:
10688         case CEE_BLE_UN:
10689                 if (inst->inst_true_bb == orig)
10690                         inst->inst_true_bb = repl;
10691                 if (inst->inst_false_bb == orig)
10692                         inst->inst_false_bb = repl;
10693                 break;
10694         default:
10695                 break;
10696         }
10697 }
10698
10699 static void 
10700 replace_basic_block (MonoBasicBlock *bb, MonoBasicBlock *orig,  MonoBasicBlock *repl)
10701 {
10702         int i, j;
10703
10704         for (i = 0; i < bb->out_count; i++) {
10705                 MonoBasicBlock *ob = bb->out_bb [i];
10706                 for (j = 0; j < ob->in_count; j++) {
10707                         if (ob->in_bb [j] == orig) {
10708                                 ob->in_bb [j] = repl;
10709                         }
10710                 }
10711         }
10712
10713 }
10714
10715 /**
10716   * Check if a bb is useless (is just made of NOPs and ends with an
10717   * unconditional branch, or nothing).
10718   * If it is so, unlink it from the CFG and nullify it, and return TRUE.
10719   * Otherwise, return FALSE;
10720   */
10721 static gboolean
10722 remove_block_if_useless (MonoCompile *cfg, MonoBasicBlock *bb, MonoBasicBlock *previous_bb) {
10723         MonoBasicBlock *target_bb = NULL;
10724         MonoInst *inst;
10725         
10726         /* Do not touch handlers */
10727         if (bb->region != -1) {
10728                 bb->not_useless = TRUE;
10729                 return FALSE;
10730         }
10731         
10732         MONO_BB_FOR_EACH_INS (bb, inst) {
10733                 switch (inst->opcode) {
10734                 case OP_NOP:
10735                         break;
10736                 case OP_BR:
10737                         target_bb = inst->inst_target_bb;
10738                         break;
10739                 default:
10740                         bb->not_useless = TRUE;
10741                         return FALSE;
10742                 }
10743         }
10744         
10745         if (target_bb == NULL) {
10746                 if ((bb->out_count == 1) && (bb->out_bb [0] == bb->next_bb)) {
10747                         target_bb = bb->next_bb;
10748                 } else {
10749                         /* Do not touch empty BBs that do not "fall through" to their next BB (like the exit BB) */
10750                         return FALSE;
10751                 }
10752         }
10753         
10754         /* Do not touch BBs following a switch (they are the "default" branch) */
10755         inst = mono_inst_list_last (&previous_bb->ins_list);
10756         if (inst && inst->opcode == OP_SWITCH)
10757                 return FALSE;
10758         
10759         /* Do not touch BBs following the entry BB and jumping to something that is not */
10760         /* thiry "next" bb (the entry BB cannot contain the branch) */
10761         if ((previous_bb == cfg->bb_entry) && (bb->next_bb != target_bb)) {
10762                 return FALSE;
10763         }
10764
10765         /* 
10766          * Do not touch BBs following a try block as the code in 
10767          * mini_method_compile needs them to compute the length of the try block.
10768          */
10769         if (MONO_BBLOCK_IS_IN_REGION (previous_bb, MONO_REGION_TRY))
10770                 return FALSE;
10771         
10772         /* Check that there is a target BB, and that bb is not an empty loop (Bug 75061) */
10773         if ((target_bb != NULL) && (target_bb != bb)) {
10774                 MonoInst *last_ins;
10775                 int i;
10776
10777                 if (cfg->verbose_level > 1) {
10778                         printf ("remove_block_if_useless, removed BB%d\n", bb->block_num);
10779                 }
10780                 
10781                 /* unlink_bblock () modifies the bb->in_bb array so can't use a for loop here */
10782                 while (bb->in_count) {
10783                         MonoBasicBlock *in_bb = bb->in_bb [0];
10784                         mono_unlink_bblock (cfg, in_bb, bb);
10785                         link_bblock (cfg, in_bb, target_bb);
10786                         replace_out_block_in_code (in_bb, bb, target_bb);
10787                 }
10788                 
10789                 mono_unlink_bblock (cfg, bb, target_bb);
10790                 
10791                 last_ins = mono_inst_list_last (&previous_bb->ins_list);
10792
10793                 if ((previous_bb != cfg->bb_entry) &&
10794                                 (previous_bb->region == bb->region) &&
10795                                 ((last_ins == NULL) ||
10796                                 ((last_ins->opcode != OP_BR) &&
10797                                 (!(MONO_IS_COND_BRANCH_OP (last_ins))) &&
10798                                 (last_ins->opcode != OP_SWITCH)))) {
10799                         for (i = 0; i < previous_bb->out_count; i++) {
10800                                 if (previous_bb->out_bb [i] == target_bb) {
10801                                         MonoInst *jump;
10802                                         MONO_INST_NEW (cfg, jump, OP_BR);
10803                                         MONO_ADD_INS (previous_bb, jump);
10804                                         jump->cil_code = previous_bb->cil_code;
10805                                         jump->inst_target_bb = target_bb;
10806                                         break;
10807                                 }
10808                         }
10809                 }
10810                 
10811                 previous_bb->next_bb = bb->next_bb;
10812                 nullify_basic_block (bb);
10813                 
10814                 return TRUE;
10815         } else {
10816                 return FALSE;
10817         }
10818 }
10819
10820 static void
10821 merge_basic_blocks (MonoBasicBlock *bb, MonoBasicBlock *bbn) 
10822 {
10823         MonoInst *last_ins;
10824
10825         bb->out_count = bbn->out_count;
10826         bb->out_bb = bbn->out_bb;
10827
10828         replace_basic_block (bb, bbn, bb);
10829
10830         last_ins = mono_inst_list_last (&bb->ins_list);
10831
10832         /* Nullify branch at the end of bb */
10833         if (last_ins && MONO_IS_BRANCH_OP (last_ins))
10834                 last_ins->opcode = OP_NOP;
10835
10836         MONO_INST_LIST_SPLICE_TAIL_INIT (&bbn->ins_list, &bb->ins_list);
10837
10838         bb->next_bb = bbn->next_bb;
10839         nullify_basic_block (bbn);
10840 }
10841
10842 static void
10843 move_basic_block_to_end (MonoCompile *cfg, MonoBasicBlock *bb)
10844 {
10845         MonoBasicBlock *bbn, *next;
10846         MonoInst *last_ins;
10847
10848         next = bb->next_bb;
10849
10850         /* Find the previous */
10851         for (bbn = cfg->bb_entry; bbn->next_bb && bbn->next_bb != bb; bbn = bbn->next_bb)
10852                 ;
10853         if (bbn->next_bb) {
10854                 bbn->next_bb = bb->next_bb;
10855         }
10856
10857         /* Find the last */
10858         for (bbn = cfg->bb_entry; bbn->next_bb; bbn = bbn->next_bb)
10859                 ;
10860         bbn->next_bb = bb;
10861         bb->next_bb = NULL;
10862
10863         last_ins = mono_inst_list_last (&bb->ins_list);
10864
10865         /* Add a branch */
10866         if (next && (!last_ins || (last_ins->opcode != OP_NOT_REACHED))) {
10867                 MonoInst *ins;
10868
10869                 MONO_INST_NEW (cfg, ins, OP_BR);
10870                 MONO_ADD_INS (bb, ins);
10871                 link_bblock (cfg, bb, next);
10872                 ins->inst_target_bb = next;
10873         }               
10874 }
10875
10876 /* checks that a and b represent the same instructions, conservatively,
10877  * it can return FALSE also for two trees that are equal.
10878  * FIXME: also make sure there are no side effects.
10879  */
10880 static int
10881 same_trees (MonoInst *a, MonoInst *b)
10882 {
10883         int arity;
10884         if (a->opcode != b->opcode)
10885                 return FALSE;
10886         arity = mono_burg_arity [a->opcode];
10887         if (arity == 1) {
10888                 if (a->ssa_op == b->ssa_op && a->ssa_op == MONO_SSA_LOAD && a->inst_i0 == b->inst_i0)
10889                         return TRUE;
10890                 return same_trees (a->inst_left, b->inst_left);
10891         } else if (arity == 2) {
10892                 return same_trees (a->inst_left, b->inst_left) && same_trees (a->inst_right, b->inst_right);
10893         } else if (arity == 0) {
10894                 switch (a->opcode) {
10895                 case OP_ICONST:
10896                         return a->inst_c0 == b->inst_c0;
10897                 default:
10898                         return FALSE;
10899                 }
10900         }
10901         return FALSE;
10902 }
10903
10904 static int
10905 get_unsigned_condbranch (int opcode)
10906 {
10907         switch (opcode) {
10908         case CEE_BLE: return CEE_BLE_UN;
10909         case CEE_BLT: return CEE_BLT_UN;
10910         case CEE_BGE: return CEE_BGE_UN;
10911         case CEE_BGT: return CEE_BGT_UN;
10912         }
10913         g_assert_not_reached ();
10914         return 0;
10915 }
10916
10917 static int
10918 tree_is_unsigned (MonoInst* ins) {
10919         switch (ins->opcode) {
10920         case OP_ICONST:
10921                 return (int)ins->inst_c0 >= 0;
10922         /* array lengths are positive as are string sizes */
10923         case CEE_LDLEN:
10924         case OP_STRLEN:
10925                 return TRUE;
10926         case CEE_CONV_U1:
10927         case CEE_CONV_U2:
10928         case CEE_CONV_U4:
10929         case CEE_CONV_OVF_U1:
10930         case CEE_CONV_OVF_U2:
10931         case CEE_CONV_OVF_U4:
10932                 return TRUE;
10933         case CEE_LDIND_U1:
10934         case CEE_LDIND_U2:
10935         case CEE_LDIND_U4:
10936                 return TRUE;
10937         default:
10938                 return FALSE;
10939         }
10940 }
10941
10942 /* check if an unsigned compare can be used instead of two signed compares
10943  * for (val < 0 || val > limit) conditionals.
10944  * Returns TRUE if the optimization has been applied.
10945  * Note that this can't be applied if the second arg is not positive...
10946  */
10947 static int
10948 try_unsigned_compare (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *bb_last)
10949 {
10950         MonoBasicBlock *truet, *falset;
10951         MonoInst *cmp_inst = bb_last->inst_left;
10952         MonoInst *condb;
10953         if (!cmp_inst->inst_right->inst_c0 == 0)
10954                 return FALSE;
10955         truet = bb_last->inst_true_bb;
10956         falset = bb_last->inst_false_bb;
10957         if (falset->in_count != 1)
10958                 return FALSE;
10959         condb = mono_inst_list_last (&falset->ins_list);
10960         /* target bb must have one instruction */
10961         if (!condb || (condb->node.next != &falset->ins_list))
10962                 return FALSE;
10963         if ((((condb->opcode == CEE_BLE || condb->opcode == CEE_BLT) && (condb->inst_false_bb == truet))
10964                         || ((condb->opcode == CEE_BGE || condb->opcode == CEE_BGT) && (condb->inst_true_bb == truet)))
10965                         && same_trees (cmp_inst->inst_left, condb->inst_left->inst_left)) {
10966                 if (!tree_is_unsigned (condb->inst_left->inst_right))
10967                         return FALSE;
10968                 condb->opcode = get_unsigned_condbranch (condb->opcode);
10969                 /* change the original condbranch to just point to the new unsigned check */
10970                 bb_last->opcode = OP_BR;
10971                 bb_last->inst_target_bb = falset;
10972                 replace_out_block (bb, truet, NULL);
10973                 replace_in_block (truet, bb, NULL);
10974                 return TRUE;
10975         }
10976         return FALSE;
10977 }
10978
10979 /*
10980  * Optimizes the branches on the Control Flow Graph
10981  *
10982  */
10983 static void
10984 optimize_branches (MonoCompile *cfg)
10985 {
10986         int i, changed = FALSE;
10987         MonoBasicBlock *bb, *bbn;
10988         guint32 niterations;
10989
10990         /*
10991          * Some crazy loops could cause the code below to go into an infinite
10992          * loop, see bug #53003 for an example. To prevent this, we put an upper
10993          * bound on the number of iterations.
10994          */
10995         if (cfg->num_bblocks > 1000)
10996                 niterations = cfg->num_bblocks * 2;
10997         else
10998                 niterations = 1000;
10999
11000         do {
11001                 MonoBasicBlock *previous_bb;
11002                 changed = FALSE;
11003                 niterations --;
11004
11005                 /* we skip the entry block (exit is handled specially instead ) */
11006                 for (previous_bb = cfg->bb_entry, bb = cfg->bb_entry->next_bb; bb; previous_bb = bb, bb = bb->next_bb) {
11007                         MonoInst *last_ins;
11008
11009                         /* dont touch code inside exception clauses */
11010                         if (bb->region != -1)
11011                                 continue;
11012
11013                         if (!bb->not_useless && remove_block_if_useless (cfg, bb, previous_bb)) {
11014                                 changed = TRUE;
11015                                 continue;
11016                         }
11017
11018                         if ((bbn = bb->next_bb) && bbn->in_count == 0 && bb->region == bbn->region) {
11019                                 if (cfg->verbose_level > 2)
11020                                         g_print ("nullify block triggered %d\n", bbn->block_num);
11021
11022                                 bb->next_bb = bbn->next_bb;
11023
11024                                 for (i = 0; i < bbn->out_count; i++)
11025                                         replace_in_block (bbn->out_bb [i], bbn, NULL);
11026
11027                                 nullify_basic_block (bbn);                      
11028                                 changed = TRUE;
11029                         }
11030
11031                         last_ins = mono_inst_list_last (&bb->ins_list);
11032                         if (bb->out_count == 1) {
11033                                 bbn = bb->out_bb [0];
11034
11035                                 /* conditional branches where true and false targets are the same can be also replaced with OP_BR */
11036                                 if (last_ins && MONO_IS_COND_BRANCH_OP (last_ins)) {
11037                                         MonoInst *pop;
11038                                         MONO_INST_NEW (cfg, pop, CEE_POP);
11039                                         pop->inst_left = last_ins->inst_left->inst_left;
11040                                         mono_add_ins_to_end (bb, pop);
11041                                         MONO_INST_NEW (cfg, pop, CEE_POP);
11042                                         pop->inst_left = last_ins->inst_left->inst_right;
11043                                         mono_add_ins_to_end (bb, pop);
11044                                         last_ins->opcode = OP_BR;
11045                                         last_ins->inst_target_bb = last_ins->inst_true_bb;
11046                                         changed = TRUE;
11047                                         if (cfg->verbose_level > 2)
11048                                                 g_print ("cond branch removal triggered in %d %d\n", bb->block_num, bb->out_count);
11049                                 }
11050
11051                                 if (bb->region == bbn->region && bb->next_bb == bbn) {
11052                                         /* the block are in sequence anyway ... */
11053
11054                                         /* branches to the following block can be removed */
11055                                         if (last_ins && last_ins->opcode == OP_BR) {
11056                                                 last_ins->opcode = OP_NOP;
11057                                                 changed = TRUE;
11058                                                 if (cfg->verbose_level > 2)
11059                                                         g_print ("br removal triggered %d -> %d\n", bb->block_num, bbn->block_num);
11060                                         }
11061
11062                                         if (bbn->in_count == 1) {
11063
11064                                                 if (bbn != cfg->bb_exit) {
11065                                                         if (cfg->verbose_level > 2)
11066                                                                 g_print ("block merge triggered %d -> %d\n", bb->block_num, bbn->block_num);
11067                                                         merge_basic_blocks (bb, bbn);
11068                                                         changed = TRUE;
11069                                                         continue;
11070                                                 }
11071
11072                                                 //mono_print_bb_code (bb);
11073                                         }
11074                                 }
11075                         }
11076                         if ((bbn = bb->next_bb) && bbn->in_count == 0 && bb->region == bbn->region) {
11077                                 if (cfg->verbose_level > 2) {
11078                                         g_print ("nullify block triggered %d\n", bbn->block_num);
11079                                 }
11080                                 bb->next_bb = bbn->next_bb;
11081
11082                                 for (i = 0; i < bbn->out_count; i++)
11083                                         replace_in_block (bbn->out_bb [i], bbn, NULL);
11084
11085                                 nullify_basic_block (bbn);                      
11086                                 changed = TRUE;
11087                                 continue;
11088                         }
11089
11090                         if (bb->out_count == 1) {
11091                                 bbn = bb->out_bb [0];
11092
11093                                 if (last_ins && last_ins->opcode == OP_BR) {
11094                                         MonoInst *bbn_code;
11095
11096                                         bbn = last_ins->inst_target_bb;
11097                                         bbn_code = mono_inst_list_first (&bbn->ins_list);
11098                                         if (bb->region == bbn->region && bbn_code &&
11099                                                         bbn_code->opcode == OP_BR &&
11100                                                         bbn_code->inst_target_bb->region == bb->region) {
11101                                                 if (cfg->verbose_level > 2)
11102                                                         g_print ("in %s branch to branch triggered %d -> %d -> %d\n", cfg->method->name, 
11103                                                                  bb->block_num, bbn->block_num, bbn_code->inst_target_bb->block_num);
11104
11105                                                 replace_in_block (bbn, bb, NULL);
11106                                                 replace_out_block (bb, bbn, bbn_code->inst_target_bb);
11107                                                 link_bblock (cfg, bb, bbn_code->inst_target_bb);
11108                                                 last_ins->inst_target_bb = bbn_code->inst_target_bb;
11109                                                 changed = TRUE;
11110                                                 continue;
11111                                         }
11112                                 }
11113                         } else if (bb->out_count == 2) {
11114                                 if (last_ins && MONO_IS_COND_BRANCH_NOFP (last_ins)) {
11115                                         int branch_result = mono_eval_cond_branch (last_ins);
11116                                         MonoBasicBlock *taken_branch_target = NULL, *untaken_branch_target = NULL;
11117                                         MonoInst *bbn_code;
11118
11119                                         if (branch_result == BRANCH_TAKEN) {
11120                                                 taken_branch_target = last_ins->inst_true_bb;
11121                                                 untaken_branch_target = last_ins->inst_false_bb;
11122                                         } else if (branch_result == BRANCH_NOT_TAKEN) {
11123                                                 taken_branch_target = last_ins->inst_false_bb;
11124                                                 untaken_branch_target = last_ins->inst_true_bb;
11125                                         }
11126                                         if (taken_branch_target) {
11127                                                 /* if mono_eval_cond_branch () is ever taken to handle 
11128                                                  * non-constant values to compare, issue a pop here.
11129                                                  */
11130                                                 last_ins->opcode = OP_BR;
11131                                                 last_ins->inst_target_bb = taken_branch_target;
11132                                                 mono_unlink_bblock (cfg, bb, untaken_branch_target);
11133                                                 changed = TRUE;
11134                                                 continue;
11135                                         }
11136                                         bbn = last_ins->inst_true_bb;
11137                                         bbn_code = mono_inst_list_first (&bbn->ins_list);
11138                                         if (bb->region == bbn->region && bbn_code && bbn_code->opcode == OP_BR &&
11139                                                         bbn_code->inst_target_bb->region == bb->region) {
11140                                                 if (cfg->verbose_level > 2)             
11141                                                         g_print ("cbranch1 to branch triggered %d -> (%d) %d (0x%02x)\n", 
11142                                                                  bb->block_num, bbn->block_num, bbn_code->inst_target_bb->block_num, 
11143                                                                  bbn_code->opcode);
11144
11145                                                 /* 
11146                                                  * Unlink, then relink bblocks to avoid various
11147                                                  * tricky situations when the two targets of the branch
11148                                                  * are equal, or will become equal after the change.
11149                                                  */
11150                                                 mono_unlink_bblock (cfg, bb, last_ins->inst_true_bb);
11151                                                 mono_unlink_bblock (cfg, bb, last_ins->inst_false_bb);
11152
11153                                                 last_ins->inst_true_bb = bbn_code->inst_target_bb;
11154
11155                                                 link_bblock (cfg, bb, last_ins->inst_true_bb);
11156                                                 link_bblock (cfg, bb, last_ins->inst_false_bb);
11157
11158                                                 changed = TRUE;
11159                                                 continue;
11160                                         }
11161
11162                                         bbn = last_ins->inst_false_bb;
11163                                         bbn_code = mono_inst_list_first (&bbn->ins_list);
11164                                         if (bb->region == bbn->region && bbn_code && bbn_code->opcode == OP_BR &&
11165                                                         bbn_code->inst_target_bb->region == bb->region) {
11166                                                 if (cfg->verbose_level > 2)
11167                                                         g_print ("cbranch2 to branch triggered %d -> (%d) %d (0x%02x)\n", 
11168                                                                  bb->block_num, bbn->block_num, bbn_code->inst_target_bb->block_num, 
11169                                                                  bbn_code->opcode);
11170
11171                                                 mono_unlink_bblock (cfg, bb, last_ins->inst_true_bb);
11172                                                 mono_unlink_bblock (cfg, bb, last_ins->inst_false_bb);
11173
11174                                                 last_ins->inst_false_bb = bbn_code->inst_target_bb;
11175
11176                                                 link_bblock (cfg, bb, last_ins->inst_true_bb);
11177                                                 link_bblock (cfg, bb, last_ins->inst_false_bb);
11178
11179                                                 changed = TRUE;
11180                                                 continue;
11181                                         }
11182                                 }
11183
11184                                 /* detect and optimize to unsigned compares checks like: if (v < 0 || v > limit */
11185                                 if (last_ins && last_ins->opcode == CEE_BLT && last_ins->inst_left->inst_right->opcode == OP_ICONST) {
11186                                         if (try_unsigned_compare (cfg, bb, last_ins)) {
11187                                                 /*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));*/
11188                                                 changed = TRUE;
11189                                                 continue;
11190                                         }
11191                                 }
11192
11193                                 if (last_ins && MONO_IS_COND_BRANCH_NOFP (last_ins)) {
11194                                         if (last_ins->inst_false_bb->out_of_line && (bb->region == last_ins->inst_false_bb->region)) {
11195                                                 /* Reverse the branch */
11196                                                 last_ins->opcode = reverse_branch_op (last_ins->opcode);
11197                                                 bbn = last_ins->inst_false_bb;
11198                                                 last_ins->inst_false_bb = last_ins->inst_true_bb;
11199                                                 last_ins->inst_true_bb = bbn;
11200
11201                                                 move_basic_block_to_end (cfg, last_ins->inst_true_bb);
11202                                                 if (cfg->verbose_level > 2)
11203                                                         g_print ("cbranch to throw block triggered %d.\n", 
11204                                                                          bb->block_num);
11205                                         }
11206                                 }
11207                         }
11208                 }
11209         } while (changed && (niterations > 0));
11210
11211 }
11212
11213 static void
11214 mono_compile_create_vars (MonoCompile *cfg)
11215 {
11216         MonoMethodSignature *sig;
11217         MonoMethodHeader *header;
11218         int i;
11219
11220         header = mono_method_get_header (cfg->method);
11221
11222         sig = mono_method_signature (cfg->method);
11223         
11224         if (!MONO_TYPE_IS_VOID (sig->ret)) {
11225                 cfg->ret = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst));
11226                 cfg->ret->opcode = OP_RETARG;
11227                 cfg->ret->inst_vtype = sig->ret;
11228                 cfg->ret->klass = mono_class_from_mono_type (sig->ret);
11229         }
11230         if (cfg->verbose_level > 2)
11231                 g_print ("creating vars\n");
11232
11233         cfg->args = mono_mempool_alloc0 (cfg->mempool, (sig->param_count + sig->hasthis) * sizeof (MonoInst*));
11234
11235         if (sig->hasthis)
11236                 cfg->args [0] = mono_compile_create_var (cfg, &cfg->method->klass->this_arg, OP_ARG);
11237
11238         for (i = 0; i < sig->param_count; ++i) {
11239                 cfg->args [i + sig->hasthis] = mono_compile_create_var (cfg, sig->params [i], OP_ARG);
11240                 if (sig->params [i]->byref) {
11241                         cfg->disable_ssa = TRUE;
11242                 }
11243         }
11244
11245         cfg->locals_start = cfg->num_varinfo;
11246
11247         if (cfg->verbose_level > 2)
11248                 g_print ("creating locals\n");
11249
11250         for (i = 0; i < header->num_locals; ++i)
11251                 mono_compile_create_var (cfg, header->locals [i], OP_LOCAL);
11252         if (cfg->verbose_level > 2)
11253                 g_print ("locals done\n");
11254
11255         mono_arch_create_vars (cfg);
11256 }
11257
11258 void
11259 mono_print_code (MonoCompile *cfg)
11260 {
11261         MonoBasicBlock *bb;
11262         
11263         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
11264                 MonoInst *tree;
11265
11266                 if (!MONO_INST_LIST_EMPTY (&bb->ins_list))
11267                         g_print ("CODE BLOCK %d (nesting %d):\n",
11268                                  bb->block_num, bb->nesting);
11269
11270                 MONO_BB_FOR_EACH_INS (bb, tree) {
11271                         mono_print_tree (tree);
11272                         g_print ("\n");
11273                 }
11274         }
11275 }
11276
11277 extern const char * const mono_burg_rule_string [];
11278
11279 static void
11280 emit_state (MonoCompile *cfg, MBState *state, int goal)
11281 {
11282         MBState *kids [10];
11283         int ern = mono_burg_rule (state, goal);
11284         const guint16 *nts = mono_burg_nts_data + mono_burg_nts [ern];
11285
11286         //g_print ("rule: %s\n", mono_burg_rule_string [ern]);
11287         switch (goal) {
11288         case MB_NTERM_reg:
11289                 //if (state->reg2)
11290                 //      state->reg1 = state->reg2; /* chain rule */
11291                 //else
11292 #ifdef MONO_ARCH_ENABLE_EMIT_STATE_OPT
11293                 if (!state->reg1)
11294 #endif
11295                         state->reg1 = mono_regstate_next_int (cfg->rs);
11296                 //g_print ("alloc symbolic R%d (reg2: R%d) in block %d\n", state->reg1, state->reg2, cfg->cbb->block_num);
11297                 break;
11298         case MB_NTERM_lreg:
11299                 state->reg1 = mono_regstate_next_int (cfg->rs);
11300                 state->reg2 = mono_regstate_next_int (cfg->rs);
11301                 break;
11302         case MB_NTERM_freg:
11303 #ifdef MONO_ARCH_SOFT_FLOAT
11304                 state->reg1 = mono_regstate_next_int (cfg->rs);
11305                 state->reg2 = mono_regstate_next_int (cfg->rs);
11306 #else
11307                 state->reg1 = mono_regstate_next_float (cfg->rs);
11308 #endif
11309                 break;
11310         default:
11311 #ifdef MONO_ARCH_ENABLE_EMIT_STATE_OPT
11312                 /*
11313                  * Enabling this might cause bugs to surface in the local register
11314                  * allocators on some architectures like x86.
11315                  */
11316                 if ((state->tree->ssa_op == MONO_SSA_STORE) && (state->left->tree->opcode == OP_REGVAR)) {
11317                         /* Do not optimize away reg-reg moves */
11318                         if (! ((state->right->tree->ssa_op == MONO_SSA_LOAD) && (state->right->left->tree->opcode == OP_REGVAR))) {
11319                                 state->right->reg1 = state->left->tree->dreg;
11320                         }
11321                 }
11322 #endif
11323
11324                 /* do nothing */
11325                 break;
11326         }
11327         if (nts [0]) {
11328                 mono_burg_kids (state, ern, kids);
11329
11330                 emit_state (cfg, kids [0], nts [0]);
11331                 if (nts [1]) {
11332                         emit_state (cfg, kids [1], nts [1]);
11333                         if (nts [2]) {
11334                                 emit_state (cfg, kids [2], nts [2]);
11335                                 if (nts [3]) {
11336                                         g_assert (!nts [4]);
11337                                         emit_state (cfg, kids [3], nts [3]);
11338                                 }
11339                         }
11340                 }
11341         }
11342
11343 //      g_print ("emit: %s (%p)\n", mono_burg_rule_string [ern], state);
11344         mono_burg_emit (ern, state, state->tree, cfg);
11345 }
11346
11347 #define DEBUG_SELECTION
11348
11349 static void 
11350 mini_select_instructions (MonoCompile *cfg)
11351 {
11352         MonoBasicBlock *bb;
11353         
11354         cfg->state_pool = mono_mempool_new ();
11355         cfg->rs = mono_regstate_new ();
11356
11357         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
11358                 MonoInst *last_ins = mono_inst_list_last (&bb->ins_list);
11359
11360                 if (last_ins && MONO_IS_COND_BRANCH_OP (last_ins) &&
11361                                 bb->next_bb != last_ins->inst_false_bb) {
11362
11363                         /* we are careful when inverting, since bugs like #59580
11364                          * could show up when dealing with NaNs.
11365                          */
11366                         if (MONO_IS_COND_BRANCH_NOFP(last_ins) && bb->next_bb == last_ins->inst_true_bb) {
11367                                 MonoBasicBlock *tmp =  last_ins->inst_true_bb;
11368                                 last_ins->inst_true_bb = last_ins->inst_false_bb;
11369                                 last_ins->inst_false_bb = tmp;
11370
11371                                 last_ins->opcode = reverse_branch_op (last_ins->opcode);
11372                         } else {                        
11373                                 MonoInst *inst = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst));
11374                                 inst->opcode = OP_BR;
11375                                 inst->inst_target_bb = last_ins->inst_false_bb;
11376                                 mono_bblock_add_inst (bb, inst);
11377                         }
11378                 }
11379         }
11380
11381 #ifdef DEBUG_SELECTION
11382         if (cfg->verbose_level >= 4) {
11383         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
11384                 MonoInst *tree; 
11385                 g_print ("DUMP BLOCK %d:\n", bb->block_num);
11386
11387                 MONO_BB_FOR_EACH_INS (bb, tree) {
11388                         mono_print_tree (tree);
11389                         g_print ("\n");
11390                 }
11391         }
11392         }
11393 #endif
11394
11395         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
11396                 MonoInst *tree, *n;     
11397                 MonoInstList head;
11398                 MBState *mbstate;
11399
11400                 MONO_INST_LIST_INIT (&head);
11401                 if (MONO_INST_LIST_EMPTY (&bb->ins_list))
11402                         continue;
11403                 MONO_INST_LIST_SPLICE_INIT (&bb->ins_list, &head);
11404                 
11405                 cfg->cbb = bb;
11406                 mono_regstate_reset (cfg->rs);
11407
11408 #ifdef DEBUG_SELECTION
11409                 if (cfg->verbose_level >= 3)
11410                         g_print ("LABEL BLOCK %d:\n", bb->block_num);
11411 #endif
11412                 MONO_INST_LIST_FOR_EACH_ENTRY_SAFE (tree, n, &head, node) {
11413 #ifdef DEBUG_SELECTION
11414                         if (cfg->verbose_level >= 3) {
11415                                 mono_print_tree (tree);
11416                                 g_print ("\n");
11417                         }
11418 #endif
11419
11420                         cfg->ip = tree->cil_code;
11421                         if (!(mbstate = mono_burg_label (tree, cfg))) {
11422                                 g_warning ("unable to label tree %p", tree);
11423                                 mono_print_tree (tree);
11424                                 g_print ("\n");                         
11425                                 g_assert_not_reached ();
11426                         }
11427                         emit_state (cfg, mbstate, MB_NTERM_stmt);
11428                 }
11429                 bb->max_vreg = cfg->rs->next_vreg;
11430
11431                 mono_mempool_empty (cfg->state_pool); 
11432         }
11433         mono_mempool_destroy (cfg->state_pool); 
11434
11435         cfg->ip = NULL;
11436 }
11437
11438 /*
11439  * mono_normalize_opcodes:
11440  *
11441  *   Replace CEE_ and OP_ opcodes with the corresponding OP_I or OP_L opcodes.
11442  */
11443
11444 static gint16 *remap_table;
11445
11446 #if SIZEOF_VOID_P == 8
11447 #define REMAP_OPCODE(opcode) OP_L ## opcode
11448 #else
11449 #define REMAP_OPCODE(opcode) OP_I ## opcode
11450 #endif
11451
11452 static G_GNUC_UNUSED void
11453 mono_normalize_opcodes (MonoCompile *cfg, MonoBasicBlock *bb)
11454 {
11455         MonoInst *ins;
11456
11457         if (!remap_table) {
11458                 remap_table = g_new0 (gint16, OP_LAST);
11459
11460 #if SIZEOF_VOID_P == 8
11461                 remap_table [CEE_CONV_U8] = OP_ZEXT_I4;
11462                 remap_table [CEE_CONV_U] = OP_ZEXT_I4;
11463                 remap_table [CEE_CONV_I8] = OP_SEXT_I4;
11464                 remap_table [CEE_CONV_I] = OP_SEXT_I4;
11465                 remap_table [CEE_CONV_OVF_U4] = OP_LCONV_TO_OVF_U4;
11466                 remap_table [CEE_CONV_OVF_I4_UN] = OP_LCONV_TO_OVF_I4_UN;
11467 #else
11468 #endif
11469                 remap_table [CEE_CONV_R4] = OP_ICONV_TO_R4;
11470                 remap_table [CEE_CONV_R8] = OP_ICONV_TO_R8;
11471                 remap_table [CEE_CONV_I4] = OP_MOVE;
11472                 remap_table [CEE_CONV_U4] = OP_MOVE;
11473                 remap_table [CEE_CONV_I1] = REMAP_OPCODE (CONV_TO_I1);
11474                 remap_table [CEE_CONV_I2] = REMAP_OPCODE (CONV_TO_I2);
11475                 remap_table [CEE_CONV_U1] = REMAP_OPCODE (CONV_TO_U1);
11476                 remap_table [CEE_CONV_U2] = REMAP_OPCODE (CONV_TO_U2);
11477                 remap_table [CEE_CONV_R_UN] = REMAP_OPCODE (CONV_TO_R_UN);
11478                 remap_table [CEE_ADD] = REMAP_OPCODE (ADD);
11479                 remap_table [CEE_SUB] = REMAP_OPCODE (SUB);
11480                 remap_table [CEE_MUL] = REMAP_OPCODE (MUL);
11481                 remap_table [CEE_DIV] = REMAP_OPCODE (DIV);
11482                 remap_table [CEE_REM] = REMAP_OPCODE (REM);
11483                 remap_table [CEE_DIV_UN] = REMAP_OPCODE (DIV_UN);
11484                 remap_table [CEE_REM_UN] = REMAP_OPCODE (REM_UN);
11485                 remap_table [CEE_AND] = REMAP_OPCODE (AND);
11486                 remap_table [CEE_OR] = REMAP_OPCODE (OR);
11487                 remap_table [CEE_XOR] = REMAP_OPCODE (XOR);
11488                 remap_table [CEE_SHL] = REMAP_OPCODE (SHL);
11489                 remap_table [CEE_SHR] = REMAP_OPCODE (SHR);
11490                 remap_table [CEE_SHR_UN] = REMAP_OPCODE (SHR_UN);
11491                 remap_table [CEE_NOT] = REMAP_OPCODE (NOT);
11492                 remap_table [CEE_NEG] = REMAP_OPCODE (NEG);
11493                 remap_table [CEE_CALL] = OP_CALL;
11494                 remap_table [CEE_BEQ] = REMAP_OPCODE (BEQ);
11495                 remap_table [CEE_BNE_UN] = REMAP_OPCODE (BNE_UN);
11496                 remap_table [CEE_BLT] = REMAP_OPCODE (BLT);
11497                 remap_table [CEE_BLT_UN] = REMAP_OPCODE (BLT_UN);
11498                 remap_table [CEE_BGT] = REMAP_OPCODE (BGT);
11499                 remap_table [CEE_BGT_UN] = REMAP_OPCODE (BGT_UN);
11500                 remap_table [CEE_BGE] = REMAP_OPCODE (BGE);
11501                 remap_table [CEE_BGE_UN] = REMAP_OPCODE (BGE_UN);
11502                 remap_table [CEE_BLE] = REMAP_OPCODE (BLE);
11503                 remap_table [CEE_BLE_UN] = REMAP_OPCODE (BLE_UN);
11504                 remap_table [CEE_ADD_OVF] = REMAP_OPCODE (ADD_OVF);
11505                 remap_table [CEE_ADD_OVF_UN] = REMAP_OPCODE (ADD_OVF_UN);
11506                 remap_table [CEE_SUB_OVF] = REMAP_OPCODE (SUB_OVF);
11507                 remap_table [CEE_SUB_OVF_UN] = REMAP_OPCODE (SUB_OVF_UN);
11508                 remap_table [CEE_MUL_OVF] = REMAP_OPCODE (MUL_OVF);
11509                 remap_table [CEE_MUL_OVF_UN] = REMAP_OPCODE (MUL_OVF_UN);
11510         }
11511
11512         MONO_BB_FOR_EACH_INS (bb, ins) {
11513                 int remapped = remap_table [ins->opcode];
11514                 if (remapped)
11515                         ins->opcode = remapped;
11516         }
11517 }
11518
11519 void
11520 mono_codegen (MonoCompile *cfg)
11521 {
11522         MonoJumpInfo *patch_info;
11523         MonoBasicBlock *bb;
11524         int i, max_epilog_size;
11525         guint8 *code;
11526
11527         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
11528                 cfg->spill_count = 0;
11529                 /* we reuse dfn here */
11530                 /* bb->dfn = bb_count++; */
11531 #ifdef MONO_ARCH_ENABLE_NORMALIZE_OPCODES
11532                 mono_normalize_opcodes (cfg, bb);
11533 #endif
11534
11535                 mono_arch_lowering_pass (cfg, bb);
11536
11537                 if (cfg->opt & MONO_OPT_PEEPHOLE)
11538                         mono_arch_peephole_pass_1 (cfg, bb);
11539
11540                 mono_local_regalloc (cfg, bb);
11541
11542                 if (cfg->opt & MONO_OPT_PEEPHOLE)
11543                         mono_arch_peephole_pass_2 (cfg, bb);
11544         }
11545
11546         if (cfg->prof_options & MONO_PROFILE_COVERAGE)
11547                 cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, cfg->num_bblocks);
11548
11549         code = mono_arch_emit_prolog (cfg);
11550
11551         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
11552                 code = mono_arch_instrument_prolog (cfg, mono_profiler_method_enter, code, FALSE);
11553
11554         cfg->code_len = code - cfg->native_code;
11555         cfg->prolog_end = cfg->code_len;
11556
11557         mono_debug_open_method (cfg);
11558
11559         /* emit code all basic blocks */
11560         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
11561                 bb->native_offset = cfg->code_len;
11562                 mono_arch_output_basic_block (cfg, bb);
11563
11564                 if (bb == cfg->bb_exit) {
11565                         cfg->epilog_begin = cfg->code_len;
11566
11567                         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE) {
11568                                 code = cfg->native_code + cfg->code_len;
11569                                 code = mono_arch_instrument_epilog (cfg, mono_profiler_method_leave, code, FALSE);
11570                                 cfg->code_len = code - cfg->native_code;
11571                                 g_assert (cfg->code_len < cfg->code_size);
11572                         }
11573
11574                         mono_arch_emit_epilog (cfg);
11575                 }
11576         }
11577
11578         mono_arch_emit_exceptions (cfg);
11579
11580         max_epilog_size = 0;
11581
11582         code = cfg->native_code + cfg->code_len;
11583
11584         /* we always allocate code in cfg->domain->code_mp to increase locality */
11585         cfg->code_size = cfg->code_len + max_epilog_size;
11586         /* fixme: align to MONO_ARCH_CODE_ALIGNMENT */
11587
11588         if (cfg->method->dynamic) {
11589                 /* Allocate the code into a separate memory pool so it can be freed */
11590                 cfg->dynamic_info = g_new0 (MonoJitDynamicMethodInfo, 1);
11591                 cfg->dynamic_info->code_mp = mono_code_manager_new_dynamic ();
11592                 mono_domain_lock (cfg->domain);
11593                 mono_dynamic_code_hash_insert (cfg->domain, cfg->method, cfg->dynamic_info);
11594                 mono_domain_unlock (cfg->domain);
11595
11596                 code = mono_code_manager_reserve (cfg->dynamic_info->code_mp, cfg->code_size);
11597         } else {
11598                 mono_domain_lock (cfg->domain);
11599                 code = mono_code_manager_reserve (cfg->domain->code_mp, cfg->code_size);
11600                 mono_domain_unlock (cfg->domain);
11601         }
11602
11603         memcpy (code, cfg->native_code, cfg->code_len);
11604         g_free (cfg->native_code);
11605         cfg->native_code = code;
11606         code = cfg->native_code + cfg->code_len;
11607   
11608         /* g_assert (((int)cfg->native_code & (MONO_ARCH_CODE_ALIGNMENT - 1)) == 0); */
11609         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
11610                 switch (patch_info->type) {
11611                 case MONO_PATCH_INFO_ABS: {
11612                         MonoJitICallInfo *info = mono_find_jit_icall_by_addr (patch_info->data.target);
11613                         if (info) {
11614                                 //printf ("TEST %s %p\n", info->name, patch_info->data.target);
11615                                 if ((cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) && 
11616                                         strstr (cfg->method->name, info->name))
11617                                         /*
11618                                          * This is an icall wrapper, and this is a call to the
11619                                          * wrapped function.
11620                                          */
11621                                         ;
11622                                 else {
11623                                         /* for these array methods we currently register the same function pointer
11624                                          * since it's a vararg function. But this means that mono_find_jit_icall_by_addr ()
11625                                          * will return the incorrect one depending on the order they are registered.
11626                                          * See tests/test-arr.cs
11627                                          */
11628                                         if (strstr (info->name, "ves_array_new_va_") == NULL && strstr (info->name, "ves_array_element_address_") == NULL) {
11629                                                 patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
11630                                                 patch_info->data.name = info->name;
11631                                         }
11632                                 }
11633                         }
11634                         else {
11635                                 MonoVTable *vtable = mono_find_class_init_trampoline_by_addr (patch_info->data.target);
11636                                 if (vtable) {
11637                                         patch_info->type = MONO_PATCH_INFO_CLASS_INIT;
11638                                         patch_info->data.klass = vtable->klass;
11639                                 } else {
11640                                         MonoClass *klass = mono_find_delegate_trampoline_by_addr (patch_info->data.target);
11641                                         if (klass) {
11642                                                 patch_info->type = MONO_PATCH_INFO_DELEGATE_TRAMPOLINE;
11643                                                 patch_info->data.klass = klass;
11644                                         }
11645                                 }
11646                         }
11647                         break;
11648                 }
11649                 case MONO_PATCH_INFO_SWITCH: {
11650                         gpointer *table;
11651                         if (cfg->method->dynamic) {
11652                                 table = mono_code_manager_reserve (cfg->dynamic_info->code_mp, sizeof (gpointer) * patch_info->data.table->table_size);
11653                         } else {
11654                                 mono_domain_lock (cfg->domain);
11655                                 table = mono_code_manager_reserve (cfg->domain->code_mp, sizeof (gpointer) * patch_info->data.table->table_size);
11656                                 mono_domain_unlock (cfg->domain);
11657                         }
11658
11659                         if (!cfg->compile_aot)
11660                                 /* In the aot case, the patch already points to the correct location */
11661                                 patch_info->ip.i = patch_info->ip.label->inst_c0;
11662                         for (i = 0; i < patch_info->data.table->table_size; i++) {
11663                                 table [i] = GINT_TO_POINTER (patch_info->data.table->table [i]->native_offset);
11664                         }
11665                         patch_info->data.table->table = (MonoBasicBlock**)table;
11666                         break;
11667                 }
11668                 default:
11669                         /* do nothing */
11670                         break;
11671                 }
11672         }
11673
11674 #ifdef VALGRIND_JIT_REGISTER_MAP
11675 if (valgrind_register){
11676                 char* nm = mono_method_full_name (cfg->method, TRUE);
11677                 VALGRIND_JIT_REGISTER_MAP (nm, cfg->native_code, cfg->native_code + cfg->code_len);
11678                 g_free (nm);
11679         }
11680 #endif
11681  
11682         if (cfg->verbose_level > 0) {
11683                 char* nm = mono_method_full_name (cfg->method, TRUE);
11684                 g_print ("Method %s emitted at %p to %p (code length %d) [%s]\n", 
11685                                  nm, 
11686                                  cfg->native_code, cfg->native_code + cfg->code_len, cfg->code_len, cfg->domain->friendly_name);
11687                 g_free (nm);
11688         }
11689
11690 #ifdef MONO_ARCH_HAVE_SAVE_UNWIND_INFO
11691         mono_arch_save_unwind_info (cfg);
11692 #endif
11693         
11694         mono_arch_patch_code (cfg->method, cfg->domain, cfg->native_code, cfg->patch_info, cfg->run_cctors);
11695
11696         if (cfg->method->dynamic) {
11697                 mono_code_manager_commit (cfg->dynamic_info->code_mp, cfg->native_code, cfg->code_size, cfg->code_len);
11698         } else {
11699                 mono_domain_lock (cfg->domain);
11700                 mono_code_manager_commit (cfg->domain->code_mp, cfg->native_code, cfg->code_size, cfg->code_len);
11701                 mono_domain_unlock (cfg->domain);
11702         }
11703         
11704         mono_arch_flush_icache (cfg->native_code, cfg->code_len);
11705
11706         mono_debug_close_method (cfg);
11707 }
11708
11709
11710
11711 static void
11712 remove_critical_edges (MonoCompile *cfg) {
11713         MonoBasicBlock *bb;
11714         MonoBasicBlock *previous_bb;
11715         
11716         if (cfg->verbose_level > 3) {
11717                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
11718                         MonoInst *last_ins;
11719                         int i;
11720                         printf ("remove_critical_edges %s, BEFORE BB%d (in:", mono_method_full_name (cfg->method, TRUE), bb->block_num);
11721                         for (i = 0; i < bb->in_count; i++) {
11722                                 printf (" %d", bb->in_bb [i]->block_num);
11723                         }
11724                         printf (") (out:");
11725                         for (i = 0; i < bb->out_count; i++) {
11726                                 printf (" %d", bb->out_bb [i]->block_num);
11727                         }
11728                         printf (")");
11729                         last_ins = mono_inst_list_last (&bb->ins_list);
11730                         if (last_ins) {
11731                                 printf (" ");
11732                                 mono_print_tree (last_ins);
11733                         }
11734                         printf ("\n");
11735                 }
11736         }
11737         
11738         for (previous_bb = cfg->bb_entry, bb = previous_bb->next_bb; bb != NULL; previous_bb = previous_bb->next_bb, bb = bb->next_bb) {
11739                 if (bb->in_count > 1) {
11740                         int in_bb_index;
11741                         for (in_bb_index = 0; in_bb_index < bb->in_count; in_bb_index++) {
11742                                 MonoBasicBlock *in_bb = bb->in_bb [in_bb_index];
11743                                 if (in_bb->out_count > 1) {
11744                                         MonoBasicBlock *new_bb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
11745                                         MONO_INST_LIST_INIT (&new_bb->ins_list);
11746                                         new_bb->block_num = cfg->num_bblocks++;
11747 //                                      new_bb->real_offset = bb->real_offset;
11748                                         new_bb->region = bb->region;
11749                                         
11750                                         /* Do not alter the CFG while altering the BB list */
11751                                         if (previous_bb->region == bb->region) {
11752                                                 if (previous_bb != cfg->bb_entry) {
11753                                                         MonoInst *last_ins;
11754                                                         /* If previous_bb "followed through" to bb, */
11755                                                         /* keep it linked with a OP_BR */
11756                                                         last_ins = mono_inst_list_last (&previous_bb->ins_list);
11757                                                         if ((last_ins == NULL) ||
11758                                                                         ((last_ins->opcode != OP_BR) &&
11759                                                                         (!(MONO_IS_COND_BRANCH_OP (last_ins))) &&
11760                                                                         (last_ins->opcode != OP_SWITCH))) {
11761                                                                 int i;
11762                                                                 /* Make sure previous_bb really falls through bb */
11763                                                                 for (i = 0; i < previous_bb->out_count; i++) {
11764                                                                         if (previous_bb->out_bb [i] == bb) {
11765                                                                                 MonoInst *jump;
11766                                                                                 MONO_INST_NEW (cfg, jump, OP_BR);
11767                                                                                 MONO_ADD_INS (previous_bb, jump);
11768                                                                                 jump->cil_code = previous_bb->cil_code;
11769                                                                                 jump->inst_target_bb = bb;
11770                                                                                 break;
11771                                                                         }
11772                                                                 }
11773                                                         }
11774                                                 } else {
11775                                                         /* We cannot add any inst to the entry BB, so we must */
11776                                                         /* put a new BB in the middle to hold the OP_BR */
11777                                                         MonoInst *jump;
11778                                                         MonoBasicBlock *new_bb_after_entry = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
11779                                                         MONO_INST_LIST_INIT (&new_bb_after_entry->ins_list);
11780                                                         new_bb_after_entry->block_num = cfg->num_bblocks++;
11781 //                                                      new_bb_after_entry->real_offset = bb->real_offset;
11782                                                         new_bb_after_entry->region = bb->region;
11783                                                         
11784                                                         MONO_INST_NEW (cfg, jump, OP_BR);
11785                                                         MONO_ADD_INS (new_bb_after_entry, jump);
11786                                                         jump->cil_code = bb->cil_code;
11787                                                         jump->inst_target_bb = bb;
11788                                                         
11789                                                         previous_bb->next_bb = new_bb_after_entry;
11790                                                         previous_bb = new_bb_after_entry;
11791                                                         
11792                                                         if (cfg->verbose_level > 2) {
11793                                                                 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);
11794                                                         }
11795                                                 }
11796                                         }
11797                                         
11798                                         /* Insert new_bb in the BB list */
11799                                         previous_bb->next_bb = new_bb;
11800                                         new_bb->next_bb = bb;
11801                                         previous_bb = new_bb;
11802                                         
11803                                         /* Setup in_bb and out_bb */
11804                                         new_bb->in_bb = mono_mempool_alloc ((cfg)->mempool, sizeof (MonoBasicBlock*));
11805                                         new_bb->in_bb [0] = in_bb;
11806                                         new_bb->in_count = 1;
11807                                         new_bb->out_bb = mono_mempool_alloc ((cfg)->mempool, sizeof (MonoBasicBlock*));
11808                                         new_bb->out_bb [0] = bb;
11809                                         new_bb->out_count = 1;
11810                                         
11811                                         /* Relink in_bb and bb to (from) new_bb */
11812                                         replace_out_block (in_bb, bb, new_bb);
11813                                         replace_out_block_in_code (in_bb, bb, new_bb);
11814                                         replace_in_block (bb, in_bb, new_bb);
11815                                         
11816                                         if (cfg->verbose_level > 2) {
11817                                                 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);
11818                                         }
11819                                 }
11820                         }
11821                 }
11822         }
11823         
11824         if (cfg->verbose_level > 3) {
11825                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
11826                         MonoInst *last_ins;
11827                         int i;
11828                         printf ("remove_critical_edges %s, AFTER BB%d (in:", mono_method_full_name (cfg->method, TRUE), bb->block_num);
11829                         for (i = 0; i < bb->in_count; i++) {
11830                                 printf (" %d", bb->in_bb [i]->block_num);
11831                         }
11832                         printf (") (out:");
11833                         for (i = 0; i < bb->out_count; i++) {
11834                                 printf (" %d", bb->out_bb [i]->block_num);
11835                         }
11836                         printf (")");
11837                         last_ins = mono_inst_list_last (&bb->ins_list);
11838                         if (last_ins) {
11839                                 printf (" ");
11840                                 mono_print_tree (last_ins);
11841                         }
11842                         printf ("\n");
11843                 }
11844         }
11845 }
11846
11847 /*
11848  * mini_method_compile:
11849  * @method: the method to compile
11850  * @opts: the optimization flags to use
11851  * @domain: the domain where the method will be compiled in
11852  * @run_cctors: whether we should run type ctors if possible
11853  * @compile_aot: whether this is an AOT compilation
11854  * @parts: debug flag
11855  *
11856  * Returns: a MonoCompile* pointer. Caller must check the exception_type
11857  * field in the returned struct to see if compilation succeded.
11858  */
11859 MonoCompile*
11860 mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gboolean run_cctors, gboolean compile_aot, int parts)
11861 {
11862         MonoMethodHeader *header;
11863         guint8 *ip;
11864         MonoCompile *cfg;
11865         MonoJitInfo *jinfo;
11866         int dfn = 0, i, code_size_ratio;
11867         gboolean deadce_has_run = FALSE;
11868         gboolean try_generic_shared;
11869         MonoMethod *method_to_compile;
11870         int generic_info_size;
11871
11872         mono_jit_stats.methods_compiled++;
11873         if (mono_profiler_get_events () & MONO_PROFILE_JIT_COMPILATION)
11874                 mono_profiler_method_jit (method);
11875         if (MONO_PROBE_METHOD_COMPILE_BEGIN_ENABLED ())
11876                 MONO_PROBE_METHOD_COMPILE_BEGIN (method);
11877  
11878         if (compile_aot)
11879                 /* We are passed the original generic method definition */
11880                 try_generic_shared = mono_class_generic_sharing_enabled (method->klass) &&
11881                         (opts & MONO_OPT_GSHARED) && (method->is_generic || method->klass->generic_container);
11882         else
11883                 try_generic_shared = mono_class_generic_sharing_enabled (method->klass) &&
11884                         (opts & MONO_OPT_GSHARED) && mono_method_is_generic_sharable_impl (method);
11885
11886         if (opts & MONO_OPT_GSHARED) {
11887                 if (try_generic_shared)
11888                         mono_stats.generics_sharable_methods++;
11889                 else if (mono_method_is_generic_impl (method))
11890                         mono_stats.generics_unsharable_methods++;
11891         }
11892
11893  restart_compile:
11894         if (try_generic_shared) {
11895                 MonoMethod *declaring_method;
11896                 MonoGenericContext *shared_context;
11897
11898                 if (compile_aot) {
11899                         declaring_method = method;
11900                 } else {
11901                         declaring_method = mono_method_get_declaring_generic_method (method);
11902                         g_assert (method->klass->generic_class->container_class == declaring_method->klass);
11903                 }
11904
11905                 if (declaring_method->is_generic)
11906                         shared_context = &(mono_method_get_generic_container (declaring_method)->context);
11907                 else
11908                         shared_context = &declaring_method->klass->generic_container->context;
11909
11910                 method_to_compile = mono_class_inflate_generic_method (declaring_method, shared_context);
11911                 g_assert (method_to_compile);
11912         } else {
11913                 method_to_compile = method;
11914         }
11915
11916         cfg = g_new0 (MonoCompile, 1);
11917         cfg->method = method_to_compile;
11918         cfg->mempool = mono_mempool_new ();
11919         cfg->opt = opts;
11920         cfg->prof_options = mono_profiler_get_events ();
11921         cfg->run_cctors = run_cctors;
11922         cfg->domain = domain;
11923         cfg->verbose_level = mini_verbose;
11924         cfg->compile_aot = compile_aot;
11925         cfg->skip_visibility = method->skip_visibility;
11926         if (try_generic_shared)
11927                 cfg->generic_sharing_context = (MonoGenericSharingContext*)&cfg->generic_sharing_context;
11928         cfg->token_info_hash = g_hash_table_new (NULL, NULL);
11929
11930         /* The debugger has no liveness information, so avoid sharing registers/stack slots */
11931         if (mono_debug_using_mono_debugger () || debug_options.mdb_optimizations) {
11932                 cfg->disable_reuse_registers = TRUE;
11933                 cfg->disable_reuse_stack_slots = TRUE;
11934                 /* 
11935                  * This decreases the change the debugger will read registers/stack slots which are
11936                  * not yet initialized.
11937                  */
11938                 cfg->disable_initlocals_opt = TRUE;
11939
11940                 /* Temporarily disable this when running in the debugger until we have support
11941                  * for this in the debugger. */
11942                 cfg->disable_omit_fp = TRUE;
11943
11944                 // cfg->opt |= MONO_OPT_SHARED;
11945                 cfg->opt &= ~MONO_OPT_INLINE;
11946                 cfg->opt &= ~MONO_OPT_COPYPROP;
11947                 cfg->opt &= ~MONO_OPT_CONSPROP;
11948         }
11949
11950         header = mono_method_get_header (method_to_compile);
11951         if (!header) {
11952                 cfg->exception_type = MONO_EXCEPTION_INVALID_PROGRAM;
11953                 cfg->exception_message = g_strdup_printf ("Missing or incorrect header for method %s", cfg->method->name);
11954                 if (MONO_PROBE_METHOD_COMPILE_END_ENABLED ())
11955                         MONO_PROBE_METHOD_COMPILE_END (method, FALSE);
11956                 if (cfg->prof_options & MONO_PROFILE_JIT_COMPILATION)
11957                         mono_profiler_method_end_jit (method, NULL, MONO_PROFILE_FAILED);
11958                 return cfg;
11959         }
11960
11961         ip = (guint8 *)header->code;
11962
11963         if (cfg->verbose_level > 2) {
11964                 if (cfg->generic_sharing_context)
11965                         g_print ("converting shared method %s\n", mono_method_full_name (method, TRUE));
11966                 else
11967                         g_print ("converting method %s\n", mono_method_full_name (method, TRUE));
11968         }
11969
11970         /*
11971          * create MonoInst* which represents arguments and local variables
11972          */
11973         mono_compile_create_vars (cfg);
11974
11975         if ((i = mono_method_to_ir (cfg, method_to_compile, NULL, NULL, cfg->locals_start, NULL, NULL, NULL, 0, FALSE)) < 0) {
11976                 if (try_generic_shared && cfg->exception_type == MONO_EXCEPTION_GENERIC_SHARING_FAILED) {
11977                         if (compile_aot) {
11978                                 if (MONO_PROBE_METHOD_COMPILE_END_ENABLED ())
11979                                         MONO_PROBE_METHOD_COMPILE_END (method, FALSE);
11980                                 return cfg;
11981                         }
11982                         mono_destroy_compile (cfg);
11983                         try_generic_shared = FALSE;
11984                         goto restart_compile;
11985                 }
11986                 g_assert (cfg->exception_type != MONO_EXCEPTION_GENERIC_SHARING_FAILED);
11987
11988                 if (MONO_PROBE_METHOD_COMPILE_END_ENABLED ())
11989                         MONO_PROBE_METHOD_COMPILE_END (method, FALSE);
11990                 if (cfg->prof_options & MONO_PROFILE_JIT_COMPILATION)
11991                         mono_profiler_method_end_jit (method, NULL, MONO_PROFILE_FAILED);
11992                 /* cfg contains the details of the failure, so let the caller cleanup */
11993                 return cfg;
11994         }
11995
11996         mono_jit_stats.basic_blocks += cfg->num_bblocks;
11997         mono_jit_stats.max_basic_blocks = MAX (cfg->num_bblocks, mono_jit_stats.max_basic_blocks);
11998
11999         if ((cfg->num_varinfo > 2000) && !cfg->compile_aot) {
12000                 /* 
12001                  * we disable some optimizations if there are too many variables
12002                  * because JIT time may become too expensive. The actual number needs 
12003                  * to be tweaked and eventually the non-linear algorithms should be fixed.
12004                  */
12005                 cfg->opt &= ~ (MONO_OPT_LINEARS | MONO_OPT_COPYPROP | MONO_OPT_CONSPROP);
12006                 cfg->disable_ssa = TRUE;
12007         }
12008
12009         /*g_print ("numblocks = %d\n", cfg->num_bblocks);*/
12010
12011         if (cfg->opt & MONO_OPT_BRANCH)
12012                 optimize_branches (cfg);
12013
12014         if (cfg->opt & MONO_OPT_SSAPRE) {
12015                 remove_critical_edges (cfg);
12016         }
12017
12018         /* Depth-first ordering on basic blocks */
12019         cfg->bblocks = mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * (cfg->num_bblocks + 1));
12020
12021         df_visit (cfg->bb_entry, &dfn, cfg->bblocks);
12022         if (cfg->num_bblocks != dfn + 1) {
12023                 MonoBasicBlock *bb;
12024
12025                 cfg->num_bblocks = dfn + 1;
12026
12027                 if (!header->clauses) {
12028                         /* remove unreachable code, because the code in them may be 
12029                          * inconsistent  (access to dead variables for example) */
12030                         for (bb = cfg->bb_entry; bb;) {
12031                                 MonoBasicBlock *bbn = bb->next_bb;
12032
12033                                 if (bbn && bbn->region == -1 && !bbn->dfn) {
12034                                         if (cfg->verbose_level > 1)
12035                                                 g_print ("found unreachable code in BB%d\n", bbn->block_num);
12036                                         bb->next_bb = bbn->next_bb;
12037                                         nullify_basic_block (bbn);                      
12038                                 } else {
12039                                         bb = bb->next_bb;
12040                                 }
12041                         }
12042                 }
12043         }
12044
12045         if (cfg->opt & MONO_OPT_LOOP) {
12046                 mono_compile_dominator_info (cfg, MONO_COMP_DOM | MONO_COMP_IDOM);
12047                 mono_compute_natural_loops (cfg);
12048         }
12049
12050         /* after method_to_ir */
12051         if (parts == 1) {
12052                 if (MONO_PROBE_METHOD_COMPILE_END_ENABLED ())
12053                         MONO_PROBE_METHOD_COMPILE_END (method, TRUE);
12054                 return cfg;
12055         }
12056
12057 //#define DEBUGSSA "logic_run"
12058 #define DEBUGSSA_CLASS "Tests"
12059 #ifdef DEBUGSSA
12060
12061         if (!header->num_clauses && !cfg->disable_ssa) {
12062                 mono_local_cprop (cfg);
12063 #ifndef DISABLE_SSA
12064                 mono_ssa_compute (cfg);
12065 #endif
12066         }
12067 #else 
12068
12069         /* fixme: add all optimizations which requires SSA */
12070         if (cfg->opt & (MONO_OPT_SSA | MONO_OPT_ABCREM | MONO_OPT_SSAPRE)) {
12071                 if (!(cfg->comp_done & MONO_COMP_SSA) && !header->num_clauses && !cfg->disable_ssa) {
12072                         mono_local_cprop (cfg);
12073 #ifndef DISABLE_SSA
12074                         mono_ssa_compute (cfg);
12075 #endif
12076
12077                         if (cfg->verbose_level >= 2) {
12078                                 print_dfn (cfg);
12079                         }
12080                 }
12081         }
12082 #endif
12083
12084         /* after SSA translation */
12085         if (parts == 2) {
12086                 if (MONO_PROBE_METHOD_COMPILE_END_ENABLED ())
12087                         MONO_PROBE_METHOD_COMPILE_END (method, TRUE);
12088                 return cfg;
12089         }
12090
12091         if ((cfg->opt & MONO_OPT_CONSPROP) || (cfg->opt & MONO_OPT_COPYPROP)) {
12092                 if (cfg->comp_done & MONO_COMP_SSA) {
12093 #ifndef DISABLE_SSA
12094                         mono_ssa_cprop (cfg);
12095 #endif
12096                 } else {
12097                         mono_local_cprop (cfg);
12098                 }
12099         }
12100
12101 #ifndef DISABLE_SSA
12102         if (cfg->comp_done & MONO_COMP_SSA) {                   
12103                 //mono_ssa_deadce (cfg);
12104
12105                 //mono_ssa_strength_reduction (cfg);
12106
12107                 if (cfg->opt & MONO_OPT_SSAPRE) {
12108                         mono_perform_ssapre (cfg);
12109                         //mono_local_cprop (cfg);
12110                 }
12111                 
12112                 if (cfg->opt & MONO_OPT_DEADCE) {
12113                         mono_ssa_deadce (cfg);
12114                         deadce_has_run = TRUE;
12115                 }
12116                 
12117                 if ((cfg->flags & MONO_CFG_HAS_LDELEMA) && (cfg->opt & MONO_OPT_ABCREM))
12118                         mono_perform_abc_removal (cfg);
12119                 
12120                 mono_ssa_remove (cfg);
12121
12122                 if (cfg->opt & MONO_OPT_BRANCH)
12123                         optimize_branches (cfg);
12124         }
12125 #endif
12126
12127         /* after SSA removal */
12128         if (parts == 3) {
12129                 if (MONO_PROBE_METHOD_COMPILE_END_ENABLED ())
12130                         MONO_PROBE_METHOD_COMPILE_END (method, TRUE);
12131                 return cfg;
12132         }
12133
12134         if (cfg->verbose_level > 4) {
12135                 printf ("BEFORE DECOMPSE START\n");
12136                 mono_print_code (cfg);
12137                 printf ("BEFORE DECOMPSE END\n");
12138         }
12139         
12140         decompose_pass (cfg);
12141
12142         if (cfg->got_var) {
12143                 GList *regs;
12144
12145                 g_assert (cfg->got_var_allocated);
12146
12147                 /* 
12148                  * Allways allocate the GOT var to a register, because keeping it
12149                  * in memory will increase the number of live temporaries in some
12150                  * code created by inssel.brg, leading to the well known spills+
12151                  * branches problem. Testcase: mcs crash in 
12152                  * System.MonoCustomAttrs:GetCustomAttributes.
12153                  */
12154                 regs = mono_arch_get_global_int_regs (cfg);
12155                 g_assert (regs);
12156                 cfg->got_var->opcode = OP_REGVAR;
12157                 cfg->got_var->dreg = GPOINTER_TO_INT (regs->data);
12158                 cfg->used_int_regs |= 1LL << cfg->got_var->dreg;
12159                 
12160                 g_list_free (regs);
12161         }
12162
12163         /* todo: remove code when we have verified that the liveness for try/catch blocks
12164          * works perfectly 
12165          */
12166         /* 
12167          * Currently, this can't be commented out since exception blocks are not
12168          * processed during liveness analysis.
12169          */
12170         mono_liveness_handle_exception_clauses (cfg);
12171
12172         if (cfg->opt & MONO_OPT_LINEARS) {
12173                 GList *vars, *regs;
12174                 
12175                 /* For now, compute aliasing info only if needed for deadce... */
12176                 if ((cfg->opt & MONO_OPT_DEADCE) && (! deadce_has_run) && (header->num_clauses == 0)) {
12177                         cfg->aliasing_info = mono_build_aliasing_information (cfg);
12178                 }
12179
12180                 /* fixme: maybe we can avoid to compute livenesss here if already computed ? */
12181                 cfg->comp_done &= ~MONO_COMP_LIVENESS;
12182                 if (!(cfg->comp_done & MONO_COMP_LIVENESS))
12183                         mono_analyze_liveness (cfg);
12184
12185                 if (cfg->aliasing_info != NULL) {
12186                         mono_aliasing_deadce (cfg->aliasing_info);
12187                         deadce_has_run = TRUE;
12188                 }
12189                 
12190                 if ((vars = mono_arch_get_allocatable_int_vars (cfg))) {
12191                         regs = mono_arch_get_global_int_regs (cfg);
12192                         if (cfg->got_var)
12193                                 regs = g_list_delete_link (regs, regs);
12194                         mono_linear_scan (cfg, vars, regs, &cfg->used_int_regs);
12195                 }
12196                 
12197                 if (cfg->aliasing_info != NULL) {
12198                         mono_destroy_aliasing_information (cfg->aliasing_info);
12199                         cfg->aliasing_info = NULL;
12200                 }
12201         }
12202
12203         //mono_print_code (cfg);
12204
12205     //print_dfn (cfg);
12206         
12207         /* variables are allocated after decompose, since decompose could create temps */
12208         mono_arch_allocate_vars (cfg);
12209
12210         if (cfg->opt & MONO_OPT_CFOLD)
12211                 mono_constant_fold (cfg);
12212
12213         mini_select_instructions (cfg);
12214
12215         mono_codegen (cfg);
12216         if (cfg->verbose_level >= 2) {
12217                 char *id =  mono_method_full_name (cfg->method, FALSE);
12218                 mono_disassemble_code (cfg, cfg->native_code, cfg->code_len, id + 3);
12219                 g_free (id);
12220         }
12221
12222         if (cfg->generic_sharing_context)
12223                 generic_info_size = sizeof (MonoGenericJitInfo);
12224         else
12225                 generic_info_size = 0;
12226
12227         if (cfg->method->dynamic) {
12228                 jinfo = g_malloc0 (sizeof (MonoJitInfo) + (header->num_clauses * sizeof (MonoJitExceptionInfo)) +
12229                                 generic_info_size);
12230         } else {
12231                 /* we access cfg->domain->mp */
12232                 mono_domain_lock (cfg->domain);
12233                 jinfo = mono_mempool_alloc0 (cfg->domain->mp, sizeof (MonoJitInfo) +
12234                                 (header->num_clauses * sizeof (MonoJitExceptionInfo)) +
12235                                 generic_info_size);
12236                 mono_domain_unlock (cfg->domain);
12237         }
12238
12239         jinfo->method = method;
12240         jinfo->code_start = cfg->native_code;
12241         jinfo->code_size = cfg->code_len;
12242         jinfo->used_regs = cfg->used_int_regs;
12243         jinfo->domain_neutral = (cfg->opt & MONO_OPT_SHARED) != 0;
12244         jinfo->cas_inited = FALSE; /* initialization delayed at the first stalk walk using this method */
12245         jinfo->num_clauses = header->num_clauses;
12246
12247         /*
12248          * Static methods only get a generic JIT info if they use the
12249          * rgctx variable (which they are forced to if they have any
12250          * open catch clauses).
12251          */
12252         if (cfg->generic_sharing_context &&
12253                         (cfg->rgctx_var || !(method_to_compile->flags & METHOD_ATTRIBUTE_STATIC))) {
12254                 MonoInst *inst;
12255                 MonoGenericJitInfo *gi;
12256
12257                 jinfo->has_generic_jit_info = 1;
12258
12259                 gi = mono_jit_info_get_generic_jit_info (jinfo);
12260                 g_assert (gi);
12261
12262                 gi->generic_sharing_context = cfg->generic_sharing_context;
12263
12264                 if (method_to_compile->flags & METHOD_ATTRIBUTE_STATIC) {
12265                         inst = cfg->rgctx_var;
12266                         g_assert (inst->opcode == OP_REGOFFSET);
12267                 } else {
12268                         inst = cfg->args [0];
12269                 }
12270
12271                 if (inst->opcode == OP_REGVAR) {
12272                         gi->this_in_reg = 1;
12273                         gi->this_reg = inst->dreg;
12274
12275                         //g_print ("this in reg %d\n", inst->dreg);
12276                 } else {
12277                         g_assert (inst->opcode == OP_REGOFFSET);
12278 #ifdef __i386__
12279                         g_assert (inst->inst_basereg == X86_EBP);
12280 #elif defined(__x86_64__)
12281                         g_assert (inst->inst_basereg == X86_EBP || inst->inst_basereg == X86_ESP);
12282 #endif
12283                         g_assert (inst->inst_offset >= G_MININT32 && inst->inst_offset <= G_MAXINT32);
12284
12285                         gi->this_in_reg = 0;
12286                         gi->this_reg = inst->inst_basereg;
12287                         gi->this_offset = inst->inst_offset;
12288
12289                         //g_print ("this at offset %d\n", inst->inst_offset);
12290                 }
12291         }
12292
12293         if (header->num_clauses) {
12294                 int i;
12295
12296                 for (i = 0; i < header->num_clauses; i++) {
12297                         MonoExceptionClause *ec = &header->clauses [i];
12298                         MonoJitExceptionInfo *ei = &jinfo->clauses [i];
12299                         MonoBasicBlock *tblock;
12300                         MonoInst *exvar;
12301
12302                         ei->flags = ec->flags;
12303
12304                         exvar = mono_find_exvar_for_offset (cfg, ec->handler_offset);
12305                         ei->exvar_offset = exvar ? exvar->inst_offset : 0;
12306
12307                         if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
12308                                 tblock = cfg->cil_offset_to_bb [ec->data.filter_offset];
12309                                 g_assert (tblock);
12310                                 ei->data.filter = cfg->native_code + tblock->native_offset;
12311                         } else {
12312                                 ei->data.catch_class = ec->data.catch_class;
12313                         }
12314
12315                         tblock = cfg->cil_offset_to_bb [ec->try_offset];
12316                         g_assert (tblock);
12317                         ei->try_start = cfg->native_code + tblock->native_offset;
12318                         g_assert (tblock->native_offset);
12319                         tblock = cfg->cil_offset_to_bb [ec->try_offset + ec->try_len];
12320                         g_assert (tblock);
12321                         ei->try_end = cfg->native_code + tblock->native_offset;
12322                         g_assert (tblock->native_offset);
12323                         tblock = cfg->cil_offset_to_bb [ec->handler_offset];
12324                         g_assert (tblock);
12325                         ei->handler_start = cfg->native_code + tblock->native_offset;
12326                 }
12327         }
12328
12329         cfg->jit_info = jinfo;
12330 #if defined(__arm__)
12331         mono_arch_fixup_jinfo (cfg);
12332 #endif
12333
12334         mono_domain_lock (cfg->domain);
12335         mono_jit_info_table_add (cfg->domain, jinfo);
12336
12337         if (cfg->method->dynamic)
12338                 mono_dynamic_code_hash_lookup (cfg->domain, cfg->method)->ji = jinfo;
12339         mono_domain_unlock (cfg->domain);
12340
12341         /* collect statistics */
12342         mono_jit_stats.allocated_code_size += cfg->code_len;
12343         code_size_ratio = cfg->code_len;
12344         if (code_size_ratio > mono_jit_stats.biggest_method_size) {
12345                         mono_jit_stats.biggest_method_size = code_size_ratio;
12346                         mono_jit_stats.biggest_method = method;
12347         }
12348         code_size_ratio = (code_size_ratio * 100) / mono_method_get_header (method)->code_size;
12349         if (code_size_ratio > mono_jit_stats.max_code_size_ratio) {
12350                 mono_jit_stats.max_code_size_ratio = code_size_ratio;
12351                 mono_jit_stats.max_ratio_method = method;
12352         }
12353         mono_jit_stats.native_code_size += cfg->code_len;
12354
12355         if (MONO_PROBE_METHOD_COMPILE_END_ENABLED ())
12356                 MONO_PROBE_METHOD_COMPILE_END (method, TRUE);
12357         if (cfg->prof_options & MONO_PROFILE_JIT_COMPILATION)
12358                 mono_profiler_method_end_jit (method, jinfo, MONO_PROFILE_OK);
12359
12360         return cfg;
12361 }
12362
12363 static MonoJitInfo*
12364 lookup_generic_method (MonoDomain *domain, MonoMethod *method)
12365 {
12366         MonoMethod *open_method;
12367
12368         if (!mono_method_is_generic_sharable_impl (method))
12369                 return NULL;
12370
12371         open_method = mono_method_get_declaring_generic_method (method);
12372
12373         return mono_domain_lookup_shared_generic (domain, open_method);
12374 }
12375
12376 static MonoJitInfo*
12377 lookup_method (MonoDomain *domain, MonoMethod *method)
12378 {
12379         MonoJitInfo *ji = mono_internal_hash_table_lookup (&domain->jit_code_hash, method);
12380
12381         if (ji != NULL)
12382                 return ji;
12383
12384         return lookup_generic_method (domain, method);
12385 }
12386
12387 static gpointer
12388 mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, int opt)
12389 {
12390         MonoCompile *cfg;
12391         gpointer code = NULL;
12392         MonoJitInfo *info;
12393         MonoVTable *vtable;
12394
12395 #ifdef MONO_USE_AOT_COMPILER
12396         if ((opt & MONO_OPT_AOT) && !(mono_profiler_get_events () & MONO_PROFILE_JIT_COMPILATION)) {
12397                 MonoDomain *domain = mono_domain_get ();
12398
12399                 mono_class_init (method->klass);
12400
12401                 mono_domain_lock (domain);
12402                 if ((code = mono_aot_get_method (domain, method))) {
12403                         mono_domain_unlock (domain);
12404                         vtable = mono_class_vtable (domain, method->klass);
12405                         g_assert (vtable);
12406                         mono_runtime_class_init (vtable);
12407                         return code;
12408                 }
12409
12410                 mono_domain_unlock (domain);
12411         }
12412 #endif
12413
12414         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
12415             (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
12416                 MonoMethod *nm;
12417                 MonoMethodPInvoke* piinfo = (MonoMethodPInvoke *) method;
12418
12419                 if (!piinfo->addr) {
12420                         if (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL)
12421                                 piinfo->addr = mono_lookup_internal_call (method);
12422                         else if (method->iflags & METHOD_IMPL_ATTRIBUTE_NATIVE)
12423 #ifdef PLATFORM_WIN32
12424                                 g_warning ("Method '%s' in assembly '%s' contains native code that cannot be executed by Mono in modules loaded from byte arrays. The assembly was probably created using C++/CLI.\n", mono_method_full_name (method, TRUE), method->klass->image->name);
12425 #else
12426                                 g_warning ("Method '%s' in assembly '%s' contains native code that cannot be executed by Mono on this platform. The assembly was probably created using C++/CLI.\n", mono_method_full_name (method, TRUE), method->klass->image->name);
12427 #endif
12428                         else
12429                                 mono_lookup_pinvoke_call (method, NULL, NULL);
12430                 }
12431                         nm = mono_marshal_get_native_wrapper (method, check_for_pending_exc);
12432                         return mono_get_addr_from_ftnptr (mono_compile_method (nm));
12433
12434                         //if (mono_debug_format != MONO_DEBUG_FORMAT_NONE) 
12435                         //mono_debug_add_wrapper (method, nm);
12436         } else if ((method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME)) {
12437                 const char *name = method->name;
12438                 MonoMethod *nm;
12439
12440                 if (method->klass->parent == mono_defaults.multicastdelegate_class) {
12441                         if (*name == '.' && (strcmp (name, ".ctor") == 0)) {
12442                                 MonoJitICallInfo *mi = mono_find_jit_icall_by_name ("mono_delegate_ctor");
12443                                 g_assert (mi);
12444                                 return mono_get_addr_from_ftnptr ((gpointer)mono_icall_get_wrapper (mi));
12445                         } else if (*name == 'I' && (strcmp (name, "Invoke") == 0)) {
12446 #ifdef MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE
12447                                 return mono_create_delegate_trampoline (method->klass);
12448 #else
12449                                 nm = mono_marshal_get_delegate_invoke (method, NULL);
12450                                 return mono_get_addr_from_ftnptr (mono_compile_method (nm));
12451 #endif
12452                         } else if (*name == 'B' && (strcmp (name, "BeginInvoke") == 0)) {
12453                                 nm = mono_marshal_get_delegate_begin_invoke (method);
12454                                 return mono_get_addr_from_ftnptr (mono_compile_method (nm));
12455                         } else if (*name == 'E' && (strcmp (name, "EndInvoke") == 0)) {
12456                                 nm = mono_marshal_get_delegate_end_invoke (method);
12457                                 return mono_get_addr_from_ftnptr (mono_compile_method (nm));
12458                         }
12459                 }
12460                 return NULL;
12461         }
12462
12463         cfg = mini_method_compile (method, opt, target_domain, TRUE, FALSE, 0);
12464
12465         switch (cfg->exception_type) {
12466         case MONO_EXCEPTION_NONE: break;
12467         case MONO_EXCEPTION_TYPE_LOAD:
12468         case MONO_EXCEPTION_MISSING_FIELD:
12469         case MONO_EXCEPTION_MISSING_METHOD:
12470         case MONO_EXCEPTION_FILE_NOT_FOUND: {
12471                 /* Throw a type load exception if needed */
12472                 MonoLoaderError *error = mono_loader_get_last_error ();
12473                 MonoException *ex;
12474
12475                 if (error) {
12476                         ex = mono_loader_error_prepare_exception (error);
12477                 } else {
12478                         if (cfg->exception_ptr) {
12479                                 ex = mono_class_get_exception_for_failure (cfg->exception_ptr);
12480                         } else {
12481                                 if (cfg->exception_type == MONO_EXCEPTION_MISSING_FIELD)
12482                                         ex = mono_exception_from_name_msg (mono_defaults.corlib, "System", "MissingFieldException", cfg->exception_message);
12483                                 else if (cfg->exception_type == MONO_EXCEPTION_MISSING_METHOD)
12484                                         ex = mono_exception_from_name_msg (mono_defaults.corlib, "System", "MissingMethodException", cfg->exception_message);
12485                                 else if (cfg->exception_type == MONO_EXCEPTION_TYPE_LOAD)
12486                                         ex = mono_exception_from_name_msg (mono_defaults.corlib, "System", "TypeLoadException", cfg->exception_message);
12487                                 else if (cfg->exception_type == MONO_EXCEPTION_FILE_NOT_FOUND)
12488                                         ex = mono_exception_from_name_msg (mono_defaults.corlib, "System", "FileNotFoundException", cfg->exception_message);
12489                                 else
12490                                         g_assert_not_reached ();
12491                         }
12492                 }
12493                 mono_destroy_compile (cfg);
12494                 mono_raise_exception (ex);
12495                 break;
12496         }
12497         case MONO_EXCEPTION_INVALID_PROGRAM: {
12498                 MonoException *ex = mono_exception_from_name_msg (mono_defaults.corlib, "System", "InvalidProgramException", cfg->exception_message);
12499                 mono_destroy_compile (cfg);
12500                 mono_raise_exception (ex);
12501                 break;
12502         }
12503         case MONO_EXCEPTION_UNVERIFIABLE_IL: {
12504                 MonoException *ex = mono_exception_from_name_msg (mono_defaults.corlib, "System.Security", "VerificationException", cfg->exception_message);
12505                 mono_destroy_compile (cfg);
12506                 mono_raise_exception (ex);
12507                 break;
12508         }
12509         case MONO_EXCEPTION_METHOD_ACCESS: {
12510                 MonoException *ex = mono_exception_from_name_msg (mono_defaults.corlib, "System", "MethodAccessException", cfg->exception_message);
12511                 mono_destroy_compile (cfg);
12512                 mono_raise_exception (ex);
12513                 break;
12514         }
12515         case MONO_EXCEPTION_FIELD_ACCESS: {
12516                 MonoException *ex = mono_exception_from_name_msg (mono_defaults.corlib, "System", "FieldAccessException", cfg->exception_message);
12517                 mono_destroy_compile (cfg);
12518                 mono_raise_exception (ex);
12519                 break;
12520         }
12521         /* this can only be set if the security manager is active */
12522         case MONO_EXCEPTION_SECURITY_LINKDEMAND: {
12523                 MonoSecurityManager* secman = mono_security_manager_get_methods ();
12524                 MonoObject *exc = NULL;
12525                 gpointer args [2];
12526
12527                 args [0] = &cfg->exception_data;
12528                 args [1] = &method;
12529                 mono_runtime_invoke (secman->linkdemandsecurityexception, NULL, args, &exc);
12530
12531                 mono_destroy_compile (cfg);
12532                 cfg = NULL;
12533
12534                 mono_raise_exception ((MonoException*)exc);
12535         }
12536         default:
12537                 g_assert_not_reached ();
12538         }
12539
12540         mono_domain_lock (target_domain);
12541
12542         /* Check if some other thread already did the job. In this case, we can
12543        discard the code this thread generated. */
12544
12545         if ((info = lookup_method (target_domain, method))) {
12546                 /* We can't use a domain specific method in another domain */
12547                 if ((target_domain == mono_domain_get ()) || info->domain_neutral) {
12548                         code = info->code_start;
12549 //                      printf("Discarding code for method %s\n", method->name);
12550                 }
12551         }
12552         
12553         if (code == NULL) {
12554                 mono_internal_hash_table_insert (&target_domain->jit_code_hash, method, cfg->jit_info);
12555                 code = cfg->native_code;
12556
12557                 if (cfg->generic_sharing_context && mono_method_is_generic_sharable_impl (method)) {
12558                         /* g_print ("inserting method %s.%s.%s\n", method->klass->name_space, method->klass->name, method->name); */
12559                         mono_domain_register_shared_generic (target_domain, 
12560                                 mono_method_get_declaring_generic_method (method), cfg->jit_info);
12561                         mono_stats.generics_shared_methods++;
12562                 }
12563         }
12564
12565         mono_destroy_compile (cfg);
12566
12567         if (target_domain->jump_target_hash) {
12568                 MonoJumpInfo patch_info;
12569                 GSList *list, *tmp;
12570                 list = g_hash_table_lookup (target_domain->jump_target_hash, method);
12571                 if (list) {
12572                         patch_info.next = NULL;
12573                         patch_info.ip.i = 0;
12574                         patch_info.type = MONO_PATCH_INFO_METHOD_JUMP;
12575                         patch_info.data.method = method;
12576                         g_hash_table_remove (target_domain->jump_target_hash, method);
12577                 }
12578                 for (tmp = list; tmp; tmp = tmp->next)
12579                         mono_arch_patch_code (NULL, target_domain, tmp->data, &patch_info, TRUE);
12580                 g_slist_free (list);
12581         }
12582
12583         mono_domain_unlock (target_domain);
12584
12585         vtable = mono_class_vtable (target_domain, method->klass);
12586         if (!vtable) {
12587                 MonoException *exc;
12588                 exc = mono_class_get_exception_for_failure (method->klass);
12589                 g_assert (exc);
12590                 mono_raise_exception (exc);
12591         }
12592         mono_runtime_class_init (vtable);
12593         return code;
12594 }
12595
12596 static gpointer
12597 mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt)
12598 {
12599         MonoDomain *target_domain, *domain = mono_domain_get ();
12600         MonoJitInfo *info;
12601         gpointer p;
12602         MonoJitICallInfo *callinfo = NULL;
12603
12604         /*
12605          * ICALL wrappers are handled specially, since there is only one copy of them
12606          * shared by all appdomains.
12607          */
12608         if ((method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) && (strstr (method->name, "__icall_wrapper_") == method->name)) {
12609                 const char *icall_name;
12610
12611                 icall_name = method->name + strlen ("__icall_wrapper_");
12612                 g_assert (icall_name);
12613                 callinfo = mono_find_jit_icall_by_name (icall_name);
12614                 g_assert (callinfo);
12615
12616                 /* Must be domain neutral since there is only one copy */
12617                 opt |= MONO_OPT_SHARED;
12618         }
12619
12620         if (opt & MONO_OPT_SHARED)
12621                 target_domain = mono_get_root_domain ();
12622         else 
12623                 target_domain = domain;
12624
12625         mono_domain_lock (target_domain);
12626
12627         if ((info = lookup_method (target_domain, method))) {
12628                 /* We can't use a domain specific method in another domain */
12629                 if (! ((domain != target_domain) && !info->domain_neutral)) {
12630                         MonoVTable *vtable;
12631
12632                         mono_domain_unlock (target_domain);
12633                         mono_jit_stats.methods_lookups++;
12634                         vtable = mono_class_vtable (domain, method->klass);
12635                         mono_runtime_class_init (vtable);
12636                         return mono_create_ftnptr (target_domain, info->code_start);
12637                 }
12638         }
12639
12640         mono_domain_unlock (target_domain);
12641         p = mono_create_ftnptr (target_domain, mono_jit_compile_method_inner (method, target_domain, opt));
12642
12643         if (callinfo) {
12644                 mono_jit_lock ();
12645                 if (!callinfo->wrapper) {
12646                         callinfo->wrapper = p;
12647                         mono_register_jit_icall_wrapper (callinfo, p);
12648                         mono_debug_add_icall_wrapper (method, callinfo);
12649                 }
12650                 mono_jit_unlock ();
12651         }
12652
12653         return p;
12654 }
12655
12656 static gpointer
12657 mono_jit_compile_method (MonoMethod *method)
12658 {
12659         return mono_jit_compile_method_with_opt (method, default_opt);
12660 }
12661
12662 static void
12663 invalidated_delegate_trampoline (char *desc)
12664 {
12665         g_error ("Unmanaged code called delegate of type %s which was already garbage collected.\n"
12666                  "See http://www.go-mono.com/delegate.html for an explanation and ways to fix this.",
12667                  desc);
12668 }
12669
12670 /*
12671  * mono_jit_free_method:
12672  *
12673  *  Free all memory allocated by the JIT for METHOD.
12674  */
12675 static void
12676 mono_jit_free_method (MonoDomain *domain, MonoMethod *method)
12677 {
12678         MonoJitDynamicMethodInfo *ji;
12679         gboolean destroy = TRUE;
12680
12681         g_assert (method->dynamic);
12682
12683         mono_domain_lock (domain);
12684         ji = mono_dynamic_code_hash_lookup (domain, method);
12685         mono_domain_unlock (domain);
12686
12687         if (!ji)
12688                 return;
12689         mono_domain_lock (domain);
12690         g_hash_table_remove (domain->dynamic_code_hash, method);
12691         mono_internal_hash_table_remove (&domain->jit_code_hash, method);
12692         g_hash_table_remove (domain->jump_trampoline_hash, method);
12693         mono_domain_unlock (domain);
12694
12695 #ifdef MONO_ARCH_HAVE_INVALIDATE_METHOD
12696         if (debug_options.keep_delegates && method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
12697                 /*
12698                  * Instead of freeing the code, change it to call an error routine
12699                  * so people can fix their code.
12700                  */
12701                 char *type = mono_type_full_name (&method->klass->byval_arg);
12702                 char *type_and_method = g_strdup_printf ("%s.%s", type, method->name);
12703
12704                 g_free (type);
12705                 mono_arch_invalidate_method (ji->ji, invalidated_delegate_trampoline, type_and_method);
12706                 destroy = FALSE;
12707         }
12708 #endif
12709
12710         /* 
12711          * This needs to be done before freeing code_mp, since the code address is the
12712          * key in the table, so if we free the code_mp first, another thread can grab the
12713          * same code address and replace our entry in the table.
12714          */
12715         mono_jit_info_table_remove (domain, ji->ji);
12716
12717         if (destroy)
12718                 mono_code_manager_destroy (ji->code_mp);
12719         g_free (ji);
12720 }
12721
12722 gpointer
12723 mono_jit_find_compiled_method (MonoDomain *domain, MonoMethod *method)
12724 {
12725         MonoDomain *target_domain;
12726         MonoJitInfo *info;
12727
12728         if (default_opt & MONO_OPT_SHARED)
12729                 target_domain = mono_get_root_domain ();
12730         else 
12731                 target_domain = domain;
12732
12733         mono_domain_lock (target_domain);
12734
12735         if ((info = lookup_method (target_domain, method))) {
12736                 /* We can't use a domain specific method in another domain */
12737                 if (! ((domain != target_domain) && !info->domain_neutral)) {
12738                         mono_domain_unlock (target_domain);
12739                         mono_jit_stats.methods_lookups++;
12740                         return info->code_start;
12741                 }
12742         }
12743
12744         mono_domain_unlock (target_domain);
12745
12746         return NULL;
12747 }
12748
12749 /**
12750  * mono_jit_runtime_invoke:
12751  * @method: the method to invoke
12752  * @obj: this pointer
12753  * @params: array of parameter values.
12754  * @exc: used to catch exceptions objects
12755  */
12756 static MonoObject*
12757 mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
12758 {
12759         MonoMethod *to_compile;
12760         MonoMethod *invoke;
12761         MonoObject *(*runtime_invoke) (MonoObject *this, void **params, MonoObject **exc, void* compiled_method);
12762         void* compiled_method;
12763         MonoVTable *vtable;
12764
12765         if (obj == NULL && !(method->flags & METHOD_ATTRIBUTE_STATIC) && !method->string_ctor && (method->wrapper_type == 0)) {
12766                 g_warning ("Ignoring invocation of an instance method on a NULL instance.\n");
12767                 return NULL;
12768         }
12769
12770         if ((method->flags & METHOD_ATTRIBUTE_STATIC) &&
12771                         mono_class_generic_sharing_enabled (method->klass) &&
12772                         mono_method_is_generic_sharable_impl (method)) {
12773                 to_compile = mono_marshal_get_static_rgctx_invoke (method);
12774         } else {
12775                 to_compile = method;
12776         }
12777
12778         invoke = mono_marshal_get_runtime_invoke (method);
12779         runtime_invoke = mono_jit_compile_method (invoke);
12780         
12781         /* We need this here becuase mono_marshal_get_runtime_invoke can be place 
12782          * the helper method in System.Object and not the target class
12783          */
12784         vtable = mono_class_vtable (mono_domain_get (), method->klass);
12785         g_assert (vtable);
12786         mono_runtime_class_init (vtable);
12787
12788         if (method->klass->rank && (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) &&
12789                 (method->iflags & METHOD_IMPL_ATTRIBUTE_NATIVE)) {
12790                 /* 
12791                  * Array Get/Set/Address methods. The JIT implements them using inline code 
12792                  * inside the runtime invoke wrappers, so no need to compile them.
12793                  */
12794                 compiled_method = NULL;
12795         } else {
12796                 compiled_method = mono_jit_compile_method (to_compile);
12797         }
12798         return runtime_invoke (obj, params, exc, compiled_method);
12799 }
12800
12801 #ifdef MONO_GET_CONTEXT
12802 #define GET_CONTEXT MONO_GET_CONTEXT
12803 #endif
12804
12805 #ifndef GET_CONTEXT
12806 #ifdef PLATFORM_WIN32
12807 #define GET_CONTEXT \
12808         struct sigcontext *ctx = (struct sigcontext*)_dummy;
12809 #else
12810 #ifdef MONO_ARCH_USE_SIGACTION
12811 #define GET_CONTEXT \
12812     void *ctx = context;
12813 #elif defined(__sparc__)
12814 #define GET_CONTEXT \
12815     void *ctx = sigctx;
12816 #else
12817 #define GET_CONTEXT \
12818         void **_p = (void **)&_dummy; \
12819         struct sigcontext *ctx = (struct sigcontext *)++_p;
12820 #endif
12821 #endif
12822 #endif
12823
12824 #ifdef MONO_ARCH_USE_SIGACTION
12825 #define SIG_HANDLER_SIGNATURE(ftn) ftn (int _dummy, siginfo_t *info, void *context)
12826 #elif defined(__sparc__)
12827 #define SIG_HANDLER_SIGNATURE(ftn) ftn (int _dummy, void *sigctx)
12828 #else
12829 #define SIG_HANDLER_SIGNATURE(ftn) ftn (int _dummy)
12830 #endif
12831
12832 static void
12833 SIG_HANDLER_SIGNATURE (sigfpe_signal_handler)
12834 {
12835         MonoException *exc = NULL;
12836 #ifndef MONO_ARCH_USE_SIGACTION
12837         void *info = NULL;
12838 #endif
12839         GET_CONTEXT;
12840
12841 #if defined(MONO_ARCH_HAVE_IS_INT_OVERFLOW)
12842         if (mono_arch_is_int_overflow (ctx, info))
12843                 exc = mono_get_exception_arithmetic ();
12844         else
12845                 exc = mono_get_exception_divide_by_zero ();
12846 #else
12847         exc = mono_get_exception_divide_by_zero ();
12848 #endif
12849         
12850         mono_arch_handle_exception (ctx, exc, FALSE);
12851 }
12852
12853 static void
12854 SIG_HANDLER_SIGNATURE (sigill_signal_handler)
12855 {
12856         MonoException *exc;
12857         GET_CONTEXT;
12858
12859         exc = mono_get_exception_execution_engine ("SIGILL");
12860         
12861         mono_arch_handle_exception (ctx, exc, FALSE);
12862 }
12863
12864 static void
12865 SIG_HANDLER_SIGNATURE (sigsegv_signal_handler)
12866 {
12867 #ifndef MONO_ARCH_SIGSEGV_ON_ALTSTACK
12868         MonoException *exc = NULL;
12869 #endif
12870         MonoJitInfo *ji;
12871
12872 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
12873         MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
12874 #endif
12875         GET_CONTEXT;
12876
12877 #ifdef MONO_ARCH_USE_SIGACTION
12878         if (debug_options.collect_pagefault_stats) {
12879                 if (mono_raw_buffer_is_pagefault (info->si_addr)) {
12880                         mono_raw_buffer_handle_pagefault (info->si_addr);
12881                         return;
12882                 }
12883                 if (mono_aot_is_pagefault (info->si_addr)) {
12884                         mono_aot_handle_pagefault (info->si_addr);
12885                         return;
12886                 }
12887         }
12888 #endif
12889
12890         ji = mono_jit_info_table_find (mono_domain_get (), mono_arch_ip_from_context (ctx));
12891
12892 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
12893         /* we got a stack overflow in the soft-guard pages
12894          * There are two cases:
12895          * 1) managed code caused the overflow: we unprotect the soft-guard page
12896          * and let the arch-specific code trigger the exception handling mechanism
12897          * in the thread stack. The soft-guard pages will be protected again as the stack is unwound.
12898          * 2) unmanaged code caused the overflow: we unprotect the soft-guard page
12899          * and hope we can continue with those enabled, at least until the hard-guard page
12900          * is hit. The alternative to continuing here is to just print a message and abort.
12901          * We may add in the future the code to protect the pages again in the codepath
12902          * when we return from unmanaged to managed code.
12903          */
12904         if (jit_tls->stack_ovf_guard_size && (guint8*)info->si_addr >= (guint8*)jit_tls->stack_ovf_guard_base &&
12905                         (guint8*)info->si_addr < (guint8*)jit_tls->stack_ovf_guard_base + jit_tls->stack_ovf_guard_size) {
12906                 mono_mprotect (jit_tls->stack_ovf_guard_base, jit_tls->stack_ovf_guard_size, MONO_MMAP_READ|MONO_MMAP_WRITE|MONO_MMAP_EXEC);
12907                 if (ji) {
12908                         mono_arch_handle_altstack_exception (ctx, info->si_addr, TRUE);
12909                 } else {
12910                         /* We print a message: after this even managed stack overflows
12911                          * may crash the runtime
12912                          */
12913                         fprintf (stderr, "Stack overflow in unmanaged: IP: %p, fault addr: %p\n", mono_arch_ip_from_context (ctx), (gpointer)info->si_addr);
12914                 }
12915                 return;
12916         }
12917         /* The hard-guard page has been hit: there is not much we can do anymore
12918          * Print a hopefully clear message and abort.
12919          */
12920         if (jit_tls->stack_size && 
12921                         ABS ((guint8*)info->si_addr - ((guint8*)jit_tls->end_of_stack - jit_tls->stack_size)) < 32768) {
12922                 const char *method;
12923                 /* we don't do much now, but we can warn the user with a useful message */
12924                 fprintf (stderr, "Stack overflow: IP: %p, fault addr: %p\n", mono_arch_ip_from_context (ctx), (gpointer)info->si_addr);
12925                 if (ji && ji->method)
12926                         method = mono_method_full_name (ji->method, TRUE);
12927                 else
12928                         method = "Unmanaged";
12929                 fprintf (stderr, "At %s\n", method);
12930                 abort ();
12931         } else {
12932                 mono_arch_handle_altstack_exception (ctx, info->si_addr, FALSE);
12933         }
12934 #else
12935
12936         if (!ji) {
12937                 mono_handle_native_sigsegv (SIGSEGV, ctx);
12938         }
12939                         
12940         mono_arch_handle_exception (ctx, exc, FALSE);
12941 #endif
12942 }
12943
12944 #ifndef PLATFORM_WIN32
12945
12946 static void
12947 SIG_HANDLER_SIGNATURE (sigabrt_signal_handler)
12948 {
12949         MonoJitInfo *ji;
12950         GET_CONTEXT;
12951
12952         ji = mono_jit_info_table_find (mono_domain_get (), mono_arch_ip_from_context(ctx));
12953         if (!ji) {
12954                 mono_handle_native_sigsegv (SIGABRT, ctx);
12955         }
12956 }
12957
12958 static void
12959 SIG_HANDLER_SIGNATURE (sigusr1_signal_handler)
12960 {
12961         gboolean running_managed;
12962         MonoException *exc;
12963         MonoThread *thread = mono_thread_current ();
12964         void *ji;
12965         
12966         GET_CONTEXT;
12967
12968         if (thread->thread_dump_requested) {
12969                 thread->thread_dump_requested = FALSE;
12970
12971                 mono_print_thread_dump (ctx);
12972         }
12973
12974         /*
12975          * FIXME:
12976          * This is an async signal, so the code below must not call anything which
12977          * is not async safe. That includes the pthread locking functions. If we
12978          * know that we interrupted managed code, then locking is safe.
12979          */
12980         ji = mono_jit_info_table_find (mono_domain_get (), mono_arch_ip_from_context(ctx));
12981         running_managed = ji != NULL;
12982         
12983         exc = mono_thread_request_interruption (running_managed); 
12984         if (!exc) return;
12985
12986         mono_arch_handle_exception (ctx, exc, FALSE);
12987 }
12988
12989 #if defined(__i386__) || defined(__x86_64__)
12990 #define FULL_STAT_PROFILER_BACKTRACE 1
12991 #define CURRENT_FRAME_GET_BASE_POINTER(f) (* (gpointer*)(f))
12992 #define CURRENT_FRAME_GET_RETURN_ADDRESS(f) (* (((gpointer*)(f)) + 1))
12993 #if MONO_ARCH_STACK_GROWS_UP
12994 #define IS_BEFORE_ON_STACK <
12995 #define IS_AFTER_ON_STACK >
12996 #else
12997 #define IS_BEFORE_ON_STACK >
12998 #define IS_AFTER_ON_STACK <
12999 #endif
13000 #else
13001 #define FULL_STAT_PROFILER_BACKTRACE 0
13002 #endif
13003
13004 #if defined(__ia64__) || defined(__sparc__) || defined(sparc) || defined(__s390__) || defined(s390)
13005
13006 static void
13007 SIG_HANDLER_SIGNATURE (sigprof_signal_handler)
13008 {
13009         NOT_IMPLEMENTED;
13010 }
13011
13012 #else
13013
13014 static void
13015 SIG_HANDLER_SIGNATURE (sigprof_signal_handler)
13016 {
13017         int call_chain_depth = mono_profiler_stat_get_call_chain_depth ();
13018         GET_CONTEXT;
13019         
13020         if (call_chain_depth == 0) {
13021                 mono_profiler_stat_hit (mono_arch_ip_from_context (ctx), ctx);
13022         } else {
13023                 MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
13024                 int current_frame_index = 1;
13025                 MonoContext mono_context;
13026 #if FULL_STAT_PROFILER_BACKTRACE
13027                 guchar *current_frame;
13028                 guchar *stack_bottom;
13029                 guchar *stack_top;
13030 #else
13031                 MonoDomain *domain;
13032 #endif
13033                 guchar *ips [call_chain_depth + 1];
13034
13035                 mono_arch_sigctx_to_monoctx (ctx, &mono_context);
13036                 ips [0] = MONO_CONTEXT_GET_IP (&mono_context);
13037                 
13038                 if (jit_tls != NULL) {
13039 #if FULL_STAT_PROFILER_BACKTRACE
13040                         stack_bottom = jit_tls->end_of_stack;
13041                         stack_top = MONO_CONTEXT_GET_SP (&mono_context);
13042                         current_frame = MONO_CONTEXT_GET_BP (&mono_context);
13043                         
13044                         while ((current_frame_index <= call_chain_depth) &&
13045                                         (stack_bottom IS_BEFORE_ON_STACK (guchar*) current_frame) &&
13046                                         ((guchar*) current_frame IS_BEFORE_ON_STACK stack_top)) {
13047                                 ips [current_frame_index] = CURRENT_FRAME_GET_RETURN_ADDRESS (current_frame);
13048                                 current_frame_index ++;
13049                                 stack_top = current_frame;
13050                                 current_frame = CURRENT_FRAME_GET_BASE_POINTER (current_frame);
13051                         }
13052 #else
13053                         domain = mono_domain_get ();
13054                         if (domain != NULL) {
13055                                 MonoLMF *lmf = NULL;
13056                                 MonoJitInfo *ji;
13057                                 MonoJitInfo res;
13058                                 MonoContext new_mono_context;
13059                                 int native_offset;
13060                                 ji = mono_arch_find_jit_info (domain, jit_tls, &res, NULL, &mono_context,
13061                                                 &new_mono_context, NULL, &lmf, &native_offset, NULL);
13062                                 while ((ji != NULL) && (current_frame_index <= call_chain_depth)) {
13063                                         ips [current_frame_index] = MONO_CONTEXT_GET_IP (&new_mono_context);
13064                                         current_frame_index ++;
13065                                         mono_context = new_mono_context;
13066                                         ji = mono_arch_find_jit_info (domain, jit_tls, &res, NULL, &mono_context,
13067                                                         &new_mono_context, NULL, &lmf, &native_offset, NULL);
13068                                 }
13069                         }
13070 #endif
13071                 }
13072                 
13073                 
13074                 mono_profiler_stat_call_chain (current_frame_index, & ips [0], ctx);
13075         }
13076 }
13077
13078 #endif
13079
13080 static void
13081 SIG_HANDLER_SIGNATURE (sigquit_signal_handler)
13082 {
13083         GET_CONTEXT;
13084
13085         printf ("Full thread dump:\n");
13086
13087         mono_threads_request_thread_dump ();
13088
13089         /*
13090          * print_thread_dump () skips the current thread, since sending a signal
13091          * to it would invoke the signal handler below the sigquit signal handler,
13092          * and signal handlers don't create an lmf, so the stack walk could not
13093          * be performed.
13094          */
13095         mono_print_thread_dump (ctx);
13096 }
13097
13098 static void
13099 SIG_HANDLER_SIGNATURE (sigusr2_signal_handler)
13100 {
13101         gboolean enabled = mono_trace_is_enabled ();
13102
13103         mono_trace_enable (!enabled);
13104 }
13105
13106 #endif
13107
13108 static void
13109 SIG_HANDLER_SIGNATURE (sigint_signal_handler)
13110 {
13111         MonoException *exc;
13112         GET_CONTEXT;
13113
13114         exc = mono_get_exception_execution_engine ("Interrupted (SIGINT).");
13115         
13116         mono_arch_handle_exception (ctx, exc, FALSE);
13117 }
13118
13119 #ifdef PLATFORM_MACOSX
13120
13121 /*
13122  * This code disables the CrashReporter of MacOS X by installing
13123  * a dummy Mach exception handler.
13124  */
13125
13126 /*
13127  * http://darwinsource.opendarwin.org/10.4.3/xnu-792.6.22/osfmk/man/exc_server.html
13128  */
13129 extern
13130 boolean_t
13131 exc_server (mach_msg_header_t *request_msg,
13132             mach_msg_header_t *reply_msg);
13133
13134 /*
13135  * The exception message
13136  */
13137 typedef struct {
13138         mach_msg_base_t msg;  /* common mach message header */
13139         char payload [1024];  /* opaque */
13140 } mach_exception_msg_t;
13141
13142 /* The exception port */
13143 static mach_port_t mach_exception_port = VM_MAP_NULL;
13144
13145 /*
13146  * Implicitly called by exc_server. Must be public.
13147  *
13148  * http://darwinsource.opendarwin.org/10.4.3/xnu-792.6.22/osfmk/man/catch_exception_raise.html
13149  */
13150 kern_return_t
13151 catch_exception_raise (
13152         mach_port_t exception_port,
13153         mach_port_t thread,
13154         mach_port_t task,
13155         exception_type_t exception,
13156         exception_data_t code,
13157         mach_msg_type_number_t code_count)
13158 {
13159         /* consume the exception */
13160         return KERN_FAILURE;
13161 }
13162
13163 /*
13164  * Exception thread handler.
13165  */
13166 static
13167 void *
13168 mach_exception_thread (void *arg)
13169 {
13170         for (;;) {
13171                 mach_exception_msg_t request;
13172                 mach_exception_msg_t reply;
13173                 mach_msg_return_t result;
13174
13175                 /* receive from "mach_exception_port" */
13176                 result = mach_msg (&request.msg.header,
13177                                    MACH_RCV_MSG | MACH_RCV_LARGE,
13178                                    0,
13179                                    sizeof (request),
13180                                    mach_exception_port,
13181                                    MACH_MSG_TIMEOUT_NONE,
13182                                    MACH_PORT_NULL);
13183
13184                 g_assert (result == MACH_MSG_SUCCESS);
13185
13186                 /* dispatch to catch_exception_raise () */
13187                 exc_server (&request.msg.header, &reply.msg.header);
13188
13189                 /* send back to sender */
13190                 result = mach_msg (&reply.msg.header,
13191                                    MACH_SEND_MSG,
13192                                    reply.msg.header.msgh_size,
13193                                    0,
13194                                    MACH_PORT_NULL,
13195                                    MACH_MSG_TIMEOUT_NONE,
13196                                    MACH_PORT_NULL);
13197
13198                 g_assert (result == MACH_MSG_SUCCESS);
13199         }
13200         return NULL;
13201 }
13202
13203 static void
13204 macosx_register_exception_handler ()
13205 {
13206         mach_port_t task;
13207         pthread_attr_t attr;
13208         pthread_t thread;
13209
13210         if (mach_exception_port != VM_MAP_NULL)
13211                 return;
13212
13213         task = mach_task_self ();
13214
13215         /* create the "mach_exception_port" with send & receive rights */
13216         g_assert (mach_port_allocate (task, MACH_PORT_RIGHT_RECEIVE,
13217                                       &mach_exception_port) == KERN_SUCCESS);
13218         g_assert (mach_port_insert_right (task, mach_exception_port, mach_exception_port,
13219                                           MACH_MSG_TYPE_MAKE_SEND) == KERN_SUCCESS);
13220
13221         /* create the exception handler thread */
13222         g_assert (!pthread_attr_init (&attr));
13223         g_assert (!pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED));
13224         g_assert (!pthread_create (&thread, &attr, mach_exception_thread, NULL));
13225         pthread_attr_destroy (&attr);
13226
13227         /*
13228          * register "mach_exception_port" as a receiver for the
13229          * EXC_BAD_ACCESS exception
13230          *
13231          * http://darwinsource.opendarwin.org/10.4.3/xnu-792.6.22/osfmk/man/task_set_exception_ports.html
13232          */
13233         g_assert (task_set_exception_ports (task, EXC_MASK_BAD_ACCESS,
13234                                             mach_exception_port,
13235                                             EXCEPTION_DEFAULT,
13236                                             MACHINE_THREAD_STATE) == KERN_SUCCESS);
13237 }
13238 #endif
13239
13240 #ifndef PLATFORM_WIN32
13241 static void
13242 add_signal_handler (int signo, gpointer handler)
13243 {
13244         struct sigaction sa;
13245
13246 #ifdef MONO_ARCH_USE_SIGACTION
13247         sa.sa_sigaction = handler;
13248         sigemptyset (&sa.sa_mask);
13249         sa.sa_flags = SA_SIGINFO;
13250 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
13251         if (signo == SIGSEGV)
13252                 sa.sa_flags |= SA_ONSTACK;
13253 #endif
13254 #else
13255         sa.sa_handler = handler;
13256         sigemptyset (&sa.sa_mask);
13257         sa.sa_flags = 0;
13258 #endif
13259         g_assert (sigaction (signo, &sa, NULL) != -1);
13260 }
13261
13262 static void
13263 remove_signal_handler (int signo)
13264 {
13265         struct sigaction sa;
13266
13267         sa.sa_handler = SIG_DFL;
13268         sigemptyset (&sa.sa_mask);
13269         sa.sa_flags = 0;
13270
13271         g_assert (sigaction (signo, &sa, NULL) != -1);
13272 }
13273 #endif
13274
13275 static void
13276 mono_runtime_install_handlers (void)
13277 {
13278 #ifdef PLATFORM_WIN32
13279         win32_seh_init();
13280         win32_seh_set_handler(SIGFPE, sigfpe_signal_handler);
13281         win32_seh_set_handler(SIGILL, sigill_signal_handler);
13282         win32_seh_set_handler(SIGSEGV, sigsegv_signal_handler);
13283         if (debug_options.handle_sigint)
13284                 win32_seh_set_handler(SIGINT, sigint_signal_handler);
13285
13286 #else /* !PLATFORM_WIN32 */
13287
13288
13289 #ifdef PLATFORM_MACOSX
13290         macosx_register_exception_handler ();
13291 #endif
13292
13293         if (debug_options.handle_sigint)
13294                 add_signal_handler (SIGINT, sigint_signal_handler);
13295
13296         add_signal_handler (SIGFPE, sigfpe_signal_handler);
13297         add_signal_handler (SIGQUIT, sigquit_signal_handler);
13298         add_signal_handler (SIGILL, sigill_signal_handler);
13299         add_signal_handler (SIGBUS, sigsegv_signal_handler);
13300         if (mono_jit_trace_calls != NULL)
13301                 add_signal_handler (SIGUSR2, sigusr2_signal_handler);
13302
13303         add_signal_handler (mono_thread_get_abort_signal (), sigusr1_signal_handler);
13304         signal (SIGPIPE, SIG_IGN);
13305
13306         add_signal_handler (SIGABRT, sigabrt_signal_handler);
13307
13308         /* catch SIGSEGV */
13309         add_signal_handler (SIGSEGV, sigsegv_signal_handler);
13310 #endif /* PLATFORM_WIN32 */
13311 }
13312
13313 static void
13314 mono_runtime_cleanup_handlers (void)
13315 {
13316 #ifdef PLATFORM_WIN32
13317         win32_seh_cleanup();
13318 #else
13319         if (debug_options.handle_sigint)
13320                 remove_signal_handler (SIGINT);
13321
13322         remove_signal_handler (SIGFPE);
13323         remove_signal_handler (SIGQUIT);
13324         remove_signal_handler (SIGILL);
13325         remove_signal_handler (SIGBUS);
13326         if (mono_jit_trace_calls != NULL)
13327                 remove_signal_handler (SIGUSR2);
13328
13329         remove_signal_handler (mono_thread_get_abort_signal ());
13330
13331         remove_signal_handler (SIGABRT);
13332
13333         remove_signal_handler (SIGSEGV);
13334 #endif /* PLATFORM_WIN32 */
13335 }
13336
13337
13338 #ifdef HAVE_LINUX_RTC_H
13339 #include <linux/rtc.h>
13340 #include <sys/ioctl.h>
13341 #include <fcntl.h>
13342 static int rtc_fd = -1;
13343
13344 static int
13345 enable_rtc_timer (gboolean enable)
13346 {
13347         int flags;
13348         flags = fcntl (rtc_fd, F_GETFL);
13349         if (flags < 0) {
13350                 perror ("getflags");
13351                 return 0;
13352         }
13353         if (enable)
13354                 flags |= FASYNC;
13355         else
13356                 flags &= ~FASYNC;
13357         if (fcntl (rtc_fd, F_SETFL, flags) == -1) {
13358                 perror ("setflags");
13359                 return 0;
13360         }
13361         return 1;
13362 }
13363 #endif
13364
13365 #ifdef PLATFORM_WIN32
13366 static HANDLE win32_main_thread;
13367 static MMRESULT win32_timer;
13368
13369 static void CALLBACK
13370 win32_time_proc (UINT uID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2)
13371 {
13372         CONTEXT context;
13373
13374         context.ContextFlags = CONTEXT_CONTROL;
13375         if (GetThreadContext (win32_main_thread, &context)) {
13376 #ifdef _WIN64
13377                 mono_profiler_stat_hit ((guchar *) context.Rip, &context);
13378 #else
13379                 mono_profiler_stat_hit ((guchar *) context.Eip, &context);
13380 #endif
13381         }
13382 }
13383 #endif
13384
13385 static void
13386 setup_stat_profiler (void)
13387 {
13388 #ifdef ITIMER_PROF
13389         struct itimerval itval;
13390         static int inited = 0;
13391 #ifdef HAVE_LINUX_RTC_H
13392         const char *rtc_freq;
13393         if (!inited && (rtc_freq = g_getenv ("MONO_RTC"))) {
13394                 int freq = 0;
13395                 inited = 1;
13396                 if (*rtc_freq)
13397                         freq = atoi (rtc_freq);
13398                 if (!freq)
13399                         freq = 1024;
13400                 rtc_fd = open ("/dev/rtc", O_RDONLY);
13401                 if (rtc_fd == -1) {
13402                         perror ("open /dev/rtc");
13403                         return;
13404                 }
13405                 add_signal_handler (SIGPROF, sigprof_signal_handler);
13406                 if (ioctl (rtc_fd, RTC_IRQP_SET, freq) == -1) {
13407                         perror ("set rtc freq");
13408                         return;
13409                 }
13410                 if (ioctl (rtc_fd, RTC_PIE_ON, 0) == -1) {
13411                         perror ("start rtc");
13412                         return;
13413                 }
13414                 if (fcntl (rtc_fd, F_SETSIG, SIGPROF) == -1) {
13415                         perror ("setsig");
13416                         return;
13417                 }
13418                 if (fcntl (rtc_fd, F_SETOWN, getpid ()) == -1) {
13419                         perror ("setown");
13420                         return;
13421                 }
13422                 enable_rtc_timer (TRUE);
13423                 return;
13424         }
13425         if (rtc_fd >= 0)
13426                 return;
13427 #endif
13428
13429         itval.it_interval.tv_usec = 999;
13430         itval.it_interval.tv_sec = 0;
13431         itval.it_value = itval.it_interval;
13432         setitimer (ITIMER_PROF, &itval, NULL);
13433         if (inited)
13434                 return;
13435         inited = 1;
13436         add_signal_handler (SIGPROF, sigprof_signal_handler);
13437 #elif defined (PLATFORM_WIN32)
13438         static int inited = 0;
13439         TIMECAPS timecaps;
13440
13441         if (inited)
13442                 return;
13443
13444         inited = 1;
13445         if (timeGetDevCaps (&timecaps, sizeof (timecaps)) != TIMERR_NOERROR)
13446                 return;
13447
13448         if ((win32_main_thread = OpenThread (READ_CONTROL | THREAD_GET_CONTEXT, FALSE, GetCurrentThreadId ())) == NULL)
13449                 return;
13450
13451         if (timeBeginPeriod (1) != TIMERR_NOERROR)
13452                 return;
13453
13454         if ((win32_timer = timeSetEvent (1, 0, win32_time_proc, 0, TIME_PERIODIC)) == 0) {
13455                 timeEndPeriod (1);
13456                 return;
13457         }
13458 #endif
13459 }
13460
13461 /* mono_jit_create_remoting_trampoline:
13462  * @method: pointer to the method info
13463  *
13464  * Creates a trampoline which calls the remoting functions. This
13465  * is used in the vtable of transparent proxies.
13466  * 
13467  * Returns: a pointer to the newly created code 
13468  */
13469 static gpointer
13470 mono_jit_create_remoting_trampoline (MonoMethod *method, MonoRemotingTarget target)
13471 {
13472         MonoMethod *nm;
13473         guint8 *addr = NULL;
13474
13475         if ((method->flags & METHOD_ATTRIBUTE_ABSTRACT) || 
13476             (mono_method_signature (method)->hasthis && (method->klass->marshalbyref || method->klass == mono_defaults.object_class))) {
13477                 nm = mono_marshal_get_remoting_invoke_for_target (method, target);
13478                 addr = mono_compile_method (nm);
13479         } else {
13480                 addr = mono_compile_method (method);
13481         }
13482         return mono_get_addr_from_ftnptr (addr);
13483 }
13484
13485 #ifdef MONO_ARCH_HAVE_IMT
13486 static gpointer
13487 mini_get_imt_trampoline (void)
13488 {
13489         static gpointer tramp = NULL;
13490         if (!tramp)
13491                 tramp =  mono_arch_create_specific_trampoline (MONO_FAKE_IMT_METHOD, MONO_TRAMPOLINE_GENERIC, mono_get_root_domain (), NULL);
13492         return tramp;
13493 }
13494 #endif
13495
13496 #ifdef MONO_ARCH_COMMON_VTABLE_TRAMPOLINE
13497 gpointer
13498 mini_get_vtable_trampoline (void)
13499 {
13500         static gpointer tramp = NULL;
13501         if (!tramp)
13502                 tramp =  mono_arch_create_specific_trampoline (MONO_FAKE_VTABLE_METHOD, MONO_TRAMPOLINE_GENERIC, mono_get_root_domain (), NULL);
13503         return tramp;
13504 }
13505 #endif
13506
13507 static void
13508 mini_parse_debug_options (void)
13509 {
13510         char *options = getenv ("MONO_DEBUG");
13511         gchar **args, **ptr;
13512         
13513         if (!options)
13514                 return;
13515
13516         args = g_strsplit (options, ",", -1);
13517
13518         for (ptr = args; ptr && *ptr; ptr++) {
13519                 const char *arg = *ptr;
13520
13521                 if (!strcmp (arg, "handle-sigint"))
13522                         debug_options.handle_sigint = TRUE;
13523                 else if (!strcmp (arg, "keep-delegates"))
13524                         debug_options.keep_delegates = TRUE;
13525                 else if (!strcmp (arg, "collect-pagefault-stats"))
13526                         debug_options.collect_pagefault_stats = TRUE;
13527                 else if (!strcmp (arg, "break-on-unverified"))
13528                         debug_options.break_on_unverified = TRUE;
13529                 else if (!strcmp (arg, "no-gdb-backtrace"))
13530                         debug_options.no_gdb_backtrace = TRUE;
13531                 else {
13532                         fprintf (stderr, "Invalid option for the MONO_DEBUG env variable: %s\n", arg);
13533                         fprintf (stderr, "Available options: 'handle-sigint', 'keep-delegates', 'collect-pagefault-stats', 'break-on-unverified', 'no-gdb-backtrace'\n");
13534                         exit (1);
13535                 }
13536         }
13537 }
13538
13539 MonoDebugOptions *
13540 mini_get_debug_options (void)
13541 {
13542         return &debug_options;
13543 }
13544
13545 MonoDomain *
13546 mini_init (const char *filename, const char *runtime_version)
13547 {
13548         MonoDomain *domain;
13549
13550         MONO_PROBE_VES_INIT_BEGIN ();
13551
13552 #ifdef __linux__
13553         if (access ("/proc/self/maps", F_OK) != 0) {
13554                 g_print ("Mono requires /proc to be mounted.\n");
13555                 exit (1);
13556         }
13557 #endif
13558
13559         /* Happens when using the embedding interface */
13560         if (!default_opt_set)
13561                 default_opt = mono_parse_default_optimizations (NULL);
13562
13563         InitializeCriticalSection (&jit_mutex);
13564
13565         if (!global_codeman)
13566                 global_codeman = mono_code_manager_new ();
13567         jit_icall_name_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
13568
13569         mono_arch_cpu_init ();
13570
13571         mono_arch_init ();
13572
13573         mono_trampolines_init ();
13574
13575         mono_exceptions_init ();
13576
13577         if (!g_thread_supported ())
13578                 g_thread_init (NULL);
13579
13580         if (getenv ("MONO_DEBUG") != NULL)
13581                 mini_parse_debug_options ();
13582
13583         mono_gc_base_init ();
13584
13585         mono_jit_tls_id = TlsAlloc ();
13586         setup_jit_tls_data ((gpointer)-1, mono_thread_abort);
13587
13588         mono_burg_init ();
13589
13590         if (default_opt & MONO_OPT_AOT)
13591                 mono_aot_init ();
13592
13593         mono_runtime_install_handlers ();
13594         mono_threads_install_cleanup (mini_thread_cleanup);
13595
13596 #ifdef MONO_ARCH_HAVE_NOTIFY_PENDING_EXC
13597         // This is experimental code so provide an env var to switch it off
13598         if (getenv ("MONO_DISABLE_PENDING_EXCEPTIONS")) {
13599                 printf ("MONO_DISABLE_PENDING_EXCEPTIONS env var set.\n");
13600         } else {
13601                 check_for_pending_exc = FALSE;
13602                 mono_threads_install_notify_pending_exc (mono_arch_notify_pending_exc);
13603         }
13604 #endif
13605
13606 #define JIT_TRAMPOLINES_WORK
13607 #ifdef JIT_TRAMPOLINES_WORK
13608         mono_install_compile_method (mono_jit_compile_method);
13609         mono_install_free_method (mono_jit_free_method);
13610         mono_install_trampoline (mono_create_jit_trampoline);
13611         mono_install_jump_trampoline (mono_create_jump_trampoline);
13612         mono_install_remoting_trampoline (mono_jit_create_remoting_trampoline);
13613         mono_install_delegate_trampoline (mono_create_delegate_trampoline);
13614 #endif
13615 #define JIT_INVOKE_WORKS
13616 #ifdef JIT_INVOKE_WORKS
13617         mono_install_runtime_invoke (mono_jit_runtime_invoke);
13618         mono_install_handler (mono_arch_get_throw_exception ());
13619 #endif
13620         mono_install_stack_walk (mono_jit_walk_stack);
13621         mono_install_get_cached_class_info (mono_aot_get_cached_class_info);
13622         mono_install_get_class_from_name (mono_aot_get_class_from_name);
13623         mono_install_jit_info_find_in_aot (mono_aot_find_jit_info);
13624
13625         if (debug_options.collect_pagefault_stats) {
13626                 mono_raw_buffer_set_make_unreadable (TRUE);
13627                 mono_aot_set_make_unreadable (TRUE);
13628         }
13629
13630         if (runtime_version)
13631                 domain = mono_init_version (filename, runtime_version);
13632         else
13633                 domain = mono_init_from_assembly (filename, filename);
13634 #ifdef MONO_ARCH_HAVE_IMT
13635         mono_install_imt_thunk_builder (mono_arch_build_imt_thunk);
13636         mono_install_imt_trampoline (mini_get_imt_trampoline ());
13637 #if MONO_ARCH_COMMON_VTABLE_TRAMPOLINE
13638         mono_install_vtable_trampoline (mini_get_vtable_trampoline ());
13639 #endif
13640 #endif
13641         mono_icall_init ();
13642
13643         mono_add_internal_call ("System.Diagnostics.StackFrame::get_frame_info", 
13644                                 ves_icall_get_frame_info);
13645         mono_add_internal_call ("System.Diagnostics.StackTrace::get_trace", 
13646                                 ves_icall_get_trace);
13647         mono_add_internal_call ("System.Exception::get_trace", 
13648                                 ves_icall_System_Exception_get_trace);
13649         mono_add_internal_call ("System.Security.SecurityFrame::_GetSecurityFrame",
13650                                 ves_icall_System_Security_SecurityFrame_GetSecurityFrame);
13651         mono_add_internal_call ("System.Security.SecurityFrame::_GetSecurityStack",
13652                                 ves_icall_System_Security_SecurityFrame_GetSecurityStack);
13653         mono_add_internal_call ("Mono.Runtime::mono_runtime_install_handlers", 
13654                                 mono_runtime_install_handlers);
13655
13656
13657         create_helper_signature ();
13658
13659 #define JIT_CALLS_WORK
13660 #ifdef JIT_CALLS_WORK
13661         /* Needs to be called here since register_jit_icall depends on it */
13662         mono_marshal_init ();
13663
13664         mono_arch_register_lowlevel_calls ();
13665         register_icall (mono_profiler_method_enter, "mono_profiler_method_enter", NULL, TRUE);
13666         register_icall (mono_profiler_method_leave, "mono_profiler_method_leave", NULL, TRUE);
13667         register_icall (mono_trace_enter_method, "mono_trace_enter_method", NULL, TRUE);
13668         register_icall (mono_trace_leave_method, "mono_trace_leave_method", NULL, TRUE);
13669         register_icall (mono_get_lmf_addr, "mono_get_lmf_addr", "ptr", TRUE);
13670         register_icall (mono_jit_thread_attach, "mono_jit_thread_attach", "void", TRUE);
13671         register_icall (mono_domain_get, "mono_domain_get", "ptr", TRUE);
13672
13673         register_icall (mono_arch_get_throw_exception (), "mono_arch_throw_exception", "void object", TRUE);
13674         register_icall (mono_arch_get_rethrow_exception (), "mono_arch_rethrow_exception", "void object", TRUE);
13675         register_icall (mono_arch_get_throw_exception_by_name (), "mono_arch_throw_exception_by_name", "void ptr", TRUE); 
13676 #if MONO_ARCH_HAVE_THROW_CORLIB_EXCEPTION
13677         register_icall (mono_arch_get_throw_corlib_exception (), "mono_arch_throw_corlib_exception", 
13678                                  "void ptr", TRUE);
13679 #endif
13680         register_icall (mono_thread_get_undeniable_exception, "mono_thread_get_undeniable_exception", "object", FALSE);
13681         register_icall (mono_thread_interruption_checkpoint, "mono_thread_interruption_checkpoint", "void", FALSE);
13682         register_icall (mono_thread_force_interruption_checkpoint, "mono_thread_force_interruption_checkpoint", "void", FALSE);
13683         register_icall (mono_load_remote_field_new, "mono_load_remote_field_new", "object object ptr ptr", FALSE);
13684         register_icall (mono_store_remote_field_new, "mono_store_remote_field_new", "void object ptr ptr object", FALSE);
13685
13686         /* 
13687          * NOTE, NOTE, NOTE, NOTE:
13688          * when adding emulation for some opcodes, remember to also add a dummy
13689          * rule to the burg files, because we need the arity information to be correct.
13690          */
13691 #ifndef MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS
13692         mono_register_opcode_emulation (OP_LMUL, "__emul_lmul", "long long long", mono_llmult, TRUE);
13693         mono_register_opcode_emulation (OP_LDIV, "__emul_ldiv", "long long long", mono_lldiv, FALSE);
13694         mono_register_opcode_emulation (OP_LDIV_UN, "__emul_ldiv_un", "long long long", mono_lldiv_un, FALSE);
13695         mono_register_opcode_emulation (OP_LREM, "__emul_lrem", "long long long", mono_llrem, FALSE);
13696         mono_register_opcode_emulation (OP_LREM_UN, "__emul_lrem_un", "long long long", mono_llrem_un, FALSE);
13697         mono_register_opcode_emulation (OP_LMUL_OVF_UN, "__emul_lmul_ovf_un", "long long long", mono_llmult_ovf_un, FALSE);
13698         mono_register_opcode_emulation (OP_LMUL_OVF, "__emul_lmul_ovf", "long long long", mono_llmult_ovf, FALSE);
13699 #endif
13700
13701 #ifndef MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
13702         mono_register_opcode_emulation (OP_LSHL, "__emul_lshl", "long long int32", mono_lshl, TRUE);
13703         mono_register_opcode_emulation (OP_LSHR, "__emul_lshr", "long long int32", mono_lshr, TRUE);
13704         mono_register_opcode_emulation (OP_LSHR_UN, "__emul_lshr_un", "long long int32", mono_lshr_un, TRUE);
13705 #endif
13706
13707 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
13708         mono_register_opcode_emulation (CEE_DIV, "__emul_idiv", "int32 int32 int32", mono_idiv, FALSE);
13709         mono_register_opcode_emulation (CEE_DIV_UN, "__emul_idiv_un", "int32 int32 int32", mono_idiv_un, FALSE);
13710         mono_register_opcode_emulation (CEE_REM, "__emul_irem", "int32 int32 int32", mono_irem, FALSE);
13711         mono_register_opcode_emulation (CEE_REM_UN, "__emul_irem_un", "int32 int32 int32", mono_irem_un, FALSE);
13712 #endif
13713
13714 #ifdef MONO_ARCH_EMULATE_MUL_DIV
13715         mono_register_opcode_emulation (CEE_MUL_OVF, "__emul_imul_ovf", "int32 int32 int32", mono_imul_ovf, FALSE);
13716         mono_register_opcode_emulation (CEE_MUL_OVF_UN, "__emul_imul_ovf_un", "int32 int32 int32", mono_imul_ovf_un, FALSE);
13717         mono_register_opcode_emulation (CEE_MUL, "__emul_imul", "int32 int32 int32", mono_imul, TRUE);
13718 #endif
13719 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_SOFT_FLOAT)
13720         mono_register_opcode_emulation (OP_FDIV, "__emul_fdiv", "double double double", mono_fdiv, FALSE);
13721 #endif
13722
13723         mono_register_opcode_emulation (OP_FCONV_TO_U8, "__emul_fconv_to_u8", "ulong double", mono_fconv_u8, FALSE);
13724         mono_register_opcode_emulation (OP_FCONV_TO_U4, "__emul_fconv_to_u4", "uint32 double", mono_fconv_u4, FALSE);
13725         mono_register_opcode_emulation (OP_FCONV_TO_OVF_I8, "__emul_fconv_to_ovf_i8", "long double", mono_fconv_ovf_i8, FALSE);
13726         mono_register_opcode_emulation (OP_FCONV_TO_OVF_U8, "__emul_fconv_to_ovf_u8", "ulong double", mono_fconv_ovf_u8, FALSE);
13727
13728 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
13729         mono_register_opcode_emulation (OP_FCONV_TO_I8, "__emul_fconv_to_i8", "long double", mono_fconv_i8, FALSE);
13730 #endif
13731 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
13732         mono_register_opcode_emulation (CEE_CONV_R_UN, "__emul_conv_r_un", "double int32", mono_conv_to_r8_un, FALSE);
13733 #endif
13734 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
13735         mono_register_opcode_emulation (OP_LCONV_TO_R8, "__emul_lconv_to_r8", "double long", mono_lconv_to_r8, FALSE);
13736 #endif
13737 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
13738         mono_register_opcode_emulation (OP_LCONV_TO_R4, "__emul_lconv_to_r4", "float long", mono_lconv_to_r4, FALSE);
13739 #endif
13740 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
13741         mono_register_opcode_emulation (OP_LCONV_TO_R_UN, "__emul_lconv_to_r8_un", "double long", mono_lconv_to_r8_un, FALSE);
13742 #endif
13743 #ifdef MONO_ARCH_EMULATE_FREM
13744         mono_register_opcode_emulation (OP_FREM, "__emul_frem", "double double double", fmod, FALSE);
13745 #endif
13746
13747 #ifdef MONO_ARCH_SOFT_FLOAT
13748         mono_register_opcode_emulation (OP_FSUB, "__emul_fsub", "double double double", mono_fsub, FALSE);
13749         mono_register_opcode_emulation (OP_FADD, "__emul_fadd", "double double double", mono_fadd, FALSE);
13750         mono_register_opcode_emulation (OP_FMUL, "__emul_fmul", "double double double", mono_fmul, FALSE);
13751         mono_register_opcode_emulation (OP_FNEG, "__emul_fneg", "double double", mono_fneg, FALSE);
13752         mono_register_opcode_emulation (CEE_CONV_R8, "__emul_conv_r8", "double int32", mono_conv_to_r8, FALSE);
13753         mono_register_opcode_emulation (CEE_CONV_R4, "__emul_conv_r4", "double int32", mono_conv_to_r4, FALSE);
13754         mono_register_opcode_emulation (OP_FCONV_TO_R4, "__emul_fconv_to_r4", "double double", mono_fconv_r4, FALSE);
13755         mono_register_opcode_emulation (OP_FCONV_TO_I1, "__emul_fconv_to_i1", "int8 double", mono_fconv_i1, FALSE);
13756         mono_register_opcode_emulation (OP_FCONV_TO_I2, "__emul_fconv_to_i2", "int16 double", mono_fconv_i2, FALSE);
13757         mono_register_opcode_emulation (OP_FCONV_TO_I4, "__emul_fconv_to_i4", "int32 double", mono_fconv_i4, FALSE);
13758         mono_register_opcode_emulation (OP_FCONV_TO_U1, "__emul_fconv_to_u1", "uint8 double", mono_fconv_u1, FALSE);
13759         mono_register_opcode_emulation (OP_FCONV_TO_U2, "__emul_fconv_to_u2", "uint16 double", mono_fconv_u2, FALSE);
13760
13761         mono_register_opcode_emulation (OP_FBEQ, "__emul_fcmp_eq", "uint32 double double", mono_fcmp_eq, FALSE);
13762         mono_register_opcode_emulation (OP_FBLT, "__emul_fcmp_lt", "uint32 double double", mono_fcmp_lt, FALSE);
13763         mono_register_opcode_emulation (OP_FBGT, "__emul_fcmp_gt", "uint32 double double", mono_fcmp_gt, FALSE);
13764         mono_register_opcode_emulation (OP_FBLE, "__emul_fcmp_le", "uint32 double double", mono_fcmp_le, FALSE);
13765         mono_register_opcode_emulation (OP_FBGE, "__emul_fcmp_ge", "uint32 double double", mono_fcmp_ge, FALSE);
13766         mono_register_opcode_emulation (OP_FBNE_UN, "__emul_fcmp_ne_un", "uint32 double double", mono_fcmp_ne_un, FALSE);
13767         mono_register_opcode_emulation (OP_FBLT_UN, "__emul_fcmp_lt_un", "uint32 double double", mono_fcmp_lt_un, FALSE);
13768         mono_register_opcode_emulation (OP_FBGT_UN, "__emul_fcmp_gt_un", "uint32 double double", mono_fcmp_gt_un, FALSE);
13769         mono_register_opcode_emulation (OP_FBLE_UN, "__emul_fcmp_le_un", "uint32 double double", mono_fcmp_le_un, FALSE);
13770         mono_register_opcode_emulation (OP_FBGE_UN, "__emul_fcmp_ge_un", "uint32 double double", mono_fcmp_ge_un, FALSE);
13771
13772         mono_register_opcode_emulation (OP_FCEQ, "__emul_fcmp_ceq", "uint32 double double", mono_fceq, FALSE);
13773         mono_register_opcode_emulation (OP_FCGT, "__emul_fcmp_cgt", "uint32 double double", mono_fcgt, FALSE);
13774         mono_register_opcode_emulation (OP_FCGT_UN, "__emul_fcmp_cgt_un", "uint32 double double", mono_fcgt_un, FALSE);
13775         mono_register_opcode_emulation (OP_FCLT, "__emul_fcmp_clt", "uint32 double double", mono_fclt, FALSE);
13776         mono_register_opcode_emulation (OP_FCLT_UN, "__emul_fcmp_clt_un", "uint32 double double", mono_fclt_un, FALSE);
13777
13778         register_icall (mono_fload_r4, "mono_fload_r4", "double ptr", FALSE);
13779         register_icall (mono_fstore_r4, "mono_fstore_r4", "void double ptr", FALSE);
13780         register_icall (mono_fload_r4_arg, "mono_fload_r4_arg", "uint32 double", FALSE);
13781 #endif
13782
13783 #if SIZEOF_VOID_P == 4
13784         mono_register_opcode_emulation (OP_FCONV_TO_U, "__emul_fconv_to_u", "uint32 double", mono_fconv_u4, TRUE);
13785 #endif
13786
13787         /* other jit icalls */
13788         register_icall (mono_delegate_ctor, "mono_delegate_ctor", "void object object ptr", FALSE);
13789         register_icall (mono_class_static_field_address , "mono_class_static_field_address", 
13790                                  "ptr ptr ptr", FALSE);
13791         register_icall (mono_ldtoken_wrapper, "mono_ldtoken_wrapper", "ptr ptr ptr ptr", FALSE);
13792         register_icall (mono_ldtoken_wrapper_generic_shared, "mono_ldtoken_wrapper_generic_shared",
13793                 "ptr ptr ptr ptr", FALSE);
13794         register_icall (mono_get_special_static_data, "mono_get_special_static_data", "ptr int", FALSE);
13795         register_icall (mono_ldstr, "mono_ldstr", "object ptr ptr int32", FALSE);
13796         register_icall (mono_helper_stelem_ref_check, "helper_stelem_ref_check", "void object object", FALSE);
13797         register_icall (mono_object_new, "mono_object_new", "object ptr ptr", FALSE);
13798         register_icall (mono_object_new_specific, "mono_object_new_specific", "object ptr", FALSE);
13799         register_icall (mono_array_new, "mono_array_new", "object ptr ptr int32", FALSE);
13800         register_icall (mono_array_new_specific, "mono_array_new_specific", "object ptr int32", FALSE);
13801         register_icall (mono_runtime_class_init, "mono_runtime_class_init", "void ptr", FALSE);
13802         register_icall (mono_ldftn, "mono_ldftn", "ptr ptr", FALSE);
13803         register_icall (mono_ldftn_nosync, "mono_ldftn_nosync", "ptr ptr", FALSE);
13804         register_icall (mono_ldvirtfn, "mono_ldvirtfn", "ptr object ptr", FALSE);
13805         register_icall (mono_helper_compile_generic_method, "compile_generic_method", "ptr object ptr ptr ptr", FALSE);
13806         register_icall (mono_helper_ldstr, "helper_ldstr", "object ptr int", FALSE);
13807         register_icall (mono_helper_ldstr_mscorlib, "helper_ldstr_mscorlib", "object int", FALSE);
13808         register_icall (mono_helper_newobj_mscorlib, "helper_newobj_mscorlib", "object int", FALSE);
13809         register_icall (mono_value_copy, "mono_value_copy", "void ptr ptr ptr", FALSE);
13810         register_icall (mono_helper_get_rgctx_other_ptr, "get_rgctx_other_ptr", "ptr ptr ptr int32 int32 int32 int32", FALSE);
13811         register_icall (mono_object_castclass, "mono_object_castclass", "object object ptr", FALSE);
13812         register_icall (mono_break, "mono_break", NULL, TRUE);
13813         register_icall (mono_create_corlib_exception_0, "mono_create_corlib_exception_0", "object int", TRUE);
13814         register_icall (mono_create_corlib_exception_1, "mono_create_corlib_exception_1", "object int object", TRUE);
13815         register_icall (mono_create_corlib_exception_2, "mono_create_corlib_exception_2", "object int object object", TRUE);
13816 #endif
13817
13818 #define JIT_RUNTIME_WORKS
13819 #ifdef JIT_RUNTIME_WORKS
13820         mono_install_runtime_cleanup ((MonoDomainFunc)mini_cleanup);
13821         mono_runtime_init (domain, mono_thread_start_cb, mono_thread_attach_cb);
13822 #endif
13823
13824         mono_generic_sharing_init ();
13825
13826         mono_thread_attach (domain);
13827         
13828         MONO_PROBE_VES_INIT_END ();
13829         
13830         return domain;
13831 }
13832
13833 MonoJitStats mono_jit_stats = {0};
13834
13835 static void 
13836 print_jit_stats (void)
13837 {
13838         if (mono_jit_stats.enabled) {
13839                 g_print ("Mono Jit statistics\n");
13840                 g_print ("Compiled methods:       %ld\n", mono_jit_stats.methods_compiled);
13841                 g_print ("Methods from AOT:       %ld\n", mono_jit_stats.methods_aot);
13842                 g_print ("Methods cache lookup:   %ld\n", mono_jit_stats.methods_lookups);
13843                 g_print ("Method trampolines:     %ld\n", mono_jit_stats.method_trampolines);
13844                 g_print ("Basic blocks:           %ld\n", mono_jit_stats.basic_blocks);
13845                 g_print ("Max basic blocks:       %ld\n", mono_jit_stats.max_basic_blocks);
13846                 g_print ("Allocated vars:         %ld\n", mono_jit_stats.allocate_var);
13847                 g_print ("Analyze stack repeat:   %ld\n", mono_jit_stats.analyze_stack_repeat);
13848                 g_print ("Compiled CIL code size: %ld\n", mono_jit_stats.cil_code_size);
13849                 g_print ("Native code size:       %ld\n", mono_jit_stats.native_code_size);
13850                 g_print ("Max code size ratio:    %.2f (%s::%s)\n", mono_jit_stats.max_code_size_ratio/100.0,
13851                                 mono_jit_stats.max_ratio_method->klass->name, mono_jit_stats.max_ratio_method->name);
13852                 g_print ("Biggest method:         %ld (%s::%s)\n", mono_jit_stats.biggest_method_size,
13853                                 mono_jit_stats.biggest_method->klass->name, mono_jit_stats.biggest_method->name);
13854                 g_print ("Code reallocs:          %ld\n", mono_jit_stats.code_reallocs);
13855                 g_print ("Allocated code size:    %ld\n", mono_jit_stats.allocated_code_size);
13856                 g_print ("Inlineable methods:     %ld\n", mono_jit_stats.inlineable_methods);
13857                 g_print ("Inlined methods:        %ld\n", mono_jit_stats.inlined_methods);
13858                 g_print ("Locals stack size:      %ld\n", mono_jit_stats.locals_stack_size);
13859
13860                 g_print ("\nCreated object count:   %ld\n", mono_stats.new_object_count);
13861                 g_print ("Delegates created:      %ld\n", mono_stats.delegate_creations);
13862                 g_print ("Initialized classes:    %ld\n", mono_stats.initialized_class_count);
13863                 g_print ("Used classes:           %ld\n", mono_stats.used_class_count);
13864                 g_print ("Generic vtables:        %ld\n", mono_stats.generic_vtable_count);
13865                 g_print ("Methods:                %ld\n", mono_stats.method_count);
13866                 g_print ("Static data size:       %ld\n", mono_stats.class_static_data_size);
13867                 g_print ("VTable data size:       %ld\n", mono_stats.class_vtable_size);
13868                 g_print ("Mscorlib mempool size:  %d\n", mono_mempool_get_allocated (mono_defaults.corlib->mempool));
13869
13870                 g_print ("\nGeneric instances:      %ld\n", mono_stats.generic_instance_count);
13871                 g_print ("Initialized classes:    %ld\n", mono_stats.generic_class_count);
13872                 g_print ("Inflated methods:       %ld / %ld\n", mono_stats.inflated_method_count_2,
13873                          mono_stats.inflated_method_count);
13874                 g_print ("Inflated types:         %ld\n", mono_stats.inflated_type_count);
13875                 g_print ("Generics metadata size: %ld\n", mono_stats.generics_metadata_size);
13876                 g_print ("Generics virtual invokes: %ld\n", mono_jit_stats.generic_virtual_invocations);
13877
13878                 g_print ("Sharable generic methods: %ld\n", mono_stats.generics_sharable_methods);
13879                 g_print ("Unsharable generic methods: %ld\n", mono_stats.generics_unsharable_methods);
13880                 g_print ("Shared generic methods: %ld\n", mono_stats.generics_shared_methods);
13881
13882                 g_print ("Dynamic code allocs:    %ld\n", mono_stats.dynamic_code_alloc_count);
13883                 g_print ("Dynamic code bytes:     %ld\n", mono_stats.dynamic_code_bytes_count);
13884                 g_print ("Dynamic code frees:     %ld\n", mono_stats.dynamic_code_frees_count);
13885
13886                 g_print ("IMT tables size:        %ld\n", mono_stats.imt_tables_size);
13887                 g_print ("IMT number of tables:   %ld\n", mono_stats.imt_number_of_tables);
13888                 g_print ("IMT number of methods:  %ld\n", mono_stats.imt_number_of_methods);
13889                 g_print ("IMT used slots:         %ld\n", mono_stats.imt_used_slots);
13890                 g_print ("IMT colliding slots:    %ld\n", mono_stats.imt_slots_with_collisions);
13891                 g_print ("IMT max collisions:     %ld\n", mono_stats.imt_max_collisions_in_slot);
13892                 g_print ("IMT methods at max col: %ld\n", mono_stats.imt_method_count_when_max_collisions);
13893                 g_print ("IMT thunks size:        %ld\n", mono_stats.imt_thunks_size);
13894
13895                 g_print ("JIT info table inserts: %ld\n", mono_stats.jit_info_table_insert_count);
13896                 g_print ("JIT info table removes: %ld\n", mono_stats.jit_info_table_remove_count);
13897                 g_print ("JIT info table lookups: %ld\n", mono_stats.jit_info_table_lookup_count);
13898
13899                 g_print ("Hazardous pointers:     %ld\n", mono_stats.hazardous_pointer_count);
13900 #ifdef HAVE_SGEN_GC
13901                 g_print ("Minor GC collections:   %ld\n", mono_stats.minor_gc_count);
13902                 g_print ("Major GC collections:   %ld\n", mono_stats.major_gc_count);
13903                 g_print ("Minor GC time in msecs: %lf\n", (double)mono_stats.minor_gc_time_usecs / 1000.0);
13904                 g_print ("Major GC time in msecs: %lf\n", (double)mono_stats.major_gc_time_usecs / 1000.0);
13905 #endif
13906                 if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS) {
13907                         g_print ("\nDecl security check   : %ld\n", mono_jit_stats.cas_declsec_check);
13908                         g_print ("LinkDemand (user)     : %ld\n", mono_jit_stats.cas_linkdemand);
13909                         g_print ("LinkDemand (icall)    : %ld\n", mono_jit_stats.cas_linkdemand_icall);
13910                         g_print ("LinkDemand (pinvoke)  : %ld\n", mono_jit_stats.cas_linkdemand_pinvoke);
13911                         g_print ("LinkDemand (aptc)     : %ld\n", mono_jit_stats.cas_linkdemand_aptc);
13912                         g_print ("Demand (code gen)     : %ld\n", mono_jit_stats.cas_demand_generation);
13913                 }
13914                 if (debug_options.collect_pagefault_stats) {
13915                         g_print ("Metadata pagefaults   : %d\n", mono_raw_buffer_get_n_pagefaults ());
13916                         g_print ("AOT pagefaults        : %d\n", mono_aot_get_n_pagefaults ());
13917                 }
13918         }
13919 }
13920
13921 void
13922 mini_cleanup (MonoDomain *domain)
13923 {
13924 #ifdef HAVE_LINUX_RTC_H
13925         if (rtc_fd >= 0)
13926                 enable_rtc_timer (FALSE);
13927 #endif
13928
13929         /* 
13930          * mono_runtime_cleanup() and mono_domain_finalize () need to
13931          * be called early since they need the execution engine still
13932          * fully working (mono_domain_finalize may invoke managed finalizers
13933          * and mono_runtime_cleanup will wait for other threads to finish).
13934          */
13935         mono_domain_finalize (domain, 2000);
13936
13937         /* This accesses metadata so needs to be called before runtime shutdown */
13938         print_jit_stats ();
13939
13940         mono_runtime_cleanup (domain);
13941
13942         mono_profiler_shutdown ();
13943
13944         mono_icall_cleanup ();
13945
13946         mono_runtime_cleanup_handlers ();
13947
13948         mono_domain_free (domain, TRUE);
13949
13950         mono_debugger_cleanup ();
13951
13952         mono_trampolines_cleanup ();
13953
13954         mono_code_manager_destroy (global_codeman);
13955         g_hash_table_destroy (jit_icall_name_hash);
13956         g_free (emul_opcode_map);
13957
13958         mono_arch_cleanup ();
13959
13960         mono_cleanup ();
13961
13962         mono_trace_cleanup ();
13963
13964         mono_counters_dump (-1, stdout);
13965
13966         if (mono_inject_async_exc_method)
13967                 mono_method_desc_free (mono_inject_async_exc_method);
13968
13969         TlsFree(mono_jit_tls_id);
13970
13971         DeleteCriticalSection (&jit_mutex);
13972
13973         DeleteCriticalSection (&mono_delegate_section);
13974 }
13975
13976 void
13977 mono_set_defaults (int verbose_level, guint32 opts)
13978 {
13979         mini_verbose = verbose_level;
13980         default_opt = opts;
13981         default_opt_set = TRUE;
13982 }
13983
13984 static void
13985 mono_precompile_assembly (MonoAssembly *ass, void *user_data)
13986 {
13987         GHashTable *assemblies = (GHashTable*)user_data;
13988         MonoImage *image = mono_assembly_get_image (ass);
13989         MonoMethod *method, *invoke;
13990         int i, count = 0;
13991
13992         if (g_hash_table_lookup (assemblies, ass))
13993                 return;
13994
13995         g_hash_table_insert (assemblies, ass, ass);
13996
13997         if (mini_verbose > 0)
13998                 printf ("PRECOMPILE: %s.\n", mono_image_get_filename (image));
13999
14000         for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_METHOD); ++i) {
14001                 method = mono_get_method (image, MONO_TOKEN_METHOD_DEF | (i + 1), NULL);
14002                 if (method->flags & METHOD_ATTRIBUTE_ABSTRACT)
14003                         continue;
14004
14005                 count++;
14006                 if (mini_verbose > 1) {
14007                         char * desc = mono_method_full_name (method, TRUE);
14008                         g_print ("Compiling %d %s\n", count, desc);
14009                         g_free (desc);
14010                 }
14011                 mono_compile_method (method);
14012                 if (strcmp (method->name, "Finalize") == 0) {
14013                         invoke = mono_marshal_get_runtime_invoke (method);
14014                         mono_compile_method (invoke);
14015                 }
14016                 if (method->klass->marshalbyref && mono_method_signature (method)->hasthis) {
14017                         invoke = mono_marshal_get_remoting_invoke_with_check (method);
14018                         mono_compile_method (invoke);
14019                 }
14020         }
14021
14022         /* Load and precompile referenced assemblies as well */
14023         for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_ASSEMBLYREF); ++i) {
14024                 mono_assembly_load_reference (image, i);
14025                 if (image->references [i])
14026                         mono_precompile_assembly (image->references [i], assemblies);
14027         }
14028 }
14029
14030 void mono_precompile_assemblies ()
14031 {
14032         GHashTable *assemblies = g_hash_table_new (NULL, NULL);
14033
14034         mono_assembly_foreach ((GFunc)mono_precompile_assembly, assemblies);
14035
14036         g_hash_table_destroy (assemblies);
14037 }