2008-04-20 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mono / mini / mini.c
1 /*
2  * mini.c: The new Mono code generator.
3  *
4  * Author:
5  *   Paolo Molaro (lupus@ximian.com)
6  *   Dietmar Maurer (dietmar@ximian.com)
7  *
8  * (C) 2002 Ximian, Inc.
9  */
10
11 #include <config.h>
12 #include <signal.h>
13 #ifdef HAVE_UNISTD_H
14 #include <unistd.h>
15 #endif
16 #include <math.h>
17 #ifdef HAVE_SYS_TIME_H
18 #include <sys/time.h>
19 #endif
20
21 #ifdef PLATFORM_MACOSX
22 #include <mach/mach.h>
23 #include <mach/mach_error.h>
24 #include <mach/exception.h>
25 #include <mach/task.h>
26 #include <pthread.h>
27 #endif
28
29 #ifdef HAVE_VALGRIND_MEMCHECK_H
30 #include <valgrind/memcheck.h>
31 #endif
32
33 #include <mono/metadata/assembly.h>
34 #include <mono/metadata/loader.h>
35 #include <mono/metadata/tabledefs.h>
36 #include <mono/metadata/class.h>
37 #include <mono/metadata/object.h>
38 #include <mono/metadata/exception.h>
39 #include <mono/metadata/opcodes.h>
40 #include <mono/metadata/mono-endian.h>
41 #include <mono/metadata/tokentype.h>
42 #include <mono/metadata/tabledefs.h>
43 #include <mono/metadata/threads.h>
44 #include <mono/metadata/marshal.h>
45 #include <mono/metadata/socket-io.h>
46 #include <mono/metadata/appdomain.h>
47 #include <mono/metadata/debug-helpers.h>
48 #include <mono/io-layer/io-layer.h>
49 #include "mono/metadata/profiler.h"
50 #include <mono/metadata/profiler-private.h>
51 #include <mono/metadata/mono-config.h>
52 #include <mono/metadata/environment.h>
53 #include <mono/metadata/mono-debug.h>
54 #include <mono/metadata/monitor.h>
55 #include <mono/metadata/gc-internal.h>
56 #include <mono/metadata/security-manager.h>
57 #include <mono/metadata/threads-types.h>
58 #include <mono/metadata/rawbuffer.h>
59 #include <mono/metadata/security-core-clr.h>
60 #include <mono/metadata/verify.h>
61 #include <mono/metadata/verify-internals.h>
62 #include <mono/utils/mono-math.h>
63 #include <mono/utils/mono-compiler.h>
64 #include <mono/utils/mono-counters.h>
65 #include <mono/utils/mono-logger.h>
66 #include <mono/utils/mono-mmap.h>
67
68 #include "mini.h"
69 #include <string.h>
70 #include <ctype.h>
71 #include "inssel.h"
72 #include "trace.h"
73
74 #include "jit-icalls.h"
75
76 #include "aliasing.h"
77
78 #include "debug-mini.h"
79
80 #define BRANCH_COST 100
81 #define INLINE_LENGTH_LIMIT 20
82 #define INLINE_FAILURE do {\
83                 if ((cfg->method != method) && (method->wrapper_type == MONO_WRAPPER_NONE))\
84                         goto inline_failure;\
85         } while (0)
86 #define CHECK_CFG_EXCEPTION do {\
87                 if (cfg->exception_type != MONO_EXCEPTION_NONE)\
88                         goto exception_exit;\
89         } while (0)
90 #define METHOD_ACCESS_FAILURE do {      \
91                 char *method_fname = mono_method_full_name (method, TRUE);      \
92                 char *cil_method_fname = mono_method_full_name (cil_method, TRUE);      \
93                 cfg->exception_type = MONO_EXCEPTION_METHOD_ACCESS;     \
94                 cfg->exception_message = g_strdup_printf ("Method `%s' is inaccessible from method `%s'\n", cil_method_fname, method_fname);    \
95                 g_free (method_fname);  \
96                 g_free (cil_method_fname);      \
97                 goto exception_exit;    \
98         } while (0)
99 #define FIELD_ACCESS_FAILURE do {       \
100                 char *method_fname = mono_method_full_name (method, TRUE);      \
101                 char *field_fname = mono_field_full_name (field);       \
102                 cfg->exception_type = MONO_EXCEPTION_FIELD_ACCESS;      \
103                 cfg->exception_message = g_strdup_printf ("Field `%s' is inaccessible from method `%s'\n", field_fname, method_fname);  \
104                 g_free (method_fname);  \
105                 g_free (field_fname);   \
106                 goto exception_exit;    \
107         } while (0)
108 #define GENERIC_SHARING_FAILURE(opcode) do {            \
109                 if (cfg->generic_sharing_context) {     \
110             if (cfg->verbose_level > 1) \
111                             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__); \
112                         cfg->exception_type = MONO_EXCEPTION_GENERIC_SHARING_FAILED;    \
113                         goto exception_exit;    \
114                 }                       \
115         } while (0)
116 #define GENERIC_SHARING_FAILURE_IF_VALUETYPE_METHOD(opcode) do {                        \
117                 if (method->klass->valuetype)   \
118                         GENERIC_SHARING_FAILURE ((opcode)); \
119         } while (0)
120
121 #define MONO_CHECK_THIS(ins) (mono_method_signature (cfg->method)->hasthis && (ins)->ssa_op == MONO_SSA_LOAD && (ins)->inst_left->inst_c0 == 0)
122
123 static void setup_stat_profiler (void);
124 gboolean  mono_arch_print_tree(MonoInst *tree, int arity);
125 static gpointer mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt);
126 static gpointer mono_jit_compile_method (MonoMethod *method);
127 inline static int mono_emit_jit_icall (MonoCompile *cfg, MonoBasicBlock *bblock, gconstpointer func, MonoInst **args, const guint8 *ip);
128
129 static void handle_stobj (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *dest, MonoInst *src, 
130                           const unsigned char *ip, MonoClass *klass, gboolean to_end, gboolean native, gboolean write_barrier);
131
132 static void dec_foreach (MonoInst *tree, MonoCompile *cfg);
133
134 static int mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock, 
135                    int locals_offset, MonoInst *return_var, GList *dont_inline, MonoInst **inline_args, 
136                    guint inline_offset, gboolean is_virtual_call);
137
138 #ifdef MONO_ARCH_SOFT_FLOAT
139 static void
140 handle_store_float (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *ptr, MonoInst *val, const unsigned char *ip);
141 #endif
142
143 /* helper methods signature */
144 static MonoMethodSignature *helper_sig_class_init_trampoline = NULL;
145 static MonoMethodSignature *helper_sig_generic_class_init_trampoline = NULL;
146 static MonoMethodSignature *helper_sig_rgctx_lazy_fetch_trampoline = NULL;
147 static MonoMethodSignature *helper_sig_domain_get = NULL;
148
149 static guint32 default_opt = 0;
150 static gboolean default_opt_set = FALSE;
151
152 guint32 mono_jit_tls_id = -1;
153
154 #ifdef HAVE_KW_THREAD
155 static __thread gpointer mono_jit_tls MONO_TLS_FAST;
156 #endif
157
158 MonoTraceSpec *mono_jit_trace_calls = NULL;
159 gboolean mono_break_on_exc = FALSE;
160 #ifndef DISABLE_AOT
161 gboolean mono_compile_aot = FALSE;
162 #endif
163 MonoMethodDesc *mono_inject_async_exc_method = NULL;
164 int mono_inject_async_exc_pos;
165 MonoMethodDesc *mono_break_at_bb_method = NULL;
166 int mono_break_at_bb_bb_num;
167
168 static int mini_verbose = 0;
169
170 #define mono_jit_lock() EnterCriticalSection (&jit_mutex)
171 #define mono_jit_unlock() LeaveCriticalSection (&jit_mutex)
172 static CRITICAL_SECTION jit_mutex;
173
174 static GHashTable *rgctx_lazy_fetch_trampoline_hash = NULL;
175
176 static MonoCodeManager *global_codeman = NULL;
177
178 static GHashTable *jit_icall_name_hash = NULL;
179
180 static MonoDebugOptions debug_options;
181
182 #ifdef VALGRIND_JIT_REGISTER_MAP
183 static int valgrind_register = 0;
184 #endif
185
186 /*
187  * Table written to by the debugger with a 1-based index into the
188  * mono_breakpoint_info table, which contains changes made to
189  * the JIT instructions by the debugger.
190  */
191 gssize
192 mono_breakpoint_info_index [MONO_BREAKPOINT_ARRAY_SIZE];
193
194 /* Whenever to check for pending exceptions in managed-to-native wrappers */
195 gboolean check_for_pending_exc = TRUE;
196
197 gboolean
198 mono_running_on_valgrind (void)
199 {
200 #ifdef HAVE_VALGRIND_MEMCHECK_H
201                 if (RUNNING_ON_VALGRIND){
202 #ifdef VALGRIND_JIT_REGISTER_MAP
203                         valgrind_register = TRUE;
204 #endif
205                         return TRUE;
206                 } else
207                         return FALSE;
208 #else
209                 return FALSE;
210 #endif
211 }
212
213 typedef struct {
214         void *ip;
215         MonoMethod *method;
216 } FindTrampUserData;
217
218 static void
219 find_tramp (gpointer key, gpointer value, gpointer user_data)
220 {
221         FindTrampUserData *ud = (FindTrampUserData*)user_data;
222
223         if (value == ud->ip)
224                 ud->method = (MonoMethod*)key;
225 }
226
227 /* debug function */
228 G_GNUC_UNUSED static char*
229 get_method_from_ip (void *ip)
230 {
231         MonoJitInfo *ji;
232         char *method;
233         char *res;
234         MonoDomain *domain = mono_domain_get ();
235         MonoDebugSourceLocation *location;
236         FindTrampUserData user_data;
237         
238         ji = mono_jit_info_table_find (domain, ip);
239         if (!ji) {
240                 user_data.ip = ip;
241                 user_data.method = NULL;
242                 mono_domain_lock (domain);
243                 g_hash_table_foreach (domain->jit_trampoline_hash, find_tramp, &user_data);
244                 mono_domain_unlock (domain);
245                 if (user_data.method) {
246                         char *mname = mono_method_full_name (user_data.method, TRUE);
247                         res = g_strdup_printf ("<%p - JIT trampoline for %s>", ip, mname);
248                         g_free (mname);
249                         return res;
250                 }
251                 else
252                         return NULL;
253         }
254         method = mono_method_full_name (ji->method, TRUE);
255         /* FIXME: unused ? */
256         location = mono_debug_lookup_source_location (ji->method, (guint32)((guint8*)ip - (guint8*)ji->code_start), domain);
257
258         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);
259
260         mono_debug_free_source_location (location);
261         g_free (method);
262
263         return res;
264 }
265
266 /** 
267  * mono_pmip:
268  * @ip: an instruction pointer address
269  *
270  * This method is used from a debugger to get the name of the
271  * method at address @ip.   This routine is typically invoked from
272  * a debugger like this:
273  *
274  * (gdb) print mono_pmip ($pc)
275  *
276  * Returns: the name of the method at address @ip.
277  */
278 G_GNUC_UNUSED char *
279 mono_pmip (void *ip)
280 {
281         return get_method_from_ip (ip);
282 }
283
284 /** 
285  * mono_print_method_from_ip
286  * @ip: an instruction pointer address
287  *
288  * This method is used from a debugger to get the name of the
289  * method at address @ip.
290  *
291  * This prints the name of the method at address @ip in the standard
292  * output.  Unlike mono_pmip which returns a string, this routine
293  * prints the value on the standard output. 
294  */
295 void
296 mono_print_method_from_ip (void *ip)
297 {
298         MonoJitInfo *ji;
299         char *method;
300         MonoDebugSourceLocation *source;
301         MonoDomain *domain = mono_domain_get ();
302         FindTrampUserData user_data;
303         
304         ji = mono_jit_info_table_find (domain, ip);
305         if (!ji) {
306                 user_data.ip = ip;
307                 user_data.method = NULL;
308                 mono_domain_lock (domain);
309                 g_hash_table_foreach (domain->jit_trampoline_hash, find_tramp, &user_data);
310                 mono_domain_unlock (domain);
311                 if (user_data.method) {
312                         char *mname = mono_method_full_name (user_data.method, TRUE);
313                         printf ("IP %p is a JIT trampoline for %s\n", ip, mname);
314                         g_free (mname);
315                 }
316                 else
317                         g_print ("No method at %p\n", ip);
318                 return;
319         }
320         method = mono_method_full_name (ji->method, TRUE);
321         source = mono_debug_lookup_source_location (ji->method, (guint32)((guint8*)ip - (guint8*)ji->code_start), domain);
322
323         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);
324
325         if (source)
326                 g_print ("%s:%d\n", source->source_file, source->row);
327
328         mono_debug_free_source_location (source);
329         g_free (method);
330 }
331         
332 /* 
333  * mono_method_same_domain:
334  *
335  * Determine whenever two compiled methods are in the same domain, thus
336  * the address of the callee can be embedded in the caller.
337  */
338 gboolean mono_method_same_domain (MonoJitInfo *caller, MonoJitInfo *callee)
339 {
340         if (!caller || !callee)
341                 return FALSE;
342
343         /*
344          * If the call was made from domain-neutral to domain-specific 
345          * code, we can't patch the call site.
346          */
347         if (caller->domain_neutral && !callee->domain_neutral)
348                 return FALSE;
349
350         if ((caller->method->klass == mono_defaults.appdomain_class) &&
351                 (strstr (caller->method->name, "InvokeInDomain"))) {
352                  /* The InvokeInDomain methods change the current appdomain */
353                 return FALSE;
354         }
355
356         return TRUE;
357 }
358
359 /*
360  * mono_global_codeman_reserve:
361  *
362  *  Allocate code memory from the global code manager.
363  */
364 void *mono_global_codeman_reserve (int size)
365 {
366         void *ptr;
367
368         if (!global_codeman) {
369                 /* This can happen during startup */
370                 global_codeman = mono_code_manager_new ();
371                 return mono_code_manager_reserve (global_codeman, size);
372         }
373         else {
374                 mono_jit_lock ();
375                 ptr = mono_code_manager_reserve (global_codeman, size);
376                 mono_jit_unlock ();
377                 return ptr;
378         }
379 }
380
381 MonoJumpInfoToken *
382 mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
383 {
384         MonoJumpInfoToken *res = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoToken));
385         res->image = image;
386         res->token = token;
387
388         return res;
389 }
390
391 #define MONO_INIT_VARINFO(vi,id) do { \
392         (vi)->range.first_use.pos.bid = 0xffff; \
393         (vi)->reg = -1; \
394         (vi)->idx = (id); \
395 } while (0)
396
397 //#define UNVERIFIED do { G_BREAKPOINT (); goto unverified; } while (0)
398 #define UNVERIFIED do { if (debug_options.break_on_unverified) G_BREAKPOINT (); else goto unverified; } while (0)
399
400 /*
401  * Basic blocks have two numeric identifiers:
402  * dfn: Depth First Number
403  * block_num: unique ID assigned at bblock creation
404  */
405 #define NEW_BBLOCK(cfg,new_bb) do {     \
406                 new_bb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock)); \
407                 MONO_INST_LIST_INIT (&new_bb->ins_list); \
408         } while (0)
409
410 #define ADD_BBLOCK(cfg,b) do {  \
411                 cfg->cil_offset_to_bb [(b)->cil_code - cfg->cil_start] = (b);   \
412                 (b)->block_num = cfg->num_bblocks++;    \
413                 (b)->real_offset = real_offset; \
414         } while (0)
415
416 #define GET_BBLOCK(cfg,tblock,ip) do {  \
417                 (tblock) = cfg->cil_offset_to_bb [(ip) - cfg->cil_start]; \
418                 if (!(tblock)) {        \
419                         if ((ip) >= end || (ip) < header->code) UNVERIFIED; \
420                         NEW_BBLOCK (cfg, (tblock));     \
421                         (tblock)->cil_code = (ip);      \
422                         ADD_BBLOCK (cfg, (tblock));     \
423                 } \
424         } while (0)
425
426 #define CHECK_BBLOCK(target,ip,tblock) do {     \
427                 if ((target) < (ip) && \
428                                 MONO_INST_LIST_EMPTY (&(tblock)->ins_list)) { \
429                         bb_recheck = g_list_prepend (bb_recheck, (tblock)); \
430                         if (cfg->verbose_level > 2) \
431                                 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)); \
432                 } \
433         } while (0)
434
435 #define NEW_ICONST(cfg,dest,val) do {   \
436                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
437                 (dest)->opcode = OP_ICONST;     \
438                 (dest)->inst_c0 = (val);        \
439                 (dest)->type = STACK_I4;        \
440         } while (0)
441
442 #define NEW_PCONST(cfg,dest,val) do {   \
443                 MONO_INST_NEW ((cfg), (dest), OP_PCONST);       \
444                 (dest)->inst_p0 = (val);        \
445                 (dest)->type = STACK_PTR;       \
446         } while (0)
447
448
449 #ifdef MONO_ARCH_NEED_GOT_VAR
450
451 #define NEW_PATCH_INFO(cfg,dest,el1,el2) do {   \
452                 MONO_INST_NEW ((cfg), (dest), OP_PATCH_INFO);   \
453                 (dest)->inst_left = (gpointer)(el1);    \
454                 (dest)->inst_right = (gpointer)(el2);   \
455         } while (0)
456
457 #define NEW_AOTCONST(cfg,dest,patch_type,cons) do {                     \
458                 MONO_INST_NEW ((cfg), (dest), OP_NOP); \
459                 (dest)->opcode = cfg->compile_aot ? OP_GOT_ENTRY : OP_PCONST; \
460                 if (cfg->compile_aot) {                                 \
461                         MonoInst *group, *got_var, *got_loc;            \
462                         got_loc = mono_get_got_var (cfg);               \
463                         NEW_TEMPLOAD ((cfg), got_var, got_loc->inst_c0); \
464                         NEW_PATCH_INFO ((cfg), group, cons, patch_type); \
465                         (dest)->inst_p0 = got_var;                      \
466                         (dest)->inst_p1 = group;                        \
467                 } else {                                                \
468                         (dest)->inst_p0 = (cons);                       \
469                         (dest)->inst_i1 = (gpointer)(patch_type);       \
470                 }                                                       \
471                 (dest)->type = STACK_PTR;                               \
472         } while (0)
473
474 #define NEW_AOTCONST_TOKEN(cfg,dest,patch_type,image,token,stack_type,stack_class) do { \
475                 MonoInst *group, *got_var, *got_loc;                    \
476                 MONO_INST_NEW ((cfg), (dest), OP_GOT_ENTRY); \
477                 got_loc = mono_get_got_var (cfg);                       \
478                 NEW_TEMPLOAD ((cfg), got_var, got_loc->inst_c0);        \
479                 NEW_PATCH_INFO ((cfg), group, NULL, patch_type);        \
480                 group->inst_p0 = mono_jump_info_token_new ((cfg)->mempool, (image), (token)); \
481                 (dest)->inst_p0 = got_var;                              \
482                 (dest)->inst_p1 = group;                                \
483                 (dest)->type = (stack_type);                    \
484         (dest)->klass = (stack_class);          \
485         } while (0)
486
487 #else
488
489 #define NEW_AOTCONST(cfg,dest,patch_type,cons) do {    \
490                 MONO_INST_NEW ((cfg), (dest), OP_NOP);  \
491                 (dest)->opcode = cfg->compile_aot ? OP_AOTCONST : OP_PCONST;    \
492                 (dest)->inst_p0 = (cons);       \
493                 (dest)->inst_i1 = (gpointer)(patch_type); \
494                 (dest)->type = STACK_PTR;       \
495     } while (0)
496
497 #define NEW_AOTCONST_TOKEN(cfg,dest,patch_type,image,token,stack_type,stack_class) do { \
498                 MONO_INST_NEW ((cfg), (dest), OP_AOTCONST);     \
499                 (dest)->inst_p0 = mono_jump_info_token_new ((cfg)->mempool, (image), (token));  \
500                 (dest)->inst_p1 = (gpointer)(patch_type); \
501                 (dest)->type = (stack_type);    \
502         (dest)->klass = (stack_class);          \
503     } while (0)
504
505 #endif
506
507 #define NEW_CLASSCONST(cfg,dest,val) NEW_AOTCONST ((cfg), (dest), MONO_PATCH_INFO_CLASS, (val))
508
509 #define NEW_IMAGECONST(cfg,dest,val) NEW_AOTCONST ((cfg), (dest), MONO_PATCH_INFO_IMAGE, (val))
510
511 #define NEW_FIELDCONST(cfg,dest,val) NEW_AOTCONST ((cfg), (dest), MONO_PATCH_INFO_FIELD, (val))
512
513 #define NEW_METHODCONST(cfg,dest,val) NEW_AOTCONST ((cfg), (dest), MONO_PATCH_INFO_METHODCONST, (val))
514
515 #define NEW_VTABLECONST(cfg,dest,vtable) NEW_AOTCONST ((cfg), (dest), MONO_PATCH_INFO_VTABLE, cfg->compile_aot ? (gpointer)((vtable)->klass) : (vtable))
516
517 #define NEW_SFLDACONST(cfg,dest,val) NEW_AOTCONST ((cfg), (dest), MONO_PATCH_INFO_SFLDA, (val))
518
519 #define NEW_LDSTRCONST(cfg,dest,image,token) NEW_AOTCONST_TOKEN ((cfg), (dest), MONO_PATCH_INFO_LDSTR, (image), (token), STACK_OBJ, mono_defaults.string_class)
520
521 #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)
522
523 #define NEW_LDTOKENCONST(cfg,dest,image,token) NEW_AOTCONST_TOKEN ((cfg), (dest), MONO_PATCH_INFO_LDTOKEN, (image), (token), STACK_PTR, NULL)
524
525 #define NEW_DECLSECCONST(cfg,dest,image,entry) do { \
526                 if (cfg->compile_aot) { \
527                         NEW_AOTCONST_TOKEN (cfg, dest, MONO_PATCH_INFO_DECLSEC, image, (entry).index, STACK_OBJ, NULL); \
528                 } else { \
529                         NEW_PCONST (cfg, args [0], (entry).blob); \
530                 } \
531         } while (0)
532
533 #define NEW_DOMAINCONST(cfg,dest) do { \
534                 if (cfg->opt & MONO_OPT_SHARED) { \
535                         /* avoid depending on undefined C behavior in sequence points */ \
536                         MonoInst* __domain_var = mono_get_domainvar (cfg); \
537                         NEW_TEMPLOAD (cfg, dest, __domain_var->inst_c0); \
538                 } else { \
539                         NEW_PCONST (cfg, dest, (cfg)->domain); \
540                 } \
541         } while (0)
542
543 #define GET_VARINFO_INST(cfg,num) ((cfg)->varinfo [(num)]->inst)
544
545 #define NEW_ARGLOAD(cfg,dest,num) do {  \
546                 if (arg_array [(num)]->opcode == OP_ICONST) (dest) = arg_array [(num)]; else { \
547                 MONO_INST_NEW ((cfg), (dest), OP_NOP);  \
548                 (dest)->ssa_op = MONO_SSA_LOAD; \
549                 (dest)->inst_i0 = arg_array [(num)];    \
550                 (dest)->opcode = mini_type_to_ldind ((cfg), (dest)->inst_i0->inst_vtype); \
551                 type_to_eval_stack_type ((cfg), param_types [(num)], (dest));   \
552                 (dest)->klass = (dest)->inst_i0->klass; \
553         }} while (0)
554
555 #define NEW_LOCLOAD(cfg,dest,num) do {  \
556                 MONO_INST_NEW ((cfg), (dest), OP_NOP);  \
557                 (dest)->ssa_op = MONO_SSA_LOAD; \
558                 (dest)->inst_i0 = (cfg)->varinfo [locals_offset + (num)];       \
559                 (dest)->opcode = mini_type_to_ldind ((cfg), (dest)->inst_i0->inst_vtype); \
560                 type_to_eval_stack_type ((cfg), header->locals [(num)], (dest));        \
561                 (dest)->klass = (dest)->inst_i0->klass; \
562         } while (0)
563
564 #define NEW_LOCLOADA(cfg,dest,num) do { \
565                 MONO_INST_NEW ((cfg), (dest), OP_LDADDR);       \
566                 (dest)->ssa_op = MONO_SSA_ADDRESS_TAKEN;        \
567                 (dest)->inst_i0 = (cfg)->varinfo [locals_offset + (num)];       \
568                 (dest)->inst_i0->flags |= MONO_INST_INDIRECT;   \
569                 (dest)->type = STACK_MP;        \
570                 (dest)->klass = (dest)->inst_i0->klass; \
571         if (!MONO_TYPE_ISSTRUCT (header->locals [(num)])) \
572            (cfg)->disable_ssa = TRUE; \
573         } while (0)
574
575 #define NEW_RETLOADA(cfg,dest) do {     \
576         if (cfg->vret_addr) { \
577                     MONO_INST_NEW ((cfg), (dest), OP_NOP);      \
578                     (dest)->ssa_op = MONO_SSA_LOAD;     \
579                     (dest)->inst_i0 = cfg->vret_addr; \
580                     (dest)->opcode = mini_type_to_ldind ((cfg), (dest)->inst_i0->inst_vtype); \
581             (dest)->type = STACK_MP; \
582                     (dest)->klass = (dest)->inst_i0->klass;     \
583         } else { \
584                         MONO_INST_NEW ((cfg), (dest), OP_NOP);  \
585                     (dest)->ssa_op = MONO_SSA_ADDRESS_TAKEN;    \
586                     (dest)->inst_i0 = (cfg)->ret;       \
587                     (dest)->inst_i0->flags |= MONO_INST_INDIRECT;       \
588                     (dest)->opcode = cfg->ret_var_is_local ? OP_LDADDR : CEE_LDIND_I;   \
589                     (dest)->type = STACK_MP;    \
590                     (dest)->klass = (dest)->inst_i0->klass;     \
591             (cfg)->disable_ssa = TRUE; \
592         } \
593         } while (0)
594
595 #define NEW_ARGLOADA(cfg,dest,num) do { \
596                 if (arg_array [(num)]->opcode == OP_ICONST) goto inline_failure; \
597                 MONO_INST_NEW ((cfg), (dest), OP_LDADDR);       \
598                 (dest)->ssa_op = MONO_SSA_ADDRESS_TAKEN;        \
599                 (dest)->inst_i0 = arg_array [(num)];    \
600                 (dest)->inst_i0->flags |= MONO_INST_INDIRECT;   \
601                 (dest)->type = STACK_MP;        \
602                 (dest)->klass = (dest)->inst_i0->klass; \
603                 (cfg)->disable_ssa = TRUE; \
604         } while (0)
605
606 #define NEW_TEMPLOAD(cfg,dest,num) do { \
607                 MONO_INST_NEW ((cfg), (dest), OP_NOP);  \
608                 (dest)->ssa_op = MONO_SSA_LOAD; \
609                 (dest)->inst_i0 = (cfg)->varinfo [(num)];       \
610                 (dest)->opcode = mini_type_to_ldind ((cfg), (dest)->inst_i0->inst_vtype); \
611                 type_to_eval_stack_type ((cfg), (dest)->inst_i0->inst_vtype, (dest));   \
612                 (dest)->klass = (dest)->inst_i0->klass; \
613         } while (0)
614
615 #define NEW_TEMPLOADA(cfg,dest,num) do {        \
616                 MONO_INST_NEW ((cfg), (dest), OP_LDADDR);       \
617                 (dest)->ssa_op = MONO_SSA_ADDRESS_TAKEN;        \
618                 (dest)->inst_i0 = (cfg)->varinfo [(num)];       \
619                 (dest)->inst_i0->flags |= MONO_INST_INDIRECT;   \
620                 (dest)->type = STACK_MP;        \
621                 (dest)->klass = (dest)->inst_i0->klass; \
622         if (!MONO_TYPE_ISSTRUCT (cfg->varinfo [(num)]->inst_vtype)) \
623            (cfg)->disable_ssa = TRUE; \
624         } while (0)
625
626
627 #define NEW_INDLOAD(cfg,dest,addr,vtype) do {   \
628                 MONO_INST_NEW ((cfg), (dest), OP_NOP);  \
629                 (dest)->inst_left = addr;       \
630                 (dest)->opcode = mini_type_to_ldind ((cfg), vtype);     \
631                 type_to_eval_stack_type ((cfg), vtype, (dest)); \
632                 /* FIXME: (dest)->klass = (dest)->inst_i0->klass;*/     \
633         } while (0)
634
635 #define NEW_INDSTORE(cfg,dest,addr,value,vtype) do {    \
636                 MONO_INST_NEW ((cfg), (dest), OP_NOP);  \
637                 (dest)->inst_i0 = addr; \
638                 (dest)->opcode = mini_type_to_stind ((cfg), vtype);     \
639                 (dest)->inst_i1 = (value);      \
640                 /* FIXME: (dest)->klass = (dest)->inst_i0->klass;*/     \
641         } while (0)
642
643 #define NEW_TEMPSTORE(cfg,dest,num,inst) do {   \
644                 MONO_INST_NEW ((cfg), (dest), OP_NOP);  \
645                 (dest)->ssa_op = MONO_SSA_STORE;        \
646                 (dest)->inst_i0 = (cfg)->varinfo [(num)];       \
647                 (dest)->opcode = mini_type_to_stind ((cfg), (dest)->inst_i0->inst_vtype); \
648                 (dest)->inst_i1 = (inst);       \
649                 (dest)->klass = (dest)->inst_i0->klass; \
650         } while (0)
651
652 #define NEW_LOCSTORE(cfg,dest,num,inst) do {    \
653                 MONO_INST_NEW ((cfg), (dest), OP_NOP);  \
654                 (dest)->opcode = mini_type_to_stind ((cfg), header->locals [(num)]); \
655                 (dest)->ssa_op = MONO_SSA_STORE;        \
656                 (dest)->inst_i0 = (cfg)->varinfo [locals_offset + (num)];       \
657                 (dest)->inst_i1 = (inst);       \
658                 (dest)->klass = (dest)->inst_i0->klass; \
659         } while (0)
660
661 #define NEW_ARGSTORE(cfg,dest,num,inst) do {    \
662                 if (arg_array [(num)]->opcode == OP_ICONST) goto inline_failure; \
663                 MONO_INST_NEW ((cfg), (dest), OP_NOP);  \
664                 (dest)->opcode = mini_type_to_stind ((cfg), param_types [(num)]); \
665                 (dest)->ssa_op = MONO_SSA_STORE;        \
666                 (dest)->inst_i0 = arg_array [(num)];    \
667                 (dest)->inst_i1 = (inst);       \
668                 (dest)->klass = (dest)->inst_i0->klass; \
669         } while (0)
670
671 #define NEW_MEMCPY(cfg,dest,dst,src,memcpy_size,memcpy_align) do { \
672                 MONO_INST_NEW (cfg, dest, OP_MEMCPY); \
673         (dest)->inst_left = (dst); \
674                 (dest)->inst_right = (src); \
675                 (dest)->cil_code = ip; \
676         (dest)->backend.memcpy_args = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoMemcpyArgs)); \
677                 (dest)->backend.memcpy_args->size = (memcpy_size); \
678                 (dest)->backend.memcpy_args->align = (memcpy_align); \
679     } while (0)
680
681 #define NEW_MEMSET(cfg,dest,dst,imm,memcpy_size,memcpy_align) do { \
682                 MONO_INST_NEW (cfg, dest, OP_MEMSET); \
683         (dest)->inst_left = (dst); \
684                 (dest)->inst_imm = (imm); \
685                 (dest)->cil_code = ip; \
686         (dest)->backend.memcpy_args = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoMemcpyArgs)); \
687                 (dest)->backend.memcpy_args->size = (memcpy_size); \
688                 (dest)->backend.memcpy_args->align = (memcpy_align); \
689     } while (0)
690
691 #define NEW_DUMMY_USE(cfg,dest,load) do { \
692                 MONO_INST_NEW ((cfg), (dest), OP_DUMMY_USE);    \
693                 (dest)->inst_left = (load); \
694     } while (0)
695
696 #define NEW_DUMMY_STORE(cfg,dest,num) do { \
697                 MONO_INST_NEW ((cfg), (dest), OP_DUMMY_STORE);  \
698                 (dest)->inst_i0 = (cfg)->varinfo [(num)];       \
699                 (dest)->klass = (dest)->inst_i0->klass; \
700         } while (0)
701
702 #define ADD_BINOP(op) do {      \
703                 MONO_INST_NEW (cfg, ins, (op)); \
704                 ins->cil_code = ip;     \
705                 sp -= 2;        \
706                 ins->inst_i0 = sp [0];  \
707                 ins->inst_i1 = sp [1];  \
708                 *sp++ = ins;    \
709                 type_from_op (ins);     \
710                 CHECK_TYPE (ins);       \
711         } while (0)
712
713 #define ADD_UNOP(op) do {       \
714                 MONO_INST_NEW (cfg, ins, (op)); \
715                 ins->cil_code = ip;     \
716                 sp--;   \
717                 ins->inst_i0 = sp [0];  \
718                 *sp++ = ins;    \
719                 type_from_op (ins);     \
720                 CHECK_TYPE (ins);       \
721         } while (0)
722
723 #define ADD_BINCOND(next_block) do {    \
724                 MonoInst *cmp;  \
725                 sp -= 2;                \
726                 MONO_INST_NEW(cfg, cmp, OP_COMPARE);    \
727                 cmp->inst_i0 = sp [0];  \
728                 cmp->inst_i1 = sp [1];  \
729                 cmp->cil_code = ins->cil_code;  \
730                 type_from_op (cmp);     \
731                 CHECK_TYPE (cmp);       \
732                 ins->inst_i0 = cmp;     \
733                 MONO_ADD_INS (bblock, ins);     \
734                 ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);      \
735                 GET_BBLOCK (cfg, tblock, target);               \
736                 link_bblock (cfg, bblock, tblock);      \
737                 ins->inst_true_bb = tblock;     \
738                 CHECK_BBLOCK (target, ip, tblock);      \
739                 if ((next_block)) {     \
740                         link_bblock (cfg, bblock, (next_block));        \
741                         ins->inst_false_bb = (next_block);      \
742                         start_new_bblock = 1;   \
743                 } else {        \
744                         GET_BBLOCK (cfg, tblock, ip);           \
745                         link_bblock (cfg, bblock, tblock);      \
746                         ins->inst_false_bb = tblock;    \
747                         start_new_bblock = 2;   \
748                 }       \
749         } while (0)
750
751 /* FIXME: handle float, long ... */
752 #define ADD_UNCOND(istrue) do { \
753                 MonoInst *cmp;  \
754                 sp--;           \
755                 MONO_INST_NEW(cfg, cmp, OP_COMPARE);    \
756                 cmp->inst_i0 = sp [0];  \
757                 switch (cmp->inst_i0->type) { \
758                 case STACK_I8: \
759                         cmp->inst_i1 = zero_int64; break; \
760                 case STACK_R8: \
761                         cmp->inst_i1 = zero_r8; break; \
762                 case STACK_PTR: \
763                 case STACK_MP: \
764                         cmp->inst_i1 = zero_ptr; break; \
765                 case STACK_OBJ: \
766                         cmp->inst_i1 = zero_obj; break; \
767                 default: \
768                         cmp->inst_i1 = zero_int32;  \
769                 }  \
770                 cmp->cil_code = ins->cil_code;  \
771                 type_from_op (cmp);     \
772                 CHECK_TYPE (cmp);       \
773                 ins->inst_i0 = cmp;     \
774                 ins->opcode = (istrue)? CEE_BNE_UN: CEE_BEQ;    \
775                 MONO_ADD_INS (bblock, ins);     \
776                 ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);      \
777                 GET_BBLOCK (cfg, tblock, target);               \
778                 link_bblock (cfg, bblock, tblock);      \
779                 ins->inst_true_bb = tblock;     \
780                 CHECK_BBLOCK (target, ip, tblock);      \
781                 GET_BBLOCK (cfg, tblock, ip);           \
782                 link_bblock (cfg, bblock, tblock);      \
783                 ins->inst_false_bb = tblock;    \
784                 start_new_bblock = 2;   \
785         } while (0)
786
787 #define NEW_LDELEMA(cfg,dest,sp,k) do { \
788                 MONO_INST_NEW ((cfg), (dest), CEE_LDELEMA);     \
789                 (dest)->inst_left = (sp) [0];   \
790                 (dest)->inst_right = (sp) [1];  \
791                 (dest)->type = STACK_MP;        \
792                 (dest)->klass = (k);    \
793                 (cfg)->flags |= MONO_CFG_HAS_LDELEMA; \
794         } while (0)
795
796 #define NEW_GROUP(cfg,dest,el1,el2) do {        \
797                 MONO_INST_NEW ((cfg), (dest), OP_GROUP);        \
798                 (dest)->inst_left = (el1);      \
799                 (dest)->inst_right = (el2);     \
800         } while (0)
801
802 #if 0
803 static gint
804 compare_bblock (gconstpointer a, gconstpointer b)
805 {
806         const MonoBasicBlock *b1 = a;
807         const MonoBasicBlock *b2 = b;
808
809         return b2->cil_code - b1->cil_code;
810 }
811 #endif
812
813 /* *
814  * link_bblock: Links two basic blocks
815  *
816  * links two basic blocks in the control flow graph, the 'from'
817  * argument is the starting block and the 'to' argument is the block
818  * the control flow ends to after 'from'.
819  */
820 static void
821 link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
822 {
823         MonoBasicBlock **newa;
824         int i, found;
825
826 #if 0
827         if (from->cil_code) {
828                 if (to->cil_code)
829                         g_print ("edge from IL%04x to IL_%04x\n", from->cil_code - cfg->cil_code, to->cil_code - cfg->cil_code);
830                 else
831                         g_print ("edge from IL%04x to exit\n", from->cil_code - cfg->cil_code);
832         } else {
833                 if (to->cil_code)
834                         g_print ("edge from entry to IL_%04x\n", to->cil_code - cfg->cil_code);
835                 else
836                         g_print ("edge from entry to exit\n");
837         }
838 #endif
839         found = FALSE;
840         for (i = 0; i < from->out_count; ++i) {
841                 if (to == from->out_bb [i]) {
842                         found = TRUE;
843                         break;
844                 }
845         }
846         if (!found) {
847                 newa = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (from->out_count + 1));
848                 for (i = 0; i < from->out_count; ++i) {
849                         newa [i] = from->out_bb [i];
850                 }
851                 newa [i] = to;
852                 from->out_count++;
853                 from->out_bb = newa;
854         }
855
856         found = FALSE;
857         for (i = 0; i < to->in_count; ++i) {
858                 if (from == to->in_bb [i]) {
859                         found = TRUE;
860                         break;
861                 }
862         }
863         if (!found) {
864                 newa = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (to->in_count + 1));
865                 for (i = 0; i < to->in_count; ++i) {
866                         newa [i] = to->in_bb [i];
867                 }
868                 newa [i] = from;
869                 to->in_count++;
870                 to->in_bb = newa;
871         }
872 }
873
874 /**
875  * mono_unlink_bblock:
876  *
877  *   Unlink two basic blocks.
878  */
879 static void
880 mono_unlink_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
881 {
882         int i, pos;
883         gboolean found;
884
885         found = FALSE;
886         for (i = 0; i < from->out_count; ++i) {
887                 if (to == from->out_bb [i]) {
888                         found = TRUE;
889                         break;
890                 }
891         }
892         if (found) {
893                 pos = 0;
894                 for (i = 0; i < from->out_count; ++i) {
895                         if (from->out_bb [i] != to)
896                                 from->out_bb [pos ++] = from->out_bb [i];
897                 }
898                 g_assert (pos == from->out_count - 1);
899                 from->out_count--;
900         }
901
902         found = FALSE;
903         for (i = 0; i < to->in_count; ++i) {
904                 if (from == to->in_bb [i]) {
905                         found = TRUE;
906                         break;
907                 }
908         }
909         if (found) {
910                 pos = 0;
911                 for (i = 0; i < to->in_count; ++i) {
912                         if (to->in_bb [i] != from)
913                                 to->in_bb [pos ++] = to->in_bb [i];
914                 }
915                 g_assert (pos == to->in_count - 1);
916                 to->in_count--;
917         }
918 }
919
920 /**
921  * mono_find_block_region:
922  *
923  *   We mark each basic block with a region ID. We use that to avoid BB
924  *   optimizations when blocks are in different regions.
925  *
926  * Returns:
927  *   A region token that encodes where this region is, and information
928  *   about the clause owner for this block.
929  *
930  *   The region encodes the try/catch/filter clause that owns this block
931  *   as well as the type.  -1 is a special value that represents a block
932  *   that is in none of try/catch/filter.
933  */
934 static int
935 mono_find_block_region (MonoCompile *cfg, int offset)
936 {
937         MonoMethod *method = cfg->method;
938         MonoMethodHeader *header = mono_method_get_header (method);
939         MonoExceptionClause *clause;
940         int i;
941
942         /* first search for handlers and filters */
943         for (i = 0; i < header->num_clauses; ++i) {
944                 clause = &header->clauses [i];
945                 if ((clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) && (offset >= clause->data.filter_offset) &&
946                     (offset < (clause->handler_offset)))
947                         return ((i + 1) << 8) | MONO_REGION_FILTER | clause->flags;
948                            
949                 if (MONO_OFFSET_IN_HANDLER (clause, offset)) {
950                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY)
951                                 return ((i + 1) << 8) | MONO_REGION_FINALLY | clause->flags;
952                         else if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
953                                 return ((i + 1) << 8) | MONO_REGION_FAULT | clause->flags;
954                         else if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE)
955                                 return ((i + 1) << 8) | MONO_REGION_CATCH | clause->flags;
956                 }
957         }
958
959         /* search the try blocks */
960         for (i = 0; i < header->num_clauses; ++i) {
961                 clause = &header->clauses [i];
962                 if (MONO_OFFSET_IN_CLAUSE (clause, offset))
963                         return ((i + 1) << 8) | clause->flags;
964         }
965
966         return -1;
967 }
968
969 static GList*
970 mono_find_final_block (MonoCompile *cfg, unsigned char *ip, unsigned char *target, int type)
971 {
972         MonoMethod *method = cfg->method;
973         MonoMethodHeader *header = mono_method_get_header (method);
974         MonoExceptionClause *clause;
975         MonoBasicBlock *handler;
976         int i;
977         GList *res = NULL;
978
979         for (i = 0; i < header->num_clauses; ++i) {
980                 clause = &header->clauses [i];
981                 if (MONO_OFFSET_IN_CLAUSE (clause, (ip - header->code)) && 
982                     (!MONO_OFFSET_IN_CLAUSE (clause, (target - header->code)))) {
983                         if (clause->flags == type) {
984                                 handler = cfg->cil_offset_to_bb [clause->handler_offset];
985                                 g_assert (handler);
986                                 res = g_list_append (res, handler);
987                         }
988                 }
989         }
990         return res;
991 }
992
993 MonoInst *
994 mono_find_spvar_for_region (MonoCompile *cfg, int region)
995 {
996         return g_hash_table_lookup (cfg->spvars, GINT_TO_POINTER (region));
997 }
998
999 static void
1000 mono_create_spvar_for_region (MonoCompile *cfg, int region)
1001 {
1002         MonoInst *var;
1003
1004         var = g_hash_table_lookup (cfg->spvars, GINT_TO_POINTER (region));
1005         if (var)
1006                 return;
1007
1008         var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1009         /* prevent it from being register allocated */
1010         var->flags |= MONO_INST_INDIRECT;
1011
1012         g_hash_table_insert (cfg->spvars, GINT_TO_POINTER (region), var);
1013 }
1014
1015 static MonoInst *
1016 mono_find_exvar_for_offset (MonoCompile *cfg, int offset)
1017 {
1018         return g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
1019 }
1020
1021 static MonoInst*
1022 mono_create_exvar_for_offset (MonoCompile *cfg, int offset)
1023 {
1024         MonoInst *var;
1025
1026         var = g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
1027         if (var)
1028                 return var;
1029
1030         var = mono_compile_create_var (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL);
1031         /* prevent it from being register allocated */
1032         var->flags |= MONO_INST_INDIRECT;
1033
1034         g_hash_table_insert (cfg->exvars, GINT_TO_POINTER (offset), var);
1035
1036         return var;
1037 }
1038
1039 static void
1040 df_visit (MonoBasicBlock *start, int *dfn, MonoBasicBlock **array)
1041 {
1042         int i;
1043
1044         array [*dfn] = start;
1045         /*g_print ("visit %d at %p (BB%ld)\n", *dfn, start->cil_code, start->block_num);*/
1046         for (i = 0; i < start->out_count; ++i) {
1047                 if (start->out_bb [i]->dfn)
1048                         continue;
1049                 (*dfn)++;
1050                 start->out_bb [i]->dfn = *dfn;
1051                 start->out_bb [i]->df_parent = start;
1052                 array [*dfn] = start->out_bb [i];
1053                 df_visit (start->out_bb [i], dfn, array);
1054         }
1055 }
1056
1057 static MonoBasicBlock*
1058 find_previous (MonoBasicBlock **bblocks, guint32 n_bblocks, MonoBasicBlock *start, const guchar *code)
1059 {
1060         MonoBasicBlock *best = start;
1061         int i;
1062
1063         for (i = 0; i < n_bblocks; ++i) {
1064                 if (bblocks [i]) {
1065                         MonoBasicBlock *bb = bblocks [i];
1066
1067                         if (bb->cil_code && bb->cil_code < code && bb->cil_code > best->cil_code)
1068                                 best = bb;
1069                 }
1070         }
1071
1072         return best;
1073 }
1074
1075 static void
1076 split_bblock (MonoCompile *cfg, MonoBasicBlock *first, MonoBasicBlock *second) {
1077         int i, j;
1078         MonoInst *inst;
1079         MonoBasicBlock *bb;
1080
1081         if (!MONO_INST_LIST_EMPTY (&second->ins_list))
1082                 return;
1083         
1084         /* 
1085          * FIXME: take into account all the details:
1086          * second may have been the target of more than one bblock
1087          */
1088         second->out_count = first->out_count;
1089         second->out_bb = first->out_bb;
1090
1091         for (i = 0; i < first->out_count; ++i) {
1092                 bb = first->out_bb [i];
1093                 for (j = 0; j < bb->in_count; ++j) {
1094                         if (bb->in_bb [j] == first)
1095                                 bb->in_bb [j] = second;
1096                 }
1097         }
1098
1099         first->out_count = 0;
1100         first->out_bb = NULL;
1101         link_bblock (cfg, first, second);
1102
1103         /*g_print ("start search at %p for %p\n", first->cil_code, second->cil_code);*/
1104         MONO_BB_FOR_EACH_INS (first, inst) {
1105                 MonoInst *inst_next;
1106
1107                 /*char *code = mono_disasm_code_one (NULL, cfg->method, inst->next->cil_code, NULL);
1108                 g_print ("found %p: %s", inst->next->cil_code, code);
1109                 g_free (code);*/
1110                 if (inst->cil_code >= second->cil_code)
1111                         continue;
1112
1113                 inst_next = mono_inst_list_next (&inst->node, &first->ins_list);
1114                 if (!inst_next)
1115                         break;
1116
1117                 if (inst_next->cil_code < second->cil_code)
1118                         continue;
1119                         
1120                 second->ins_list.next = inst->node.next;
1121                 second->ins_list.prev = first->ins_list.prev;
1122                 inst->node.next = &first->ins_list;
1123                 first->ins_list.prev = &inst->node;
1124
1125                 second->next_bb = first->next_bb;
1126                 first->next_bb = second;
1127                 return;
1128         }
1129         if (MONO_INST_LIST_EMPTY (&second->ins_list)) {
1130                 g_warning ("bblock split failed in %s::%s\n", cfg->method->klass->name, cfg->method->name);
1131                 //G_BREAKPOINT ();
1132         }
1133 }
1134
1135 static guint32
1136 reverse_branch_op (guint32 opcode)
1137 {
1138         static const int reverse_map [] = {
1139                 CEE_BNE_UN, CEE_BLT, CEE_BLE, CEE_BGT, CEE_BGE,
1140                 CEE_BEQ, CEE_BLT_UN, CEE_BLE_UN, CEE_BGT_UN, CEE_BGE_UN
1141         };
1142         static const int reverse_fmap [] = {
1143                 OP_FBNE_UN, OP_FBLT, OP_FBLE, OP_FBGT, OP_FBGE,
1144                 OP_FBEQ, OP_FBLT_UN, OP_FBLE_UN, OP_FBGT_UN, OP_FBGE_UN
1145         };
1146         static const int reverse_lmap [] = {
1147                 OP_LBNE_UN, OP_LBLT, OP_LBLE, OP_LBGT, OP_LBGE,
1148                 OP_LBEQ, OP_LBLT_UN, OP_LBLE_UN, OP_LBGT_UN, OP_LBGE_UN
1149         };
1150         static const int reverse_imap [] = {
1151                 OP_IBNE_UN, OP_IBLT, OP_IBLE, OP_IBGT, OP_IBGE,
1152                 OP_IBEQ, OP_IBLT_UN, OP_IBLE_UN, OP_IBGT_UN, OP_IBGE_UN
1153         };
1154                                 
1155         if (opcode >= CEE_BEQ && opcode <= CEE_BLT_UN) {
1156                 opcode = reverse_map [opcode - CEE_BEQ];
1157         } else if (opcode >= OP_FBEQ && opcode <= OP_FBLT_UN) {
1158                 opcode = reverse_fmap [opcode - OP_FBEQ];
1159         } else if (opcode >= OP_LBEQ && opcode <= OP_LBLT_UN) {
1160                 opcode = reverse_lmap [opcode - OP_LBEQ];
1161         } else if (opcode >= OP_IBEQ && opcode <= OP_IBLT_UN) {
1162                 opcode = reverse_imap [opcode - OP_IBEQ];
1163         } else
1164                 g_assert_not_reached ();
1165
1166         return opcode;
1167 }
1168
1169 #ifdef MONO_ARCH_SOFT_FLOAT
1170 static int
1171 condbr_to_fp_br (int opcode)
1172 {
1173         switch (opcode) {
1174         case CEE_BEQ: return OP_FBEQ;
1175         case CEE_BGE: return OP_FBGE;
1176         case CEE_BGT: return OP_FBGT;
1177         case CEE_BLE: return OP_FBLE;
1178         case CEE_BLT: return OP_FBLT;
1179         case CEE_BNE_UN: return OP_FBNE_UN;
1180         case CEE_BGE_UN: return OP_FBGE_UN;
1181         case CEE_BGT_UN: return OP_FBGT_UN;
1182         case CEE_BLE_UN: return OP_FBLE_UN;
1183         case CEE_BLT_UN: return OP_FBLT_UN;
1184         }
1185         g_assert_not_reached ();
1186         return 0;
1187 }
1188 #endif
1189
1190 /*
1191  * Returns the type used in the eval stack when @type is loaded.
1192  * FIXME: return a MonoType/MonoClass for the byref and VALUETYPE cases.
1193  */
1194 static void
1195 type_to_eval_stack_type (MonoCompile *cfg, MonoType *type, MonoInst *inst)
1196 {
1197         MonoClass *klass;
1198
1199         inst->klass = klass = mono_class_from_mono_type (type);
1200         if (type->byref) {
1201                 inst->type = STACK_MP;
1202                 return;
1203         }
1204
1205 handle_enum:
1206         switch (type->type) {
1207         case MONO_TYPE_VOID:
1208                 inst->type = STACK_INV;
1209                 return;
1210         case MONO_TYPE_I1:
1211         case MONO_TYPE_U1:
1212         case MONO_TYPE_BOOLEAN:
1213         case MONO_TYPE_I2:
1214         case MONO_TYPE_U2:
1215         case MONO_TYPE_CHAR:
1216         case MONO_TYPE_I4:
1217         case MONO_TYPE_U4:
1218                 inst->type = STACK_I4;
1219                 return;
1220         case MONO_TYPE_I:
1221         case MONO_TYPE_U:
1222         case MONO_TYPE_PTR:
1223         case MONO_TYPE_FNPTR:
1224                 inst->type = STACK_PTR;
1225                 return;
1226         case MONO_TYPE_CLASS:
1227         case MONO_TYPE_STRING:
1228         case MONO_TYPE_OBJECT:
1229         case MONO_TYPE_SZARRAY:
1230         case MONO_TYPE_ARRAY:    
1231                 inst->type = STACK_OBJ;
1232                 return;
1233         case MONO_TYPE_I8:
1234         case MONO_TYPE_U8:
1235                 inst->type = STACK_I8;
1236                 return;
1237         case MONO_TYPE_R4:
1238         case MONO_TYPE_R8:
1239                 inst->type = STACK_R8;
1240                 return;
1241         case MONO_TYPE_VALUETYPE:
1242                 if (type->data.klass->enumtype) {
1243                         type = type->data.klass->enum_basetype;
1244                         goto handle_enum;
1245                 } else {
1246                         inst->klass = klass;
1247                         inst->type = STACK_VTYPE;
1248                         return;
1249                 }
1250         case MONO_TYPE_TYPEDBYREF:
1251                 inst->klass = mono_defaults.typed_reference_class;
1252                 inst->type = STACK_VTYPE;
1253                 return;
1254         case MONO_TYPE_GENERICINST:
1255                 type = &type->data.generic_class->container_class->byval_arg;
1256                 goto handle_enum;
1257         case MONO_TYPE_VAR :
1258         case MONO_TYPE_MVAR :
1259                 /* FIXME: all the arguments must be references for now,
1260                  * later look inside cfg and see if the arg num is
1261                  * really a reference
1262                  */
1263                 g_assert (cfg->generic_sharing_context);
1264                 inst->type = STACK_OBJ;
1265                 return;
1266         default:
1267                 g_error ("unknown type 0x%02x in eval stack type", type->type);
1268         }
1269 }
1270
1271 /*
1272  * The following tables are used to quickly validate the IL code in type_from_op ().
1273  */
1274 static const char
1275 bin_num_table [STACK_MAX] [STACK_MAX] = {
1276         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1277         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
1278         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1279         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
1280         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_R8,  STACK_INV, STACK_INV, STACK_INV},
1281         {STACK_INV, STACK_MP,  STACK_INV, STACK_MP,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV},
1282         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1283         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
1284 };
1285
1286 static const char 
1287 neg_table [] = {
1288         STACK_INV, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_INV, STACK_INV, STACK_INV
1289 };
1290
1291 /* reduce the size of this table */
1292 static const char
1293 bin_int_table [STACK_MAX] [STACK_MAX] = {
1294         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1295         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1296         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1297         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1298         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1299         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1300         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1301         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
1302 };
1303
1304 static const char
1305 bin_comp_table [STACK_MAX] [STACK_MAX] = {
1306 /*      Inv i  L  p  F  &  O  vt */
1307         {0},
1308         {0, 1, 0, 1, 0, 0, 0, 0}, /* i, int32 */
1309         {0, 0, 1, 0, 0, 0, 0, 0}, /* L, int64 */
1310         {0, 1, 0, 1, 0, 2, 4, 0}, /* p, ptr */
1311         {0, 0, 0, 0, 1, 0, 0, 0}, /* F, R8 */
1312         {0, 0, 0, 2, 0, 1, 0, 0}, /* &, managed pointer */
1313         {0, 0, 0, 4, 0, 0, 3, 0}, /* O, reference */
1314         {0, 0, 0, 0, 0, 0, 0, 0}, /* vt value type */
1315 };
1316
1317 /* reduce the size of this table */
1318 static const char
1319 shift_table [STACK_MAX] [STACK_MAX] = {
1320         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1321         {STACK_INV, STACK_I4,  STACK_INV, STACK_I4,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1322         {STACK_INV, STACK_I8,  STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1323         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1324         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1325         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1326         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1327         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
1328 };
1329
1330 /*
1331  * Tables to map from the non-specific opcode to the matching
1332  * type-specific opcode.
1333  */
1334 /* handles from CEE_ADD to CEE_SHR_UN (CEE_REM_UN for floats) */
1335 static const guint16
1336 binops_op_map [STACK_MAX] = {
1337         0, 0, OP_LADD-CEE_ADD, OP_PADD-CEE_ADD, OP_FADD-CEE_ADD, OP_PADD-CEE_ADD
1338 };
1339
1340 /* handles from CEE_NEG to CEE_CONV_U8 */
1341 static const guint16
1342 unops_op_map [STACK_MAX] = {
1343         0, 0, OP_LNEG-CEE_NEG, OP_PNEG-CEE_NEG, OP_FNEG-CEE_NEG, OP_PNEG-CEE_NEG
1344 };
1345
1346 /* handles from CEE_CONV_U2 to CEE_SUB_OVF_UN */
1347 static const guint16
1348 ovfops_op_map [STACK_MAX] = {
1349         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
1350 };
1351
1352 /* handles from CEE_CONV_OVF_I1_UN to CEE_CONV_OVF_U_UN */
1353 static const guint16
1354 ovf2ops_op_map [STACK_MAX] = {
1355         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
1356 };
1357
1358 /* handles from CEE_CONV_OVF_I1 to CEE_CONV_OVF_U8 */
1359 static const guint16
1360 ovf3ops_op_map [STACK_MAX] = {
1361         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
1362 };
1363
1364 /* handles from CEE_CEQ to CEE_CLT_UN */
1365 static const guint16
1366 ceqops_op_map [STACK_MAX] = {
1367         0, 0, OP_LCEQ-OP_CEQ, OP_PCEQ-OP_CEQ, OP_FCEQ-OP_CEQ, OP_LCEQ-OP_CEQ
1368 };
1369
1370 /*
1371  * Sets ins->type (the type on the eval stack) according to the
1372  * type of the opcode and the arguments to it.
1373  * Invalid IL code is marked by setting ins->type to the invalid value STACK_INV.
1374  *
1375  * FIXME: this function sets ins->type unconditionally in some cases, but
1376  * it should set it to invalid for some types (a conv.x on an object)
1377  */
1378 static void
1379 type_from_op (MonoInst *ins) {
1380         switch (ins->opcode) {
1381         /* binops */
1382         case CEE_ADD:
1383         case CEE_SUB:
1384         case CEE_MUL:
1385         case CEE_DIV:
1386         case CEE_REM:
1387                 /* FIXME: check unverifiable args for STACK_MP */
1388                 ins->type = bin_num_table [ins->inst_i0->type] [ins->inst_i1->type];
1389                 ins->opcode += binops_op_map [ins->type];
1390                 return;
1391         case CEE_DIV_UN:
1392         case CEE_REM_UN:
1393         case CEE_AND:
1394         case CEE_OR:
1395         case CEE_XOR:
1396                 ins->type = bin_int_table [ins->inst_i0->type] [ins->inst_i1->type];
1397                 ins->opcode += binops_op_map [ins->type];
1398                 return;
1399         case CEE_SHL:
1400         case CEE_SHR:
1401         case CEE_SHR_UN:
1402                 ins->type = shift_table [ins->inst_i0->type] [ins->inst_i1->type];
1403                 ins->opcode += binops_op_map [ins->type];
1404                 return;
1405         case OP_COMPARE:
1406         case OP_LCOMPARE:
1407                 /* FIXME: handle some specifics with ins->next->type */
1408                 ins->type = bin_comp_table [ins->inst_i0->type] [ins->inst_i1->type] ? STACK_I4: STACK_INV;
1409                 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))))
1410                         ins->opcode = OP_LCOMPARE;
1411                 return;
1412         case OP_CEQ:
1413                 ins->type = bin_comp_table [ins->inst_i0->type] [ins->inst_i1->type] ? STACK_I4: STACK_INV;
1414                 ins->opcode += ceqops_op_map [ins->inst_i0->type];
1415                 return;
1416                 
1417         case OP_CGT:
1418         case OP_CGT_UN:
1419         case OP_CLT:
1420         case OP_CLT_UN:
1421                 ins->type = (bin_comp_table [ins->inst_i0->type] [ins->inst_i1->type] & 1) ? STACK_I4: STACK_INV;
1422                 ins->opcode += ceqops_op_map [ins->inst_i0->type];
1423                 return;
1424         /* unops */
1425         case CEE_NEG:
1426                 ins->type = neg_table [ins->inst_i0->type];
1427                 ins->opcode += unops_op_map [ins->type];
1428                 return;
1429         case CEE_NOT:
1430                 if (ins->inst_i0->type >= STACK_I4 && ins->inst_i0->type <= STACK_PTR)
1431                         ins->type = ins->inst_i0->type;
1432                 else
1433                         ins->type = STACK_INV;
1434                 ins->opcode += unops_op_map [ins->type];
1435                 return;
1436         case CEE_CONV_I1:
1437         case CEE_CONV_I2:
1438         case CEE_CONV_I4:
1439         case CEE_CONV_U4:
1440                 ins->type = STACK_I4;
1441                 ins->opcode += unops_op_map [ins->inst_i0->type];
1442                 return;
1443         case CEE_CONV_R_UN:
1444                 ins->type = STACK_R8;
1445                 switch (ins->inst_i0->type) {
1446                 case STACK_I4:
1447                 case STACK_PTR:
1448                         break;
1449                 case STACK_I8:
1450                         ins->opcode = OP_LCONV_TO_R_UN; 
1451                         break;
1452                 }
1453                 return;
1454         case CEE_CONV_OVF_I1:
1455         case CEE_CONV_OVF_U1:
1456         case CEE_CONV_OVF_I2:
1457         case CEE_CONV_OVF_U2:
1458         case CEE_CONV_OVF_I4:
1459         case CEE_CONV_OVF_U4:
1460                 ins->type = STACK_I4;
1461                 ins->opcode += ovf3ops_op_map [ins->inst_i0->type];
1462                 return;
1463         case CEE_CONV_OVF_I_UN:
1464         case CEE_CONV_OVF_U_UN:
1465                 ins->type = STACK_PTR;
1466                 ins->opcode += ovf2ops_op_map [ins->inst_i0->type];
1467                 return;
1468         case CEE_CONV_OVF_I1_UN:
1469         case CEE_CONV_OVF_I2_UN:
1470         case CEE_CONV_OVF_I4_UN:
1471         case CEE_CONV_OVF_U1_UN:
1472         case CEE_CONV_OVF_U2_UN:
1473         case CEE_CONV_OVF_U4_UN:
1474                 ins->type = STACK_I4;
1475                 ins->opcode += ovf2ops_op_map [ins->inst_i0->type];
1476                 return;
1477         case CEE_CONV_U:
1478                 ins->type = STACK_PTR;
1479                 switch (ins->inst_i0->type) {
1480                 case STACK_I4:
1481                         break;
1482                 case STACK_PTR:
1483                 case STACK_MP:
1484 #if SIZEOF_VOID_P == 8
1485                         ins->opcode = OP_LCONV_TO_U;
1486 #endif
1487                         break;
1488                 case STACK_I8:
1489                         ins->opcode = OP_LCONV_TO_U;
1490                         break;
1491                 case STACK_R8:
1492                         ins->opcode = OP_FCONV_TO_U;
1493                         break;
1494                 }
1495                 return;
1496         case CEE_CONV_I8:
1497         case CEE_CONV_U8:
1498                 ins->type = STACK_I8;
1499                 ins->opcode += unops_op_map [ins->inst_i0->type];
1500                 return;
1501         case CEE_CONV_OVF_I8:
1502         case CEE_CONV_OVF_U8:
1503                 ins->type = STACK_I8;
1504                 ins->opcode += ovf3ops_op_map [ins->inst_i0->type];
1505                 return;
1506         case CEE_CONV_OVF_U8_UN:
1507         case CEE_CONV_OVF_I8_UN:
1508                 ins->type = STACK_I8;
1509                 ins->opcode += ovf2ops_op_map [ins->inst_i0->type];
1510                 return;
1511         case CEE_CONV_R4:
1512         case CEE_CONV_R8:
1513                 ins->type = STACK_R8;
1514                 ins->opcode += unops_op_map [ins->inst_i0->type];
1515                 return;
1516         case OP_CKFINITE:
1517                 ins->type = STACK_R8;           
1518                 return;
1519         case CEE_CONV_U2:
1520         case CEE_CONV_U1:
1521                 ins->type = STACK_I4;
1522                 ins->opcode += ovfops_op_map [ins->inst_i0->type];
1523                 break;
1524         case CEE_CONV_I:
1525         case CEE_CONV_OVF_I:
1526         case CEE_CONV_OVF_U:
1527                 ins->type = STACK_PTR;
1528                 ins->opcode += ovfops_op_map [ins->inst_i0->type];
1529                 return;
1530         case CEE_ADD_OVF:
1531         case CEE_ADD_OVF_UN:
1532         case CEE_MUL_OVF:
1533         case CEE_MUL_OVF_UN:
1534         case CEE_SUB_OVF:
1535         case CEE_SUB_OVF_UN:
1536                 ins->type = bin_num_table [ins->inst_i0->type] [ins->inst_i1->type];
1537                 ins->opcode += ovfops_op_map [ins->inst_i0->type];
1538                 if (ins->type == STACK_R8)
1539                         ins->type = STACK_INV;
1540                 return;
1541         default:
1542                 g_error ("opcode 0x%04x not handled in type from op", ins->opcode);
1543                 break;
1544         }
1545 }
1546
1547 static const char 
1548 ldind_type [] = {
1549         STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_R8, STACK_OBJ
1550 };
1551
1552 /* map ldelem.x to the matching ldind.x opcode */
1553 static const guchar
1554 ldelem_to_ldind [] = {
1555         CEE_LDIND_I1,
1556         CEE_LDIND_U1,
1557         CEE_LDIND_I2,
1558         CEE_LDIND_U2,
1559         CEE_LDIND_I4,
1560         CEE_LDIND_U4,
1561         CEE_LDIND_I8,
1562         CEE_LDIND_I,
1563         CEE_LDIND_R4,
1564         CEE_LDIND_R8,
1565         CEE_LDIND_REF
1566 };
1567
1568 /* map stelem.x to the matching stind.x opcode */
1569 static const guchar
1570 stelem_to_stind [] = {
1571         CEE_STIND_I,
1572         CEE_STIND_I1,
1573         CEE_STIND_I2,
1574         CEE_STIND_I4,
1575         CEE_STIND_I8,
1576         CEE_STIND_R4,
1577         CEE_STIND_R8,
1578         CEE_STIND_REF
1579 };
1580
1581 #if 0
1582
1583 static const char
1584 param_table [STACK_MAX] [STACK_MAX] = {
1585         {0},
1586 };
1587
1588 static int
1589 check_values_to_signature (MonoInst *args, MonoType *this, MonoMethodSignature *sig)
1590 {
1591         int i;
1592
1593         if (sig->hasthis) {
1594                 switch (args->type) {
1595                 case STACK_I4:
1596                 case STACK_I8:
1597                 case STACK_R8:
1598                 case STACK_VTYPE:
1599                 case STACK_INV:
1600                         return 0;
1601                 }
1602                 args++;
1603         }
1604         for (i = 0; i < sig->param_count; ++i) {
1605                 switch (args [i].type) {
1606                 case STACK_INV:
1607                         return 0;
1608                 case STACK_MP:
1609                         if (!sig->params [i]->byref)
1610                                 return 0;
1611                         continue;
1612                 case STACK_OBJ:
1613                         if (sig->params [i]->byref)
1614                                 return 0;
1615                         switch (sig->params [i]->type) {
1616                         case MONO_TYPE_CLASS:
1617                         case MONO_TYPE_STRING:
1618                         case MONO_TYPE_OBJECT:
1619                         case MONO_TYPE_SZARRAY:
1620                         case MONO_TYPE_ARRAY:
1621                                 break;
1622                         default:
1623                                 return 0;
1624                         }
1625                         continue;
1626                 case STACK_R8:
1627                         if (sig->params [i]->byref)
1628                                 return 0;
1629                         if (sig->params [i]->type != MONO_TYPE_R4 && sig->params [i]->type != MONO_TYPE_R8)
1630                                 return 0;
1631                         continue;
1632                 case STACK_PTR:
1633                 case STACK_I4:
1634                 case STACK_I8:
1635                 case STACK_VTYPE:
1636                         break;
1637                 }
1638                 /*if (!param_table [args [i].type] [sig->params [i]->type])
1639                         return 0;*/
1640         }
1641         return 1;
1642 }
1643 #endif
1644
1645 static guint
1646 mini_type_to_ldind (MonoCompile* cfg, MonoType *type)
1647 {
1648         if (cfg->generic_sharing_context && !type->byref) {
1649                 /* FIXME: all the arguments must be references for now,
1650                  * later look inside cfg and see if the arg num is
1651                  * really a reference
1652                  */
1653                 if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)
1654                         return CEE_LDIND_REF;
1655         }
1656         return mono_type_to_ldind (type);
1657 }
1658
1659 static guint
1660 mini_type_to_stind (MonoCompile* cfg, MonoType *type)
1661 {
1662         if (cfg->generic_sharing_context && !type->byref) {
1663                 /* FIXME: all the arguments must be references for now,
1664                  * later look inside cfg and see if the arg num is
1665                  * really a reference
1666                  */
1667                 if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)
1668                         return CEE_STIND_REF;
1669         }
1670         return mono_type_to_stind (type);
1671 }
1672
1673 int
1674 mono_op_imm_to_op (int opcode)
1675 {
1676         switch (opcode) {
1677         case OP_ADD_IMM:
1678                 return OP_PADD;
1679         case OP_IADD_IMM:
1680                 return OP_IADD;
1681         case OP_LADD_IMM:
1682                 return OP_LADD;
1683         case OP_ISUB_IMM:
1684                 return OP_ISUB;
1685         case OP_LSUB_IMM:
1686                 return OP_LSUB;
1687         case OP_AND_IMM:
1688 #if SIZEOF_VOID_P == 4
1689                 return OP_IAND;
1690 #else
1691                 return OP_LAND;
1692 #endif
1693         case OP_IAND_IMM:
1694                 return OP_IAND;
1695         case OP_LAND_IMM:
1696                 return OP_LAND;
1697         case OP_IOR_IMM:
1698                 return OP_IOR;
1699         case OP_LOR_IMM:
1700                 return OP_LOR;
1701         case OP_IXOR_IMM:
1702                 return OP_IXOR;
1703         case OP_LXOR_IMM:
1704                 return OP_LXOR;
1705         case OP_ISHL_IMM:
1706                 return OP_ISHL;
1707         case OP_LSHL_IMM:
1708                 return OP_LSHL;
1709         case OP_ISHR_IMM:
1710                 return OP_ISHR;
1711         case OP_LSHR_IMM:
1712                 return OP_LSHR;
1713         case OP_ISHR_UN_IMM:
1714                 return OP_ISHR_UN;
1715         case OP_LSHR_UN_IMM:
1716                 return OP_LSHR_UN;
1717         case OP_IDIV_IMM:
1718                 return OP_IDIV;
1719         case OP_IDIV_UN_IMM:
1720                 return OP_IDIV_UN;
1721         case OP_IREM_UN_IMM:
1722                 return OP_IREM_UN;
1723         case OP_IREM_IMM:
1724                 return OP_IREM;
1725         case OP_DIV_IMM:
1726 #if SIZEOF_VOID_P == 4
1727                 return OP_IDIV;
1728 #else
1729                 return OP_LDIV;
1730 #endif
1731         case OP_REM_IMM:
1732 #if SIZEOF_VOID_P == 4
1733                 return OP_IREM;
1734 #else
1735                 return OP_LREM;
1736 #endif
1737         case OP_ADDCC_IMM:
1738                 return OP_ADDCC;
1739         case OP_ADC_IMM:
1740                 return OP_ADC;
1741         case OP_SUBCC_IMM:
1742                 return OP_SUBCC;
1743         case OP_SBB_IMM:
1744                 return OP_SBB;
1745         case OP_IADC_IMM:
1746                 return OP_IADC;
1747         case OP_ISBB_IMM:
1748                 return OP_ISBB;
1749         case OP_COMPARE_IMM:
1750                 return OP_COMPARE;
1751         case OP_ICOMPARE_IMM:
1752                 return OP_ICOMPARE;
1753         default:
1754                 printf ("%s\n", mono_inst_name (opcode));
1755                 g_assert_not_reached ();
1756         }
1757 }
1758
1759 /*
1760  * mono_decompose_op_imm:
1761  *
1762  *   Replace the OP_.._IMM INS with its non IMM variant.
1763  */
1764 void
1765 mono_decompose_op_imm (MonoCompile *cfg, MonoInst *ins)
1766 {
1767         MonoInst *temp;
1768
1769         MONO_INST_NEW (cfg, temp, OP_ICONST);
1770         temp->inst_c0 = ins->inst_imm;
1771         temp->dreg = mono_regstate_next_int (cfg->rs);
1772         MONO_INST_LIST_ADD_TAIL (&(temp)->node, &(ins)->node);
1773         ins->opcode = mono_op_imm_to_op (ins->opcode);
1774         ins->sreg2 = temp->dreg;
1775 }
1776
1777 /*
1778  * When we need a pointer to the current domain many times in a method, we
1779  * call mono_domain_get() once and we store the result in a local variable.
1780  * This function returns the variable that represents the MonoDomain*.
1781  */
1782 inline static MonoInst *
1783 mono_get_domainvar (MonoCompile *cfg)
1784 {
1785         if (!cfg->domainvar)
1786                 cfg->domainvar = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1787         return cfg->domainvar;
1788 }
1789
1790 /*
1791  * The got_var contains the address of the Global Offset Table when AOT 
1792  * compiling.
1793  */
1794 inline static MonoInst *
1795 mono_get_got_var (MonoCompile *cfg)
1796 {
1797 #ifdef MONO_ARCH_NEED_GOT_VAR
1798         if (!cfg->compile_aot)
1799                 return NULL;
1800         if (!cfg->got_var) {
1801                 cfg->got_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1802         }
1803         return cfg->got_var;
1804 #else
1805         return NULL;
1806 #endif
1807 }
1808
1809 static MonoInst *
1810 mono_get_rgctx_var (MonoCompile *cfg)
1811 {
1812         g_assert (cfg->generic_sharing_context);
1813
1814         if (!cfg->rgctx_var) {
1815                 cfg->rgctx_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1816                 /* force the var to be stack allocated */
1817                 cfg->rgctx_var->flags |= MONO_INST_INDIRECT;
1818         }
1819
1820         return cfg->rgctx_var;
1821 }
1822
1823 MonoInst*
1824 mono_compile_create_var (MonoCompile *cfg, MonoType *type, int opcode)
1825 {
1826         MonoInst *inst;
1827         int num = cfg->num_varinfo;
1828
1829         if ((num + 1) >= cfg->varinfo_count) {
1830                 int orig_count = cfg->varinfo_count;
1831                 cfg->varinfo_count = (cfg->varinfo_count + 2) * 2;
1832                 cfg->varinfo = (MonoInst **)g_realloc (cfg->varinfo, sizeof (MonoInst*) * cfg->varinfo_count);
1833                 cfg->vars = (MonoMethodVar *)g_realloc (cfg->vars, sizeof (MonoMethodVar) * cfg->varinfo_count);
1834                 memset (&cfg->vars [orig_count], 0, (cfg->varinfo_count - orig_count) * sizeof (MonoMethodVar));
1835         }
1836
1837         /*g_print ("created temp %d of type 0x%x\n", num, type->type);*/
1838         mono_jit_stats.allocate_var++;
1839
1840         MONO_INST_NEW (cfg, inst, opcode);
1841         inst->inst_c0 = num;
1842         inst->inst_vtype = type;
1843         inst->klass = mono_class_from_mono_type (type);
1844         /* if set to 1 the variable is native */
1845         inst->backend.is_pinvoke = 0;
1846
1847         cfg->varinfo [num] = inst;
1848
1849         MONO_INIT_VARINFO (&cfg->vars [num], num);
1850
1851         cfg->num_varinfo++;
1852         if (cfg->verbose_level > 2)
1853                 g_print ("created temp %d of type %s\n", num, mono_type_get_name (type));
1854         return inst;
1855 }
1856
1857 /*
1858  * Transform a MonoInst into a load from the variable of index var_index.
1859  */
1860 void
1861 mono_compile_make_var_load (MonoCompile *cfg, MonoInst *dest, gssize var_index) {
1862         memset (dest, 0, sizeof (MonoInst));
1863         dest->ssa_op = MONO_SSA_LOAD;
1864         dest->inst_i0 = cfg->varinfo [var_index];
1865         dest->opcode = mini_type_to_ldind (cfg, dest->inst_i0->inst_vtype);
1866         type_to_eval_stack_type (cfg, dest->inst_i0->inst_vtype, dest);
1867         dest->klass = dest->inst_i0->klass;
1868 }
1869
1870 /*
1871  * Create a MonoInst that is a load from the variable of index var_index.
1872  */
1873 MonoInst*
1874 mono_compile_create_var_load (MonoCompile *cfg, gssize var_index) {
1875         MonoInst *dest;
1876         NEW_TEMPLOAD (cfg,dest,var_index);
1877         return dest;
1878 }
1879
1880 /*
1881  * Create a MonoInst that is a store of the given value into the variable of index var_index.
1882  */
1883 MonoInst*
1884 mono_compile_create_var_store (MonoCompile *cfg, gssize var_index, MonoInst *value) {
1885         MonoInst *dest;
1886         NEW_TEMPSTORE (cfg, dest, var_index, value);
1887         return dest;
1888 }
1889
1890 static MonoType*
1891 type_from_stack_type (MonoInst *ins) {
1892         switch (ins->type) {
1893         case STACK_I4: return &mono_defaults.int32_class->byval_arg;
1894         case STACK_I8: return &mono_defaults.int64_class->byval_arg;
1895         case STACK_PTR: return &mono_defaults.int_class->byval_arg;
1896         case STACK_R8: return &mono_defaults.double_class->byval_arg;
1897         case STACK_MP:
1898                 /* 
1899                  * this if used to be commented without any specific reason, but
1900                  * it breaks #80235 when commented
1901                  */
1902                 if (ins->klass)
1903                         return &ins->klass->this_arg;
1904                 else
1905                         return &mono_defaults.object_class->this_arg;
1906         case STACK_OBJ:
1907                 /* ins->klass may not be set for ldnull.
1908                  * Also, if we have a boxed valuetype, we want an object lass,
1909                  * not the valuetype class
1910                  */
1911                 if (ins->klass && !ins->klass->valuetype)
1912                         return &ins->klass->byval_arg;
1913                 return &mono_defaults.object_class->byval_arg;
1914         case STACK_VTYPE: return &ins->klass->byval_arg;
1915         default:
1916                 g_error ("stack type %d to montype not handled\n", ins->type);
1917         }
1918         return NULL;
1919 }
1920
1921 MonoType*
1922 mono_type_from_stack_type (MonoInst *ins) {
1923         return type_from_stack_type (ins);
1924 }
1925
1926 static MonoClass*
1927 array_access_to_klass (int opcode, MonoInst *array_obj)
1928 {
1929         switch (opcode) {
1930         case CEE_LDELEM_U1:
1931                 return mono_defaults.byte_class;
1932         case CEE_LDELEM_U2:
1933                 return mono_defaults.uint16_class;
1934         case CEE_LDELEM_I:
1935         case CEE_STELEM_I:
1936                 return mono_defaults.int_class;
1937         case CEE_LDELEM_I1:
1938         case CEE_STELEM_I1:
1939                 return mono_defaults.sbyte_class;
1940         case CEE_LDELEM_I2:
1941         case CEE_STELEM_I2:
1942                 return mono_defaults.int16_class;
1943         case CEE_LDELEM_I4:
1944         case CEE_STELEM_I4:
1945                 return mono_defaults.int32_class;
1946         case CEE_LDELEM_U4:
1947                 return mono_defaults.uint32_class;
1948         case CEE_LDELEM_I8:
1949         case CEE_STELEM_I8:
1950                 return mono_defaults.int64_class;
1951         case CEE_LDELEM_R4:
1952         case CEE_STELEM_R4:
1953                 return mono_defaults.single_class;
1954         case CEE_LDELEM_R8:
1955         case CEE_STELEM_R8:
1956                 return mono_defaults.double_class;
1957         case CEE_LDELEM_REF:
1958         case CEE_STELEM_REF: {
1959                 MonoClass *klass = array_obj->klass;
1960                 /* FIXME: add assert */
1961                 if (klass && klass->rank)
1962                         return klass->element_class;
1963                 return mono_defaults.object_class;
1964         }
1965         default:
1966                 g_assert_not_reached ();
1967         }
1968         return NULL;
1969 }
1970
1971 void
1972 mono_add_ins_to_end (MonoBasicBlock *bb, MonoInst *inst)
1973 {
1974         MonoInst *last = mono_inst_list_last (&bb->ins_list);
1975
1976         if (last && ((last->opcode >= CEE_BEQ &&
1977                         last->opcode <= CEE_BLT_UN) ||
1978                         last->opcode == OP_BR ||
1979                         last->opcode == OP_SWITCH)) {
1980                 MONO_INST_LIST_ADD_TAIL (&inst->node, &last->node);
1981         } else {
1982                 MONO_ADD_INS (bb, inst);
1983         }
1984 }
1985
1986 void
1987 mono_add_varcopy_to_end (MonoCompile *cfg, MonoBasicBlock *bb, int src, int dest)
1988 {
1989         MonoInst *inst, *load;
1990
1991         NEW_TEMPLOAD (cfg, load, src);
1992
1993         NEW_TEMPSTORE (cfg, inst, dest, load);
1994         /* FIXME: handle CEE_STIND_R4 */
1995         if (inst->opcode == CEE_STOBJ) {
1996                 NEW_TEMPLOADA (cfg, inst, dest);
1997                 handle_stobj (cfg, bb, inst, load, NULL, inst->klass, TRUE, FALSE, FALSE);
1998         } else {
1999                 inst->cil_code = NULL;
2000                 mono_add_ins_to_end (bb, inst);
2001         }
2002 }
2003
2004 /*
2005  * This function is called to handle items that are left on the evaluation stack
2006  * at basic block boundaries. What happens is that we save the values to local variables
2007  * and we reload them later when first entering the target basic block (with the
2008  * handle_loaded_temps () function).
2009  * It is also used to handle items on the stack in store opcodes, since it is
2010  * possible that the variable to be stored into is already on the stack, in
2011  * which case its old value should be used.
2012  * A single joint point will use the same variables (stored in the array bb->out_stack or
2013  * bb->in_stack, if the basic block is before or after the joint point).
2014  * If the stack merge fails at a join point, cfg->unverifiable is set.
2015  */
2016 static void
2017 handle_stack_args (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst **sp, int count)
2018 {
2019         int i, bindex;
2020         MonoBasicBlock *outb;
2021         MonoInst *inst, **locals;
2022         gboolean found;
2023
2024         if (!count)
2025                 return;
2026         if (cfg->verbose_level > 3)
2027                 g_print ("%d item(s) on exit from B%d\n", count, bb->block_num);
2028
2029         if (!bb->out_scount) {
2030                 bb->out_scount = count;
2031                 //g_print ("bblock %d has out:", bb->block_num);
2032                 found = FALSE;
2033                 for (i = 0; i < bb->out_count; ++i) {
2034                         outb = bb->out_bb [i];
2035                         /* exception handlers are linked, but they should not be considered for stack args */
2036                         if (outb->flags & BB_EXCEPTION_HANDLER)
2037                                 continue;
2038                         //g_print (" %d", outb->block_num);
2039                         if (outb->in_stack) {
2040                                 found = TRUE;
2041                                 bb->out_stack = outb->in_stack;
2042                                 break;
2043                         }
2044                 }
2045                 //g_print ("\n");
2046                 if (!found) {
2047                         bb->out_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * count);
2048                         for (i = 0; i < count; ++i) {
2049                                 /* 
2050                                  * try to reuse temps already allocated for this purpouse, if they occupy the same
2051                                  * stack slot and if they are of the same type.
2052                                  * This won't cause conflicts since if 'local' is used to 
2053                                  * store one of the values in the in_stack of a bblock, then
2054                                  * the same variable will be used for the same outgoing stack 
2055                                  * slot as well. 
2056                                  * This doesn't work when inlining methods, since the bblocks
2057                                  * in the inlined methods do not inherit their in_stack from
2058                                  * the bblock they are inlined to. See bug #58863 for an
2059                                  * example.
2060                                  * This hack is disabled since it also prevents proper tracking of types.
2061                                  */
2062 #if 1
2063                                 bb->out_stack [i] = mono_compile_create_var (cfg, type_from_stack_type (sp [i]), OP_LOCAL);
2064 #else
2065                                 if (cfg->inlined_method)
2066                                         bb->out_stack [i] = mono_compile_create_var (cfg, type_from_stack_type (sp [i]), OP_LOCAL);
2067                                 else
2068                                         bb->out_stack [i] = mono_compile_get_interface_var (cfg, i, sp [i]);
2069 #endif
2070                         }
2071                 }
2072         }
2073
2074         for (i = 0; i < bb->out_count; ++i) {
2075                 outb = bb->out_bb [i];
2076                 /* exception handlers are linked, but they should not be considered for stack args */
2077                 if (outb->flags & BB_EXCEPTION_HANDLER)
2078                         continue;
2079                 if (outb->in_scount) {
2080                         if (outb->in_scount != bb->out_scount) {
2081                                 cfg->unverifiable = TRUE;
2082                                 return;
2083                         }
2084                         continue; /* check they are the same locals */
2085                 }
2086                 outb->in_scount = count;
2087                 outb->in_stack = bb->out_stack;
2088         }
2089
2090         locals = bb->out_stack;
2091         for (i = 0; i < count; ++i) {
2092                 /* add store ops at the end of the bb, before the branch */
2093                 NEW_TEMPSTORE (cfg, inst, locals [i]->inst_c0, sp [i]);
2094                 if (inst->opcode == CEE_STOBJ) {
2095                         NEW_TEMPLOADA (cfg, inst, locals [i]->inst_c0);
2096                         handle_stobj (cfg, bb, inst, sp [i], sp [i]->cil_code, inst->klass, TRUE, FALSE, FALSE);
2097                 } else {
2098                         inst->cil_code = sp [i]->cil_code;
2099                         mono_add_ins_to_end (bb, inst);
2100                 }
2101                 if (cfg->verbose_level > 3)
2102                         g_print ("storing %d to temp %d\n", i, (int)locals [i]->inst_c0);
2103         }
2104
2105         /*
2106          * It is possible that the out bblocks already have in_stack assigned, and
2107          * the in_stacks differ. In this case, we will store to all the different 
2108          * in_stacks.
2109          */
2110
2111         found = TRUE;
2112         bindex = 0;
2113         while (found) {
2114                 /* Find a bblock which has a different in_stack */
2115                 found = FALSE;
2116                 while (bindex < bb->out_count) {
2117                         outb = bb->out_bb [bindex];
2118                         /* exception handlers are linked, but they should not be considered for stack args */
2119                         if (outb->flags & BB_EXCEPTION_HANDLER) {
2120                                 bindex++;
2121                                 continue;
2122                         }
2123                         if (outb->in_stack != locals) {
2124                                 /* 
2125                                  * Instead of storing sp [i] to locals [i], we need to store
2126                                  * locals [i] to <new locals>[i], since the sp [i] tree can't
2127                                  * be shared between trees.
2128                                  */
2129                                 for (i = 0; i < count; ++i)
2130                                         mono_add_varcopy_to_end (cfg, bb, locals [i]->inst_c0, outb->in_stack [i]->inst_c0);
2131                                 locals = outb->in_stack;
2132                                 found = TRUE;
2133                                 break;
2134                         }
2135                         bindex ++;
2136                 }
2137         }
2138 }
2139
2140 static int
2141 ret_type_to_call_opcode (MonoType *type, int calli, int virt, MonoGenericSharingContext *gsctx)
2142 {
2143         if (type->byref)
2144                 return calli? OP_CALL_REG: virt? OP_CALLVIRT: OP_CALL;
2145
2146 handle_enum:
2147         type = mini_get_basic_type_from_generic (gsctx, type);
2148         switch (type->type) {
2149         case MONO_TYPE_VOID:
2150                 return calli? OP_VOIDCALL_REG: virt? OP_VOIDCALLVIRT: OP_VOIDCALL;
2151         case MONO_TYPE_I1:
2152         case MONO_TYPE_U1:
2153         case MONO_TYPE_BOOLEAN:
2154         case MONO_TYPE_I2:
2155         case MONO_TYPE_U2:
2156         case MONO_TYPE_CHAR:
2157         case MONO_TYPE_I4:
2158         case MONO_TYPE_U4:
2159                 return calli? OP_CALL_REG: virt? OP_CALLVIRT: OP_CALL;
2160         case MONO_TYPE_I:
2161         case MONO_TYPE_U:
2162         case MONO_TYPE_PTR:
2163         case MONO_TYPE_FNPTR:
2164                 return calli? OP_CALL_REG: virt? OP_CALLVIRT: OP_CALL;
2165         case MONO_TYPE_CLASS:
2166         case MONO_TYPE_STRING:
2167         case MONO_TYPE_OBJECT:
2168         case MONO_TYPE_SZARRAY:
2169         case MONO_TYPE_ARRAY:    
2170                 return calli? OP_CALL_REG: virt? OP_CALLVIRT: OP_CALL;
2171         case MONO_TYPE_I8:
2172         case MONO_TYPE_U8:
2173                 return calli? OP_LCALL_REG: virt? OP_LCALLVIRT: OP_LCALL;
2174         case MONO_TYPE_R4:
2175         case MONO_TYPE_R8:
2176                 return calli? OP_FCALL_REG: virt? OP_FCALLVIRT: OP_FCALL;
2177         case MONO_TYPE_VALUETYPE:
2178                 if (type->data.klass->enumtype) {
2179                         type = type->data.klass->enum_basetype;
2180                         goto handle_enum;
2181                 } else
2182                         return calli? OP_VCALL_REG: virt? OP_VCALLVIRT: OP_VCALL;
2183         case MONO_TYPE_TYPEDBYREF:
2184                 return calli? OP_VCALL_REG: virt? OP_VCALLVIRT: OP_VCALL;
2185         case MONO_TYPE_GENERICINST:
2186                 type = &type->data.generic_class->container_class->byval_arg;
2187                 goto handle_enum;
2188         default:
2189                 g_error ("unknown type 0x%02x in ret_type_to_call_opcode", type->type);
2190         }
2191         return -1;
2192 }
2193
2194 void
2195 mono_create_jump_table (MonoCompile *cfg, MonoInst *label, MonoBasicBlock **bbs, int num_blocks)
2196 {
2197         MonoJumpInfo *ji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo));
2198         MonoJumpInfoBBTable *table;
2199
2200         table = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfoBBTable));
2201         table->table = bbs;
2202         table->table_size = num_blocks;
2203         
2204         ji->ip.label = label;
2205         ji->type = MONO_PATCH_INFO_SWITCH;
2206         ji->data.table = table;
2207         ji->next = cfg->patch_info;
2208         cfg->patch_info = ji;
2209 }
2210
2211 static void
2212 mono_save_token_info (MonoCompile *cfg, MonoImage *image, guint32 token, gpointer key)
2213 {
2214         if (cfg->compile_aot) {
2215                 MonoJumpInfoToken *jump_info_token = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoToken));
2216                 jump_info_token->image = image;
2217                 jump_info_token->token = token;
2218                 g_hash_table_insert (cfg->token_info_hash, key, jump_info_token);
2219         }
2220 }
2221
2222 /*
2223  * When we add a tree of instructions, we need to ensure the instructions currently
2224  * on the stack are executed before (like, if we load a value from a local).
2225  * We ensure this by saving the currently loaded values to temps and rewriting the
2226  * instructions to load the values.
2227  * This is not done for opcodes that terminate a basic block (because it's handled already
2228  * by handle_stack_args ()) and for opcodes that can't change values, like POP.
2229  */
2230 static void
2231 handle_loaded_temps (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst **stack, MonoInst **sp)
2232 {
2233         MonoInst *load, *store, *temp, *ins;
2234
2235         while (stack < sp) {
2236                 ins = *stack;
2237                 /* handle also other constants */
2238                 if ((ins->opcode != OP_ICONST) &&
2239                     /* temps never get written to again, so we can safely avoid duplicating them */
2240                     !(ins->ssa_op == MONO_SSA_LOAD && ins->inst_i0->opcode == OP_LOCAL && ins->inst_i0->flags & MONO_INST_IS_TEMP)) {
2241                         temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
2242                         temp->flags |= MONO_INST_IS_TEMP;
2243                         NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
2244                         store->cil_code = ins->cil_code;
2245                         if (store->opcode == CEE_STOBJ) {
2246                                 NEW_TEMPLOADA (cfg, store, temp->inst_c0);
2247                                 handle_stobj (cfg, bblock, store, ins, ins->cil_code, temp->klass, FALSE, FALSE, FALSE);
2248                         } else
2249                                 MONO_ADD_INS (bblock, store);
2250                         NEW_TEMPLOAD (cfg, load, temp->inst_c0);
2251                         load->cil_code = ins->cil_code;
2252                         *stack = load;
2253                 }
2254                 stack++;
2255         }
2256 }
2257
2258 /*
2259  * target_type_is_incompatible:
2260  * @cfg: MonoCompile context
2261  *
2262  * Check that the item @arg on the evaluation stack can be stored
2263  * in the target type (can be a local, or field, etc).
2264  * The cfg arg can be used to check if we need verification or just
2265  * validity checks.
2266  *
2267  * Returns: non-0 value if arg can't be stored on a target.
2268  */
2269 static int
2270 target_type_is_incompatible (MonoCompile *cfg, MonoType *target, MonoInst *arg)
2271 {
2272         MonoType *simple_type;
2273         MonoClass *klass;
2274
2275         if (target->byref) {
2276                 /* FIXME: check that the pointed to types match */
2277                 if (arg->type == STACK_MP)
2278                         return arg->klass != mono_class_from_mono_type (target);
2279                 if (arg->type == STACK_PTR)
2280                         return 0;
2281                 return 1;
2282         }
2283         simple_type = mono_type_get_underlying_type (target);
2284         switch (simple_type->type) {
2285         case MONO_TYPE_VOID:
2286                 return 1;
2287         case MONO_TYPE_I1:
2288         case MONO_TYPE_U1:
2289         case MONO_TYPE_BOOLEAN:
2290         case MONO_TYPE_I2:
2291         case MONO_TYPE_U2:
2292         case MONO_TYPE_CHAR:
2293         case MONO_TYPE_I4:
2294         case MONO_TYPE_U4:
2295                 if (arg->type != STACK_I4 && arg->type != STACK_PTR)
2296                         return 1;
2297                 return 0;
2298         case MONO_TYPE_PTR:
2299                 /* STACK_MP is needed when setting pinned locals */
2300                 if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
2301                         return 1;
2302                 return 0;
2303         case MONO_TYPE_I:
2304         case MONO_TYPE_U:
2305         case MONO_TYPE_FNPTR:
2306                 if (arg->type != STACK_I4 && arg->type != STACK_PTR)
2307                         return 1;
2308                 return 0;
2309         case MONO_TYPE_OBJECT:
2310                 if (arg->type != STACK_OBJ)
2311                         return 1;
2312                 return 0;
2313         case MONO_TYPE_STRING:
2314                 if (arg->type != STACK_OBJ)
2315                         return 1;
2316                 /* ldnull has arg->klass unset */
2317                 /*if (arg->klass && arg->klass != mono_defaults.string_class) {
2318                         G_BREAKPOINT ();
2319                         return 1;
2320                 }*/
2321                 return 0;
2322         case MONO_TYPE_CLASS:
2323         case MONO_TYPE_SZARRAY:
2324         case MONO_TYPE_ARRAY:    
2325                 if (arg->type != STACK_OBJ)
2326                         return 1;
2327                 /* FIXME: check type compatibility */
2328                 return 0;
2329         case MONO_TYPE_I8:
2330         case MONO_TYPE_U8:
2331                 if (arg->type != STACK_I8)
2332                         return 1;
2333                 return 0;
2334         case MONO_TYPE_R4:
2335         case MONO_TYPE_R8:
2336                 if (arg->type != STACK_R8)
2337                         return 1;
2338                 return 0;
2339         case MONO_TYPE_VALUETYPE:
2340                 if (arg->type != STACK_VTYPE)
2341                         return 1;
2342                 klass = mono_class_from_mono_type (simple_type);
2343                 if (klass != arg->klass)
2344                         return 1;
2345                 return 0;
2346         case MONO_TYPE_TYPEDBYREF:
2347                 if (arg->type != STACK_VTYPE)
2348                         return 1;
2349                 klass = mono_class_from_mono_type (simple_type);
2350                 if (klass != arg->klass)
2351                         return 1;
2352                 return 0;
2353         case MONO_TYPE_GENERICINST:
2354                 if (mono_type_generic_inst_is_valuetype (simple_type)) {
2355                         klass = mono_class_from_mono_type (simple_type);
2356                         if (klass->enumtype)
2357                                 return target_type_is_incompatible (cfg, klass->enum_basetype, arg);
2358                         if (arg->type != STACK_VTYPE)
2359                                 return 1;
2360                         if (klass != arg->klass)
2361                                 return 1;
2362                         return 0;
2363                 } else {
2364                         if (arg->type != STACK_OBJ)
2365                                 return 1;
2366                         /* FIXME: check type compatibility */
2367                         return 0;
2368                 }
2369         case MONO_TYPE_VAR:
2370         case MONO_TYPE_MVAR:
2371                 /* FIXME: all the arguments must be references for now,
2372                  * later look inside cfg and see if the arg num is
2373                  * really a reference
2374                  */
2375                 g_assert (cfg->generic_sharing_context);
2376                 if (arg->type != STACK_OBJ)
2377                         return 1;
2378                 return 0;
2379         default:
2380                 g_error ("unknown type 0x%02x in target_type_is_incompatible", simple_type->type);
2381         }
2382         return 1;
2383 }
2384
2385 /*
2386  * Prepare arguments for passing to a function call.
2387  * Return a non-zero value if the arguments can't be passed to the given
2388  * signature.
2389  * The type checks are not yet complete and some conversions may need
2390  * casts on 32 or 64 bit architectures.
2391  *
2392  * FIXME: implement this using target_type_is_incompatible ()
2393  */
2394 static int
2395 check_call_signature (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args)
2396 {
2397         MonoType *simple_type;
2398         int i;
2399
2400         if (sig->hasthis) {
2401                 if (args [0]->type != STACK_OBJ && args [0]->type != STACK_MP && args [0]->type != STACK_PTR)
2402                         return 1;
2403                 args++;
2404         }
2405         for (i = 0; i < sig->param_count; ++i) {
2406                 if (sig->params [i]->byref) {
2407                         if (args [i]->type != STACK_MP && args [i]->type != STACK_PTR)
2408                                 return 1;
2409                         continue;
2410                 }
2411                 simple_type = sig->params [i];
2412                 simple_type = mini_get_basic_type_from_generic (cfg->generic_sharing_context, simple_type);
2413 handle_enum:
2414                 switch (simple_type->type) {
2415                 case MONO_TYPE_VOID:
2416                         return 1;
2417                         continue;
2418                 case MONO_TYPE_I1:
2419                 case MONO_TYPE_U1:
2420                 case MONO_TYPE_BOOLEAN:
2421                 case MONO_TYPE_I2:
2422                 case MONO_TYPE_U2:
2423                 case MONO_TYPE_CHAR:
2424                 case MONO_TYPE_I4:
2425                 case MONO_TYPE_U4:
2426                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR)
2427                                 return 1;
2428                         continue;
2429                 case MONO_TYPE_I:
2430                 case MONO_TYPE_U:
2431                 case MONO_TYPE_PTR:
2432                 case MONO_TYPE_FNPTR:
2433                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR && args [i]->type != STACK_MP && args [i]->type != STACK_OBJ)
2434                                 return 1;
2435                         continue;
2436                 case MONO_TYPE_CLASS:
2437                 case MONO_TYPE_STRING:
2438                 case MONO_TYPE_OBJECT:
2439                 case MONO_TYPE_SZARRAY:
2440                 case MONO_TYPE_ARRAY:    
2441                         if (args [i]->type != STACK_OBJ)
2442                                 return 1;
2443                         continue;
2444                 case MONO_TYPE_I8:
2445                 case MONO_TYPE_U8:
2446                         if (args [i]->type != STACK_I8)
2447                                 return 1;
2448                         continue;
2449                 case MONO_TYPE_R4:
2450                 case MONO_TYPE_R8:
2451                         if (args [i]->type != STACK_R8)
2452                                 return 1;
2453                         continue;
2454                 case MONO_TYPE_VALUETYPE:
2455                         if (simple_type->data.klass->enumtype) {
2456                                 simple_type = simple_type->data.klass->enum_basetype;
2457                                 goto handle_enum;
2458                         }
2459                         if (args [i]->type != STACK_VTYPE)
2460                                 return 1;
2461                         continue;
2462                 case MONO_TYPE_TYPEDBYREF:
2463                         if (args [i]->type != STACK_VTYPE)
2464                                 return 1;
2465                         continue;
2466                 case MONO_TYPE_GENERICINST:
2467                         simple_type = &simple_type->data.generic_class->container_class->byval_arg;
2468                         goto handle_enum;
2469
2470                 default:
2471                         g_error ("unknown type 0x%02x in check_call_signature",
2472                                  simple_type->type);
2473                 }
2474         }
2475         return 0;
2476 }
2477
2478 inline static int
2479 mono_spill_call (MonoCompile *cfg, MonoBasicBlock *bblock, MonoCallInst *call, MonoMethodSignature *sig, gboolean ret_object, 
2480                  const guint8 *ip, gboolean to_end)
2481 {
2482         MonoInst *temp, *store, *ins = (MonoInst*)call;
2483         MonoType *ret = sig->ret;
2484
2485         if (!MONO_TYPE_IS_VOID (ret) || ret_object) {
2486                 if (ret_object) {
2487                         call->inst.type = STACK_OBJ;
2488                         call->inst.opcode = OP_CALL;
2489                         temp = mono_compile_create_var (cfg, &mono_defaults.string_class->byval_arg, OP_LOCAL);
2490                 } else {
2491                         type_to_eval_stack_type (cfg, ret, ins);
2492                         temp = mono_compile_create_var (cfg, ret, OP_LOCAL);
2493                 }
2494                 
2495                 temp->flags |= MONO_INST_IS_TEMP;
2496
2497                 if (MONO_TYPE_ISSTRUCT (ret)) {
2498                         MonoInst *loada, *dummy_store;
2499
2500                         /* 
2501                          * Emit a dummy store to the local holding the result so the
2502                          * liveness info remains correct.
2503                          */
2504                         NEW_DUMMY_STORE (cfg, dummy_store, temp->inst_c0);
2505                         if (to_end)
2506                                 mono_add_ins_to_end (bblock, dummy_store);
2507                         else
2508                                 MONO_ADD_INS (bblock, dummy_store);
2509
2510                         /* we use this to allocate native sized structs */
2511                         temp->backend.is_pinvoke = sig->pinvoke;
2512
2513                         NEW_TEMPLOADA (cfg, loada, temp->inst_c0);
2514                         if (call->inst.opcode == OP_VCALL || call->inst.opcode == OP_VCALL_RGCTX)
2515                                 ins->inst_left = loada;
2516                         else
2517                                 ins->inst_right = loada; /* a virtual or indirect call */
2518
2519                         if (to_end)
2520                                 mono_add_ins_to_end (bblock, ins);
2521                         else
2522                                 MONO_ADD_INS (bblock, ins);
2523                 } else {
2524                         NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
2525                         store->cil_code = ip;
2526                         
2527 #ifdef MONO_ARCH_SOFT_FLOAT
2528                         if (store->opcode == CEE_STIND_R4) {
2529                                 /*FIXME implement proper support for to_end*/
2530                                 g_assert (!to_end);
2531                                 NEW_TEMPLOADA (cfg, store, temp->inst_c0);
2532                                 handle_store_float (cfg, bblock, store, ins, ip);
2533                         } else
2534 #endif
2535                         if (to_end)
2536                                 mono_add_ins_to_end (bblock, store);
2537                         else
2538                                 MONO_ADD_INS (bblock, store);
2539                 }
2540                 return temp->inst_c0;
2541         } else {
2542                 if (to_end)
2543                         mono_add_ins_to_end (bblock, ins);
2544                 else
2545                         MONO_ADD_INS (bblock, ins);
2546                 return -1;
2547         }
2548 }
2549
2550 inline static MonoCallInst *
2551 mono_emit_call_args (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethodSignature *sig, 
2552                      MonoInst **args, int calli, int virtual, const guint8 *ip, gboolean to_end)
2553 {
2554         MonoCallInst *call;
2555         MonoInst *arg, *n;
2556
2557         MONO_INST_NEW_CALL (cfg, call, ret_type_to_call_opcode (sig->ret, calli, virtual, cfg->generic_sharing_context));
2558
2559 #ifdef MONO_ARCH_SOFT_FLOAT
2560         /* we need to convert the r4 value to an int value */
2561         {
2562                 int i;
2563                 for (i = 0; i < sig->param_count; ++i) {
2564                         if (!sig->params [i]->byref && sig->params [i]->type == MONO_TYPE_R4) {
2565                                 MonoInst *iargs [1];
2566                                 int temp;
2567                                 iargs [0] = args [i + sig->hasthis];
2568
2569                                 temp = mono_emit_jit_icall (cfg, bblock, mono_fload_r4_arg, iargs, ip);
2570                                 NEW_TEMPLOAD (cfg, arg, temp);
2571                                 args [i + sig->hasthis] = arg;
2572                         }
2573                 }
2574         }
2575 #endif
2576
2577         call->inst.cil_code = ip;
2578         call->args = args;
2579         call->signature = sig;
2580         call = mono_arch_call_opcode (cfg, bblock, call, virtual);
2581         type_to_eval_stack_type (cfg, sig->ret, &call->inst);
2582
2583         MONO_INST_LIST_FOR_EACH_ENTRY_SAFE (arg, n, &call->out_args, node) {
2584                 if (!arg->cil_code)
2585                         arg->cil_code = ip;
2586                 if (to_end)
2587                         mono_add_ins_to_end (bblock, arg);
2588                 else
2589                         MONO_ADD_INS (bblock, arg);
2590         }
2591         return call;
2592 }
2593
2594 inline static MonoCallInst*
2595 mono_emit_calli (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethodSignature *sig, 
2596                  MonoInst **args, MonoInst *addr, const guint8 *ip)
2597 {
2598         MonoCallInst *call = mono_emit_call_args (cfg, bblock, sig, args, TRUE, FALSE, ip, FALSE);
2599
2600         call->inst.inst_i0 = addr;
2601
2602         return call;
2603 }
2604
2605 inline static MonoCallInst*
2606 mono_emit_rgctx_calli (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethodSignature *sig,
2607         MonoInst **args, MonoInst *addr, MonoInst *rgctx_arg, const guint8 *ip)
2608 {
2609         MonoCallInst *call = mono_emit_calli (cfg, bblock, sig, args, addr, ip);
2610
2611         if (rgctx_arg) {
2612                 switch (call->inst.opcode) {
2613                 case OP_CALL_REG: call->inst.opcode = OP_CALL_REG_RGCTX; break;
2614                 case OP_VOIDCALL_REG: call->inst.opcode = OP_VOIDCALL_REG_RGCTX; break;
2615                 case OP_FCALL_REG: call->inst.opcode = OP_FCALL_REG_RGCTX; break;
2616                 case OP_LCALL_REG: call->inst.opcode = OP_LCALL_REG_RGCTX; break;
2617                 case OP_VCALL_REG: {
2618                         MonoInst *group;
2619
2620                         NEW_GROUP (cfg, group, call->inst.inst_left, NULL);
2621                         call->inst.inst_left = group;
2622                         call->inst.opcode = OP_VCALL_REG_RGCTX;
2623                         break;
2624                 }
2625                 default: g_assert_not_reached ();
2626                 }
2627
2628                 if (call->inst.opcode != OP_VCALL_REG_RGCTX) {
2629                         g_assert (!call->inst.inst_right);
2630                         call->inst.inst_right = rgctx_arg;
2631                 } else {
2632                         g_assert (!call->inst.inst_left->inst_right);
2633                         call->inst.inst_left->inst_right = rgctx_arg;
2634                 }
2635         }
2636
2637         return call;
2638 }
2639
2640 inline static int
2641 mono_emit_calli_spilled (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethodSignature *sig, 
2642                                                  MonoInst **args, MonoInst *addr, const guint8 *ip)
2643 {
2644         MonoCallInst *call = mono_emit_calli (cfg, bblock, sig, args, addr, ip);
2645
2646         return mono_spill_call (cfg, bblock, call, sig, FALSE, ip, FALSE);
2647 }
2648
2649 static int
2650 mono_emit_rgctx_calli_spilled (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethodSignature *sig,
2651         MonoInst **args, MonoInst *addr, MonoInst *rgctx_arg, const guint8 *ip)
2652 {
2653         MonoCallInst *call = mono_emit_rgctx_calli (cfg, bblock, sig, args, addr, rgctx_arg, ip);
2654
2655         return mono_spill_call (cfg, bblock, call, sig, FALSE, ip, FALSE);
2656 }
2657
2658 static MonoCallInst*
2659 mono_emit_method_call_full (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *method, MonoMethodSignature *sig,
2660                        MonoInst **args, const guint8 *ip, MonoInst *this, gboolean to_end)
2661 {
2662         gboolean virtual = this != NULL;
2663         MonoCallInst *call;
2664
2665         call = mono_emit_call_args (cfg, bblock, sig, args, FALSE, virtual, ip, to_end);
2666
2667         if (this && sig->hasthis && 
2668             (method->klass->marshalbyref || method->klass == mono_defaults.object_class) && 
2669             !(method->flags & METHOD_ATTRIBUTE_VIRTUAL) && !MONO_CHECK_THIS (this)) {
2670                 call->method = mono_marshal_get_remoting_invoke_with_check (method);
2671         } else {
2672                 call->method = method;
2673         }
2674         call->inst.flags |= MONO_INST_HAS_METHOD;
2675         call->inst.inst_left = this;
2676
2677         if (call->method->klass->flags & TYPE_ATTRIBUTE_INTERFACE)
2678                 /* Needed by the code generated in inssel.brg */
2679                 mono_get_got_var (cfg);
2680
2681         return call;
2682 }
2683
2684 static MonoCallInst*
2685 mono_emit_method_call (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *method, MonoMethodSignature *sig,
2686                        MonoInst **args, const guint8 *ip, MonoInst *this)
2687 {
2688         return mono_emit_method_call_full (cfg, bblock, method, sig, args, ip, this, FALSE);
2689 }
2690
2691 inline static int
2692 mono_emit_method_call_spilled (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *method,  
2693                        MonoMethodSignature *signature, MonoInst **args, const guint8 *ip, MonoInst *this)
2694 {
2695         MonoCallInst *call = mono_emit_method_call (cfg, bblock, method, signature, args, ip, this);
2696
2697         return mono_spill_call (cfg, bblock, call, signature, method->string_ctor, ip, FALSE);
2698 }
2699
2700 inline static int
2701 mono_emit_method_call_spilled_full (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *method,  
2702                        MonoMethodSignature *signature, MonoInst **args, const guint8 *ip, MonoInst *this,
2703                        gboolean ret_object, gboolean to_end)
2704 {
2705         MonoCallInst *call = mono_emit_method_call_full (cfg, bblock, method, signature, args, ip, this, to_end);
2706
2707         return mono_spill_call (cfg, bblock, call, signature, ret_object, ip, to_end);
2708 }
2709
2710 inline static int
2711 mono_emit_native_call (MonoCompile *cfg, MonoBasicBlock *bblock, gconstpointer func, MonoMethodSignature *sig,
2712                        MonoInst **args, const guint8 *ip, gboolean ret_object, gboolean to_end)
2713 {
2714         MonoCallInst *call;
2715
2716         g_assert (sig);
2717
2718         call = mono_emit_call_args (cfg, bblock, sig, args, FALSE, FALSE, ip, to_end);
2719         call->fptr = func;
2720
2721         return mono_spill_call (cfg, bblock, call, sig, ret_object, ip, to_end);
2722 }
2723
2724 inline static int
2725 mono_emit_jit_icall (MonoCompile *cfg, MonoBasicBlock *bblock, gconstpointer func, MonoInst **args, const guint8 *ip)
2726 {
2727         MonoJitICallInfo *info = mono_find_jit_icall_by_addr (func);
2728         
2729         if (!info) {
2730                 g_warning ("unregistered JIT ICall");
2731                 g_assert_not_reached ();
2732         }
2733
2734         return mono_emit_native_call (cfg, bblock, mono_icall_get_wrapper (info), info->sig, args, ip, FALSE, FALSE);
2735 }
2736
2737 static MonoCallInst*
2738 mono_emit_rgctx_method_call (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *method, MonoMethodSignature *sig,
2739                 MonoInst **args, MonoInst *rgctx_arg, const guint8 *ip, MonoInst *this)
2740 {
2741         MonoCallInst *call = mono_emit_method_call_full (cfg, bblock, method, sig, args, ip, this, FALSE);
2742
2743         if (rgctx_arg) {
2744                 switch (call->inst.opcode) {
2745                 case OP_CALL: call->inst.opcode = OP_CALL_RGCTX; break;
2746                 case OP_VOIDCALL: call->inst.opcode = OP_VOIDCALL_RGCTX; break;
2747                 case OP_FCALL: call->inst.opcode = OP_FCALL_RGCTX; break;
2748                 case OP_LCALL: call->inst.opcode = OP_LCALL_RGCTX; break;
2749                 case OP_VCALL: call->inst.opcode = OP_VCALL_RGCTX; break;
2750                 default: g_assert_not_reached ();
2751                 }
2752
2753                 if (call->inst.opcode != OP_VCALL_RGCTX) {
2754                         g_assert (!call->inst.inst_left);
2755                         call->inst.inst_left = rgctx_arg;
2756                 } else {
2757                         g_assert (!call->inst.inst_right);
2758                         call->inst.inst_right = rgctx_arg;
2759                 }
2760         }
2761
2762         return call;
2763 }
2764
2765 inline static int
2766 mono_emit_rgctx_method_call_spilled (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *method,  
2767                 MonoMethodSignature *signature, MonoInst **args, MonoInst *rgctx_arg, const guint8 *ip,
2768                 MonoInst *this)
2769 {
2770         MonoCallInst *call = mono_emit_rgctx_method_call (cfg, bblock, method, signature, args, rgctx_arg, ip, this);
2771
2772         return mono_spill_call (cfg, bblock, call, signature, method->string_ctor, ip, FALSE);
2773 }
2774
2775 static void
2776 mono_emulate_opcode (MonoCompile *cfg, MonoInst *tree, MonoInst **iargs, MonoJitICallInfo *info)
2777 {
2778         MonoInst *ins, *temp = NULL, *store, *load;
2779         MonoInstList *head, *list;
2780         int nargs;
2781         MonoCallInst *call;
2782
2783         //g_print ("emulating: ");
2784         //mono_print_tree_nl (tree);
2785         MONO_INST_NEW_CALL (cfg, call, ret_type_to_call_opcode (info->sig->ret, FALSE, FALSE, cfg->generic_sharing_context));
2786         ins = (MonoInst*)call;
2787         MONO_INST_LIST_INIT (&ins->node);
2788         
2789         call->inst.cil_code = tree->cil_code;
2790         call->args = iargs;
2791         call->signature = info->sig;
2792
2793         call = mono_arch_call_opcode (cfg, cfg->cbb, call, FALSE);
2794
2795         if (!MONO_TYPE_IS_VOID (info->sig->ret)) {
2796                 temp = mono_compile_create_var (cfg, info->sig->ret, OP_LOCAL);
2797                 temp->flags |= MONO_INST_IS_TEMP;
2798                 NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
2799                 MONO_INST_LIST_INIT (&store->node);
2800                 /* FIXME: handle CEE_STIND_R4 */
2801                 store->cil_code = tree->cil_code;
2802         } else {
2803                 store = ins;
2804         }
2805
2806         nargs = info->sig->param_count + info->sig->hasthis;
2807
2808         if (nargs) {
2809                 MONO_INST_LIST_ADD_TAIL (&store->node,
2810                                         &call->out_args);
2811                 list = &call->out_args;
2812         } else {
2813                 list = &store->node;
2814         }
2815
2816         if (cfg->prev_ins) {
2817                 /* 
2818                  * This assumes that that in a tree, emulate_opcode is called for a
2819                  * node before it is called for its children. dec_foreach needs to
2820                  * take this into account.
2821                  */
2822                 head = &cfg->prev_ins->node;
2823         } else {
2824                 head = &cfg->cbb->ins_list;
2825         }
2826
2827         MONO_INST_LIST_SPLICE_INIT (list, head);
2828
2829         call->fptr = mono_icall_get_wrapper (info);
2830
2831         if (!MONO_TYPE_IS_VOID (info->sig->ret)) {
2832                 NEW_TEMPLOAD (cfg, load, temp->inst_c0);
2833                 *tree = *load;
2834         }
2835 }
2836
2837 /*
2838  * This entry point could be used later for arbitrary method
2839  * redirection.
2840  */
2841 inline static int
2842 mini_redirect_call (int *temp, MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *method,  
2843                        MonoMethodSignature *signature, MonoInst **args, const guint8 *ip, MonoInst *this)
2844 {
2845
2846         if (method->klass == mono_defaults.string_class) {
2847                 /* managed string allocation support */
2848                 if (strcmp (method->name, "InternalAllocateStr") == 0) {
2849                         MonoInst *iargs [2];
2850                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
2851                         MonoMethod *managed_alloc = mono_gc_get_managed_allocator (vtable, FALSE);
2852                         if (!managed_alloc)
2853                                 return FALSE;
2854                         NEW_VTABLECONST (cfg, iargs [0], vtable);
2855                         iargs [1] = args [0];
2856                         *temp = mono_emit_method_call_spilled (cfg, bblock, managed_alloc, mono_method_signature (managed_alloc), iargs, ip, this);
2857                         return TRUE;
2858                 }
2859         }
2860         return FALSE;
2861 }
2862
2863 static MonoMethodSignature *
2864 mono_get_array_new_va_signature (int arity)
2865 {
2866         static GHashTable *sighash = NULL;
2867         MonoMethodSignature *res;
2868         int i;
2869
2870         mono_jit_lock ();
2871         if (!sighash) {
2872                 sighash = g_hash_table_new (NULL, NULL);
2873         }
2874         else if ((res = g_hash_table_lookup (sighash, GINT_TO_POINTER (arity)))) {
2875                 mono_jit_unlock ();
2876                 return res;
2877         }
2878
2879         res = mono_metadata_signature_alloc (mono_defaults.corlib, arity + 1);
2880
2881         res->pinvoke = 1;
2882 #ifdef MONO_ARCH_VARARG_ICALLS
2883         /* Only set this only some archs since not all backends can handle varargs+pinvoke */
2884         res->call_convention = MONO_CALL_VARARG;
2885 #endif
2886
2887 #ifdef PLATFORM_WIN32
2888         res->call_convention = MONO_CALL_C;
2889 #endif
2890
2891         res->params [0] = &mono_defaults.int_class->byval_arg;  
2892         for (i = 0; i < arity; i++)
2893                 res->params [i + 1] = &mono_defaults.int_class->byval_arg;
2894
2895         res->ret = &mono_defaults.int_class->byval_arg;
2896
2897         g_hash_table_insert (sighash, GINT_TO_POINTER (arity), res);
2898         mono_jit_unlock ();
2899
2900         return res;
2901 }
2902
2903 #ifdef MONO_ARCH_SOFT_FLOAT
2904 static void
2905 handle_store_float (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *ptr, MonoInst *val, const unsigned char *ip)
2906 {
2907         MonoInst *iargs [2];
2908         iargs [0] = val;
2909         iargs [1] = ptr;
2910
2911         mono_emit_jit_icall (cfg, bblock, mono_fstore_r4, iargs, ip);
2912 }
2913
2914 static int
2915 handle_load_float (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *ptr, const unsigned char *ip)
2916 {
2917         MonoInst *iargs [1];
2918         iargs [0] = ptr;
2919
2920         return mono_emit_jit_icall (cfg, bblock, mono_fload_r4, iargs, ip);
2921 }
2922
2923 #define LDLOC_SOFT_FLOAT(cfg,ins,idx,ip) do {\
2924                 if (header->locals [(idx)]->type == MONO_TYPE_R4 && !header->locals [(idx)]->byref) {   \
2925                         int temp;       \
2926                         NEW_LOCLOADA (cfg, (ins), (idx));       \
2927                         temp = handle_load_float (cfg, bblock, (ins), (ip));    \
2928                         NEW_TEMPLOAD (cfg, (ins), temp);        \
2929                 }       \
2930         } while (0)
2931 #define STLOC_SOFT_FLOAT(cfg,ins,idx,ip) do {\
2932                 if (header->locals [(idx)]->type == MONO_TYPE_R4 && !header->locals [(idx)]->byref) {   \
2933                         int temp;       \
2934                         NEW_LOCLOADA (cfg, (ins), (idx));       \
2935                         handle_store_float (cfg, bblock, (ins), *sp, (ip));     \
2936                         MONO_INST_NEW (cfg, (ins), OP_NOP);     \
2937                 }       \
2938         } while (0)
2939 #define LDARG_SOFT_FLOAT(cfg,ins,idx,ip) do {\
2940                 if (param_types [(idx)]->type == MONO_TYPE_R4 && !param_types [(idx)]->byref) { \
2941                         int temp;       \
2942                         NEW_ARGLOADA (cfg, (ins), (idx));       \
2943                         temp = handle_load_float (cfg, bblock, (ins), (ip));    \
2944                         NEW_TEMPLOAD (cfg, (ins), temp);        \
2945                 }       \
2946         } while (0)
2947 #define STARG_SOFT_FLOAT(cfg,ins,idx,ip) do {\
2948                 if (param_types [(idx)]->type == MONO_TYPE_R4 && !param_types [(idx)]->byref) { \
2949                         int temp;       \
2950                         NEW_ARGLOADA (cfg, (ins), (idx));       \
2951                         handle_store_float (cfg, bblock, (ins), *sp, (ip));     \
2952                         MONO_INST_NEW (cfg, (ins), OP_NOP);     \
2953                 }       \
2954         } while (0)
2955 #else
2956 #define LDLOC_SOFT_FLOAT(cfg,ins,idx,ip)
2957 #define STLOC_SOFT_FLOAT(cfg,ins,idx,ip)
2958 #define LDARG_SOFT_FLOAT(cfg,ins,idx,ip)
2959 #define STARG_SOFT_FLOAT(cfg,ins,idx,ip)
2960 #endif
2961
2962 static MonoMethod*
2963 get_memcpy_method (void)
2964 {
2965         static MonoMethod *memcpy_method = NULL;
2966         if (!memcpy_method) {
2967                 memcpy_method = mono_class_get_method_from_name (mono_defaults.string_class, "memcpy", 3);
2968                 if (!memcpy_method)
2969                         g_error ("Old corlib found. Install a new one");
2970         }
2971         return memcpy_method;
2972 }
2973
2974 static void
2975 handle_stobj (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *dest, MonoInst *src, const unsigned char *ip, MonoClass *klass, gboolean to_end, gboolean native, gboolean write_barrier) {
2976         MonoInst *iargs [3];
2977         int n;
2978         guint32 align = 0;
2979         MonoMethod *memcpy_method;
2980
2981         g_assert (klass);
2982         /*
2983          * This check breaks with spilled vars... need to handle it during verification anyway.
2984          * g_assert (klass && klass == src->klass && klass == dest->klass);
2985          */
2986
2987         if (native)
2988                 n = mono_class_native_size (klass, &align);
2989         else
2990                 n = mono_class_value_size (klass, &align);
2991
2992 #if HAVE_WRITE_BARRIERS
2993         /* if native is true there should be no references in the struct */
2994         if (write_barrier && klass->has_references && !native) {
2995                 iargs [0] = dest;
2996                 iargs [1] = src;
2997                 NEW_PCONST (cfg, iargs [2], klass);
2998
2999                 mono_emit_jit_icall (cfg, bblock, mono_value_copy, iargs, ip);
3000                 return;
3001         }
3002 #endif
3003
3004         /* FIXME: add write barrier handling */
3005         if ((cfg->opt & MONO_OPT_INTRINS) && !to_end && n <= sizeof (gpointer) * 5) {
3006                 MonoInst *inst;
3007                 if (dest->opcode == OP_LDADDR) {
3008                         /* Keep liveness info correct */
3009                         NEW_DUMMY_STORE (cfg, inst, dest->inst_i0->inst_c0);
3010                         MONO_ADD_INS (bblock, inst);
3011                 }
3012                 NEW_MEMCPY (cfg, inst, dest, src, n, align);
3013                 MONO_ADD_INS (bblock, inst);
3014                 return;
3015         }
3016         iargs [0] = dest;
3017         iargs [1] = src;
3018         NEW_ICONST (cfg, iargs [2], n);
3019
3020         memcpy_method = get_memcpy_method ();
3021         mono_emit_method_call_spilled_full (cfg, bblock, memcpy_method, memcpy_method->signature, iargs, ip, NULL, FALSE, to_end);
3022 }
3023
3024 static MonoMethod*
3025 get_memset_method (void)
3026 {
3027         static MonoMethod *memset_method = NULL;
3028         if (!memset_method) {
3029                 memset_method = mono_class_get_method_from_name (mono_defaults.string_class, "memset", 3);
3030                 if (!memset_method)
3031                         g_error ("Old corlib found. Install a new one");
3032         }
3033         return memset_method;
3034 }
3035
3036 static void
3037 handle_initobj (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *dest, const guchar *ip, MonoClass *klass, MonoInst **stack_start, MonoInst **sp)
3038 {
3039         MonoInst *iargs [3];
3040         MonoInst *ins, *zero_int32;
3041         int n;
3042         guint32 align;
3043         MonoMethod *memset_method;
3044
3045         NEW_ICONST (cfg, zero_int32, 0);
3046
3047         mono_class_init (klass);
3048         n = mono_class_value_size (klass, &align);
3049         MONO_INST_NEW (cfg, ins, 0);
3050         ins->cil_code = ip;
3051         ins->inst_left = dest;
3052         ins->inst_right = zero_int32;
3053         if (n == 1) {
3054                 ins->opcode = CEE_STIND_I1;
3055                 MONO_ADD_INS (bblock, ins);
3056         } else if ((n == 2) && (align >= 2)) {
3057                 ins->opcode = CEE_STIND_I2;
3058                 MONO_ADD_INS (bblock, ins);
3059         } else if ((n == 2) && (align >= 4)) {
3060                 ins->opcode = CEE_STIND_I4;
3061                 MONO_ADD_INS (bblock, ins);
3062         } else if (n <= sizeof (gpointer) * 5) {
3063                 NEW_MEMSET (cfg, ins, dest, 0, n, align);
3064                 MONO_ADD_INS (bblock, ins);
3065         } else {
3066                 memset_method = get_memset_method ();
3067                 handle_loaded_temps (cfg, bblock, stack_start, sp);
3068                 iargs [0] = dest;
3069                 NEW_ICONST (cfg, iargs [1], 0);
3070                 NEW_ICONST (cfg, iargs [2], n);
3071                 mono_emit_method_call_spilled (cfg, bblock, memset_method, memset_method->signature, iargs, ip, NULL);
3072         }
3073 }
3074
3075 static int
3076 handle_alloc (MonoCompile *cfg, MonoBasicBlock *bblock, MonoClass *klass, gboolean for_box, const guchar *ip)
3077 {
3078         MonoInst *iargs [2];
3079         void *alloc_ftn;
3080
3081         if (cfg->opt & MONO_OPT_SHARED) {
3082                 NEW_DOMAINCONST (cfg, iargs [0]);
3083                 NEW_CLASSCONST (cfg, iargs [1], klass);
3084
3085                 alloc_ftn = mono_object_new;
3086         } else if (cfg->compile_aot && bblock->out_of_line && klass->type_token && klass->image == mono_defaults.corlib) {
3087                 /* This happens often in argument checking code, eg. throw new FooException... */
3088                 /* Avoid relocations by calling a helper function specialized to mscorlib */
3089                 NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (klass->type_token));
3090                 return mono_emit_jit_icall (cfg, bblock, mono_helper_newobj_mscorlib, iargs, ip);
3091         } else {
3092                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
3093                 MonoMethod *managed_alloc = mono_gc_get_managed_allocator (vtable, for_box);
3094                 gboolean pass_lw;
3095
3096                 if (managed_alloc) {
3097                         NEW_VTABLECONST (cfg, iargs [0], vtable);
3098                         return mono_emit_method_call_spilled (cfg, bblock, managed_alloc, mono_method_signature (managed_alloc), iargs, ip, NULL);
3099                 }
3100                 alloc_ftn = mono_class_get_allocation_ftn (vtable, for_box, &pass_lw);
3101                 if (pass_lw) {
3102                         guint32 lw = vtable->klass->instance_size;
3103                         lw = ((lw + (sizeof (gpointer) - 1)) & ~(sizeof (gpointer) - 1)) / sizeof (gpointer);
3104                         NEW_ICONST (cfg, iargs [0], lw);
3105                         NEW_VTABLECONST (cfg, iargs [1], vtable);
3106                 }
3107                 else
3108                         NEW_VTABLECONST (cfg, iargs [0], vtable);
3109         }
3110
3111         return mono_emit_jit_icall (cfg, bblock, alloc_ftn, iargs, ip);
3112 }
3113
3114 static int
3115 handle_alloc_from_inst (MonoCompile *cfg, MonoBasicBlock *bblock, MonoClass *klass, MonoInst *vtable_inst,
3116                 gboolean for_box, const guchar *ip)
3117 {
3118         MonoInst *iargs [2];
3119         MonoMethod *managed_alloc = NULL;
3120         /*
3121           FIXME: we cannot get managed_alloc here because we can't get
3122           the class's vtable (because it's not a closed class)
3123
3124         MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
3125         MonoMethod *managed_alloc = mono_gc_get_managed_allocator (vtable, for_box);
3126         */
3127
3128         g_assert (!(cfg->opt & MONO_OPT_SHARED));
3129         g_assert (!cfg->compile_aot);
3130
3131         if (managed_alloc) {
3132                 iargs [0] = vtable_inst;
3133                 return mono_emit_method_call_spilled (cfg, bblock, managed_alloc, mono_method_signature (managed_alloc), iargs, ip, NULL);
3134         }
3135
3136         iargs [0] = vtable_inst;
3137
3138         return mono_emit_jit_icall (cfg, bblock, mono_object_new_specific, iargs, ip);
3139 }
3140
3141 /**
3142  * Handles unbox of a Nullable<T>, returning a temp variable
3143  * where the result is stored
3144  */
3145 static int
3146 handle_unbox_nullable (MonoCompile* cfg, MonoBasicBlock* bblock, MonoInst* val, const guchar *ip, MonoClass* klass)
3147 {
3148        MonoMethod* method = mono_class_get_method_from_name (klass, "Unbox", 1);
3149        return mono_emit_method_call_spilled (cfg, bblock, method, mono_method_signature (method), &val, ip, NULL);
3150         
3151 }
3152
3153
3154 static MonoInst*
3155 handle_box_copy (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *val, const guchar *ip, MonoClass *klass, int temp)
3156 {
3157         MonoInst *dest, *vtoffset, *add, *vstore;
3158
3159         NEW_TEMPLOAD (cfg, dest, temp);
3160         NEW_ICONST (cfg, vtoffset, sizeof (MonoObject));
3161         MONO_INST_NEW (cfg, add, OP_PADD);
3162         add->inst_left = dest;
3163         add->inst_right = vtoffset;
3164         add->cil_code = ip;
3165         add->klass = klass;
3166         MONO_INST_NEW (cfg, vstore, CEE_STIND_I);
3167         vstore->opcode = mini_type_to_stind (cfg, &klass->byval_arg);
3168         vstore->cil_code = ip;
3169         vstore->inst_left = add;
3170         vstore->inst_right = val;
3171
3172 #ifdef MONO_ARCH_SOFT_FLOAT
3173         if (vstore->opcode == CEE_STIND_R4) {
3174                 handle_store_float (cfg, bblock, add, val, ip);
3175         } else
3176 #endif
3177         if (vstore->opcode == CEE_STOBJ) {
3178                 handle_stobj (cfg, bblock, add, val, ip, klass, FALSE, FALSE, TRUE);
3179         } else
3180                 MONO_ADD_INS (bblock, vstore);
3181
3182         NEW_TEMPLOAD (cfg, dest, temp);
3183         return dest;
3184 }
3185
3186 static MonoInst *
3187 handle_box (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *val, const guchar *ip, MonoClass *klass)
3188 {
3189         MonoInst *dest;
3190         int temp;
3191
3192         if (mono_class_is_nullable (klass)) {
3193                 MonoMethod* method = mono_class_get_method_from_name (klass, "Box", 1);
3194                 temp = mono_emit_method_call_spilled (cfg, bblock, method, mono_method_signature (method), &val, ip, NULL);
3195                 NEW_TEMPLOAD (cfg, dest, temp);
3196                 return dest;
3197         }
3198
3199         temp = handle_alloc (cfg, bblock, klass, TRUE, ip);
3200
3201         return handle_box_copy (cfg, bblock, val, ip, klass, temp);
3202 }
3203
3204 static MonoInst *
3205 handle_box_from_inst (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *val, const guchar *ip,
3206                 MonoClass *klass, MonoInst *vtable_inst)
3207 {
3208         int temp;
3209
3210         g_assert (!mono_class_is_nullable (klass));
3211
3212         temp = handle_alloc_from_inst (cfg, bblock, klass, vtable_inst, TRUE, ip);
3213
3214         return handle_box_copy (cfg, bblock, val, ip, klass, temp);
3215 }
3216
3217 static MonoInst*
3218 handle_delegate_ctor (MonoCompile *cfg, MonoBasicBlock *bblock, MonoClass *klass, MonoInst *target, MonoMethod *method, unsigned char *ip)
3219 {
3220         gpointer *trampoline;
3221         MonoInst *obj, *ins, *store, *offset_ins, *method_ins, *tramp_ins;
3222         int temp;
3223
3224         temp = handle_alloc (cfg, bblock, klass, FALSE, ip);
3225
3226         /* Inline the contents of mono_delegate_ctor */
3227
3228         /* Set target field */
3229         /* Optimize away setting of NULL target */
3230         if (!(target->opcode == OP_PCONST && target->inst_p0 == 0)) {
3231                 NEW_TEMPLOAD (cfg, obj, temp);
3232                 NEW_ICONST (cfg, offset_ins, G_STRUCT_OFFSET (MonoDelegate, target));
3233                 MONO_INST_NEW (cfg, ins, OP_PADD);
3234                 ins->cil_code = ip;
3235                 ins->inst_left = obj;
3236                 ins->inst_right = offset_ins;
3237
3238                 MONO_INST_NEW (cfg, store, CEE_STIND_REF);
3239                 store->cil_code = ip;
3240                 store->inst_left = ins;
3241                 store->inst_right = target;
3242                 mono_bblock_add_inst (bblock, store);
3243         }
3244
3245         /* Set method field */
3246         NEW_TEMPLOAD (cfg, obj, temp);
3247         NEW_ICONST (cfg, offset_ins, G_STRUCT_OFFSET (MonoDelegate, method));
3248         MONO_INST_NEW (cfg, ins, OP_PADD);
3249         ins->cil_code = ip;
3250         ins->inst_left = obj;
3251         ins->inst_right = offset_ins;
3252
3253         NEW_METHODCONST (cfg, method_ins, method);
3254
3255         MONO_INST_NEW (cfg, store, CEE_STIND_I);
3256         store->cil_code = ip;
3257         store->inst_left = ins;
3258         store->inst_right = method_ins;
3259         mono_bblock_add_inst (bblock, store);
3260
3261         /* Set invoke_impl field */
3262         NEW_TEMPLOAD (cfg, obj, temp);
3263         NEW_ICONST (cfg, offset_ins, G_STRUCT_OFFSET (MonoDelegate, invoke_impl));
3264         MONO_INST_NEW (cfg, ins, OP_PADD);
3265         ins->cil_code = ip;
3266         ins->inst_left = obj;
3267         ins->inst_right = offset_ins;
3268
3269         trampoline = mono_create_delegate_trampoline (klass);
3270         NEW_AOTCONST (cfg, tramp_ins, MONO_PATCH_INFO_ABS, trampoline);
3271
3272         MONO_INST_NEW (cfg, store, CEE_STIND_I);
3273         store->cil_code = ip;
3274         store->inst_left = ins;
3275         store->inst_right = tramp_ins;
3276         mono_bblock_add_inst (bblock, store);
3277
3278         /* All the checks which are in mono_delegate_ctor () are done by the delegate trampoline */
3279
3280         NEW_TEMPLOAD (cfg, obj, temp);
3281
3282         return obj;
3283 }
3284
3285 static int
3286 handle_array_new (MonoCompile *cfg, MonoBasicBlock *bblock, int rank, MonoInst **sp, unsigned char *ip)
3287 {
3288         MonoMethodSignature *esig;
3289         char icall_name [256];
3290         char *name;
3291         MonoJitICallInfo *info;
3292
3293         /* Need to register the icall so it gets an icall wrapper */
3294         sprintf (icall_name, "ves_array_new_va_%d", rank);
3295
3296         mono_jit_lock ();
3297         info = mono_find_jit_icall_by_name (icall_name);
3298         if (info == NULL) {
3299                 esig = mono_get_array_new_va_signature (rank);
3300                 name = g_strdup (icall_name);
3301                 info = mono_register_jit_icall (mono_array_new_va, name, esig, FALSE);
3302
3303                 g_hash_table_insert (jit_icall_name_hash, name, name);
3304         }
3305         mono_jit_unlock ();
3306
3307         cfg->flags |= MONO_CFG_HAS_VARARGS;
3308
3309         /* FIXME: This uses info->sig, but it should use the signature of the wrapper */
3310         return mono_emit_native_call (cfg, bblock, mono_icall_get_wrapper (info), info->sig, sp, ip, TRUE, FALSE);
3311 }
3312
3313 static void
3314 mono_emit_load_got_addr (MonoCompile *cfg)
3315 {
3316         MonoInst *load, *store, *dummy_use;
3317         MonoInst *get_got;
3318
3319         if (!cfg->got_var || cfg->got_var_allocated)
3320                 return;
3321
3322         MONO_INST_NEW (cfg, get_got, OP_LOAD_GOTADDR);
3323         NEW_TEMPSTORE (cfg, store, cfg->got_var->inst_c0, get_got);
3324
3325         /* Add it to the start of the first bblock */
3326         MONO_INST_LIST_ADD (&store->node, &cfg->bb_entry->ins_list);
3327
3328         cfg->got_var_allocated = TRUE;
3329
3330         /* 
3331          * Add a dummy use to keep the got_var alive, since real uses might
3332          * only be generated in the decompose or instruction selection phases.
3333          * Add it to end_bblock, so the variable's lifetime covers the whole
3334          * method.
3335          */
3336         NEW_TEMPLOAD (cfg, load, cfg->got_var->inst_c0);
3337         NEW_DUMMY_USE (cfg, dummy_use, load);
3338         MONO_ADD_INS (cfg->bb_exit, dummy_use);
3339 }
3340
3341 #define CODE_IS_STLOC(ip) (((ip) [0] >= CEE_STLOC_0 && (ip) [0] <= CEE_STLOC_3) || ((ip) [0] == CEE_STLOC_S))
3342
3343 static gboolean
3344 mini_class_is_system_array (MonoClass *klass)
3345 {
3346         if (klass->parent == mono_defaults.array_class)
3347                 return TRUE;
3348         else
3349                 return FALSE;
3350 }
3351
3352 static gboolean
3353 mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method)
3354 {
3355         MonoMethodHeader *header = mono_method_get_header (method);
3356         MonoMethodSignature *signature = mono_method_signature (method);
3357         MonoVTable *vtable;
3358         int i;
3359
3360         if (cfg->generic_sharing_context)
3361                 return FALSE;
3362
3363         if (method->inline_failure)
3364                 return FALSE;
3365
3366 #ifdef MONO_ARCH_HAVE_LMF_OPS
3367         if (((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
3368                  (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) &&
3369             !MONO_TYPE_ISSTRUCT (signature->ret) && !mini_class_is_system_array (method->klass))
3370                 return TRUE;
3371 #endif
3372
3373         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
3374             (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
3375             (method->iflags & METHOD_IMPL_ATTRIBUTE_NOINLINING) ||
3376             (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) ||
3377             (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
3378             (method->klass->marshalbyref) ||
3379             !header || header->num_clauses ||
3380             /* fixme: why cant we inline valuetype returns? */
3381             MONO_TYPE_ISSTRUCT (signature->ret))
3382                 return FALSE;
3383
3384 #ifdef MONO_ARCH_SOFT_FLOAT
3385         /* this complicates things, fix later */
3386         if (signature->ret->type == MONO_TYPE_R4)
3387                 return FALSE;
3388 #endif
3389         /* its not worth to inline methods with valuetype arguments?? */
3390         for (i = 0; i < signature->param_count; i++) {
3391                 if (MONO_TYPE_ISSTRUCT (signature->params [i])) {
3392                         return FALSE;
3393                 }
3394 #ifdef MONO_ARCH_SOFT_FLOAT
3395                 /* this complicates things, fix later */
3396                 if (!signature->params [i]->byref && signature->params [i]->type == MONO_TYPE_R4)
3397                         return FALSE;
3398 #endif
3399         }
3400
3401         /*
3402          * if we can initialize the class of the method right away, we do,
3403          * otherwise we don't allow inlining if the class needs initialization,
3404          * since it would mean inserting a call to mono_runtime_class_init()
3405          * inside the inlined code
3406          */
3407         if (!(cfg->opt & MONO_OPT_SHARED)) {
3408                 vtable = mono_class_vtable (cfg->domain, method->klass);
3409                 if (method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) {
3410                         if (cfg->run_cctors && method->klass->has_cctor) {
3411                                 /* This makes so that inline cannot trigger */
3412                                 /* .cctors: too many apps depend on them */
3413                                 /* running with a specific order... */
3414                                 if (! vtable->initialized)
3415                                         return FALSE;
3416                                 mono_runtime_class_init (vtable);
3417                         }
3418                 }
3419                 else if (!vtable->initialized && mono_class_needs_cctor_run (method->klass, NULL))
3420                         return FALSE;
3421         } else {
3422                 /* 
3423                  * If we're compiling for shared code
3424                  * the cctor will need to be run at aot method load time, for example,
3425                  * or at the end of the compilation of the inlining method.
3426                  */
3427                 if (mono_class_needs_cctor_run (method->klass, NULL) && !((method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT)))
3428                         return FALSE;
3429         }
3430         //if (!MONO_TYPE_IS_VOID (signature->ret)) return FALSE;
3431
3432         /*
3433          * CAS - do not inline methods with declarative security
3434          * Note: this has to be before any possible return TRUE;
3435          */
3436         if (mono_method_has_declsec (method))
3437                 return FALSE;
3438
3439         /* also consider num_locals? */
3440         if (getenv ("MONO_INLINELIMIT")) {
3441                 if (header->code_size < atoi (getenv ("MONO_INLINELIMIT"))) {
3442                         return TRUE;
3443                 }
3444         } else if (header->code_size < INLINE_LENGTH_LIMIT)
3445                 return TRUE;
3446
3447         return FALSE;
3448 }
3449
3450 static gboolean
3451 mini_field_access_needs_cctor_run (MonoCompile *cfg, MonoMethod *method, MonoVTable *vtable)
3452 {
3453         if (vtable->initialized && !cfg->compile_aot)
3454                 return FALSE;
3455
3456         if (vtable->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT)
3457                 return FALSE;
3458
3459         if (!mono_class_needs_cctor_run (vtable->klass, method))
3460                 return FALSE;
3461
3462         if (! (method->flags & METHOD_ATTRIBUTE_STATIC) && (vtable->klass == method->klass))
3463                 /* The initialization is already done before the method is called */
3464                 return FALSE;
3465
3466         return TRUE;
3467 }
3468
3469 static MonoInst*
3470 mini_get_ldelema_ins (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *cmethod, MonoInst **sp, unsigned char *ip, gboolean is_set)
3471 {
3472         int temp, rank;
3473         MonoInst *addr;
3474         MonoMethod *addr_method;
3475         int element_size;
3476
3477         rank = mono_method_signature (cmethod)->param_count - (is_set? 1: 0);
3478
3479         if (rank == 1) {
3480                 MONO_INST_NEW (cfg, addr, CEE_LDELEMA);
3481                 addr->inst_left = sp [0];
3482                 addr->inst_right = sp [1];
3483                 addr->cil_code = ip;
3484                 addr->type = STACK_MP;
3485                 addr->klass = cmethod->klass->element_class;
3486                 return addr;
3487         }
3488
3489         if (rank == 2 && (cfg->opt & MONO_OPT_INTRINS)) {
3490 #if defined(MONO_ARCH_EMULATE_MUL_DIV) && !defined(MONO_ARCH_NO_EMULATE_MUL)
3491                 /* OP_LDELEMA2D depends on OP_LMUL */
3492 #else
3493                 MonoInst *indexes;
3494                 NEW_GROUP (cfg, indexes, sp [1], sp [2]);
3495                 MONO_INST_NEW (cfg, addr, OP_LDELEMA2D);
3496                 addr->inst_left = sp [0];
3497                 addr->inst_right = indexes;
3498                 addr->cil_code = ip;
3499                 addr->type = STACK_MP;
3500                 addr->klass = cmethod->klass->element_class;
3501                 return addr;
3502 #endif
3503         }
3504
3505         element_size = mono_class_array_element_size (cmethod->klass->element_class);
3506         addr_method = mono_marshal_get_array_address (rank, element_size);
3507         temp = mono_emit_method_call_spilled (cfg, bblock, addr_method, addr_method->signature, sp, ip, NULL);
3508         NEW_TEMPLOAD (cfg, addr, temp);
3509         return addr;
3510
3511 }
3512
3513 static MonoJitICallInfo **emul_opcode_map = NULL;
3514
3515 MonoJitICallInfo *
3516 mono_find_jit_opcode_emulation (int opcode)
3517 {
3518         g_assert (opcode >= 0 && opcode <= OP_LAST);
3519         if  (emul_opcode_map)
3520                 return emul_opcode_map [opcode];
3521         else
3522                 return NULL;
3523 }
3524
3525 static int
3526 is_unsigned_regsize_type (MonoType *type)
3527 {
3528         switch (type->type) {
3529         case MONO_TYPE_U1:
3530         case MONO_TYPE_U2:
3531         case MONO_TYPE_U4:
3532 #if SIZEOF_VOID_P == 8
3533         /*case MONO_TYPE_U8: this requires different opcodes in inssel.brg */
3534 #endif
3535                 return TRUE;
3536         default:
3537                 return FALSE;
3538         }
3539 }
3540
3541 static MonoInst*
3542 mini_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
3543 {
3544         MonoInst *ins = NULL;
3545         
3546         static MonoClass *runtime_helpers_class = NULL;
3547         if (! runtime_helpers_class)
3548                 runtime_helpers_class = mono_class_from_name (mono_defaults.corlib,
3549                         "System.Runtime.CompilerServices", "RuntimeHelpers");
3550
3551         if (cmethod->klass == mono_defaults.string_class) {
3552                 if (strcmp (cmethod->name, "get_Chars") == 0) {
3553                         MONO_INST_NEW (cfg, ins, OP_GETCHR);
3554                         ins->inst_i0 = args [0];
3555                         ins->inst_i1 = args [1];
3556                         return ins;
3557                 } else if (strcmp (cmethod->name, "get_Length") == 0) {
3558                         MONO_INST_NEW (cfg, ins, OP_STRLEN);
3559                         ins->inst_i0 = args [0];
3560                         return ins;
3561                 } else if (strcmp (cmethod->name, "InternalSetChar") == 0) {
3562                         MonoInst *get_addr;
3563                         MONO_INST_NEW (cfg, get_addr, OP_STR_CHAR_ADDR);
3564                         get_addr->inst_i0 = args [0];
3565                         get_addr->inst_i1 = args [1];
3566                         MONO_INST_NEW (cfg, ins, CEE_STIND_I2);
3567                         ins->inst_i0 = get_addr;
3568                         ins->inst_i1 = args [2];
3569                         return ins;
3570                 } else 
3571                         return NULL;
3572         } else if (cmethod->klass == mono_defaults.object_class) {
3573                 if (strcmp (cmethod->name, "GetType") == 0) {
3574                         MONO_INST_NEW (cfg, ins, OP_GETTYPE);
3575                         ins->inst_i0 = args [0];
3576                         return ins;
3577                 /* The OP_GETHASHCODE rule depends on OP_MUL */
3578 #if !defined(MONO_ARCH_EMULATE_MUL_DIV) && !defined(HAVE_MOVING_COLLECTOR)
3579                 } else if (strcmp (cmethod->name, "InternalGetHashCode") == 0) {
3580                         MONO_INST_NEW (cfg, ins, OP_GETHASHCODE);
3581                         ins->inst_i0 = args [0];
3582                         return ins;
3583 #endif
3584                 } else if (strcmp (cmethod->name, ".ctor") == 0) {
3585                         MONO_INST_NEW (cfg, ins, OP_NOP);
3586                         return ins;
3587                 } else
3588                         return NULL;
3589         } else if (cmethod->klass == mono_defaults.array_class) {
3590                 if (cmethod->name [0] != 'g')
3591                         return NULL;
3592
3593                 if (strcmp (cmethod->name, "get_Rank") == 0) {
3594                         MONO_INST_NEW (cfg, ins, OP_ARRAY_RANK);
3595                         ins->inst_i0 = args [0];
3596                         return ins;
3597                 } else if (strcmp (cmethod->name, "get_Length") == 0) {
3598                         MONO_INST_NEW (cfg, ins, CEE_LDLEN);
3599                         ins->inst_i0 = args [0];
3600                         return ins;
3601                 } else
3602                         return NULL;
3603         } else if (cmethod->klass == runtime_helpers_class) {
3604                 if (strcmp (cmethod->name, "get_OffsetToStringData") == 0) {
3605                         NEW_ICONST (cfg, ins, G_STRUCT_OFFSET (MonoString, chars));
3606                         return ins;
3607                 } else
3608                         return NULL;
3609         } else if (cmethod->klass == mono_defaults.thread_class) {
3610                 if (strcmp (cmethod->name, "get_CurrentThread") == 0 && (ins = mono_arch_get_thread_intrinsic (cfg)))
3611                         return ins;
3612                 if (strcmp (cmethod->name, "MemoryBarrier") == 0) {
3613                         MONO_INST_NEW (cfg, ins, OP_MEMORY_BARRIER);
3614                         return ins;
3615                 }
3616         } else if (mini_class_is_system_array (cmethod->klass) &&
3617                         strcmp (cmethod->name, "GetGenericValueImpl") == 0) {
3618                 MonoInst *sp [2];
3619                 MonoInst *ldelem, *store, *load;
3620                 MonoClass *eklass = mono_class_from_mono_type (fsig->params [1]);
3621                 int n;
3622                 n = mini_type_to_stind (cfg, &eklass->byval_arg);
3623                 if (n == CEE_STOBJ)
3624                         return NULL;
3625                 sp [0] = args [0];
3626                 sp [1] = args [1];
3627                 NEW_LDELEMA (cfg, ldelem, sp, eklass);
3628                 ldelem->flags |= MONO_INST_NORANGECHECK;
3629                 MONO_INST_NEW (cfg, store, n);
3630                 MONO_INST_NEW (cfg, load, mini_type_to_ldind (cfg, &eklass->byval_arg));
3631                 type_to_eval_stack_type (cfg, &eklass->byval_arg, load);
3632                 load->inst_left = ldelem;
3633                 store->inst_left = args [2];
3634                 store->inst_right = load;
3635                 return store;
3636         } else if (cmethod->klass == mono_defaults.math_class) {
3637                 if (strcmp (cmethod->name, "Min") == 0) {
3638                         if (is_unsigned_regsize_type (fsig->params [0])) {
3639                                 MONO_INST_NEW (cfg, ins, OP_MIN);
3640                                 ins->inst_i0 = args [0];
3641                                 ins->inst_i1 = args [1];
3642                                 return ins;
3643                         }
3644                 } else if (strcmp (cmethod->name, "Max") == 0) {
3645                         if (is_unsigned_regsize_type (fsig->params [0])) {
3646                                 MONO_INST_NEW (cfg, ins, OP_MAX);
3647                                 ins->inst_i0 = args [0];
3648                                 ins->inst_i1 = args [1];
3649                                 return ins;
3650                         }
3651                 }
3652         } else if (cmethod->klass->image == mono_defaults.corlib &&
3653                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
3654                            (strcmp (cmethod->klass->name, "Interlocked") == 0)) {
3655                 ins = NULL;
3656
3657 #if SIZEOF_VOID_P == 8
3658                 if (strcmp (cmethod->name, "Read") == 0 && (fsig->params [0]->type == MONO_TYPE_I8)) {
3659                         /* 64 bit reads are already atomic */
3660                         MONO_INST_NEW (cfg, ins, CEE_LDIND_I8);
3661                         ins->inst_i0 = args [0];
3662                 }
3663 #endif
3664
3665 #ifdef MONO_ARCH_HAVE_ATOMIC_ADD
3666                 if (strcmp (cmethod->name, "Increment") == 0) {
3667                         MonoInst *ins_iconst;
3668                         guint32 opcode;
3669
3670                         if (fsig->params [0]->type == MONO_TYPE_I4)
3671                                 opcode = OP_ATOMIC_ADD_NEW_I4;
3672                         else if (fsig->params [0]->type == MONO_TYPE_I8)
3673                                 opcode = OP_ATOMIC_ADD_NEW_I8;
3674                         else
3675                                 g_assert_not_reached ();
3676
3677 #if SIZEOF_VOID_P == 4
3678                         if (opcode == OP_ATOMIC_ADD_NEW_I8)
3679                                 return NULL;
3680 #endif
3681
3682                         MONO_INST_NEW (cfg, ins, opcode);
3683                         MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
3684                         ins_iconst->inst_c0 = 1;
3685
3686                         ins->inst_i0 = args [0];
3687                         ins->inst_i1 = ins_iconst;
3688                 } else if (strcmp (cmethod->name, "Decrement") == 0) {
3689                         MonoInst *ins_iconst;
3690                         guint32 opcode;
3691
3692                         if (fsig->params [0]->type == MONO_TYPE_I4)
3693                                 opcode = OP_ATOMIC_ADD_NEW_I4;
3694                         else if (fsig->params [0]->type == MONO_TYPE_I8)
3695                                 opcode = OP_ATOMIC_ADD_NEW_I8;
3696                         else
3697                                 g_assert_not_reached ();
3698
3699 #if SIZEOF_VOID_P == 4
3700                         if (opcode == OP_ATOMIC_ADD_NEW_I8)
3701                                 return NULL;
3702 #endif
3703
3704                         MONO_INST_NEW (cfg, ins, opcode);
3705                         MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
3706                         ins_iconst->inst_c0 = -1;
3707
3708                         ins->inst_i0 = args [0];
3709                         ins->inst_i1 = ins_iconst;
3710                 } else if (strcmp (cmethod->name, "Add") == 0) {
3711                         guint32 opcode;
3712
3713                         if (fsig->params [0]->type == MONO_TYPE_I4)
3714                                 opcode = OP_ATOMIC_ADD_NEW_I4;
3715                         else if (fsig->params [0]->type == MONO_TYPE_I8)
3716                                 opcode = OP_ATOMIC_ADD_NEW_I8;
3717                         else
3718                                 g_assert_not_reached ();
3719
3720 #if SIZEOF_VOID_P == 4
3721                         if (opcode == OP_ATOMIC_ADD_NEW_I8)
3722                                 return NULL;
3723 #endif
3724                         
3725                         MONO_INST_NEW (cfg, ins, opcode);
3726
3727                         ins->inst_i0 = args [0];
3728                         ins->inst_i1 = args [1];
3729                 }
3730 #endif /* MONO_ARCH_HAVE_ATOMIC_ADD */
3731
3732 #ifdef MONO_ARCH_HAVE_ATOMIC_EXCHANGE
3733                 if (strcmp (cmethod->name, "Exchange") == 0) {
3734                         guint32 opcode;
3735
3736                         if (fsig->params [0]->type == MONO_TYPE_I4)
3737                                 opcode = OP_ATOMIC_EXCHANGE_I4;
3738 #if SIZEOF_VOID_P == 8
3739                         else if ((fsig->params [0]->type == MONO_TYPE_I8) ||
3740                                          (fsig->params [0]->type == MONO_TYPE_I) ||
3741                                          (fsig->params [0]->type == MONO_TYPE_OBJECT))
3742                                 opcode = OP_ATOMIC_EXCHANGE_I8;
3743 #else
3744                         else if ((fsig->params [0]->type == MONO_TYPE_I) ||
3745                                          (fsig->params [0]->type == MONO_TYPE_OBJECT))
3746                                 opcode = OP_ATOMIC_EXCHANGE_I4;
3747 #endif
3748                         else
3749                                 return NULL;
3750
3751 #if SIZEOF_VOID_P == 4
3752                         if (opcode == OP_ATOMIC_EXCHANGE_I8)
3753                                 return NULL;
3754 #endif
3755
3756                         MONO_INST_NEW (cfg, ins, opcode);
3757
3758                         ins->inst_i0 = args [0];
3759                         ins->inst_i1 = args [1];
3760                 }
3761 #endif /* MONO_ARCH_HAVE_ATOMIC_EXCHANGE */
3762
3763                 if (ins)
3764                         return ins;
3765         } else if (cmethod->klass->image == mono_defaults.corlib) {
3766                 if (cmethod->name [0] == 'B' && strcmp (cmethod->name, "Break") == 0
3767                                 && strcmp (cmethod->klass->name, "Debugger") == 0) {
3768                         MONO_INST_NEW (cfg, ins, OP_BREAK);
3769                         return ins;
3770                 }
3771                 if (cmethod->name [0] == 'g' && strcmp (cmethod->name, "get_IsRunningOnWindows") == 0
3772                                 && strcmp (cmethod->klass->name, "Environment") == 0) {
3773 #ifdef PLATFORM_WIN32
3774                         NEW_ICONST (cfg, ins, 1);
3775 #else
3776                         NEW_ICONST (cfg, ins, 0);
3777 #endif
3778                         return ins;
3779                 }
3780         }
3781
3782         return mono_arch_get_inst_for_method (cfg, cmethod, fsig, args);
3783 }
3784
3785 static void
3786 mono_save_args (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethodSignature *sig, MonoInst **sp, MonoInst **args)
3787 {
3788         MonoInst *store, *temp;
3789         int i;
3790
3791         g_assert (!MONO_TYPE_ISSTRUCT (sig->ret));
3792
3793         if (!sig->hasthis && sig->param_count == 0) 
3794                 return;
3795
3796         if (sig->hasthis) {
3797                 if (sp [0]->opcode == OP_ICONST) {
3798                         *args++ = sp [0];
3799                 } else {
3800                         temp = mono_compile_create_var (cfg, type_from_stack_type (*sp), OP_LOCAL);
3801                         *args++ = temp;
3802                         NEW_TEMPSTORE (cfg, store, temp->inst_c0, *sp);
3803                         /* FIXME: handle CEE_STIND_R4 */
3804                         store->cil_code = sp [0]->cil_code;
3805                         MONO_ADD_INS (bblock, store);
3806                 }
3807                 sp++;
3808         }
3809
3810         for (i = 0; i < sig->param_count; ++i) {
3811                 if (sp [0]->opcode == OP_ICONST) {
3812                         *args++ = sp [0];
3813                 } else {
3814                         temp = mono_compile_create_var (cfg, sig->params [i], OP_LOCAL);
3815                         *args++ = temp;
3816                         NEW_TEMPSTORE (cfg, store, temp->inst_c0, *sp);
3817                         store->cil_code = sp [0]->cil_code;
3818                         /* FIXME: handle CEE_STIND_R4 */
3819                         if (store->opcode == CEE_STOBJ) {
3820                                 NEW_TEMPLOADA (cfg, store, temp->inst_c0);
3821                                 handle_stobj (cfg, bblock, store, *sp, sp [0]->cil_code, temp->klass, FALSE, FALSE, FALSE);
3822 #ifdef MONO_ARCH_SOFT_FLOAT
3823                         } else if (store->opcode == CEE_STIND_R4) {
3824                                 NEW_TEMPLOADA (cfg, store, temp->inst_c0);
3825                                 handle_store_float (cfg, bblock, store, *sp, sp [0]->cil_code);
3826 #endif
3827                         } else {
3828                                 MONO_ADD_INS (bblock, store);
3829                         } 
3830                 }
3831                 sp++;
3832         }
3833 }
3834 #define MONO_INLINE_CALLED_LIMITED_METHODS 0
3835 #define MONO_INLINE_CALLER_LIMITED_METHODS 0
3836
3837 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
3838 static char*
3839 mono_inline_called_method_name_limit = NULL;
3840 static gboolean check_inline_called_method_name_limit (MonoMethod *called_method) {
3841         char *called_method_name = mono_method_full_name (called_method, TRUE);
3842         int strncmp_result;
3843         
3844         if (mono_inline_called_method_name_limit == NULL) {
3845                 char *limit_string = getenv ("MONO_INLINE_CALLED_METHOD_NAME_LIMIT");
3846                 if (limit_string != NULL) {
3847                         mono_inline_called_method_name_limit = limit_string;
3848                 } else {
3849                         mono_inline_called_method_name_limit = (char *) "";
3850                 }
3851         }
3852         
3853         strncmp_result = strncmp (called_method_name, mono_inline_called_method_name_limit, strlen (mono_inline_called_method_name_limit));
3854         g_free (called_method_name);
3855         
3856         //return (strncmp_result <= 0);
3857         return (strncmp_result == 0);
3858 }
3859 #endif
3860
3861 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
3862 static char*
3863 mono_inline_caller_method_name_limit = NULL;
3864 static gboolean check_inline_caller_method_name_limit (MonoMethod *caller_method) {
3865         char *caller_method_name = mono_method_full_name (caller_method, TRUE);
3866         int strncmp_result;
3867         
3868         if (mono_inline_caller_method_name_limit == NULL) {
3869                 char *limit_string = getenv ("MONO_INLINE_CALLER_METHOD_NAME_LIMIT");
3870                 if (limit_string != NULL) {
3871                         mono_inline_caller_method_name_limit = limit_string;
3872                 } else {
3873                         mono_inline_caller_method_name_limit = (char *) "";
3874                 }
3875         }
3876         
3877         strncmp_result = strncmp (caller_method_name, mono_inline_caller_method_name_limit, strlen (mono_inline_caller_method_name_limit));
3878         g_free (caller_method_name);
3879         
3880         //return (strncmp_result <= 0);
3881         return (strncmp_result == 0);
3882 }
3883 #endif
3884
3885 static int
3886 inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoBasicBlock *bblock, MonoInst **sp,
3887                 guchar *ip, guint real_offset, GList *dont_inline, MonoBasicBlock **last_b, gboolean inline_allways)
3888 {
3889         MonoInst *ins, *rvar = NULL;
3890         MonoMethodHeader *cheader;
3891         MonoBasicBlock *ebblock, *sbblock;
3892         int i, costs, new_locals_offset;
3893         MonoMethod *prev_inlined_method;
3894         MonoBasicBlock **prev_cil_offset_to_bb;
3895         unsigned char* prev_cil_start;
3896         guint32 prev_cil_offset_to_bb_len;
3897
3898         g_assert (cfg->exception_type == MONO_EXCEPTION_NONE);
3899
3900 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
3901         if ((! inline_allways) && ! check_inline_called_method_name_limit (cmethod))
3902                 return 0;
3903 #endif
3904 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
3905         if ((! inline_allways) && ! check_inline_caller_method_name_limit (cfg->method))
3906                 return 0;
3907 #endif
3908
3909         if (bblock->out_of_line && !inline_allways)
3910                 return 0;
3911
3912         if (cfg->verbose_level > 2)
3913                 g_print ("INLINE START %p %s -> %s\n", cmethod,  mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
3914
3915         if (!cmethod->inline_info) {
3916                 mono_jit_stats.inlineable_methods++;
3917                 cmethod->inline_info = 1;
3918         }
3919         /* allocate space to store the return value */
3920         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
3921                 rvar =  mono_compile_create_var (cfg, fsig->ret, OP_LOCAL);
3922         }
3923
3924         /* allocate local variables */
3925         cheader = mono_method_get_header (cmethod);
3926         new_locals_offset = cfg->num_varinfo;
3927         for (i = 0; i < cheader->num_locals; ++i)
3928                 mono_compile_create_var (cfg, cheader->locals [i], OP_LOCAL);
3929
3930         /* allocate starte and end blocks */
3931         NEW_BBLOCK (cfg, sbblock);
3932         sbblock->block_num = cfg->num_bblocks++;
3933         sbblock->real_offset = real_offset;
3934
3935         NEW_BBLOCK (cfg, ebblock);
3936         ebblock->block_num = cfg->num_bblocks++;
3937         ebblock->real_offset = real_offset;
3938
3939         prev_inlined_method = cfg->inlined_method;
3940         cfg->inlined_method = cmethod;
3941         prev_cil_offset_to_bb = cfg->cil_offset_to_bb;
3942         prev_cil_offset_to_bb_len = cfg->cil_offset_to_bb_len;
3943         prev_cil_start = cfg->cil_start;
3944
3945         costs = mono_method_to_ir (cfg, cmethod, sbblock, ebblock, new_locals_offset, rvar, dont_inline, sp, real_offset, *ip == CEE_CALLVIRT);
3946
3947         cfg->inlined_method = prev_inlined_method;
3948         cfg->cil_offset_to_bb = prev_cil_offset_to_bb;
3949         cfg->cil_offset_to_bb_len = prev_cil_offset_to_bb_len;
3950         cfg->cil_start = prev_cil_start;
3951
3952         if ((costs >= 0 && costs < 60) || inline_allways) {
3953                 if (cfg->verbose_level > 2)
3954                         g_print ("INLINE END %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
3955                 
3956                 mono_jit_stats.inlined_methods++;
3957
3958                 /* always add some code to avoid block split failures */
3959                 MONO_INST_NEW (cfg, ins, OP_NOP);
3960                 MONO_ADD_INS (bblock, ins);
3961                 ins->cil_code = ip;
3962
3963                 bblock->next_bb = sbblock;
3964                 link_bblock (cfg, bblock, sbblock);
3965
3966                 if (rvar) {
3967                         NEW_TEMPLOAD (cfg, ins, rvar->inst_c0);
3968 #ifdef MONO_ARCH_SOFT_FLOAT
3969                         if (ins->opcode == CEE_LDIND_R4) {
3970                                 int temp;
3971                                 NEW_TEMPLOADA (cfg, ins, rvar->inst_c0);
3972                                 temp = handle_load_float (cfg, bblock, ins, ip);
3973                                 NEW_TEMPLOAD (cfg, ins, temp);
3974                         }
3975 #endif
3976                         *sp++ = ins;
3977                 }
3978                 *last_b = ebblock;
3979                 return costs + 1;
3980         } else {
3981                 if (cfg->verbose_level > 2)
3982                         g_print ("INLINE ABORTED %s\n", mono_method_full_name (cmethod, TRUE));
3983                 cfg->exception_type = MONO_EXCEPTION_NONE;
3984                 mono_loader_clear_error ();
3985                 cmethod->inline_failure = TRUE;
3986         }
3987         return 0;
3988 }
3989
3990 /*
3991  * Some of these comments may well be out-of-date.
3992  * Design decisions: we do a single pass over the IL code (and we do bblock 
3993  * splitting/merging in the few cases when it's required: a back jump to an IL
3994  * address that was not already seen as bblock starting point).
3995  * Code is validated as we go (full verification is still better left to metadata/verify.c).
3996  * Complex operations are decomposed in simpler ones right away. We need to let the 
3997  * arch-specific code peek and poke inside this process somehow (except when the 
3998  * optimizations can take advantage of the full semantic info of coarse opcodes).
3999  * All the opcodes of the form opcode.s are 'normalized' to opcode.
4000  * MonoInst->opcode initially is the IL opcode or some simplification of that 
4001  * (OP_LOAD, OP_STORE). The arch-specific code may rearrange it to an arch-specific 
4002  * opcode with value bigger than OP_LAST.
4003  * At this point the IR can be handed over to an interpreter, a dumb code generator
4004  * or to the optimizing code generator that will translate it to SSA form.
4005  *
4006  * Profiling directed optimizations.
4007  * We may compile by default with few or no optimizations and instrument the code
4008  * or the user may indicate what methods to optimize the most either in a config file
4009  * or through repeated runs where the compiler applies offline the optimizations to 
4010  * each method and then decides if it was worth it.
4011  *
4012  */
4013
4014 #define CHECK_TYPE(ins) if (!(ins)->type) UNVERIFIED
4015 #define CHECK_STACK(num) if ((sp - stack_start) < (num)) UNVERIFIED
4016 #define CHECK_STACK_OVF(num) if (((sp - stack_start) + (num)) > header->max_stack) UNVERIFIED
4017 #define CHECK_ARG(num) if ((unsigned)(num) >= (unsigned)num_args) UNVERIFIED
4018 #define CHECK_LOCAL(num) if ((unsigned)(num) >= (unsigned)header->num_locals) UNVERIFIED
4019 #define CHECK_OPSIZE(size) if (ip + size > end) UNVERIFIED
4020 #define CHECK_UNVERIFIABLE(cfg) if (cfg->unverifiable) UNVERIFIED
4021 #define CHECK_TYPELOAD(klass) if (!(klass) || (klass)->exception_type) {cfg->exception_ptr = klass; goto load_error;}
4022
4023 /* offset from br.s -> br like opcodes */
4024 #define BIG_BRANCH_OFFSET 13
4025
4026 static inline gboolean
4027 ip_in_bb (MonoCompile *cfg, MonoBasicBlock *bb, const guint8* ip)
4028 {
4029         MonoBasicBlock *b = cfg->cil_offset_to_bb [ip - cfg->cil_start];
4030         
4031         return b == NULL || b == bb;
4032 }
4033
4034 static int
4035 get_basic_blocks (MonoCompile *cfg, MonoMethodHeader* header, guint real_offset, unsigned char *start, unsigned char *end, unsigned char **pos)
4036 {
4037         unsigned char *ip = start;
4038         unsigned char *target;
4039         int i;
4040         guint cli_addr;
4041         MonoBasicBlock *bblock;
4042         const MonoOpcode *opcode;
4043
4044         while (ip < end) {
4045                 cli_addr = ip - start;
4046                 i = mono_opcode_value ((const guint8 **)&ip, end);
4047                 if (i < 0)
4048                         UNVERIFIED;
4049                 opcode = &mono_opcodes [i];
4050                 switch (opcode->argument) {
4051                 case MonoInlineNone:
4052                         ip++; 
4053                         break;
4054                 case MonoInlineString:
4055                 case MonoInlineType:
4056                 case MonoInlineField:
4057                 case MonoInlineMethod:
4058                 case MonoInlineTok:
4059                 case MonoInlineSig:
4060                 case MonoShortInlineR:
4061                 case MonoInlineI:
4062                         ip += 5;
4063                         break;
4064                 case MonoInlineVar:
4065                         ip += 3;
4066                         break;
4067                 case MonoShortInlineVar:
4068                 case MonoShortInlineI:
4069                         ip += 2;
4070                         break;
4071                 case MonoShortInlineBrTarget:
4072                         target = start + cli_addr + 2 + (signed char)ip [1];
4073                         GET_BBLOCK (cfg, bblock, target);
4074                         ip += 2;
4075                         if (ip < end)
4076                                 GET_BBLOCK (cfg, bblock, ip);
4077                         break;
4078                 case MonoInlineBrTarget:
4079                         target = start + cli_addr + 5 + (gint32)read32 (ip + 1);
4080                         GET_BBLOCK (cfg, bblock, target);
4081                         ip += 5;
4082                         if (ip < end)
4083                                 GET_BBLOCK (cfg, bblock, ip);
4084                         break;
4085                 case MonoInlineSwitch: {
4086                         guint32 n = read32 (ip + 1);
4087                         guint32 j;
4088                         ip += 5;
4089                         cli_addr += 5 + 4 * n;
4090                         target = start + cli_addr;
4091                         GET_BBLOCK (cfg, bblock, target);
4092                         
4093                         for (j = 0; j < n; ++j) {
4094                                 target = start + cli_addr + (gint32)read32 (ip);
4095                                 GET_BBLOCK (cfg, bblock, target);
4096                                 ip += 4;
4097                         }
4098                         break;
4099                 }
4100                 case MonoInlineR:
4101                 case MonoInlineI8:
4102                         ip += 9;
4103                         break;
4104                 default:
4105                         g_assert_not_reached ();
4106                 }
4107
4108                 if (i == CEE_THROW) {
4109                         unsigned char *bb_start = ip - 1;
4110                         
4111                         /* Find the start of the bblock containing the throw */
4112                         bblock = NULL;
4113                         while ((bb_start >= start) && !bblock) {
4114                                 bblock = cfg->cil_offset_to_bb [(bb_start) - start];
4115                                 bb_start --;
4116                         }
4117                         if (bblock)
4118                                 bblock->out_of_line = 1;
4119                 }
4120         }
4121         return 0;
4122 unverified:
4123         *pos = ip;
4124         return 1;
4125 }
4126
4127 static MonoInst*
4128 emit_tree (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *ins, const guint8* ip_next)
4129 {
4130         MonoInst *store, *temp, *load;
4131         
4132         if (ip_in_bb (cfg, bblock, ip_next) &&
4133                 (CODE_IS_STLOC (ip_next) || *ip_next == CEE_RET))
4134                         return ins;
4135         
4136         temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
4137         temp->flags |= MONO_INST_IS_TEMP;
4138         NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
4139         /* FIXME: handle CEE_STIND_R4 */
4140         store->cil_code = ins->cil_code;
4141         MONO_ADD_INS (bblock, store);
4142         NEW_TEMPLOAD (cfg, load, temp->inst_c0);
4143         load->cil_code = ins->cil_code;
4144         return load;
4145 }
4146
4147 static inline MonoMethod *
4148 mini_get_method (MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
4149 {
4150         MonoMethod *method;
4151
4152         if (m->wrapper_type != MONO_WRAPPER_NONE)
4153                 return mono_method_get_wrapper_data (m, token);
4154
4155         method = mono_get_method_full (m->klass->image, token, klass, context);
4156
4157         return method;
4158 }
4159
4160 static inline MonoClass*
4161 mini_get_class (MonoMethod *method, guint32 token, MonoGenericContext *context)
4162 {
4163         MonoClass *klass;
4164
4165         if (method->wrapper_type != MONO_WRAPPER_NONE)
4166                 klass = mono_method_get_wrapper_data (method, token);
4167         else
4168                 klass = mono_class_get_full (method->klass->image, token, context);
4169         if (klass)
4170                 mono_class_init (klass);
4171         return klass;
4172 }
4173
4174 /*
4175  * Returns TRUE if the JIT should abort inlining because "callee"
4176  * is influenced by security attributes.
4177  */
4178 static
4179 gboolean check_linkdemand (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee, MonoBasicBlock *bblock, unsigned char *ip)
4180 {
4181         guint32 result;
4182         
4183         if ((cfg->method != caller) && mono_method_has_declsec (callee)) {
4184                 return TRUE;
4185         }
4186         
4187         result = mono_declsec_linkdemand (cfg->domain, caller, callee);
4188         if (result == MONO_JIT_SECURITY_OK)
4189                 return FALSE;
4190
4191         if (result == MONO_JIT_LINKDEMAND_ECMA) {
4192                 /* Generate code to throw a SecurityException before the actual call/link */
4193                 MonoSecurityManager *secman = mono_security_manager_get_methods ();
4194                 MonoInst *args [2];
4195
4196                 NEW_ICONST (cfg, args [0], 4);
4197                 NEW_METHODCONST (cfg, args [1], caller);
4198                 mono_emit_method_call_spilled (cfg, bblock, secman->linkdemandsecurityexception, mono_method_signature (secman->linkdemandsecurityexception), args, ip, NULL);
4199         } else if (cfg->exception_type == MONO_EXCEPTION_NONE) {
4200                  /* don't hide previous results */
4201                 cfg->exception_type = MONO_EXCEPTION_SECURITY_LINKDEMAND;
4202                 cfg->exception_data = result;
4203                 return TRUE;
4204         }
4205         
4206         return FALSE;
4207 }
4208
4209 static MonoMethod*
4210 method_access_exception (void)
4211 {
4212         static MonoMethod *method = NULL;
4213
4214         if (!method) {
4215                 MonoSecurityManager *secman = mono_security_manager_get_methods ();
4216                 method = mono_class_get_method_from_name (secman->securitymanager,
4217                                                           "MethodAccessException", 2);
4218         }
4219         g_assert (method);
4220         return method;
4221 }
4222
4223 static void
4224 emit_throw_method_access_exception (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee,
4225                                     MonoBasicBlock *bblock, unsigned char *ip)
4226 {
4227         MonoMethod *thrower = method_access_exception ();
4228         MonoInst *args [2];
4229
4230         NEW_METHODCONST (cfg, args [0], caller);
4231         NEW_METHODCONST (cfg, args [1], callee);
4232         mono_emit_method_call_spilled (cfg, bblock, thrower,
4233                 mono_method_signature (thrower), args, ip, NULL);
4234 }
4235
4236 static MonoMethod*
4237 verification_exception (void)
4238 {
4239         static MonoMethod *method = NULL;
4240
4241         if (!method) {
4242                 MonoSecurityManager *secman = mono_security_manager_get_methods ();
4243                 method = mono_class_get_method_from_name (secman->securitymanager,
4244                                                           "VerificationException", 0);
4245         }
4246         g_assert (method);
4247         return method;
4248 }
4249
4250 static void
4251 emit_throw_verification_exception (MonoCompile *cfg, MonoBasicBlock *bblock, unsigned char *ip)
4252 {
4253         MonoMethod *thrower = verification_exception ();
4254
4255         mono_emit_method_call_spilled (cfg, bblock, thrower,
4256                 mono_method_signature (thrower),
4257                 NULL, ip, NULL);
4258 }
4259
4260 static void
4261 ensure_method_is_allowed_to_call_method (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee,
4262                                          MonoBasicBlock *bblock, unsigned char *ip)
4263 {
4264         MonoSecurityCoreCLRLevel caller_level = mono_security_core_clr_method_level (caller, TRUE);
4265         MonoSecurityCoreCLRLevel callee_level = mono_security_core_clr_method_level (callee, TRUE);
4266         gboolean is_safe = TRUE;
4267
4268         if (!(caller_level >= callee_level ||
4269                         caller_level == MONO_SECURITY_CORE_CLR_SAFE_CRITICAL ||
4270                         callee_level == MONO_SECURITY_CORE_CLR_SAFE_CRITICAL)) {
4271                 is_safe = FALSE;
4272         }
4273
4274         if (!is_safe)
4275                 emit_throw_method_access_exception (cfg, caller, callee, bblock, ip);
4276 }
4277
4278 static gboolean
4279 method_is_safe (MonoMethod *method)
4280 {
4281         /*
4282         if (strcmp (method->name, "unsafeMethod") == 0)
4283                 return FALSE;
4284         */
4285         return TRUE;
4286 }
4287
4288 /*
4289  * Check that the IL instructions at ip are the array initialization
4290  * sequence and return the pointer to the data and the size.
4291  */
4292 static const char*
4293 initialize_array_data (MonoMethod *method, gboolean aot, unsigned char *ip, MonoInst *newarr, int *out_size)
4294 {
4295         /*
4296          * newarr[System.Int32]
4297          * dup
4298          * ldtoken field valuetype ...
4299          * call void class [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype [mscorlib]System.RuntimeFieldHandle)
4300          */
4301         if (ip [0] == CEE_DUP && ip [1] == CEE_LDTOKEN && ip [5] == 0x4 && ip [6] == CEE_CALL) {
4302                 MonoClass *klass = newarr->inst_newa_class;
4303                 guint32 field_token = read32 (ip + 2);
4304                 guint32 field_index = field_token & 0xffffff;
4305                 guint32 token = read32 (ip + 7);
4306                 guint32 rva;
4307                 const char *data_ptr;
4308                 int size = 0;
4309                 MonoMethod *cmethod;
4310                 MonoClass *dummy_class;
4311                 MonoClassField *field = mono_field_from_token (method->klass->image, field_token, &dummy_class, NULL);
4312                 int dummy_align;
4313
4314                 if (!field)
4315                         return NULL;
4316
4317                 if (newarr->inst_newa_len->opcode != OP_ICONST)
4318                         return NULL;
4319                 cmethod = mini_get_method (method, token, NULL, NULL);
4320                 if (!cmethod)
4321                         return NULL;
4322                 if (strcmp (cmethod->name, "InitializeArray") || strcmp (cmethod->klass->name, "RuntimeHelpers") || cmethod->klass->image != mono_defaults.corlib)
4323                         return NULL;
4324                 switch (mono_type_get_underlying_type (&klass->byval_arg)->type) {
4325                 case MONO_TYPE_BOOLEAN:
4326                 case MONO_TYPE_I1:
4327                 case MONO_TYPE_U1:
4328                         size = 1; break;
4329                 /* we need to swap on big endian, so punt. Should we handle R4 and R8 as well? */
4330 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
4331                 case MONO_TYPE_CHAR:
4332                 case MONO_TYPE_I2:
4333                 case MONO_TYPE_U2:
4334                         size = 2; break;
4335                 case MONO_TYPE_I4:
4336                 case MONO_TYPE_U4:
4337                 case MONO_TYPE_R4:
4338                         size = 4; break;
4339                 case MONO_TYPE_R8:
4340 #ifdef ARM_FPU_FPA
4341                         return NULL; /* stupid ARM FP swapped format */
4342 #endif
4343                 case MONO_TYPE_I8:
4344                 case MONO_TYPE_U8:
4345                         size = 8; break;
4346 #endif
4347                 default:
4348                         return NULL;
4349                 }
4350                 size *= newarr->inst_newa_len->inst_c0;
4351                 if (size > mono_type_size (field->type, &dummy_align))
4352                     return NULL;
4353                 *out_size = size;
4354                 /*g_print ("optimized in %s: size: %d, numelems: %d\n", method->name, size, newarr->inst_newa_len->inst_c0);*/
4355                 field_index = read32 (ip + 2) & 0xffffff;
4356                 mono_metadata_field_info (method->klass->image, field_index - 1, NULL, &rva, NULL);
4357                 data_ptr = mono_image_rva_map (method->klass->image, rva);
4358                 /*g_print ("field: 0x%08x, rva: %d, rva_ptr: %p\n", read32 (ip + 2), rva, data_ptr);*/
4359                 /* for aot code we do the lookup on load */
4360                 if (aot && data_ptr)
4361                         return GUINT_TO_POINTER (rva);
4362                 return data_ptr;
4363         }
4364         return NULL;
4365 }
4366
4367 static void
4368 set_exception_type_from_invalid_il (MonoCompile *cfg, MonoMethod *method, unsigned char *ip)
4369 {
4370         char *method_fname = mono_method_full_name (method, TRUE);
4371         char *method_code;
4372
4373         if (mono_method_get_header (method)->code_size == 0)
4374                 method_code = g_strdup ("method body is empty.");
4375         else
4376                 method_code = mono_disasm_code_one (NULL, method, ip, NULL);
4377         cfg->exception_type = MONO_EXCEPTION_INVALID_PROGRAM;
4378         cfg->exception_message = g_strdup_printf ("Invalid IL code in %s: %s\n", method_fname, method_code);
4379         g_free (method_fname);
4380         g_free (method_code);
4381 }
4382
4383 /*
4384  * Generates this->vtable->runtime_generic_context
4385  */
4386 static MonoInst*
4387 get_runtime_generic_context_from_this (MonoCompile *cfg, MonoInst *this, unsigned char *ip)
4388 {
4389         MonoInst *vtable, *rgc_ptr_addr, *rgc_ptr_offset, *rgc_ptr;
4390
4391         MONO_INST_NEW (cfg, vtable, CEE_LDIND_I);
4392         vtable->cil_code = ip;
4393         vtable->inst_left = this;
4394         vtable->type = STACK_PTR;
4395
4396         NEW_ICONST (cfg, rgc_ptr_offset, G_STRUCT_OFFSET (MonoVTable, runtime_generic_context));
4397
4398         MONO_INST_NEW (cfg, rgc_ptr_addr, OP_PADD);
4399         rgc_ptr_addr->cil_code = ip;
4400         rgc_ptr_addr->inst_left = vtable;
4401         rgc_ptr_addr->inst_right = rgc_ptr_offset;
4402         rgc_ptr_addr->type = STACK_PTR;
4403
4404         MONO_INST_NEW (cfg, rgc_ptr, CEE_LDIND_I);
4405         rgc_ptr->cil_code = ip;
4406         rgc_ptr->inst_left = rgc_ptr_addr;
4407         rgc_ptr->type = STACK_PTR;
4408
4409         return rgc_ptr;
4410 }
4411
4412 static MonoInst*
4413 get_runtime_generic_context (MonoCompile *cfg, MonoMethod *method, MonoInst *this, unsigned char *ip)
4414 {
4415         g_assert (!method->klass->valuetype);
4416
4417         if (method->flags & METHOD_ATTRIBUTE_STATIC) {
4418                 MonoInst *rgctx_loc, *rgctx_var;
4419
4420                 rgctx_loc = mono_get_rgctx_var (cfg);
4421                 NEW_TEMPLOAD (cfg, rgctx_var, rgctx_loc->inst_c0);
4422
4423                 return rgctx_var;
4424         } else {
4425                 return get_runtime_generic_context_from_this (cfg, this, ip);
4426         }
4427 }
4428
4429 static gpointer
4430 create_rgctx_lazy_fetch_trampoline (guint32 offset)
4431 {
4432         gpointer tramp, ptr;
4433
4434         mono_jit_lock ();
4435         if (rgctx_lazy_fetch_trampoline_hash)
4436                 tramp = g_hash_table_lookup (rgctx_lazy_fetch_trampoline_hash, GUINT_TO_POINTER (offset));
4437         else
4438                 tramp = NULL;
4439         mono_jit_unlock ();
4440         if (tramp)
4441                 return tramp;
4442
4443         tramp = mono_arch_create_rgctx_lazy_fetch_trampoline (offset);
4444         ptr = mono_create_ftnptr (mono_get_root_domain (), tramp);
4445
4446         mono_jit_lock ();
4447         if (!rgctx_lazy_fetch_trampoline_hash)
4448                 rgctx_lazy_fetch_trampoline_hash = g_hash_table_new (NULL, NULL);
4449         g_hash_table_insert (rgctx_lazy_fetch_trampoline_hash, GUINT_TO_POINTER (offset), ptr);
4450         mono_jit_unlock ();
4451
4452         return ptr;
4453 }       
4454
4455 static MonoInst*
4456 lazy_fetch_rgctx_direct_field (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *rgc_ptr, int offset, unsigned char *ip)
4457 {
4458         MonoMethodSignature *sig = helper_sig_rgctx_lazy_fetch_trampoline;
4459         guint8 *tramp = create_rgctx_lazy_fetch_trampoline (MONO_RGCTX_ENCODE_DIRECT_OFFSET (offset));
4460         int temp;
4461         MonoInst *field;
4462
4463         temp = mono_emit_native_call (cfg, bblock, tramp, sig, &rgc_ptr, ip, FALSE, FALSE); 
4464
4465         NEW_TEMPLOAD (cfg, field, temp);
4466
4467         return field;
4468 }
4469
4470 static MonoInst*
4471 lazy_fetch_rgctx_indirect_field (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *rgc_ptr, int offset, unsigned char *ip)
4472 {
4473         MonoMethodSignature *sig = helper_sig_rgctx_lazy_fetch_trampoline;
4474         guint8 *tramp = create_rgctx_lazy_fetch_trampoline (MONO_RGCTX_ENCODE_INDIRECT_OFFSET (offset));
4475         int temp;
4476         MonoInst *field;
4477
4478         temp = mono_emit_native_call (cfg, bblock, tramp, sig, &rgc_ptr, ip, FALSE, FALSE); 
4479
4480         NEW_TEMPLOAD (cfg, field, temp);
4481
4482         return field;
4483 }
4484
4485 /*
4486  * Generates ((MonoRuntimeGenericSuperInfo*)rgc)[-depth].XXX where XXX
4487  * is specified by rgctx_type.
4488  */
4489 static MonoInst*
4490 get_runtime_generic_context_super_ptr (MonoCompile *cfg, MonoBasicBlock *bblock,
4491         MonoInst *rgc_ptr, int depth, int rgctx_type, unsigned char *ip)
4492 {
4493         int field_offset_const, offset;
4494
4495         g_assert (depth >= 1);
4496
4497         switch (rgctx_type) {
4498         case MONO_RGCTX_INFO_STATIC_DATA :
4499                 field_offset_const = G_STRUCT_OFFSET (MonoRuntimeGenericSuperInfo, static_data);
4500                 break;
4501         case MONO_RGCTX_INFO_KLASS :
4502                 field_offset_const = G_STRUCT_OFFSET (MonoRuntimeGenericSuperInfo, klass);
4503                 break;
4504         case MONO_RGCTX_INFO_VTABLE:
4505                 field_offset_const = G_STRUCT_OFFSET (MonoRuntimeGenericSuperInfo, vtable);
4506                 break;
4507         default :
4508                 g_assert_not_reached ();
4509         }
4510
4511         offset = -depth * sizeof (MonoRuntimeGenericSuperInfo) + field_offset_const;
4512
4513         return lazy_fetch_rgctx_direct_field (cfg, bblock, rgc_ptr, offset, ip);
4514 }
4515
4516 static int
4517 get_rgctx_arg_info_field_offset (int rgctx_type)
4518 {
4519         switch (rgctx_type) {
4520         case MONO_RGCTX_INFO_STATIC_DATA :
4521                 return G_STRUCT_OFFSET (MonoRuntimeGenericArgInfo, static_data);
4522         case MONO_RGCTX_INFO_KLASS:
4523                 return G_STRUCT_OFFSET (MonoRuntimeGenericArgInfo, klass);
4524         case MONO_RGCTX_INFO_VTABLE :
4525                 return G_STRUCT_OFFSET (MonoRuntimeGenericArgInfo, vtable);
4526         default:
4527                 g_assert_not_reached ();
4528         }
4529 }
4530
4531 /*
4532  * Generates rgc->arg_infos [arg_num].XXX where XXX is specified by
4533  * rgctx_type;
4534  */
4535 static MonoInst*
4536 get_runtime_generic_context_arg_ptr (MonoCompile *cfg, MonoBasicBlock *bblock,
4537         MonoInst *rgc_ptr, int arg_num, int rgctx_type, unsigned char *ip)
4538 {
4539         int arg_info_offset, arg_info_field_offset, offset;
4540
4541         g_assert (arg_num >= 0);
4542         //g_assert (!lazy);
4543
4544         arg_info_offset = G_STRUCT_OFFSET (MonoRuntimeGenericContext, arg_infos) +
4545                 arg_num * sizeof (MonoRuntimeGenericArgInfo);
4546
4547         arg_info_field_offset = get_rgctx_arg_info_field_offset (rgctx_type);
4548
4549         offset = arg_info_offset + arg_info_field_offset;
4550
4551         return lazy_fetch_rgctx_direct_field (cfg, bblock, rgc_ptr, offset, ip);
4552 }
4553
4554 /*
4555  * Generates rgc->other_infos [index].XXX if index is non-negative, or
4556  * rgc->extra_other_infos [-index + 1] if index is negative.  XXX is
4557  * specified by rgctx_type;
4558  */
4559 static MonoInst*
4560 get_runtime_generic_context_other_table_ptr (MonoCompile *cfg, MonoBasicBlock *bblock,
4561         MonoInst *rgc_ptr, int index, unsigned char *ip)
4562 {
4563         if (index < MONO_RGCTX_MAX_OTHER_INFOS) {
4564                 int other_type_offset;
4565
4566                 other_type_offset = G_STRUCT_OFFSET (MonoRuntimeGenericContext, other_infos) +
4567                         index * sizeof (gpointer);
4568
4569                 return lazy_fetch_rgctx_direct_field (cfg, bblock, rgc_ptr, other_type_offset, ip);
4570         } else {
4571                 int slot_offset;
4572
4573                 slot_offset = (index - MONO_RGCTX_MAX_OTHER_INFOS) * sizeof (gpointer);
4574
4575                 return lazy_fetch_rgctx_indirect_field (cfg, bblock, rgc_ptr, slot_offset, ip);
4576         }
4577 }
4578
4579 static MonoInst*
4580 get_runtime_generic_context_other_ptr (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *bblock,
4581         MonoInst *rgc_ptr, guint32 token, int token_source, int rgctx_type, unsigned char *ip, int index)
4582 {
4583         MonoInst *args [6];
4584         int temp;
4585         MonoInst *result;
4586
4587         g_assert (method->wrapper_type == MONO_WRAPPER_NONE);
4588
4589         NEW_CLASSCONST (cfg, args [0], method->klass);
4590         args [1] = rgc_ptr;
4591         NEW_ICONST (cfg, args [2], token);
4592         NEW_ICONST (cfg, args [3], token_source);
4593         NEW_ICONST (cfg, args [4], rgctx_type);
4594         NEW_ICONST (cfg, args [5], index);
4595
4596         temp = mono_emit_jit_icall (cfg, bblock, mono_helper_get_rgctx_other_ptr, args, ip);
4597         NEW_TEMPLOAD (cfg, result, temp);
4598
4599         return result;
4600 }
4601
4602 static MonoInst*
4603 get_runtime_generic_context_ptr (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *bblock,
4604         MonoClass *klass, guint32 type_token, int token_source, MonoGenericContext *generic_context, MonoInst *rgctx,
4605         int rgctx_type, unsigned char *ip)
4606 {
4607         int arg_num = -1;
4608         int relation = mono_class_generic_class_relation (klass, rgctx_type, method->klass, generic_context, &arg_num);
4609
4610         switch (relation) {
4611         case MINI_GENERIC_CLASS_RELATION_SELF: {
4612                 int depth = klass->idepth;
4613                 return get_runtime_generic_context_super_ptr (cfg, bblock, rgctx, depth, rgctx_type, ip);
4614         }
4615         case MINI_GENERIC_CLASS_RELATION_ARGUMENT:
4616                 return get_runtime_generic_context_arg_ptr (cfg, bblock, rgctx, arg_num, rgctx_type, ip);
4617         case MINI_GENERIC_CLASS_RELATION_OTHER_TABLE:
4618                 return get_runtime_generic_context_other_table_ptr (cfg, bblock, rgctx, arg_num, ip);
4619         case MINI_GENERIC_CLASS_RELATION_OTHER:
4620                 return get_runtime_generic_context_other_ptr (cfg, method, bblock, rgctx,
4621                         type_token, token_source, rgctx_type, ip, arg_num);
4622         default:
4623                 g_assert_not_reached ();
4624                 return NULL;
4625         }
4626 }
4627
4628 static MonoInst*
4629 get_runtime_generic_context_method (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *bblock,
4630         MonoMethod *cmethod, MonoGenericContext *generic_context, MonoInst *rgctx, int rgctx_type, unsigned char *ip)
4631 {
4632         int arg_num = mono_class_lookup_or_register_other_info (method->klass, cmethod, rgctx_type, generic_context);
4633
4634         return get_runtime_generic_context_other_table_ptr (cfg, bblock, rgctx, arg_num, ip);
4635 }
4636
4637 static gboolean
4638 generic_class_is_reference_type (MonoCompile *cfg, MonoClass *klass)
4639 {
4640         MonoType *type;
4641
4642         if (cfg->generic_sharing_context)
4643                 type = mini_get_basic_type_from_generic (cfg->generic_sharing_context, &klass->byval_arg);
4644         else
4645                 type = &klass->byval_arg;
4646         return MONO_TYPE_IS_REFERENCE (type);
4647 }
4648
4649 /*
4650  * mini_method_verify:
4651  * 
4652  * Verify the method using the new verfier.
4653  * 
4654  * Returns true if the method is invalid. 
4655  */
4656 static gboolean
4657 mini_method_verify (MonoCompile *cfg, MonoMethod *method)
4658 {
4659         GSList *tmp, *res;
4660         gboolean is_fulltrust = mono_verifier_is_method_full_trust (method);
4661         MonoLoaderError *error;
4662
4663         if (!mono_verifier_is_enabled_for_method (method))
4664                 return FALSE;
4665
4666         res = mono_method_verify_with_current_settings (method, cfg->skip_visibility);
4667
4668         if ((error = mono_loader_get_last_error ())) {
4669                 cfg->exception_type = error->exception_type;
4670                 if (res)
4671                         mono_free_verify_list (res);
4672                 return TRUE;
4673         }
4674
4675         if (res) { 
4676                 for (tmp = res; tmp; tmp = tmp->next) {
4677                         MonoVerifyInfoExtended *info = (MonoVerifyInfoExtended *)tmp->data;
4678                         if (info->info.status == MONO_VERIFY_ERROR) {
4679                                 cfg->exception_type = info->exception_type;
4680                                 cfg->exception_message = g_strdup (info->info.message);
4681                                 mono_free_verify_list (res);
4682                                 return TRUE;
4683                         }
4684                         if (info->info.status == MONO_VERIFY_NOT_VERIFIABLE && !is_fulltrust) {
4685                                 cfg->exception_type = info->exception_type;
4686                                 cfg->exception_message = g_strdup (info->info.message);
4687                                 mono_free_verify_list (res);
4688                                 return TRUE;
4689                         }
4690                 }
4691                 mono_free_verify_list (res);
4692         }
4693         return FALSE;
4694 }
4695
4696 /*
4697  * mono_method_to_ir: translates IL into basic blocks containing trees
4698  */
4699 static int
4700 mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock, 
4701                    int locals_offset, MonoInst *return_var, GList *dont_inline, MonoInst **inline_args, 
4702                    guint inline_offset, gboolean is_virtual_call)
4703 {
4704         MonoInst *zero_int32, *zero_int64, *zero_ptr, *zero_obj, *zero_r8;
4705         MonoInst *ins, **sp, **stack_start;
4706         MonoBasicBlock *bblock, *tblock = NULL, *init_localsbb = NULL;
4707         MonoMethod *cmethod;
4708         MonoInst **arg_array;
4709         MonoMethodHeader *header;
4710         MonoImage *image;
4711         guint32 token, ins_flag;
4712         MonoClass *klass;
4713         MonoClass *constrained_call = NULL;
4714         unsigned char *ip, *end, *target, *err_pos;
4715         static double r8_0 = 0.0;
4716         MonoMethodSignature *sig;
4717         MonoGenericContext *generic_context = NULL;
4718         MonoGenericContainer *generic_container = NULL;
4719         MonoType **param_types;
4720         GList *bb_recheck = NULL, *tmp;
4721         int i, n, start_new_bblock, ialign;
4722         int num_calls = 0, inline_costs = 0;
4723         int breakpoint_id = 0;
4724         guint32 align;
4725         guint real_offset, num_args;
4726         MonoBoolean security, pinvoke;
4727         MonoSecurityManager* secman = NULL;
4728         MonoDeclSecurityActions actions;
4729         GSList *class_inits = NULL;
4730         gboolean dont_verify, dont_verify_stloc, readonly = FALSE;
4731
4732         /* serialization and xdomain stuff may need access to private fields and methods */
4733         dont_verify = method->klass->image->assembly->corlib_internal? TRUE: FALSE;
4734         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE;
4735         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH;
4736         dont_verify |= method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE; /* bug #77896 */
4737         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP;
4738         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP_INVOKE;
4739
4740         /* turn off visibility checks for smcs */
4741         dont_verify |= mono_security_get_mode () == MONO_SECURITY_MODE_SMCS_HACK;
4742
4743         /* still some type unsafety issues in marshal wrappers... (unknown is PtrToStructure) */
4744         dont_verify_stloc = method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE;
4745         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_UNKNOWN;
4746         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED;
4747
4748         image = method->klass->image;
4749         header = mono_method_get_header (method);
4750         generic_container = method->generic_container;
4751         sig = mono_method_signature (method);
4752         num_args = sig->hasthis + sig->param_count;
4753         ip = (unsigned char*)header->code;
4754         cfg->cil_start = ip;
4755         end = ip + header->code_size;
4756         mono_jit_stats.cil_code_size += header->code_size;
4757
4758         if (!dont_verify && mini_method_verify (cfg, method))
4759                 goto exception_exit;
4760
4761         if (sig->is_inflated)
4762                 generic_context = mono_method_get_context (method);
4763         else if (generic_container)
4764                 generic_context = &generic_container->context;
4765
4766         if (!cfg->generic_sharing_context)
4767                 g_assert (!sig->has_type_parameters);
4768
4769         if (cfg->method == method)
4770                 real_offset = 0;
4771         else
4772                 real_offset = inline_offset;
4773
4774         cfg->cil_offset_to_bb = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoBasicBlock*) * header->code_size);
4775         cfg->cil_offset_to_bb_len = header->code_size;
4776
4777         if (cfg->verbose_level > 2)
4778                 g_print ("method to IR %s\n", mono_method_full_name (method, TRUE));
4779
4780         dont_inline = g_list_prepend (dont_inline, method);
4781         if (cfg->method == method) {
4782
4783                 if (cfg->prof_options & MONO_PROFILE_INS_COVERAGE)
4784                         cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, header->code_size);
4785
4786                 /* ENTRY BLOCK */
4787                 NEW_BBLOCK (cfg, start_bblock);
4788                 cfg->bb_entry = start_bblock;
4789                 start_bblock->cil_code = NULL;
4790                 start_bblock->cil_length = 0;
4791                 start_bblock->block_num = cfg->num_bblocks++;
4792
4793                 /* EXIT BLOCK */
4794                 NEW_BBLOCK (cfg, end_bblock);
4795                 cfg->bb_exit = end_bblock;
4796                 end_bblock->cil_code = NULL;
4797                 end_bblock->cil_length = 0;
4798                 end_bblock->block_num = cfg->num_bblocks++;
4799                 g_assert (cfg->num_bblocks == 2);
4800
4801                 arg_array = alloca (sizeof (MonoInst *) * num_args);
4802                 for (i = num_args - 1; i >= 0; i--)
4803                         arg_array [i] = cfg->varinfo [i];
4804
4805                 if (header->num_clauses) {
4806                         cfg->spvars = g_hash_table_new (NULL, NULL);
4807                         cfg->exvars = g_hash_table_new (NULL, NULL);
4808                 }
4809                 /* handle exception clauses */
4810                 for (i = 0; i < header->num_clauses; ++i) {
4811                         MonoBasicBlock *try_bb;
4812                         MonoExceptionClause *clause = &header->clauses [i];
4813
4814                         GET_BBLOCK (cfg, try_bb, ip + clause->try_offset);
4815                         try_bb->real_offset = clause->try_offset;
4816                         GET_BBLOCK (cfg, tblock, ip + clause->handler_offset);
4817                         tblock->real_offset = clause->handler_offset;
4818                         tblock->flags |= BB_EXCEPTION_HANDLER;
4819
4820                         link_bblock (cfg, try_bb, tblock);
4821
4822                         if (*(ip + clause->handler_offset) == CEE_POP)
4823                                 tblock->flags |= BB_EXCEPTION_DEAD_OBJ;
4824
4825                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY ||
4826                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER ||
4827                             clause->flags == MONO_EXCEPTION_CLAUSE_FAULT) {
4828                                 MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
4829                                 MONO_ADD_INS (tblock, ins);
4830
4831                                 /* todo: is a fault block unsafe to optimize? */
4832                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
4833                                         tblock->flags |= BB_EXCEPTION_UNSAFE;
4834                         }
4835
4836
4837                         /*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);
4838                           while (p < end) {
4839                           g_print ("%s", mono_disasm_code_one (NULL, method, p, &p));
4840                           }*/
4841                         /* catch and filter blocks get the exception object on the stack */
4842                         if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE ||
4843                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
4844                                 MonoInst *load, *dummy_use;
4845
4846                                 /* mostly like handle_stack_args (), but just sets the input args */
4847                                 /* g_print ("handling clause at IL_%04x\n", clause->handler_offset); */
4848                                 tblock->in_scount = 1;
4849                                 tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
4850                                 tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
4851
4852                                 /* 
4853                                  * Add a dummy use for the exvar so its liveness info will be
4854                                  * correct.
4855                                  */
4856                                 NEW_TEMPLOAD (cfg, load, tblock->in_stack [0]->inst_c0);
4857                                 NEW_DUMMY_USE (cfg, dummy_use, load);
4858                                 MONO_ADD_INS (tblock, dummy_use);
4859                                 
4860                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
4861                                         GET_BBLOCK (cfg, tblock, ip + clause->data.filter_offset);
4862                                         tblock->real_offset = clause->data.filter_offset;
4863                                         tblock->in_scount = 1;
4864                                         tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
4865                                         /* The filter block shares the exvar with the handler block */
4866                                         tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
4867                                         MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
4868                                         MONO_ADD_INS (tblock, ins);
4869                                 }
4870                         }
4871
4872                         if (clause->flags != MONO_EXCEPTION_CLAUSE_FILTER &&
4873                                         clause->data.catch_class &&
4874                                         cfg->generic_sharing_context &&
4875                                         mono_class_check_context_used (clause->data.catch_class)) {
4876                                 /*
4877                                  * In shared generic code with catch
4878                                  * clauses containing type variables
4879                                  * the exception handling code has to
4880                                  * be able to get to the rgctx.
4881                                  * Therefore we have to make sure that
4882                                  * the rgctx argument (for static
4883                                  * methods) or the "this" argument
4884                                  * (for non-static methods) are live.
4885                                  */
4886                                 if (method->flags & METHOD_ATTRIBUTE_STATIC) {
4887                                         mono_get_rgctx_var (cfg);
4888                                 } else {
4889                                         MonoInst *this, *dummy_use;
4890                                         MonoType *this_type;
4891
4892                                         if (method->klass->valuetype)
4893                                                 this_type = &method->klass->this_arg;
4894                                         else
4895                                                 this_type = &method->klass->byval_arg;
4896
4897                                         if (arg_array [0]->opcode == OP_ICONST) {
4898                                                 this = arg_array [0];
4899                                         } else {
4900                                                 this = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));
4901                                                 this->ssa_op = MONO_SSA_LOAD;
4902                                                 this->inst_i0 = arg_array [0];
4903                                                 this->opcode = mini_type_to_ldind ((cfg), this->inst_i0->inst_vtype);
4904                                                 type_to_eval_stack_type ((cfg), this_type, this);
4905                                                 this->klass = this->inst_i0->klass;
4906                                         }
4907
4908                                         NEW_DUMMY_USE (cfg, dummy_use, this);
4909                                         MONO_ADD_INS (tblock, dummy_use);
4910                                 }
4911                         }
4912                 }
4913         } else {
4914                 arg_array = alloca (sizeof (MonoInst *) * num_args);
4915                 mono_save_args (cfg, start_bblock, sig, inline_args, arg_array);
4916         }
4917
4918         /* FIRST CODE BLOCK */
4919         NEW_BBLOCK (cfg, bblock);
4920         bblock->cil_code = ip;
4921
4922         ADD_BBLOCK (cfg, bblock);
4923
4924         if (cfg->method == method) {
4925                 breakpoint_id = mono_debugger_method_has_breakpoint (method);
4926                 if (breakpoint_id && (mono_debug_format != MONO_DEBUG_FORMAT_DEBUGGER)) {
4927                         MONO_INST_NEW (cfg, ins, OP_BREAK);
4928                         MONO_ADD_INS (bblock, ins);
4929                 }
4930         }
4931
4932         if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS)
4933                 secman = mono_security_manager_get_methods ();
4934
4935         security = (secman && mono_method_has_declsec (method));
4936         /* at this point having security doesn't mean we have any code to generate */
4937         if (security && (cfg->method == method)) {
4938                 /* Only Demand, NonCasDemand and DemandChoice requires code generation.
4939                  * And we do not want to enter the next section (with allocation) if we
4940                  * have nothing to generate */
4941                 security = mono_declsec_get_demands (method, &actions);
4942         }
4943
4944         /* we must Demand SecurityPermission.Unmanaged before P/Invoking */
4945         pinvoke = (secman && (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE));
4946         if (pinvoke) {
4947                 MonoMethod *wrapped = mono_marshal_method_from_wrapper (method);
4948                 if (wrapped && (wrapped->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
4949                         MonoCustomAttrInfo* custom = mono_custom_attrs_from_method (wrapped);
4950
4951                         /* unless the method or it's class has the [SuppressUnmanagedCodeSecurity] attribute */
4952                         if (custom && mono_custom_attrs_has_attr (custom, secman->suppressunmanagedcodesecurity)) {
4953                                 pinvoke = FALSE;
4954                         }
4955                         if (custom)
4956                                 mono_custom_attrs_free (custom);
4957
4958                         if (pinvoke) {
4959                                 custom = mono_custom_attrs_from_class (wrapped->klass);
4960                                 if (custom && mono_custom_attrs_has_attr (custom, secman->suppressunmanagedcodesecurity)) {
4961                                         pinvoke = FALSE;
4962                                 }
4963                                 if (custom)
4964                                         mono_custom_attrs_free (custom);
4965                         }
4966                 } else {
4967                         /* not a P/Invoke after all */
4968                         pinvoke = FALSE;
4969                 }
4970         }
4971         
4972         if ((header->init_locals || (cfg->method == method && (cfg->opt & MONO_OPT_SHARED))) || cfg->compile_aot || security || pinvoke) {
4973                 /* we use a separate basic block for the initialization code */
4974                 NEW_BBLOCK (cfg, init_localsbb);
4975                 cfg->bb_init = init_localsbb;
4976                 init_localsbb->real_offset = real_offset;
4977                 start_bblock->next_bb = init_localsbb;
4978                 init_localsbb->next_bb = bblock;
4979                 link_bblock (cfg, start_bblock, init_localsbb);
4980                 link_bblock (cfg, init_localsbb, bblock);
4981                 init_localsbb->block_num = cfg->num_bblocks++;
4982         } else {
4983                 start_bblock->next_bb = bblock;
4984                 link_bblock (cfg, start_bblock, bblock);
4985         }
4986
4987         /* at this point we know, if security is TRUE, that some code needs to be generated */
4988         if (security && (cfg->method == method)) {
4989                 MonoInst *args [2];
4990
4991                 mono_jit_stats.cas_demand_generation++;
4992
4993                 if (actions.demand.blob) {
4994                         /* Add code for SecurityAction.Demand */
4995                         NEW_DECLSECCONST (cfg, args[0], image, actions.demand);
4996                         NEW_ICONST (cfg, args [1], actions.demand.size);
4997                         /* Calls static void SecurityManager.InternalDemand (byte* permissions, int size); */
4998                         mono_emit_method_call_spilled (cfg, init_localsbb, secman->demand, mono_method_signature (secman->demand), args, ip, NULL);
4999                 }
5000                 if (actions.noncasdemand.blob) {
5001                         /* CLR 1.x uses a .noncasdemand (but 2.x doesn't) */
5002                         /* For Mono we re-route non-CAS Demand to Demand (as the managed code must deal with it anyway) */
5003                         NEW_DECLSECCONST (cfg, args[0], image, actions.noncasdemand);
5004                         NEW_ICONST (cfg, args [1], actions.noncasdemand.size);
5005                         /* Calls static void SecurityManager.InternalDemand (byte* permissions, int size); */
5006                         mono_emit_method_call_spilled (cfg, init_localsbb, secman->demand, mono_method_signature (secman->demand), args, ip, NULL);
5007                 }
5008                 if (actions.demandchoice.blob) {
5009                         /* New in 2.0, Demand must succeed for one of the permissions (i.e. not all) */
5010                         NEW_DECLSECCONST (cfg, args[0], image, actions.demandchoice);
5011                         NEW_ICONST (cfg, args [1], actions.demandchoice.size);
5012                         /* Calls static void SecurityManager.InternalDemandChoice (byte* permissions, int size); */
5013                         mono_emit_method_call_spilled (cfg, init_localsbb, secman->demandchoice, mono_method_signature (secman->demandchoice), args, ip, NULL);
5014                 }
5015         }
5016
5017         /* we must Demand SecurityPermission.Unmanaged before p/invoking */
5018         if (pinvoke) {
5019                 mono_emit_method_call_spilled (cfg, init_localsbb, secman->demandunmanaged, mono_method_signature (secman->demandunmanaged), NULL, ip, NULL);
5020         }
5021
5022         if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR) {
5023                 if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
5024                         MonoMethod *wrapped = mono_marshal_method_from_wrapper (method);
5025                         if (wrapped && (wrapped->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
5026                                 if (!(method->klass && method->klass->image &&
5027                                                 mono_security_core_clr_is_platform_image (method->klass->image))) {
5028                                         emit_throw_method_access_exception (cfg, method, wrapped, bblock, ip);
5029                                 }
5030                         }
5031                 }
5032                 if (!method_is_safe (method))
5033                         emit_throw_verification_exception (cfg, bblock, ip);
5034         }
5035
5036         if (header->code_size == 0)
5037                 UNVERIFIED;
5038
5039         if (get_basic_blocks (cfg, header, real_offset, ip, end, &err_pos)) {
5040                 ip = err_pos;
5041                 UNVERIFIED;
5042         }
5043
5044         if (cfg->method == method)
5045                 mono_debug_init_method (cfg, bblock, breakpoint_id);
5046
5047         param_types = mono_mempool_alloc (cfg->mempool, sizeof (MonoType*) * num_args);
5048         if (sig->hasthis)
5049                 param_types [0] = method->klass->valuetype?&method->klass->this_arg:&method->klass->byval_arg;
5050         for (n = 0; n < sig->param_count; ++n)
5051                 param_types [n + sig->hasthis] = sig->params [n];
5052         for (n = 0; n < header->num_locals; ++n) {
5053                 if (header->locals [n]->type == MONO_TYPE_VOID && !header->locals [n]->byref)
5054                         UNVERIFIED;
5055         }
5056         class_inits = NULL;
5057
5058         /* do this somewhere outside - not here */
5059         NEW_ICONST (cfg, zero_int32, 0);
5060         NEW_ICONST (cfg, zero_int64, 0);
5061         zero_int64->type = STACK_I8;
5062         NEW_PCONST (cfg, zero_ptr, 0);
5063         NEW_PCONST (cfg, zero_obj, 0);
5064         zero_obj->type = STACK_OBJ;
5065
5066         MONO_INST_NEW (cfg, zero_r8, OP_R8CONST);
5067         zero_r8->type = STACK_R8;
5068         zero_r8->inst_p0 = &r8_0;
5069
5070         /* add a check for this != NULL to inlined methods */
5071         if (is_virtual_call) {
5072                 MONO_INST_NEW (cfg, ins, OP_CHECK_THIS);
5073                 NEW_ARGLOAD (cfg, ins->inst_left, 0);
5074                 ins->cil_code = ip;
5075                 MONO_ADD_INS (bblock, ins);
5076         }
5077
5078         /* we use a spare stack slot in SWITCH and NEWOBJ and others */
5079         stack_start = sp = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (header->max_stack + 1));
5080
5081         ins_flag = 0;
5082         start_new_bblock = 0;
5083         while (ip < end) {
5084
5085                 if (cfg->method == method)
5086                         real_offset = ip - header->code;
5087                 else
5088                         real_offset = inline_offset;
5089                 cfg->ip = ip;
5090
5091                 if (start_new_bblock) {
5092                         bblock->cil_length = ip - bblock->cil_code;
5093                         if (start_new_bblock == 2) {
5094                                 g_assert (ip == tblock->cil_code);
5095                         } else {
5096                                 GET_BBLOCK (cfg, tblock, ip);
5097                         }
5098                         bblock->next_bb = tblock;
5099                         bblock = tblock;
5100                         start_new_bblock = 0;
5101                         for (i = 0; i < bblock->in_scount; ++i) {
5102                                 if (cfg->verbose_level > 3)
5103                                         g_print ("loading %d from temp %d\n", i, (int)bblock->in_stack [i]->inst_c0);                                           
5104                                 NEW_TEMPLOAD (cfg, ins, bblock->in_stack [i]->inst_c0);
5105                                 *sp++ = ins;
5106                         }
5107                         g_slist_free (class_inits);
5108                         class_inits = NULL;
5109                 } else {
5110                         if ((tblock = cfg->cil_offset_to_bb [ip - cfg->cil_start]) && (tblock != bblock)) {
5111                                 link_bblock (cfg, bblock, tblock);
5112                                 if (sp != stack_start) {
5113                                         handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
5114                                         sp = stack_start;
5115                                         CHECK_UNVERIFIABLE (cfg);
5116                                 }
5117                                 bblock->next_bb = tblock;
5118                                 bblock = tblock;
5119                                 for (i = 0; i < bblock->in_scount; ++i) {
5120                                         if (cfg->verbose_level > 3)
5121                                                 g_print ("loading %d from temp %d\n", i, (int)bblock->in_stack [i]->inst_c0);                                           
5122                                         NEW_TEMPLOAD (cfg, ins, bblock->in_stack [i]->inst_c0);
5123                                         *sp++ = ins;
5124                                 }
5125                                 g_slist_free (class_inits);
5126                                 class_inits = NULL;
5127                         }
5128                 }
5129
5130                 bblock->real_offset = real_offset;
5131
5132                 if ((cfg->method == method) && cfg->coverage_info) {
5133                         MonoInst *store, *one;
5134                         guint32 cil_offset = ip - header->code;
5135                         cfg->coverage_info->data [cil_offset].cil_code = ip;
5136
5137                         /* TODO: Use an increment here */
5138                         NEW_ICONST (cfg, one, 1);
5139                         one->cil_code = ip;
5140
5141                         NEW_PCONST (cfg, ins, &(cfg->coverage_info->data [cil_offset].count));
5142                         ins->cil_code = ip;
5143
5144                         MONO_INST_NEW (cfg, store, CEE_STIND_I);
5145                         store->cil_code = ip;
5146                         store->inst_left = ins;
5147                         store->inst_right = one;
5148
5149                         MONO_ADD_INS (bblock, store);
5150                 }
5151
5152                 if (cfg->verbose_level > 3)
5153                         g_print ("converting (in B%d: stack: %d) %s", bblock->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
5154
5155                 switch (*ip) {
5156                 case CEE_NOP:
5157                         MONO_INST_NEW (cfg, ins, OP_NOP);
5158                         ins->cil_code = ip++;
5159                         MONO_ADD_INS (bblock, ins);
5160                         break;
5161                 case CEE_BREAK:
5162                         MONO_INST_NEW (cfg, ins, OP_BREAK);
5163                         ins->cil_code = ip++;
5164                         MONO_ADD_INS (bblock, ins);
5165                         break;
5166                 case CEE_LDARG_0:
5167                 case CEE_LDARG_1:
5168                 case CEE_LDARG_2:
5169                 case CEE_LDARG_3:
5170                         CHECK_STACK_OVF (1);
5171                         n = (*ip)-CEE_LDARG_0;
5172                         CHECK_ARG (n);
5173                         NEW_ARGLOAD (cfg, ins, n);
5174                         LDARG_SOFT_FLOAT (cfg, ins, n, ip);
5175                         ins->cil_code = ip++;
5176                         *sp++ = ins;
5177                         break;
5178                 case CEE_LDLOC_0:
5179                 case CEE_LDLOC_1:
5180                 case CEE_LDLOC_2:
5181                 case CEE_LDLOC_3:
5182                         CHECK_STACK_OVF (1);
5183                         n = (*ip)-CEE_LDLOC_0;
5184                         CHECK_LOCAL (n);
5185                         NEW_LOCLOAD (cfg, ins, n);
5186                         LDLOC_SOFT_FLOAT (cfg, ins, n, ip);
5187                         ins->cil_code = ip++;
5188                         *sp++ = ins;
5189                         break;
5190                 case CEE_STLOC_0:
5191                 case CEE_STLOC_1:
5192                 case CEE_STLOC_2:
5193                 case CEE_STLOC_3:
5194                         CHECK_STACK (1);
5195                         n = (*ip)-CEE_STLOC_0;
5196                         CHECK_LOCAL (n);
5197                         --sp;
5198                         handle_loaded_temps (cfg, bblock, stack_start, sp);
5199                         NEW_LOCSTORE (cfg, ins, n, *sp);
5200                         ins->cil_code = ip;
5201                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
5202                                 UNVERIFIED;
5203                         STLOC_SOFT_FLOAT (cfg, ins, n, ip);
5204                         if (ins->opcode == CEE_STOBJ) {
5205                                 NEW_LOCLOADA (cfg, ins, n);
5206                                 handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE, FALSE);
5207                         } else
5208                                 MONO_ADD_INS (bblock, ins);
5209                         ++ip;
5210                         inline_costs += 1;
5211                         break;
5212                 case CEE_LDARG_S:
5213                         CHECK_OPSIZE (2);
5214                         CHECK_STACK_OVF (1);
5215                         CHECK_ARG (ip [1]);
5216                         NEW_ARGLOAD (cfg, ins, ip [1]);
5217                         LDARG_SOFT_FLOAT (cfg, ins, ip [1], ip);
5218                         ins->cil_code = ip;
5219                         *sp++ = ins;
5220                         ip += 2;
5221                         break;
5222                 case CEE_LDARGA_S:
5223                         CHECK_OPSIZE (2);
5224                         CHECK_STACK_OVF (1);
5225                         CHECK_ARG (ip [1]);
5226                         NEW_ARGLOADA (cfg, ins, ip [1]);
5227                         ins->cil_code = ip;
5228                         *sp++ = ins;
5229                         ip += 2;
5230                         break;
5231                 case CEE_STARG_S:
5232                         CHECK_OPSIZE (2);
5233                         CHECK_STACK (1);
5234                         --sp;
5235                         CHECK_ARG (ip [1]);
5236                         NEW_ARGSTORE (cfg, ins, ip [1], *sp);
5237                         handle_loaded_temps (cfg, bblock, stack_start, sp);
5238                         ins->cil_code = ip;
5239                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [ip [1]], *sp))
5240                                 UNVERIFIED;
5241                         STARG_SOFT_FLOAT (cfg, ins, ip [1], ip);
5242                         if (ins->opcode == CEE_STOBJ) {
5243                                 NEW_ARGLOADA (cfg, ins, ip [1]);
5244                                 handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE, FALSE);
5245                         } else
5246                                 MONO_ADD_INS (bblock, ins);
5247                         ip += 2;
5248                         break;
5249                 case CEE_LDLOC_S:
5250                         CHECK_OPSIZE (2);
5251                         CHECK_STACK_OVF (1);
5252                         CHECK_LOCAL (ip [1]);
5253                         NEW_LOCLOAD (cfg, ins, ip [1]);
5254                         LDLOC_SOFT_FLOAT (cfg, ins, ip [1], ip);
5255                         ins->cil_code = ip;
5256                         *sp++ = ins;
5257                         ip += 2;
5258                         break;
5259                 case CEE_LDLOCA_S:
5260                         CHECK_OPSIZE (2);
5261                         CHECK_STACK_OVF (1);
5262                         CHECK_LOCAL (ip [1]);
5263                         NEW_LOCLOADA (cfg, ins, ip [1]);
5264                         ins->cil_code = ip;
5265                         *sp++ = ins;
5266                         ip += 2;
5267                         break;
5268                 case CEE_STLOC_S:
5269                         CHECK_OPSIZE (2);
5270                         CHECK_STACK (1);
5271                         --sp;
5272                         handle_loaded_temps (cfg, bblock, stack_start, sp);
5273                         CHECK_LOCAL (ip [1]);
5274                         NEW_LOCSTORE (cfg, ins, ip [1], *sp);
5275                         ins->cil_code = ip;
5276                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [ip [1]], *sp))
5277                                 UNVERIFIED;
5278                         STLOC_SOFT_FLOAT (cfg, ins, ip [1], ip);
5279                         if (ins->opcode == CEE_STOBJ) {
5280                                 NEW_LOCLOADA (cfg, ins, ip [1]);
5281                                 handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE, FALSE);
5282                         } else
5283                                 MONO_ADD_INS (bblock, ins);
5284                         ip += 2;
5285                         inline_costs += 1;
5286                         break;
5287                 case CEE_LDNULL:
5288                         CHECK_STACK_OVF (1);
5289                         NEW_PCONST (cfg, ins, NULL);
5290                         ins->cil_code = ip;
5291                         ins->type = STACK_OBJ;
5292                         ++ip;
5293                         *sp++ = ins;
5294                         break;
5295                 case CEE_LDC_I4_M1:
5296                         CHECK_STACK_OVF (1);
5297                         NEW_ICONST (cfg, ins, -1);
5298                         ins->cil_code = ip;
5299                         ++ip;
5300                         *sp++ = ins;
5301                         break;
5302                 case CEE_LDC_I4_0:
5303                 case CEE_LDC_I4_1:
5304                 case CEE_LDC_I4_2:
5305                 case CEE_LDC_I4_3:
5306                 case CEE_LDC_I4_4:
5307                 case CEE_LDC_I4_5:
5308                 case CEE_LDC_I4_6:
5309                 case CEE_LDC_I4_7:
5310                 case CEE_LDC_I4_8:
5311                         CHECK_STACK_OVF (1);
5312                         NEW_ICONST (cfg, ins, (*ip) - CEE_LDC_I4_0);
5313                         ins->cil_code = ip;
5314                         ++ip;
5315                         *sp++ = ins;
5316                         break;
5317                 case CEE_LDC_I4_S:
5318                         CHECK_OPSIZE (2);
5319                         CHECK_STACK_OVF (1);
5320                         ++ip;
5321                         NEW_ICONST (cfg, ins, *((signed char*)ip));
5322                         ins->cil_code = ip;
5323                         ++ip;
5324                         *sp++ = ins;
5325                         break;
5326                 case CEE_LDC_I4:
5327                         CHECK_OPSIZE (5);
5328                         CHECK_STACK_OVF (1);
5329                         NEW_ICONST (cfg, ins, (gint32)read32 (ip + 1));
5330                         ins->cil_code = ip;
5331                         ip += 5;
5332                         *sp++ = ins;
5333                         break;
5334                 case CEE_LDC_I8:
5335                         CHECK_OPSIZE (9);
5336                         CHECK_STACK_OVF (1);
5337                         MONO_INST_NEW (cfg, ins, OP_I8CONST);
5338                         ins->cil_code = ip;
5339                         ins->type = STACK_I8;
5340                         ++ip;
5341                         ins->inst_l = (gint64)read64 (ip);
5342                         ip += 8;
5343                         *sp++ = ins;
5344                         break;
5345                 case CEE_LDC_R4: {
5346                         float *f;
5347                         /* we should really allocate this only late in the compilation process */
5348                         mono_domain_lock (cfg->domain);
5349                         f = mono_mempool_alloc (cfg->domain->mp, sizeof (float));
5350                         mono_domain_unlock (cfg->domain);
5351                         CHECK_OPSIZE (5);
5352                         CHECK_STACK_OVF (1);
5353                         MONO_INST_NEW (cfg, ins, OP_R4CONST);
5354                         ins->type = STACK_R8;
5355                         ++ip;
5356                         readr4 (ip, f);
5357                         ins->inst_p0 = f;
5358
5359                         ip += 4;
5360                         *sp++ = ins;                    
5361                         break;
5362                 }
5363                 case CEE_LDC_R8: {
5364                         double *d;
5365                         mono_domain_lock (cfg->domain);
5366                         d = mono_mempool_alloc (cfg->domain->mp, sizeof (double));
5367                         mono_domain_unlock (cfg->domain);
5368                         CHECK_OPSIZE (9);
5369                         CHECK_STACK_OVF (1);
5370                         MONO_INST_NEW (cfg, ins, OP_R8CONST);
5371                         ins->type = STACK_R8;
5372                         ++ip;
5373                         readr8 (ip, d);
5374                         ins->inst_p0 = d;
5375
5376                         ip += 8;
5377                         *sp++ = ins;                    
5378                         break;
5379                 }
5380                 case CEE_DUP: {
5381                         MonoInst *temp, *store;
5382                         CHECK_STACK (1);
5383                         CHECK_STACK_OVF (1);
5384                         sp--;
5385                         ins = *sp;
5386                 
5387                         /* 
5388                          * small optimization: if the loaded value was from a local already,
5389                          * just load it twice.
5390                          */
5391                         if (ins->ssa_op == MONO_SSA_LOAD && 
5392                             (ins->inst_i0->opcode == OP_LOCAL || ins->inst_i0->opcode == OP_ARG)) {
5393                                 sp++;
5394                                 MONO_INST_NEW (cfg, temp, 0);
5395                                 *temp = *ins;
5396                                 temp->cil_code = ip;
5397                                 *sp++ = temp;
5398                         } else {
5399                                 temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
5400                                 temp->flags |= MONO_INST_IS_TEMP;
5401                                 temp->cil_code = ip;
5402                                 NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
5403                                 store->cil_code = ip;
5404                                 /* FIXME: handle CEE_STIND_R4 */
5405                                 if (store->opcode == CEE_STOBJ) {
5406                                         NEW_TEMPLOADA (cfg, store, temp->inst_c0);
5407                                         handle_stobj (cfg, bblock, store, sp [0], sp [0]->cil_code, store->klass, TRUE, FALSE, FALSE);
5408                                 } else {
5409                                         MONO_ADD_INS (bblock, store);
5410                                 }
5411                                 NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
5412                                 *sp++ = ins;
5413                                 ins->cil_code = ip;
5414                                 NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
5415                                 *sp++ = ins;
5416                                 ins->cil_code = ip;
5417                         }
5418                         ++ip;
5419                         inline_costs += 2;
5420                         break;
5421                 }
5422                 case CEE_POP:
5423                         CHECK_STACK (1);
5424                         MONO_INST_NEW (cfg, ins, CEE_POP);
5425                         MONO_ADD_INS (bblock, ins);
5426                         ins->cil_code = ip++;
5427                         --sp;
5428                         ins->inst_i0 = *sp;
5429                         break;
5430                 case CEE_JMP:
5431                         CHECK_OPSIZE (5);
5432                         if (stack_start != sp)
5433                                 UNVERIFIED;
5434                         MONO_INST_NEW (cfg, ins, OP_JMP);
5435                         token = read32 (ip + 1);
5436                         /* FIXME: check the signature matches */
5437                         cmethod = mini_get_method (method, token, NULL, generic_context);
5438
5439                         if (!cmethod)
5440                                 goto load_error;
5441
5442                         if (cfg->generic_sharing_context && mono_method_check_context_used (cmethod))
5443                                 GENERIC_SHARING_FAILURE (CEE_JMP);
5444
5445                         if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS) {
5446                                 if (check_linkdemand (cfg, method, cmethod, bblock, ip))
5447                                         INLINE_FAILURE;
5448                                 CHECK_CFG_EXCEPTION;
5449                         }
5450
5451                         ins->inst_p0 = cmethod;
5452                         MONO_ADD_INS (bblock, ins);
5453                         ip += 5;
5454                         start_new_bblock = 1;
5455                         break;
5456                 case CEE_CALLI:
5457                 case CEE_CALL:
5458                 case CEE_CALLVIRT: {
5459                         MonoInst *addr = NULL;
5460                         MonoMethodSignature *fsig = NULL;
5461                         int temp, array_rank = 0;
5462                         int virtual = *ip == CEE_CALLVIRT;
5463                         MonoInst *rgctx_arg = NULL;
5464                         gboolean no_spill;
5465                         int context_used = 0;
5466                         gboolean pass_rgctx = FALSE;
5467
5468                         CHECK_OPSIZE (5);
5469                         token = read32 (ip + 1);
5470
5471                         if (*ip == CEE_CALLI) {
5472                                 cmethod = NULL;
5473                                 CHECK_STACK (1);
5474                                 --sp;
5475                                 addr = *sp;
5476                                 if (method->wrapper_type != MONO_WRAPPER_NONE)
5477                                         fsig = (MonoMethodSignature *)mono_method_get_wrapper_data (method, token);
5478                                 else
5479                                         fsig = mono_metadata_parse_signature (image, token);
5480
5481                                 n = fsig->param_count + fsig->hasthis;
5482                         } else {
5483                                 MonoMethod *cil_method;
5484                                 
5485                                 if (method->wrapper_type != MONO_WRAPPER_NONE) {
5486                                         cmethod =  (MonoMethod *)mono_method_get_wrapper_data (method, token);
5487                                         cil_method = cmethod;
5488                                 } else if (constrained_call) {
5489                                         cmethod = mono_get_method_constrained (image, token, constrained_call, generic_context, &cil_method);
5490                                         cil_method = cmethod;
5491                                 } else {
5492                                         cmethod = mini_get_method (method, token, NULL, generic_context);
5493                                         cil_method = cmethod;
5494                                 }
5495
5496                                 if (!cmethod)
5497                                         goto load_error;
5498                                 if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_method (method, cil_method))
5499                                         METHOD_ACCESS_FAILURE;
5500
5501                                 if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR)
5502                                         ensure_method_is_allowed_to_call_method (cfg, method, cil_method, bblock, ip);
5503
5504                                 if (!virtual && (cmethod->flags & METHOD_ATTRIBUTE_ABSTRACT))
5505                                         /* MS.NET seems to silently convert this to a callvirt */
5506                                         virtual = 1;
5507
5508                                 if (!cmethod->klass->inited){
5509                                         if (!mono_class_init (cmethod->klass))
5510                                                 goto load_error;
5511                                 }
5512
5513                                 if (mono_method_signature (cmethod)->pinvoke) {
5514                                         MonoMethod *wrapper = mono_marshal_get_native_wrapper (cmethod, check_for_pending_exc);
5515                                         fsig = mono_method_signature (wrapper);
5516                                 } else if (constrained_call) {
5517                                         fsig = mono_method_signature (cmethod);
5518                                 } else {
5519                                         fsig = mono_method_get_signature_full (cmethod, image, token, generic_context);
5520                                 }
5521
5522                                 mono_save_token_info (cfg, image, token, cmethod);
5523
5524                                 n = fsig->param_count + fsig->hasthis;
5525
5526                                 if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS) {
5527                                         if (check_linkdemand (cfg, method, cmethod, bblock, ip))
5528                                                 INLINE_FAILURE;
5529                                         CHECK_CFG_EXCEPTION;
5530                                 }
5531
5532                                 if (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL &&
5533                                     mini_class_is_system_array (cmethod->klass)) {
5534                                         array_rank = cmethod->klass->rank;
5535                                 }
5536
5537                                 if (cmethod->string_ctor)
5538                                         g_assert_not_reached ();
5539
5540                         }
5541
5542                         if (!cfg->generic_sharing_context && cmethod && cmethod->klass->generic_container)
5543                                 UNVERIFIED;
5544
5545                         CHECK_STACK (n);
5546
5547                         //g_assert (!virtual || fsig->hasthis);
5548
5549                         sp -= n;
5550
5551                         if (constrained_call) {
5552                                 /*
5553                                  * We have the `constrained.' prefix opcode.
5554                                  */
5555                                 if (constrained_call->valuetype && !cmethod->klass->valuetype) {
5556                                         MonoInst *load;
5557                                         /*
5558                                          * The type parameter is instantiated as a valuetype,
5559                                          * but that type doesn't override the method we're
5560                                          * calling, so we need to box `this'.
5561                                          * sp [0] is a pointer to the data: we need the value
5562                                          * in handle_box (), so load it here.
5563                                          */
5564                                         MONO_INST_NEW (cfg, load, mini_type_to_ldind (cfg, &constrained_call->byval_arg));
5565                                         type_to_eval_stack_type (cfg, &constrained_call->byval_arg, load);
5566                                         load->cil_code = ip;
5567                                         load->inst_left = sp [0];
5568                                         sp [0] = handle_box (cfg, bblock, load, ip, constrained_call);
5569                                 } else if (!constrained_call->valuetype) {
5570                                         MonoInst *ins;
5571
5572                                         /*
5573                                          * The type parameter is instantiated as a reference
5574                                          * type.  We have a managed pointer on the stack, so
5575                                          * we need to dereference it here.
5576                                          */
5577
5578                                         MONO_INST_NEW (cfg, ins, CEE_LDIND_REF);
5579                                         ins->cil_code = ip;
5580                                         ins->inst_i0 = sp [0];
5581                                         ins->type = STACK_OBJ;
5582                                         ins->klass = mono_class_from_mono_type (&constrained_call->byval_arg);
5583                                         sp [0] = ins;
5584                                 } else if (cmethod->klass->valuetype)
5585                                         virtual = 0;
5586                                 constrained_call = NULL;
5587                         }
5588
5589                         if (*ip != CEE_CALLI && check_call_signature (cfg, fsig, sp))
5590                                 UNVERIFIED;
5591
5592                         if (cmethod && (cmethod->flags & METHOD_ATTRIBUTE_STATIC) &&
5593                                         (cmethod->klass->generic_class || cmethod->klass->generic_container)) {
5594                                 gboolean sharing_enabled = mono_class_generic_sharing_enabled (cmethod->klass);
5595                                 MonoGenericContext *context = mini_class_get_context (cmethod->klass);
5596                                 gboolean context_sharable = mono_generic_context_is_sharable (context, TRUE);
5597
5598                                 /*
5599                                  * Pass rgctx iff target method might
5600                                  * be shared, which means that sharing
5601                                  * is enabled for its class and its
5602                                  * context is sharable (and it's not a
5603                                  * generic method).
5604                                  */
5605                                 if (sharing_enabled && context_sharable &&
5606                                                 !mini_method_get_context (cmethod)->method_inst)
5607                                         pass_rgctx = TRUE;
5608                         }
5609
5610                         if (cfg->generic_sharing_context && cmethod) {
5611                                 MonoGenericContext *cmethod_context = mono_method_get_context (cmethod);
5612
5613                                 context_used = mono_method_check_context_used (cmethod);
5614
5615                                 if (context_used & MONO_GENERIC_CONTEXT_USED_METHOD)
5616                                         GENERIC_SHARING_FAILURE (*ip);
5617
5618                                 if (context_used &&
5619                                                 ((cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) ||
5620                                                 (cmethod_context && cmethod_context->method_inst && cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))) {
5621                                         GENERIC_SHARING_FAILURE (*ip);
5622                                 }
5623                         }
5624
5625                         if (pass_rgctx) {
5626                                 if (context_used) {
5627                                         MonoInst *this = NULL, *rgctx, *vtable, *field_offset, *field_addr;
5628
5629                                         GENERIC_SHARING_FAILURE_IF_VALUETYPE_METHOD (*ip);
5630
5631                                         if (!(method->flags & METHOD_ATTRIBUTE_STATIC))
5632                                                 NEW_ARGLOAD (cfg, this, 0);
5633                                         rgctx = get_runtime_generic_context (cfg, method, this, ip);
5634                                         vtable = get_runtime_generic_context_ptr (cfg, method, bblock, cmethod->klass,
5635                                                 token, MINI_TOKEN_SOURCE_METHOD, generic_context,
5636                                                 rgctx, MONO_RGCTX_INFO_VTABLE, ip);
5637
5638                                         NEW_ICONST (cfg, field_offset, G_STRUCT_OFFSET (MonoVTable, runtime_generic_context));
5639
5640                                         MONO_INST_NEW (cfg, field_addr, OP_PADD);
5641                                         field_addr->cil_code = ip;
5642                                         field_addr->inst_left = vtable;
5643                                         field_addr->inst_right = field_offset;
5644                                         field_addr->type = STACK_PTR;
5645
5646                                         MONO_INST_NEW (cfg, rgctx_arg, CEE_LDIND_I);
5647                                         rgctx_arg->cil_code = ip;
5648                                         rgctx_arg->inst_left = field_addr;
5649                                         rgctx_arg->type = STACK_PTR;
5650                                 } else {
5651                                         MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
5652
5653                                         NEW_PCONST (cfg, rgctx_arg, vtable->runtime_generic_context);
5654                                 }
5655                         }
5656
5657                         if (cmethod && virtual && 
5658                             (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) && 
5659                             !((cmethod->flags & METHOD_ATTRIBUTE_FINAL) && 
5660                               cmethod->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK) &&
5661                             mono_method_signature (cmethod)->generic_param_count) {
5662                                 MonoInst *this_temp, *this_arg_temp, *store;
5663                                 MonoInst *iargs [4];
5664
5665                                 g_assert (mono_method_signature (cmethod)->is_inflated);
5666                                 /* Prevent inlining of methods that contain indirect calls */
5667                                 INLINE_FAILURE;
5668
5669                                 this_temp = mono_compile_create_var (cfg, type_from_stack_type (sp [0]), OP_LOCAL);
5670                                 this_temp->cil_code = ip;
5671                                 NEW_TEMPSTORE (cfg, store, this_temp->inst_c0, sp [0]);
5672
5673                                 store->cil_code = ip;
5674                                 MONO_ADD_INS (bblock, store);
5675
5676                                 /* FIXME: This should be a managed pointer */
5677                                 this_arg_temp = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
5678                                 this_arg_temp->cil_code = ip;
5679
5680                                 /* Because of the PCONST below */
5681                                 cfg->disable_aot = TRUE;
5682                                 NEW_TEMPLOAD (cfg, iargs [0], this_temp->inst_c0);
5683                                 NEW_METHODCONST (cfg, iargs [1], cmethod);
5684                                 NEW_PCONST (cfg, iargs [2], mono_method_get_context (cmethod));
5685                                 NEW_TEMPLOADA (cfg, iargs [3], this_arg_temp->inst_c0);
5686                                 temp = mono_emit_jit_icall (cfg, bblock, mono_helper_compile_generic_method, iargs, ip);
5687
5688                                 NEW_TEMPLOAD (cfg, addr, temp);
5689                                 NEW_TEMPLOAD (cfg, sp [0], this_arg_temp->inst_c0);
5690
5691                                 if ((temp = mono_emit_calli_spilled (cfg, bblock, fsig, sp, addr, ip)) != -1) {
5692                                         NEW_TEMPLOAD (cfg, *sp, temp);
5693                                         sp++;
5694                                 }
5695
5696                                 ip += 5;
5697                                 ins_flag = 0;
5698                                 break;
5699                         }
5700
5701                         /* FIXME: runtime generic context pointer for jumps? */
5702                         if ((ins_flag & MONO_INST_TAILCALL) && cmethod && (*ip == CEE_CALL) &&
5703                                  (mono_metadata_signature_equal (mono_method_signature (method), mono_method_signature (cmethod)))) {
5704                                 int i;
5705
5706                                 GENERIC_SHARING_FAILURE (*ip);
5707
5708                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
5709                                 INLINE_FAILURE;
5710                                 /* FIXME: This assumes the two methods has the same number and type of arguments */
5711                                 /*
5712                                  * We implement tail calls by storing the actual arguments into the 
5713                                  * argument variables, then emitting a OP_JMP. Since the actual arguments
5714                                  * can refer to the arg variables, we have to spill them.
5715                                  */
5716                                 handle_loaded_temps (cfg, bblock, sp, sp + n);
5717                                 for (i = 0; i < n; ++i) {
5718                                         /* Prevent argument from being register allocated */
5719                                         arg_array [i]->flags |= MONO_INST_VOLATILE;
5720
5721                                         /* Check if argument is the same */
5722                                         /* 
5723                                          * FIXME: This loses liveness info, so it can only be done if the
5724                                          * argument is not register allocated.
5725                                          */
5726                                         NEW_ARGLOAD (cfg, ins, i);
5727                                         if ((ins->opcode == sp [i]->opcode) && (ins->inst_i0 == sp [i]->inst_i0))
5728                                                 continue;
5729
5730                                         NEW_ARGSTORE (cfg, ins, i, sp [i]);
5731                                         ins->cil_code = ip;
5732                                         /* FIXME: handle CEE_STIND_R4 */
5733                                         if (ins->opcode == CEE_STOBJ) {
5734                                                 NEW_ARGLOADA (cfg, ins, i);
5735                                                 handle_stobj (cfg, bblock, ins, sp [i], sp [i]->cil_code, ins->klass, FALSE, FALSE, FALSE);
5736                                         }
5737                                         else
5738                                                 MONO_ADD_INS (bblock, ins);
5739                                 }
5740                                 MONO_INST_NEW (cfg, ins, OP_JMP);
5741                                 ins->cil_code = ip;
5742                                 ins->inst_p0 = cmethod;
5743                                 ins->inst_p1 = arg_array [0];
5744                                 MONO_ADD_INS (bblock, ins);
5745                                 link_bblock (cfg, bblock, end_bblock);                  
5746                                 start_new_bblock = 1;
5747                                 /* skip CEE_RET as well */
5748                                 ip += 6;
5749                                 ins_flag = 0;
5750                                 break;
5751                         }
5752                         if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_get_inst_for_method (cfg, cmethod, fsig, sp))) {
5753                                 ins->cil_code = ip;
5754
5755                                 if (MONO_TYPE_IS_VOID (fsig->ret)) {
5756                                         MONO_ADD_INS (bblock, ins);
5757                                 } else {
5758                                         type_to_eval_stack_type (cfg, fsig->ret, ins);
5759                                         *sp = ins;
5760                                         sp++;
5761                                 }
5762
5763                                 ip += 5;
5764                                 ins_flag = 0;
5765                                 break;
5766                         }
5767
5768                         handle_loaded_temps (cfg, bblock, stack_start, sp);
5769
5770                         if ((cfg->opt & MONO_OPT_INLINE) && cmethod &&
5771                             (!virtual || !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) || (cmethod->flags & METHOD_ATTRIBUTE_FINAL)) && 
5772                             mono_method_check_inlining (cfg, cmethod) &&
5773                                  !g_list_find (dont_inline, cmethod)) {
5774                                 int costs;
5775                                 MonoBasicBlock *ebblock;
5776                                 gboolean allways = FALSE;
5777
5778                                 if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
5779                                         (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
5780                                         /* Prevent inlining of methods that call wrappers */
5781                                         INLINE_FAILURE;
5782                                         cmethod = mono_marshal_get_native_wrapper (cmethod, check_for_pending_exc);
5783                                         allways = TRUE;
5784                                 }
5785
5786                                 if ((costs = inline_method (cfg, cmethod, fsig, bblock, sp, ip, real_offset, dont_inline, &ebblock, allways))) {
5787                                         ip += 5;
5788                                         real_offset += 5;
5789
5790                                         GET_BBLOCK (cfg, bblock, ip);
5791                                         ebblock->next_bb = bblock;
5792                                         link_bblock (cfg, ebblock, bblock);
5793
5794                                         if (!MONO_TYPE_IS_VOID (fsig->ret))
5795                                                 sp++;
5796
5797                                         /* indicates start of a new block, and triggers a load of all 
5798                                            stack arguments at bb boundarie */
5799                                         bblock = ebblock;
5800
5801                                         inline_costs += costs;
5802                                         ins_flag = 0;
5803                                         break;
5804                                 }
5805                         }
5806                         
5807                         inline_costs += 10 * num_calls++;
5808
5809                         /* tail recursion elimination */
5810                         if ((cfg->opt & MONO_OPT_TAILC) && *ip == CEE_CALL && cmethod == method && ip [5] == CEE_RET &&
5811                                         !rgctx_arg) {
5812                                 gboolean has_vtargs = FALSE;
5813                                 int i;
5814                                 
5815                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
5816                                 INLINE_FAILURE;
5817                                 /* keep it simple */
5818                                 for (i =  fsig->param_count - 1; i >= 0; i--) {
5819                                         if (MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->params [i])) 
5820                                                 has_vtargs = TRUE;
5821                                 }
5822
5823                                 if (!has_vtargs) {
5824                                         for (i = 0; i < n; ++i) {
5825                                                 /* FIXME: handle CEE_STIND_R4 */
5826                                                 NEW_ARGSTORE (cfg, ins, i, sp [i]);
5827                                                 ins->cil_code = ip;
5828                                                 MONO_ADD_INS (bblock, ins);
5829                                         }
5830                                         MONO_INST_NEW (cfg, ins, OP_BR);
5831                                         ins->cil_code = ip;
5832                                         MONO_ADD_INS (bblock, ins);
5833                                         tblock = start_bblock->out_bb [0];
5834                                         link_bblock (cfg, bblock, tblock);
5835                                         ins->inst_target_bb = tblock;
5836                                         start_new_bblock = 1;
5837
5838                                         /* skip the CEE_RET, too */
5839                                         if (ip_in_bb (cfg, bblock, ip + 5))
5840                                                 ip += 6;
5841                                         else
5842                                                 ip += 5;
5843                                         ins_flag = 0;
5844                                         break;
5845                                 }
5846                         }
5847
5848                         if (ip_in_bb (cfg, bblock, ip + 5) 
5849                                 && (!MONO_TYPE_ISSTRUCT (fsig->ret))
5850                                 && (!MONO_TYPE_IS_VOID (fsig->ret) || (cmethod && cmethod->string_ctor))
5851                                 && (CODE_IS_STLOC (ip + 5) || ip [5] == CEE_POP || ip [5] == CEE_RET))
5852                                 /* No need to spill */
5853                                 no_spill = TRUE;
5854                         else
5855                                 no_spill = FALSE;
5856
5857                         if (context_used &&
5858                                         (cmethod->klass->valuetype ||
5859                                         (cmethod->is_inflated && mono_method_get_context (cmethod)->method_inst) ||
5860                                         ((cmethod->flags & METHOD_ATTRIBUTE_STATIC) &&
5861                                                 mono_class_generic_sharing_enabled (cmethod->klass)))) {
5862                                 MonoInst *this = NULL, *rgctx;
5863
5864                                 INLINE_FAILURE;
5865
5866                                 g_assert (cfg->generic_sharing_context && cmethod);
5867                                 g_assert (addr == NULL);
5868
5869                                 /*
5870                                  * We are compiling a call to a
5871                                  * generic method from shared code,
5872                                  * which means that we have to look up
5873                                  * the method in the rgctx and do an
5874                                  * indirect call.
5875                                  */
5876
5877                                 GENERIC_SHARING_FAILURE_IF_VALUETYPE_METHOD (*ip);
5878
5879                                 if (!(method->flags & METHOD_ATTRIBUTE_STATIC))
5880                                         NEW_ARGLOAD (cfg, this, 0);
5881                                 rgctx = get_runtime_generic_context (cfg, method, this, ip);
5882                                 addr = get_runtime_generic_context_method (cfg, method, bblock, cmethod,
5883                                                 generic_context, rgctx, MONO_RGCTX_INFO_GENERIC_METHOD_CODE, ip);
5884                         }
5885
5886                         if (addr) {
5887                                 if (*ip == CEE_CALL)
5888                                         g_assert (context_used);
5889                                 else if (*ip == CEE_CALLI)
5890                                         g_assert (!rgctx_arg);
5891                                 else
5892                                         g_assert_not_reached ();
5893
5894                                 /* Prevent inlining of methods with indirect calls */
5895                                 INLINE_FAILURE;
5896                                 if (no_spill) {
5897                                         ins = (MonoInst*)mono_emit_rgctx_calli (cfg, bblock, fsig, sp, addr, rgctx_arg, ip);
5898                                         *sp++ = ins;                                    
5899                                 } else {
5900                                         temp = mono_emit_rgctx_calli_spilled (cfg, bblock, fsig, sp, addr, rgctx_arg, ip);
5901                                         if (temp != -1) {
5902                                                 NEW_TEMPLOAD (cfg, *sp, temp);
5903                                                 sp++;
5904                                         }
5905                                 }                       
5906                         } else if (array_rank) {
5907                                 MonoInst *addr;
5908
5909                                 if (strcmp (cmethod->name, "Set") == 0) { /* array Set */ 
5910                                         if (sp [fsig->param_count]->type == STACK_OBJ) {
5911                                                 MonoInst *iargs [2];
5912                                                 MonoInst *array, *to_store, *store;
5913
5914                                                 handle_loaded_temps (cfg, bblock, stack_start, sp);
5915                                                 
5916                                                 array = mono_compile_create_var (cfg, type_from_stack_type (sp [0]), OP_LOCAL);
5917                                                 NEW_TEMPSTORE (cfg, store, array->inst_c0, sp [0]);
5918                                                 store->cil_code = ip;
5919                                                 MONO_ADD_INS (bblock, store);
5920                                                 NEW_TEMPLOAD (cfg, iargs [0], array->inst_c0);
5921
5922                                                 to_store = mono_compile_create_var (cfg, type_from_stack_type (sp [fsig->param_count]), OP_LOCAL);
5923                                                 NEW_TEMPSTORE (cfg, store, to_store->inst_c0, sp [fsig->param_count]);
5924                                                 /* FIXME: handle CEE_STIND_R4 */
5925                                                 store->cil_code = ip;
5926                                                 MONO_ADD_INS (bblock, store);
5927                                                 NEW_TEMPLOAD (cfg, iargs [1], to_store->inst_c0);
5928
5929                                                 /*
5930                                                  * We first save the args for the call so that the args are copied to the stack
5931                                                  * and a new instruction tree for them is created. If we don't do this,
5932                                                  * the same MonoInst is added to two different trees and this is not 
5933                                                  * allowed by burg.
5934                                                  */
5935                                                 mono_emit_jit_icall (cfg, bblock, mono_helper_stelem_ref_check, iargs, ip);
5936
5937                                                 NEW_TEMPLOAD (cfg, sp [0], array->inst_c0);
5938                                                 NEW_TEMPLOAD (cfg, sp [fsig->param_count], to_store->inst_c0);
5939                                         }
5940
5941                                         addr = mini_get_ldelema_ins (cfg, bblock, cmethod, sp, ip, TRUE);
5942                                         NEW_INDSTORE (cfg, ins, addr, sp [fsig->param_count], fsig->params [fsig->param_count - 1]);
5943                                         ins->cil_code = ip;
5944                                         /* FIXME: handle CEE_STIND_R4 */
5945                                         if (ins->opcode == CEE_STOBJ) {
5946                                                 handle_stobj (cfg, bblock, addr, sp [fsig->param_count], ip, mono_class_from_mono_type (fsig->params [fsig->param_count-1]), FALSE, FALSE, TRUE);
5947                                         } else {
5948                                                 MONO_ADD_INS (bblock, ins);
5949                                         }
5950
5951                                 } else if (strcmp (cmethod->name, "Get") == 0) { /* array Get */
5952                                         addr = mini_get_ldelema_ins (cfg, bblock, cmethod, sp, ip, FALSE);
5953                                         NEW_INDLOAD (cfg, ins, addr, fsig->ret);
5954                                         ins->cil_code = ip;
5955
5956                                         *sp++ = ins;
5957                                 } else if (strcmp (cmethod->name, "Address") == 0) { /* array Address */
5958                                         if (!cmethod->klass->element_class->valuetype && !readonly) {
5959                                                 MonoInst* check;
5960                                                 //* Needed by the code generated in inssel.brg * /
5961                                                 mono_get_got_var (cfg);
5962
5963                                                 MONO_INST_NEW (cfg, check, OP_CHECK_ARRAY_TYPE);
5964                                                 check->cil_code = ip;
5965                                                 check->klass = cmethod->klass;
5966                                                 check->inst_left = sp [0];
5967                                                 check->type = STACK_OBJ;
5968                                                 sp [0] = check;
5969                                         }
5970
5971                                         readonly = FALSE;
5972                                         addr = mini_get_ldelema_ins (cfg, bblock, cmethod, sp, ip, FALSE);
5973                                         *sp++ = addr;
5974                                 } else {
5975                                         g_assert_not_reached ();
5976                                 }
5977
5978                         } else {
5979                                 /* Prevent inlining of methods which call other methods */
5980                                 INLINE_FAILURE;
5981                                 if (mini_redirect_call (&temp, cfg, bblock, cmethod, fsig, sp, ip, virtual ? sp [0] : NULL)) {
5982                                         if (temp != -1) {
5983                                                 NEW_TEMPLOAD (cfg, *sp, temp);
5984                                                 sp++;
5985                                         }
5986                                 } else if (no_spill) {
5987                                         ins = (MonoInst*)mono_emit_rgctx_method_call (cfg, bblock, cmethod, fsig, sp, rgctx_arg, ip, virtual ? sp [0] : NULL);
5988                                         *sp++ = ins;
5989                                 } else {
5990                                         if ((temp = mono_emit_rgctx_method_call_spilled (cfg, bblock, cmethod, fsig, sp, rgctx_arg, ip, virtual ? sp [0] : NULL)) != -1) {
5991                                                 MonoInst *load;
5992                                                 NEW_TEMPLOAD (cfg, load, temp);
5993
5994 #ifdef MONO_ARCH_SOFT_FLOAT
5995                                                 if (load->opcode == CEE_LDIND_R4) {
5996                                                         NEW_TEMPLOADA (cfg, load, temp);
5997                                                         temp = handle_load_float (cfg, bblock, load, ip);
5998                                                         NEW_TEMPLOAD (cfg, load, temp);
5999                                                 }
6000 #endif
6001                                                 *sp++ = load;
6002                                         }
6003                                 }
6004                         }
6005
6006                         ip += 5;
6007                         ins_flag = 0;
6008                         break;
6009                 }
6010                 case CEE_RET:
6011                         if (cfg->method != method) {
6012                                 /* return from inlined method */
6013                                 if (return_var) {
6014                                         MonoInst *store;
6015                                         CHECK_STACK (1);
6016                                         --sp;
6017                                         //g_assert (returnvar != -1);
6018                                         NEW_TEMPSTORE (cfg, store, return_var->inst_c0, *sp);
6019                                         store->cil_code = sp [0]->cil_code;
6020                                         /* FIXME: handle CEE_STIND_R4 */
6021                                         if (store->opcode == CEE_STOBJ) {
6022                                                 g_assert_not_reached ();
6023                                                 NEW_TEMPLOADA (cfg, store, return_var->inst_c0);
6024                                                 /* FIXME: it is possible some optimization will pass the a heap pointer for the struct address, so we'll need the write barrier */
6025                                                 handle_stobj (cfg, bblock, store, *sp, sp [0]->cil_code, return_var->klass, FALSE, FALSE, FALSE);
6026 #ifdef MONO_ARCH_SOFT_FLOAT
6027                                         } else if (store->opcode == CEE_STIND_R4) {
6028                                                 NEW_TEMPLOADA (cfg, store, return_var->inst_c0);
6029                                                 handle_store_float (cfg, bblock, store, *sp, sp [0]->cil_code);
6030 #endif
6031                                         } else
6032                                                 MONO_ADD_INS (bblock, store);
6033                                 } 
6034                         } else {
6035                                 if (cfg->ret) {
6036                                         g_assert (!return_var);
6037                                         CHECK_STACK (1);
6038                                         --sp;
6039                                         MONO_INST_NEW (cfg, ins, OP_NOP);
6040                                         ins->opcode = mini_type_to_stind (cfg, mono_method_signature (method)->ret);
6041                                         if (ins->opcode == CEE_STOBJ) {
6042                                                 NEW_RETLOADA (cfg, ins);
6043                                                 /* FIXME: it is possible some optimization will pass the a heap pointer for the struct address, so we'll need the write barrier */
6044                                                 handle_stobj (cfg, bblock, ins, *sp, ip, cfg->ret->klass, FALSE, FALSE, FALSE);
6045                                         } else {
6046                                                 ins->opcode = OP_SETRET;
6047                                                 ins->cil_code = ip;
6048                                                 ins->inst_i0 = *sp;;
6049                                                 ins->inst_i1 = NULL;
6050                                                 MONO_ADD_INS (bblock, ins);
6051                                         }
6052                                 }
6053                         }
6054                         if (sp != stack_start)
6055                                 UNVERIFIED;
6056                         MONO_INST_NEW (cfg, ins, OP_BR);
6057                         ins->cil_code = ip++;
6058                         ins->inst_target_bb = end_bblock;
6059                         MONO_ADD_INS (bblock, ins);
6060                         link_bblock (cfg, bblock, end_bblock);
6061                         start_new_bblock = 1;
6062                         break;
6063                 case CEE_BR_S:
6064                         CHECK_OPSIZE (2);
6065                         MONO_INST_NEW (cfg, ins, OP_BR);
6066                         ins->cil_code = ip++;
6067                         MONO_ADD_INS (bblock, ins);
6068                         target = ip + 1 + (signed char)(*ip);
6069                         ++ip;
6070                         GET_BBLOCK (cfg, tblock, target);
6071                         link_bblock (cfg, bblock, tblock);
6072                         CHECK_BBLOCK (target, ip, tblock);
6073                         ins->inst_target_bb = tblock;
6074                         if (sp != stack_start) {
6075                                 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
6076                                 sp = stack_start;
6077                                 CHECK_UNVERIFIABLE (cfg);
6078                         }
6079                         start_new_bblock = 1;
6080                         inline_costs += BRANCH_COST;
6081                         break;
6082                 case CEE_BRFALSE_S:
6083                 case CEE_BRTRUE_S:
6084                         CHECK_OPSIZE (2);
6085                         CHECK_STACK (1);
6086                         if (sp [-1]->type == STACK_VTYPE || sp [-1]->type == STACK_R8)
6087                                 UNVERIFIED;
6088                         MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
6089                         ins->cil_code = ip++;
6090                         target = ip + 1 + *(signed char*)ip;
6091                         ip++;
6092                         ADD_UNCOND (ins->opcode == CEE_BRTRUE);
6093                         if (sp != stack_start) {
6094                                 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
6095                                 sp = stack_start;
6096                                 CHECK_UNVERIFIABLE (cfg);
6097                         }
6098                         inline_costs += BRANCH_COST;
6099                         break;
6100                 case CEE_BEQ_S:
6101                 case CEE_BGE_S:
6102                 case CEE_BGT_S:
6103                 case CEE_BLE_S:
6104                 case CEE_BLT_S:
6105                 case CEE_BNE_UN_S:
6106                 case CEE_BGE_UN_S:
6107                 case CEE_BGT_UN_S:
6108                 case CEE_BLE_UN_S:
6109                 case CEE_BLT_UN_S:
6110                         CHECK_OPSIZE (2);
6111                         CHECK_STACK (2);
6112                         MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
6113                         ins->cil_code = ip++;
6114                         target = ip + 1 + *(signed char*)ip;
6115                         ip++;
6116 #ifdef MONO_ARCH_SOFT_FLOAT
6117                         if (sp [-1]->type == STACK_R8 || sp [-2]->type == STACK_R8) {
6118                                 ins->opcode = condbr_to_fp_br (ins->opcode);
6119                                 sp -= 2;
6120                                 ins->inst_left = sp [0];
6121                                 ins->inst_right = sp [1];
6122                                 ins->type = STACK_I4;
6123                                 *sp++ = emit_tree (cfg, bblock, ins, ins->cil_code);
6124                                 MONO_INST_NEW (cfg, ins, CEE_BRTRUE);
6125                                 ADD_UNCOND (TRUE);
6126                         } else {
6127                                 ADD_BINCOND (NULL);
6128                         }
6129 #else
6130                         ADD_BINCOND (NULL);
6131 #endif
6132                         if (sp != stack_start) {
6133                                 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
6134                                 sp = stack_start;
6135                                 CHECK_UNVERIFIABLE (cfg);
6136                         }
6137                         inline_costs += BRANCH_COST;
6138                         break;
6139                 case CEE_BR:
6140                         CHECK_OPSIZE (5);
6141                         MONO_INST_NEW (cfg, ins, OP_BR);
6142                         ins->cil_code = ip++;
6143                         MONO_ADD_INS (bblock, ins);
6144                         target = ip + 4 + (gint32)read32(ip);
6145                         ip += 4;
6146                         GET_BBLOCK (cfg, tblock, target);
6147                         link_bblock (cfg, bblock, tblock);
6148                         CHECK_BBLOCK (target, ip, tblock);
6149                         ins->inst_target_bb = tblock;
6150                         if (sp != stack_start) {
6151                                 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
6152                                 sp = stack_start;
6153                                 CHECK_UNVERIFIABLE (cfg);
6154                         }
6155                         start_new_bblock = 1;
6156                         inline_costs += BRANCH_COST;
6157                         break;
6158                 case CEE_BRFALSE:
6159                 case CEE_BRTRUE:
6160                         CHECK_OPSIZE (5);
6161                         CHECK_STACK (1);
6162                         if (sp [-1]->type == STACK_VTYPE || sp [-1]->type == STACK_R8)
6163                                 UNVERIFIED;
6164                         MONO_INST_NEW (cfg, ins, *ip);
6165                         ins->cil_code = ip++;
6166                         target = ip + 4 + (gint32)read32(ip);
6167                         ip += 4;
6168                         ADD_UNCOND(ins->opcode == CEE_BRTRUE);
6169                         if (sp != stack_start) {
6170                                 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
6171                                 sp = stack_start;
6172                                 CHECK_UNVERIFIABLE (cfg);
6173                         }
6174                         inline_costs += BRANCH_COST;
6175                         break;
6176                 case CEE_BEQ:
6177                 case CEE_BGE:
6178                 case CEE_BGT:
6179                 case CEE_BLE:
6180                 case CEE_BLT:
6181                 case CEE_BNE_UN:
6182                 case CEE_BGE_UN:
6183                 case CEE_BGT_UN:
6184                 case CEE_BLE_UN:
6185                 case CEE_BLT_UN:
6186                         CHECK_OPSIZE (5);
6187                         CHECK_STACK (2);
6188                         MONO_INST_NEW (cfg, ins, *ip);
6189                         ins->cil_code = ip++;
6190                         target = ip + 4 + (gint32)read32(ip);
6191                         ip += 4;
6192 #ifdef MONO_ARCH_SOFT_FLOAT
6193                         if (sp [-1]->type == STACK_R8 || sp [-2]->type == STACK_R8) {
6194                                 ins->opcode = condbr_to_fp_br (ins->opcode);
6195                                 sp -= 2;
6196                                 ins->inst_left = sp [0];
6197                                 ins->inst_right = sp [1];
6198                                 ins->type = STACK_I4;
6199                                 *sp++ = emit_tree (cfg, bblock, ins, ins->cil_code);
6200                                 MONO_INST_NEW (cfg, ins, CEE_BRTRUE);
6201                                 ADD_UNCOND (TRUE);
6202                         } else {
6203                                 ADD_BINCOND (NULL);
6204                         }
6205 #else
6206                         ADD_BINCOND (NULL);
6207 #endif
6208                         if (sp != stack_start) {
6209                                 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
6210                                 sp = stack_start;
6211                                 CHECK_UNVERIFIABLE (cfg);
6212                         }
6213                         inline_costs += BRANCH_COST;
6214                         break;
6215                 case CEE_SWITCH:
6216                         CHECK_OPSIZE (5);
6217                         CHECK_STACK (1);
6218                         n = read32 (ip + 1);
6219                         MONO_INST_NEW (cfg, ins, OP_SWITCH);
6220                         --sp;
6221                         ins->inst_left = *sp;
6222                         if ((ins->inst_left->type != STACK_I4) && (ins->inst_left->type != STACK_PTR)) 
6223                                 UNVERIFIED;
6224                         ins->cil_code = ip;
6225                         ip += 5;
6226                         CHECK_OPSIZE (n * sizeof (guint32));
6227                         target = ip + n * sizeof (guint32);
6228                         MONO_ADD_INS (bblock, ins);
6229                         GET_BBLOCK (cfg, tblock, target);
6230                         link_bblock (cfg, bblock, tblock);
6231                         ins->klass = GUINT_TO_POINTER (n);
6232                         ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * (n + 1));
6233                         ins->inst_many_bb [n] = tblock;
6234
6235                         for (i = 0; i < n; ++i) {
6236                                 GET_BBLOCK (cfg, tblock, target + (gint32)read32(ip));
6237                                 link_bblock (cfg, bblock, tblock);
6238                                 ins->inst_many_bb [i] = tblock;
6239                                 ip += 4;
6240                         }
6241                         if (sp != stack_start) {
6242                                 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
6243                                 sp = stack_start;
6244                                 CHECK_UNVERIFIABLE (cfg);
6245                         }
6246                         /* Needed by the code generated in inssel.brg */
6247                         mono_get_got_var (cfg);
6248                         inline_costs += (BRANCH_COST * 2);
6249                         break;
6250                 case CEE_LDIND_I1:
6251                 case CEE_LDIND_U1:
6252                 case CEE_LDIND_I2:
6253                 case CEE_LDIND_U2:
6254                 case CEE_LDIND_I4:
6255                 case CEE_LDIND_U4:
6256                 case CEE_LDIND_I8:
6257                 case CEE_LDIND_I:
6258                 case CEE_LDIND_R4:
6259                 case CEE_LDIND_R8:
6260                 case CEE_LDIND_REF:
6261                         CHECK_STACK (1);
6262                         MONO_INST_NEW (cfg, ins, *ip);
6263                         ins->cil_code = ip;
6264                         --sp;
6265                         ins->inst_i0 = *sp;
6266                         *sp++ = ins;
6267                         ins->type = ldind_type [*ip - CEE_LDIND_I1];
6268                         ins->flags |= ins_flag;
6269                         ins_flag = 0;
6270                         if (ins->type == STACK_OBJ)
6271                                 ins->klass = mono_defaults.object_class;
6272 #ifdef MONO_ARCH_SOFT_FLOAT
6273                         if (*ip == CEE_LDIND_R4) {
6274                                 int temp;
6275                                 --sp;
6276                                 temp = handle_load_float (cfg, bblock, ins->inst_i0, ip);
6277                                 NEW_TEMPLOAD (cfg, *sp, temp);
6278                                 sp++;
6279                         }
6280 #endif
6281                         ++ip;
6282                         break;
6283                 case CEE_STIND_REF:
6284                 case CEE_STIND_I1:
6285                 case CEE_STIND_I2:
6286                 case CEE_STIND_I4:
6287                 case CEE_STIND_I8:
6288                 case CEE_STIND_R4:
6289                 case CEE_STIND_R8:
6290                         CHECK_STACK (2);
6291 #ifdef MONO_ARCH_SOFT_FLOAT
6292                         if (*ip == CEE_STIND_R4) {
6293                                 sp -= 2;
6294                                 handle_store_float (cfg, bblock, sp [0], sp [1], ip);
6295                                 ip++;
6296                                 break;
6297                         }
6298 #endif
6299 #if HAVE_WRITE_BARRIERS
6300                         if (*ip == CEE_STIND_REF && method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER && !((sp [-1]->opcode == OP_PCONST) && (sp [-1]->inst_p0 == 0))) {
6301                                 /* insert call to write barrier */
6302                                 MonoMethod *write_barrier = mono_marshal_get_write_barrier ();
6303                                 sp -= 2;
6304                                 mono_emit_method_call_spilled (cfg, bblock, write_barrier, mono_method_signature (write_barrier), sp, ip, NULL);
6305                                 ip++;
6306                                 break;
6307                         }
6308 #endif
6309                         MONO_INST_NEW (cfg, ins, *ip);
6310                         ins->cil_code = ip++;
6311                         sp -= 2;
6312                         handle_loaded_temps (cfg, bblock, stack_start, sp);
6313                         MONO_ADD_INS (bblock, ins);
6314                         ins->inst_i0 = sp [0];
6315                         ins->inst_i1 = sp [1];
6316                         ins->flags |= ins_flag;
6317                         ins_flag = 0;
6318                         inline_costs += 1;
6319                         break;
6320                 case CEE_MUL:
6321                         CHECK_STACK (2);
6322                         ADD_BINOP (*ip);
6323
6324 #ifdef MONO_ARCH_NO_EMULATE_MUL_IMM
6325                         /* FIXME: This breaks with ssapre (mono -O=ssapre loader.exe) */
6326                         if ((ins->inst_right->opcode == OP_ICONST) && !(cfg->opt & MONO_OPT_SSAPRE)) {
6327                                 switch (ins->opcode) {
6328                                 case CEE_MUL:
6329                                         ins->opcode = OP_IMUL_IMM;
6330                                         ins->inst_imm = ins->inst_right->inst_c0;
6331                                         break;
6332                                 case OP_LMUL:
6333                                         ins->opcode = OP_LMUL_IMM;
6334                                         ins->inst_imm = ins->inst_right->inst_c0;
6335                                         break;
6336                                 default:
6337                                         g_assert_not_reached ();
6338                                 }
6339                         }
6340 #endif
6341
6342                         if (mono_find_jit_opcode_emulation (ins->opcode)) {
6343                                 --sp;
6344                                 *sp++ = emit_tree (cfg, bblock, ins, ip + 1);
6345                         }
6346                         ip++;
6347                         break;
6348                 case CEE_ADD:
6349                 case CEE_SUB:
6350                 case CEE_DIV:
6351                 case CEE_DIV_UN:
6352                 case CEE_REM:
6353                 case CEE_REM_UN:
6354                 case CEE_AND:
6355                 case CEE_OR:
6356                 case CEE_XOR:
6357                 case CEE_SHL:
6358                 case CEE_SHR:
6359                 case CEE_SHR_UN:
6360                         CHECK_STACK (2);
6361                         ADD_BINOP (*ip);
6362                         /* special case that gives a nice speedup and happens to workaorund a ppc jit but (for the release)
6363                          * later apply the speedup to the left shift as well
6364                          * See BUG# 57957.
6365                          */
6366                         if ((ins->opcode == OP_LSHR_UN) && (ins->type == STACK_I8) 
6367                                         && (ins->inst_right->opcode == OP_ICONST) && (ins->inst_right->inst_c0 == 32)) {
6368                                 ins->opcode = OP_LONG_SHRUN_32;
6369                                 /*g_print ("applied long shr speedup to %s\n", cfg->method->name);*/
6370                                 ip++;
6371                                 break;
6372                         }
6373                         if (mono_find_jit_opcode_emulation (ins->opcode)) {
6374                                 --sp;
6375                                 *sp++ = emit_tree (cfg, bblock, ins, ip + 1);
6376                         }
6377                         ip++;
6378                         break;
6379                 case CEE_NEG:
6380                 case CEE_NOT:
6381                 case CEE_CONV_I1:
6382                 case CEE_CONV_I2:
6383                 case CEE_CONV_I4:
6384                 case CEE_CONV_R4:
6385                 case CEE_CONV_R8:
6386                 case CEE_CONV_U4:
6387                 case CEE_CONV_I8:
6388                 case CEE_CONV_U8:
6389                 case CEE_CONV_OVF_I8:
6390                 case CEE_CONV_OVF_U8:
6391                 case CEE_CONV_R_UN:
6392                         CHECK_STACK (1);
6393                         ADD_UNOP (*ip);
6394                         if (mono_find_jit_opcode_emulation (ins->opcode)) {
6395                                 --sp;
6396                                 *sp++ = emit_tree (cfg, bblock, ins, ip + 1);
6397                         }
6398                         ip++;                   
6399                         break;
6400                 case CEE_CONV_OVF_I4:
6401                 case CEE_CONV_OVF_I1:
6402                 case CEE_CONV_OVF_I2:
6403                 case CEE_CONV_OVF_I:
6404                 case CEE_CONV_OVF_U:
6405                         CHECK_STACK (1);
6406
6407                         if (sp [-1]->type == STACK_R8) {
6408                                 ADD_UNOP (CEE_CONV_OVF_I8);
6409                                 ADD_UNOP (*ip);
6410                         } else {
6411                                 ADD_UNOP (*ip);
6412                         }
6413
6414                         ip++;
6415                         break;
6416                 case CEE_CONV_OVF_U1:
6417                 case CEE_CONV_OVF_U2:
6418                 case CEE_CONV_OVF_U4:
6419                         CHECK_STACK (1);
6420
6421                         if (sp [-1]->type == STACK_R8) {
6422                                 ADD_UNOP (CEE_CONV_OVF_U8);
6423                                 ADD_UNOP (*ip);
6424                         } else {
6425                                 ADD_UNOP (*ip);
6426                         }
6427
6428                         ip++;
6429                         break;
6430                 case CEE_CONV_OVF_I1_UN:
6431                 case CEE_CONV_OVF_I2_UN:
6432                 case CEE_CONV_OVF_I4_UN:
6433                 case CEE_CONV_OVF_I8_UN:
6434                 case CEE_CONV_OVF_U1_UN:
6435                 case CEE_CONV_OVF_U2_UN:
6436                 case CEE_CONV_OVF_U4_UN:
6437                 case CEE_CONV_OVF_U8_UN:
6438                 case CEE_CONV_OVF_I_UN:
6439                 case CEE_CONV_OVF_U_UN:
6440                         CHECK_STACK (1);
6441                         ADD_UNOP (*ip);
6442                         ip++;
6443                         break;
6444                 case CEE_CPOBJ:
6445                         CHECK_OPSIZE (5);
6446                         CHECK_STACK (2);
6447                         token = read32 (ip + 1);
6448                         klass = mini_get_class (method, token, generic_context);
6449                         CHECK_TYPELOAD (klass);
6450                         sp -= 2;
6451                         if (generic_class_is_reference_type (cfg, klass)) {
6452                                 MonoInst *store, *load;
6453                                 MONO_INST_NEW (cfg, load, CEE_LDIND_REF);
6454                                 load->cil_code = ip;
6455                                 load->inst_i0 = sp [1];
6456                                 load->type = STACK_OBJ;
6457                                 load->klass = klass;
6458                                 load->flags |= ins_flag;
6459                                 MONO_INST_NEW (cfg, store, CEE_STIND_REF);
6460                                 store->cil_code = ip;
6461                                 handle_loaded_temps (cfg, bblock, stack_start, sp);
6462                                 MONO_ADD_INS (bblock, store);
6463                                 store->inst_i0 = sp [0];
6464                                 store->inst_i1 = load;
6465                                 store->flags |= ins_flag;
6466                         } else {
6467                                 guint32 align;
6468
6469                                 n = mono_class_value_size (klass, &align);
6470                                 if ((cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 5) {
6471                                         MonoInst *copy;
6472                                         NEW_MEMCPY (cfg, copy, sp [0], sp [1], n, align);
6473                                         MONO_ADD_INS (bblock, copy);
6474                                 } else {
6475                                         MonoMethod *memcpy_method = get_memcpy_method ();
6476                                         MonoInst *iargs [3];
6477                                         iargs [0] = sp [0];
6478                                         iargs [1] = sp [1];
6479                                         NEW_ICONST (cfg, iargs [2], n);
6480                                         iargs [2]->cil_code = ip;
6481
6482                                         mono_emit_method_call_spilled (cfg, bblock, memcpy_method, memcpy_method->signature, iargs, ip, NULL);
6483                                 }
6484                         }
6485                         ins_flag = 0;
6486                         ip += 5;
6487                         break;
6488                 case CEE_LDOBJ: {
6489                         MonoInst *iargs [3];
6490                         int loc_index = -1;
6491                         int stloc_len = 0;
6492                         guint32 align;
6493
6494                         CHECK_OPSIZE (5);
6495                         CHECK_STACK (1);
6496                         --sp;
6497                         token = read32 (ip + 1);
6498                         klass = mini_get_class (method, token, generic_context);
6499                         CHECK_TYPELOAD (klass);
6500                         if (generic_class_is_reference_type (cfg, klass)) {
6501                                 MONO_INST_NEW (cfg, ins, CEE_LDIND_REF);
6502                                 ins->cil_code = ip;
6503                                 ins->inst_i0 = sp [0];
6504                                 ins->type = STACK_OBJ;
6505                                 ins->klass = klass;
6506                                 ins->flags |= ins_flag;
6507                                 ins_flag = 0;
6508                                 *sp++ = ins;
6509                                 ip += 5;
6510                                 break;
6511                         }
6512
6513                         /* Optimize the common ldobj+stloc combination */
6514                         switch (ip [5]) {
6515                         case CEE_STLOC_S:
6516                                 loc_index = ip [6];
6517                                 stloc_len = 2;
6518                                 break;
6519                         case CEE_STLOC_0:
6520                         case CEE_STLOC_1:
6521                         case CEE_STLOC_2:
6522                         case CEE_STLOC_3:
6523                                 loc_index = ip [5] - CEE_STLOC_0;
6524                                 stloc_len = 1;
6525                                 break;
6526                         default:
6527                                 break;
6528                         }
6529
6530                         if ((loc_index != -1) && ip_in_bb (cfg, bblock, ip + 5)) {
6531                                 CHECK_LOCAL (loc_index);
6532                                 NEW_LOCSTORE (cfg, ins, loc_index, *sp);
6533
6534                                 /* FIXME: handle CEE_STIND_R4 */
6535                                 if (ins->opcode == CEE_STOBJ) {
6536                                         handle_loaded_temps (cfg, bblock, stack_start, sp);
6537                                         ins->cil_code = ip;
6538                                         g_assert (ins->opcode == CEE_STOBJ);
6539                                         NEW_LOCLOADA (cfg, ins, loc_index);
6540                                         handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE, FALSE);
6541                                         ip += 5;
6542                                         ip += stloc_len;
6543                                         break;
6544                                 }
6545                         }
6546
6547                         n = mono_class_value_size (klass, &align);
6548                         ins = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
6549                         NEW_TEMPLOADA (cfg, iargs [0], ins->inst_c0);
6550                         if ((cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 5) {
6551                                 MonoInst *copy;
6552                                 NEW_MEMCPY (cfg, copy, iargs [0], *sp, n, align);
6553                                 MONO_ADD_INS (bblock, copy);
6554                         } else {
6555                                 MonoMethod *memcpy_method = get_memcpy_method ();
6556                                 iargs [1] = *sp;
6557                                 NEW_ICONST (cfg, iargs [2], n);
6558                                 iargs [2]->cil_code = ip;
6559
6560                                 mono_emit_method_call_spilled (cfg, bblock, memcpy_method, memcpy_method->signature, iargs, ip, NULL);
6561                         }
6562                         NEW_TEMPLOAD (cfg, *sp, ins->inst_c0);
6563                         ++sp;
6564                         ip += 5;
6565                         ins_flag = 0;
6566                         inline_costs += 1;
6567                         break;
6568                 }
6569                 case CEE_LDSTR:
6570                         CHECK_STACK_OVF (1);
6571                         CHECK_OPSIZE (5);
6572                         n = read32 (ip + 1);
6573
6574                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
6575                                 /* FIXME: moving GC */
6576                                 NEW_PCONST (cfg, ins, mono_method_get_wrapper_data (method, n));
6577                                 ins->cil_code = ip;
6578                                 ins->type = STACK_OBJ;
6579                                 ins->klass = mono_defaults.string_class;
6580                                 *sp = ins;
6581                         }
6582                         else if (method->wrapper_type != MONO_WRAPPER_NONE) {
6583                                 int temp;
6584                                 MonoInst *iargs [1];
6585
6586                                 NEW_PCONST (cfg, iargs [0], mono_method_get_wrapper_data (method, n));                          
6587                                 temp = mono_emit_jit_icall (cfg, bblock, mono_string_new_wrapper, iargs, ip);
6588                                 NEW_TEMPLOAD (cfg, *sp, temp);
6589
6590                         } else {
6591
6592                                 if (cfg->opt & MONO_OPT_SHARED) {
6593                                         int temp;
6594                                         MonoInst *iargs [3];
6595                                         MonoInst* domain_var;
6596                                         
6597                                         if (cfg->compile_aot) {
6598                                                 /* FIXME: bug when inlining methods from different assemblies (n is a token valid just in one). */
6599                                                 cfg->ldstr_list = g_list_prepend (cfg->ldstr_list, GINT_TO_POINTER (n));
6600                                         }
6601                                         /* avoid depending on undefined C behavior in sequence points */
6602                                         domain_var = mono_get_domainvar (cfg);
6603                                         NEW_TEMPLOAD (cfg, iargs [0], domain_var->inst_c0);
6604                                         NEW_IMAGECONST (cfg, iargs [1], image);
6605                                         NEW_ICONST (cfg, iargs [2], mono_metadata_token_index (n));
6606                                         temp = mono_emit_jit_icall (cfg, bblock, mono_ldstr, iargs, ip);
6607                                         NEW_TEMPLOAD (cfg, *sp, temp);
6608                                         mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
6609                                 } else {
6610                                         if (bblock->out_of_line) {
6611                                                 MonoInst *iargs [2];
6612                                                 int temp;
6613
6614                                                 if (cfg->method->klass->image == mono_defaults.corlib) {
6615                                                         /* 
6616                                                          * Avoid relocations and save some code size by using a 
6617                                                          * version of helper_ldstr specialized to mscorlib.
6618                                                          */
6619                                                         NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (n));
6620                                                         temp = mono_emit_jit_icall (cfg, bblock, mono_helper_ldstr_mscorlib, iargs, ip);
6621                                                 } else {
6622                                                         /* Avoid creating the string object */
6623                                                         NEW_IMAGECONST (cfg, iargs [0], image);
6624                                                         NEW_ICONST (cfg, iargs [1], mono_metadata_token_index (n));
6625                                                         temp = mono_emit_jit_icall (cfg, bblock, mono_helper_ldstr, iargs, ip);
6626                                                 }
6627                                                 NEW_TEMPLOAD (cfg, *sp, temp);
6628                                         } 
6629                                         else
6630                                         if (cfg->compile_aot) {
6631                                                 NEW_LDSTRCONST (cfg, ins, image, n);
6632                                                 *sp = ins;
6633                                         } 
6634                                         else {
6635                                                 NEW_PCONST (cfg, ins, NULL);
6636                                                 ins->cil_code = ip;
6637                                                 ins->type = STACK_OBJ;
6638                                                 ins->inst_p0 = mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
6639                                                 ins->klass = mono_defaults.string_class;
6640                                                 *sp = ins;
6641                                         }
6642                                 }
6643                         }
6644
6645                         sp++;
6646                         ip += 5;
6647                         break;
6648                 case CEE_NEWOBJ: {
6649                         MonoInst *iargs [2];
6650                         MonoMethodSignature *fsig;
6651                         int temp;
6652                         gboolean generic_shared = FALSE;
6653
6654                         CHECK_OPSIZE (5);
6655                         token = read32 (ip + 1);
6656                         cmethod = mini_get_method (method, token, NULL, generic_context);
6657                         if (!cmethod)
6658                                 goto load_error;
6659                         fsig = mono_method_get_signature (cmethod, image, token);
6660
6661                         mono_save_token_info (cfg, image, token, cmethod);
6662
6663                         if (!mono_class_init (cmethod->klass))
6664                                 goto load_error;
6665
6666                         if (cfg->generic_sharing_context) {
6667                                 int context_used = mono_method_check_context_used (cmethod);
6668
6669                                 if (context_used & MONO_GENERIC_CONTEXT_USED_METHOD)
6670                                         GENERIC_SHARING_FAILURE (CEE_NEWOBJ);
6671
6672                                 if (context_used)
6673                                         generic_shared = TRUE;
6674                         }
6675
6676                         if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS) {
6677                                 if (check_linkdemand (cfg, method, cmethod, bblock, ip))
6678                                         INLINE_FAILURE;
6679                                 CHECK_CFG_EXCEPTION;
6680                         } else if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR) {
6681                                 ensure_method_is_allowed_to_call_method (cfg, method, cmethod, bblock, ip);
6682                         }
6683
6684                         n = fsig->param_count;
6685                         CHECK_STACK (n);
6686  
6687                         /* 
6688                          * Generate smaller code for the common newobj <exception> instruction in
6689                          * argument checking code.
6690                          */
6691                         if (bblock->out_of_line && cmethod->klass->image == mono_defaults.corlib && n <= 2 && 
6692                                 ((n < 1) || (!fsig->params [0]->byref && fsig->params [0]->type == MONO_TYPE_STRING)) && 
6693                                 ((n < 2) || (!fsig->params [1]->byref && fsig->params [1]->type == MONO_TYPE_STRING))) {
6694                                 MonoInst *iargs [3];
6695                                 int temp;
6696                                 
6697                                 sp -= n;
6698
6699                                 NEW_ICONST (cfg, iargs [0], cmethod->klass->type_token);
6700                                 switch (n) {
6701                                 case 0:
6702                                         temp = mono_emit_jit_icall (cfg, bblock, mono_create_corlib_exception_0, iargs, ip);
6703                                         break;
6704                                 case 1:
6705                                         iargs [1] = sp [0];
6706                                         temp = mono_emit_jit_icall (cfg, bblock, mono_create_corlib_exception_1, iargs, ip);
6707                                         break;
6708                                 case 2:
6709                                         iargs [1] = sp [0];
6710                                         iargs [2] = sp [1];
6711                                         temp = mono_emit_jit_icall (cfg, bblock, mono_create_corlib_exception_2, iargs, ip);
6712                                         break;
6713                                 default:
6714                                         g_assert_not_reached ();
6715                                 }
6716                                 NEW_TEMPLOAD (cfg, ins, temp);
6717                                 *sp ++ = ins;
6718
6719                                 ip += 5;
6720                                 inline_costs += 5;
6721                                 break;
6722                         }
6723
6724                         /* move the args to allow room for 'this' in the first position */
6725                         while (n--) {
6726                                 --sp;
6727                                 sp [1] = sp [0];
6728                         }
6729
6730                         handle_loaded_temps (cfg, bblock, stack_start, sp);
6731
6732                         if (mini_class_is_system_array (cmethod->klass)) {
6733                                 g_assert (!generic_shared);
6734
6735                                 NEW_METHODCONST (cfg, *sp, cmethod);
6736                                 temp = handle_array_new (cfg, bblock, fsig->param_count, sp, ip);
6737                         } else if (cmethod->string_ctor) {
6738                                 g_assert (!generic_shared);
6739
6740                                 /* we simply pass a null pointer */
6741                                 NEW_PCONST (cfg, *sp, NULL); 
6742                                 /* now call the string ctor */
6743                                 temp = mono_emit_method_call_spilled (cfg, bblock, cmethod, fsig, sp, ip, NULL);
6744                         } else {
6745                                 MonoInst* callvirt_this_arg = NULL;
6746                                 
6747                                 if (cmethod->klass->valuetype) {
6748                                         iargs [0] = mono_compile_create_var (cfg, &cmethod->klass->byval_arg, OP_LOCAL);
6749                                         temp = iargs [0]->inst_c0;
6750
6751                                         NEW_TEMPLOADA (cfg, *sp, temp);
6752
6753                                         handle_initobj (cfg, bblock, *sp, NULL, cmethod->klass, stack_start, sp);
6754
6755                                         NEW_TEMPLOADA (cfg, *sp, temp);
6756
6757                                         /* 
6758                                          * The code generated by mini_emit_virtual_call () expects
6759                                          * iargs [0] to be a boxed instance, but luckily the vcall
6760                                          * will be transformed into a normal call there.
6761                                          */
6762                                 } else if (generic_shared) {
6763                                         MonoInst *this = NULL, *rgctx, *vtable;
6764
6765                                         GENERIC_SHARING_FAILURE_IF_VALUETYPE_METHOD (*ip);
6766
6767                                         if (!(method->flags & METHOD_ATTRIBUTE_STATIC))
6768                                                 NEW_ARGLOAD (cfg, this, 0);
6769                                         rgctx = get_runtime_generic_context (cfg, method, this, ip);
6770                                         vtable = get_runtime_generic_context_ptr (cfg, method, bblock, cmethod->klass,
6771                                                 token, MINI_TOKEN_SOURCE_METHOD, generic_context,
6772                                                 rgctx, MONO_RGCTX_INFO_VTABLE, ip);
6773
6774                                         temp = handle_alloc_from_inst (cfg, bblock, cmethod->klass, vtable, FALSE, ip);
6775                                         NEW_TEMPLOAD (cfg, *sp, temp);
6776                                 } else {
6777                                         MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
6778                                         if (mini_field_access_needs_cctor_run (cfg, method, vtable) && !(g_slist_find (class_inits, vtable))) {
6779                                                 guint8 *tramp = mono_create_class_init_trampoline (vtable);
6780                                                 mono_emit_native_call (cfg, bblock, tramp, 
6781                                                                                            helper_sig_class_init_trampoline,
6782                                                                                            NULL, ip, FALSE, FALSE);
6783                                                 if (cfg->verbose_level > 2)
6784                                                         g_print ("class %s.%s needs init call for ctor\n", cmethod->klass->name_space, cmethod->klass->name);
6785                                                 class_inits = g_slist_prepend (class_inits, vtable);
6786                                         }
6787                                         temp = handle_alloc (cfg, bblock, cmethod->klass, FALSE, ip);
6788                                         NEW_TEMPLOAD (cfg, *sp, temp);
6789                                 }
6790
6791                                 /* Avoid virtual calls to ctors if possible */
6792                                 if (cmethod->klass->marshalbyref)
6793                                         callvirt_this_arg = sp [0];
6794                                 
6795                                 if ((cfg->opt & MONO_OPT_INLINE) && cmethod && !generic_shared &&
6796                                     mono_method_check_inlining (cfg, cmethod) &&
6797                                     !mono_class_is_subclass_of (cmethod->klass, mono_defaults.exception_class, FALSE) &&
6798                                     !g_list_find (dont_inline, cmethod)) {
6799                                         int costs;
6800                                         MonoBasicBlock *ebblock;
6801                                         if ((costs = inline_method (cfg, cmethod, fsig, bblock, sp, ip, real_offset, dont_inline, &ebblock, FALSE))) {
6802
6803                                                 ip += 5;
6804                                                 real_offset += 5;
6805                                                 
6806                                                 GET_BBLOCK (cfg, bblock, ip);
6807                                                 ebblock->next_bb = bblock;
6808                                                 link_bblock (cfg, ebblock, bblock);
6809
6810                                                 NEW_TEMPLOAD (cfg, *sp, temp);
6811                                                 sp++;
6812
6813                                                 /* indicates start of a new block, and triggers a load 
6814                                                    of all stack arguments at bb boundarie */
6815                                                 bblock = ebblock;
6816
6817                                                 inline_costs += costs;
6818                                                 break;
6819                                                 
6820                                         } else {
6821                                                 /* Prevent inlining of methods which call other methods */
6822                                                 INLINE_FAILURE;
6823                                                 mono_emit_method_call_spilled (cfg, bblock, cmethod, fsig, sp, ip, callvirt_this_arg);
6824                                         }
6825                                 } else if (generic_shared && cmethod->klass->valuetype) {
6826                                         MonoInst *this = NULL, *rgctx, *cmethod_addr;
6827
6828                                         g_assert (!callvirt_this_arg);
6829
6830                                         GENERIC_SHARING_FAILURE_IF_VALUETYPE_METHOD (*ip);
6831
6832                                         if (!(method->flags & METHOD_ATTRIBUTE_STATIC))
6833                                                 NEW_ARGLOAD (cfg, this, 0);
6834                                         rgctx = get_runtime_generic_context (cfg, method, this, ip);
6835                                         cmethod_addr = get_runtime_generic_context_method (cfg, method, bblock, cmethod,
6836                                                         generic_context, rgctx, MONO_RGCTX_INFO_GENERIC_METHOD_CODE, ip);
6837
6838                                         mono_emit_calli_spilled (cfg, bblock, fsig, sp, cmethod_addr, ip);
6839                                 } else {
6840                                         /* Prevent inlining of methods which call other methods */
6841                                         INLINE_FAILURE;
6842                                         /* now call the actual ctor */
6843                                         mono_emit_method_call_spilled (cfg, bblock, cmethod, fsig, sp, ip, callvirt_this_arg);
6844                                 }
6845                         }
6846
6847                         NEW_TEMPLOAD (cfg, *sp, temp);
6848                         sp++;
6849                         
6850                         ip += 5;
6851                         inline_costs += 5;
6852                         break;
6853                 }
6854                 case CEE_ISINST: {
6855                         gboolean shared_access = FALSE;
6856
6857                         CHECK_STACK (1);
6858                         --sp;
6859                         CHECK_OPSIZE (5);
6860                         token = read32 (ip + 1);
6861                         klass = mini_get_class (method, token, generic_context);
6862                         CHECK_TYPELOAD (klass);
6863                         if (sp [0]->type != STACK_OBJ)
6864                                 UNVERIFIED;
6865
6866                         if (cfg->generic_sharing_context) {
6867                                 int context_used = mono_class_check_context_used (klass);
6868
6869                                 if (context_used & MONO_GENERIC_CONTEXT_USED_METHOD)
6870                                         GENERIC_SHARING_FAILURE (CEE_ISINST);
6871
6872                                 if (context_used)
6873                                         shared_access = TRUE;
6874                         }
6875
6876                         /* Needed by the code generated in inssel.brg */
6877                         if (!shared_access)
6878                                 mono_get_got_var (cfg);
6879
6880                         if (shared_access) {
6881                                 MonoInst *this = NULL, *rgctx;
6882                                 MonoInst *args [2];
6883                                 int temp;
6884
6885                                 GENERIC_SHARING_FAILURE_IF_VALUETYPE_METHOD (*ip);
6886
6887                                 /* obj */
6888                                 args [0] = *sp;
6889
6890                                 /* klass */
6891                                 if (!(method->flags & METHOD_ATTRIBUTE_STATIC))
6892                                         NEW_ARGLOAD (cfg, this, 0);
6893                                 rgctx = get_runtime_generic_context (cfg, method, this, ip);
6894                                 args [1] = get_runtime_generic_context_ptr (cfg, method, bblock, klass,
6895                                         token, MINI_TOKEN_SOURCE_CLASS, generic_context, rgctx, MONO_RGCTX_INFO_KLASS, ip);
6896
6897                                 temp = mono_emit_jit_icall (cfg, bblock, mono_object_isinst, args, ip);
6898                                 NEW_TEMPLOAD (cfg, *sp, temp);
6899
6900                                 sp++;
6901                                 ip += 5;
6902                                 inline_costs += 2;
6903                         } else if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
6904                         
6905                                 MonoMethod *mono_isinst;
6906                                 MonoInst *iargs [1];
6907                                 MonoBasicBlock *ebblock;
6908                                 int costs;
6909                                 int temp;
6910                                 
6911                                 mono_isinst = mono_marshal_get_isinst (klass); 
6912                                 iargs [0] = sp [0];
6913                                 
6914                                 costs = inline_method (cfg, mono_isinst, mono_method_signature (mono_isinst), bblock, 
6915                                                        iargs, ip, real_offset, dont_inline, &ebblock, TRUE);
6916                         
6917                                 g_assert (costs > 0);
6918                                 
6919                                 ip += 5;
6920                                 real_offset += 5;
6921                         
6922                                 GET_BBLOCK (cfg, bblock, ip);
6923                                 ebblock->next_bb = bblock;
6924                                 link_bblock (cfg, ebblock, bblock);
6925
6926                                 temp = iargs [0]->inst_i0->inst_c0;
6927                                 NEW_TEMPLOAD (cfg, *sp, temp);
6928                                 
6929                                 sp++;
6930                                 bblock = ebblock;
6931                                 inline_costs += costs;
6932                         } else {
6933                                 MONO_INST_NEW (cfg, ins, *ip);
6934                                 ins->type = STACK_OBJ;
6935                                 ins->inst_left = *sp;
6936                                 ins->inst_newa_class = klass;
6937                                 ins->klass = klass;
6938                                 ins->cil_code = ip;
6939                                 *sp++ = emit_tree (cfg, bblock, ins, ip + 5);
6940                                 ip += 5;
6941                         }
6942                         break;
6943                 }
6944                 case CEE_UNBOX_ANY: {
6945                         MonoInst *add, *vtoffset;
6946                         MonoInst *iargs [3];
6947                         guint32 align;
6948
6949                         CHECK_STACK (1);
6950                         --sp;
6951                         CHECK_OPSIZE (5);
6952                         token = read32 (ip + 1);
6953                         klass = mini_get_class (method, token, generic_context);
6954                         CHECK_TYPELOAD (klass);
6955
6956                         if (cfg->generic_sharing_context && mono_class_check_context_used (klass))
6957                                 GENERIC_SHARING_FAILURE (CEE_UNBOX_ANY);
6958
6959                         if (generic_class_is_reference_type (cfg, klass)) {
6960                                 /* CASTCLASS */
6961                                 if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
6962                                         MonoMethod *mono_castclass;
6963                                         MonoInst *iargs [1];
6964                                         MonoBasicBlock *ebblock;
6965                                         int costs;
6966                                         int temp;
6967                                         
6968                                         mono_castclass = mono_marshal_get_castclass (klass); 
6969                                         iargs [0] = sp [0];
6970                                         
6971                                         costs = inline_method (cfg, mono_castclass, mono_method_signature (mono_castclass), bblock, 
6972                                                         iargs, ip, real_offset, dont_inline, &ebblock, TRUE);
6973                                 
6974                                         g_assert (costs > 0);
6975                                         
6976                                         ip += 5;
6977                                         real_offset += 5;
6978                                 
6979                                         GET_BBLOCK (cfg, bblock, ip);
6980                                         ebblock->next_bb = bblock;
6981                                         link_bblock (cfg, ebblock, bblock);
6982         
6983                                         temp = iargs [0]->inst_i0->inst_c0;
6984                                         NEW_TEMPLOAD (cfg, *sp, temp);
6985                                         
6986                                         sp++;
6987                                         bblock = ebblock;
6988                                         inline_costs += costs;                          
6989                                 } else {
6990                                         /* Needed by the code generated in inssel.brg */
6991                                         mono_get_got_var (cfg);
6992                 
6993                                         MONO_INST_NEW (cfg, ins, CEE_CASTCLASS);
6994                                         ins->type = STACK_OBJ;
6995                                         ins->inst_left = *sp;
6996                                         ins->klass = klass;
6997                                         ins->inst_newa_class = klass;
6998                                         ins->cil_code = ip;
6999                                         *sp++ = ins;
7000                                         ip += 5;
7001                                 }
7002                                 break;
7003                         }
7004
7005                         if (mono_class_is_nullable (klass)) {
7006                                 int v = handle_unbox_nullable (cfg, bblock, *sp, ip, klass);
7007                                 NEW_TEMPLOAD (cfg, *sp, v);
7008                                 sp ++;
7009                                 ip += 5;
7010                                 break;
7011                         }
7012
7013                         /* Needed by the code generated in inssel.brg */
7014                         mono_get_got_var (cfg);
7015
7016                         MONO_INST_NEW (cfg, ins, OP_UNBOXCAST);
7017                         ins->type = STACK_OBJ;
7018                         ins->inst_left = *sp;
7019                         ins->klass = klass;
7020                         ins->inst_newa_class = klass;
7021                         ins->cil_code = ip;
7022
7023                         MONO_INST_NEW (cfg, add, OP_PADD);
7024                         NEW_ICONST (cfg, vtoffset, sizeof (MonoObject));
7025                         add->inst_left = ins;
7026                         add->inst_right = vtoffset;
7027                         add->type = STACK_MP;
7028                         add->klass = mono_defaults.object_class;
7029                         *sp = add;
7030                         ip += 5;
7031                         /* LDOBJ impl */
7032                         n = mono_class_value_size (klass, &align);
7033                         ins = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
7034                         NEW_TEMPLOADA (cfg, iargs [0], ins->inst_c0);
7035                         if ((cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 5) {
7036                                 MonoInst *copy;
7037                                 NEW_MEMCPY (cfg, copy, iargs [0], *sp, n, align);
7038                                 MONO_ADD_INS (bblock, copy);
7039                         } else {
7040                                 MonoMethod *memcpy_method = get_memcpy_method ();
7041                                 iargs [1] = *sp;
7042                                 NEW_ICONST (cfg, iargs [2], n);
7043                                 iargs [2]->cil_code = ip;
7044
7045                                 mono_emit_method_call_spilled (cfg, bblock, memcpy_method, memcpy_method->signature, iargs, ip, NULL);
7046                         }
7047                         NEW_TEMPLOAD (cfg, *sp, ins->inst_c0);
7048                         ++sp;
7049                         inline_costs += 2;
7050                         break;
7051                 }
7052                 case CEE_UNBOX: {
7053                         MonoInst *add, *vtoffset;
7054
7055                         CHECK_STACK (1);
7056                         --sp;
7057                         CHECK_OPSIZE (5);
7058                         token = read32 (ip + 1);
7059                         klass = mini_get_class (method, token, generic_context);
7060                         CHECK_TYPELOAD (klass);
7061
7062                         if (cfg->generic_sharing_context && mono_class_check_context_used (klass))
7063                                 GENERIC_SHARING_FAILURE (CEE_UNBOX);
7064
7065                         if (mono_class_is_nullable (klass)) {
7066                                 int v = handle_unbox_nullable (cfg, bblock, *sp, ip, klass);
7067                                 NEW_TEMPLOAD (cfg, *sp, v);
7068                                 sp ++;
7069                                 ip += 5;
7070                                 break;
7071                         }
7072
7073                         /* Needed by the code generated in inssel.brg */
7074                         mono_get_got_var (cfg);
7075
7076                         MONO_INST_NEW (cfg, ins, OP_UNBOXCAST);
7077                         ins->type = STACK_OBJ;
7078                         ins->inst_left = *sp;
7079                         ins->klass = klass;
7080                         ins->inst_newa_class = klass;
7081                         ins->cil_code = ip;
7082
7083                         MONO_INST_NEW (cfg, add, OP_PADD);
7084                         NEW_ICONST (cfg, vtoffset, sizeof (MonoObject));
7085                         add->inst_left = ins;
7086                         add->inst_right = vtoffset;
7087                         add->type = STACK_MP;
7088                         add->klass = klass;
7089                         *sp++ = add;
7090                         ip += 5;
7091                         inline_costs += 2;
7092                         break;
7093                 }
7094                 case CEE_CASTCLASS:
7095                         CHECK_STACK (1);
7096                         --sp;
7097                         CHECK_OPSIZE (5);
7098                         token = read32 (ip + 1);
7099                         klass = mini_get_class (method, token, generic_context);
7100                         CHECK_TYPELOAD (klass);
7101                         if (sp [0]->type != STACK_OBJ)
7102                                 UNVERIFIED;
7103
7104                         if (cfg->generic_sharing_context && mono_class_check_context_used (klass))
7105                                 GENERIC_SHARING_FAILURE (CEE_CASTCLASS);
7106
7107                         /* Needed by the code generated in inssel.brg */
7108                         mono_get_got_var (cfg);
7109                 
7110                         if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
7111                                 
7112                                 MonoMethod *mono_castclass;
7113                                 MonoInst *iargs [1];
7114                                 MonoBasicBlock *ebblock;
7115                                 int costs;
7116                                 int temp;
7117                                 
7118                                 mono_castclass = mono_marshal_get_castclass (klass); 
7119                                 iargs [0] = sp [0];
7120                                 
7121                                 costs = inline_method (cfg, mono_castclass, mono_method_signature (mono_castclass), bblock, 
7122                                                 iargs, ip, real_offset, dont_inline, &ebblock, TRUE);
7123                         
7124                                 g_assert (costs > 0);
7125                                 
7126                                 ip += 5;
7127                                 real_offset += 5;
7128                         
7129                                 GET_BBLOCK (cfg, bblock, ip);
7130                                 ebblock->next_bb = bblock;
7131                                 link_bblock (cfg, ebblock, bblock);
7132
7133                                 temp = iargs [0]->inst_i0->inst_c0;
7134                                 NEW_TEMPLOAD (cfg, *sp, temp);
7135                                 
7136                                 sp++;
7137                                 bblock = ebblock;
7138                                 inline_costs += costs;
7139                         } else {
7140                                 MONO_INST_NEW (cfg, ins, *ip);
7141                                 ins->type = STACK_OBJ;
7142                                 ins->inst_left = *sp;
7143                                 ins->klass = klass;
7144                                 ins->inst_newa_class = klass;
7145                                 ins->backend.record_cast_details = debug_options.better_cast_details;
7146                                 ins->cil_code = ip;
7147                                 *sp++ = emit_tree (cfg, bblock, ins, ip + 5);
7148                                 ip += 5;
7149                         }
7150                         break;
7151                 case CEE_THROW:
7152                         CHECK_STACK (1);
7153                         MONO_INST_NEW (cfg, ins, OP_THROW);
7154                         --sp;
7155                         ins->inst_left = *sp;
7156                         ins->cil_code = ip++;
7157                         bblock->out_of_line = TRUE;
7158                         MONO_ADD_INS (bblock, ins);
7159                         MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
7160                         ins->cil_code = ip - 1;
7161                         MONO_ADD_INS (bblock, ins);
7162                         sp = stack_start;
7163                         
7164                         link_bblock (cfg, bblock, end_bblock);
7165                         start_new_bblock = 1;
7166                         break;
7167                 case CEE_LDFLD:
7168                 case CEE_LDFLDA:
7169                 case CEE_STFLD: {
7170                         MonoInst *offset_ins;
7171                         MonoClassField *field;
7172                         MonoBasicBlock *ebblock;
7173                         int costs;
7174                         guint foffset;
7175
7176                         if (*ip == CEE_STFLD) {
7177                                 CHECK_STACK (2);
7178                                 sp -= 2;
7179                         } else {
7180                                 CHECK_STACK (1);
7181                                 --sp;
7182                         }
7183                         if (sp [0]->type == STACK_I4 || sp [0]->type == STACK_I8 || sp [0]->type == STACK_R8)
7184                                 UNVERIFIED;
7185                         if (*ip != CEE_LDFLD && sp [0]->type == STACK_VTYPE)
7186                                 UNVERIFIED;
7187                         CHECK_OPSIZE (5);
7188                         token = read32 (ip + 1);
7189                         if (method->wrapper_type != MONO_WRAPPER_NONE) {
7190                                 field = mono_method_get_wrapper_data (method, token);
7191                                 klass = field->parent;
7192                         } else {
7193                                 field = mono_field_from_token (image, token, &klass, generic_context);
7194                         }
7195                         if (!field)
7196                                 goto load_error;
7197                         mono_class_init (klass);
7198                         if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_field (method, field))
7199                                 FIELD_ACCESS_FAILURE;
7200
7201                         foffset = klass->valuetype? field->offset - sizeof (MonoObject): field->offset;
7202                         /* FIXME: mark instructions for use in SSA */
7203                         if (*ip == CEE_STFLD) {
7204                                 if (target_type_is_incompatible (cfg, field->type, sp [1]))
7205                                         UNVERIFIED;
7206                                 if ((klass->marshalbyref && !MONO_CHECK_THIS (sp [0])) || klass->contextbound || klass == mono_defaults.marshalbyrefobject_class) {
7207                                         MonoMethod *stfld_wrapper = mono_marshal_get_stfld_wrapper (field->type); 
7208                                         MonoInst *iargs [5];
7209
7210                                         iargs [0] = sp [0];
7211                                         NEW_CLASSCONST (cfg, iargs [1], klass);
7212                                         NEW_FIELDCONST (cfg, iargs [2], field);
7213                                         NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : 
7214                                                     field->offset);
7215                                         iargs [4] = sp [1];
7216
7217                                         if (cfg->opt & MONO_OPT_INLINE) {
7218                                                 costs = inline_method (cfg, stfld_wrapper, mono_method_signature (stfld_wrapper), bblock, 
7219                                                                 iargs, ip, real_offset, dont_inline, &ebblock, TRUE);
7220                                                 g_assert (costs > 0);
7221                                                       
7222                                                 ip += 5;
7223                                                 real_offset += 5;
7224
7225                                                 GET_BBLOCK (cfg, bblock, ip);
7226                                                 ebblock->next_bb = bblock;
7227                                                 link_bblock (cfg, ebblock, bblock);
7228
7229                                                 /* indicates start of a new block, and triggers a load 
7230                                                    of all stack arguments at bb boundarie */
7231                                                 bblock = ebblock;
7232
7233                                                 inline_costs += costs;
7234                                                 break;
7235                                         } else {
7236                                                 mono_emit_method_call_spilled (cfg, bblock, stfld_wrapper, mono_method_signature (stfld_wrapper), iargs, ip, NULL);
7237                                         }
7238 #if HAVE_WRITE_BARRIERS
7239                                 } else if (mini_type_to_stind (cfg, field->type) == CEE_STIND_REF) {
7240                                         /* insert call to write barrier */
7241                                         MonoMethod *write_barrier = mono_marshal_get_write_barrier ();
7242                                         MonoInst *iargs [2];
7243                                         NEW_ICONST (cfg, offset_ins, foffset);
7244                                         MONO_INST_NEW (cfg, ins, OP_PADD);
7245                                         ins->cil_code = ip;
7246                                         ins->inst_left = *sp;
7247                                         ins->inst_right = offset_ins;
7248                                         ins->type = STACK_MP;
7249                                         ins->klass = mono_defaults.object_class;
7250                                         iargs [0] = ins;
7251                                         iargs [1] = sp [1];
7252                                         mono_emit_method_call_spilled (cfg, bblock, write_barrier, mono_method_signature (write_barrier), iargs, ip, NULL);
7253 #endif
7254 #ifdef MONO_ARCH_SOFT_FLOAT
7255                                 } else if (mini_type_to_stind (cfg, field->type) == CEE_STIND_R4) {
7256                                         NEW_ICONST (cfg, offset_ins, foffset);
7257                                         MONO_INST_NEW (cfg, ins, OP_PADD);
7258                                         ins->cil_code = ip;
7259                                         ins->inst_left = *sp;
7260                                         ins->inst_right = offset_ins;
7261                                         ins->type = STACK_MP;
7262                                         ins->klass = mono_defaults.object_class;
7263                                         handle_store_float (cfg, bblock, ins, sp [1], ip);
7264 #endif
7265                                 } else {
7266                                         MonoInst *store;
7267                                         NEW_ICONST (cfg, offset_ins, foffset);
7268                                         MONO_INST_NEW (cfg, ins, OP_PADD);
7269                                         ins->cil_code = ip;
7270                                         ins->inst_left = *sp;
7271                                         ins->inst_right = offset_ins;
7272                                         ins->type = STACK_MP;
7273
7274                                         MONO_INST_NEW (cfg, store, mini_type_to_stind (cfg, field->type));
7275                                         store->cil_code = ip;
7276                                         store->inst_left = ins;
7277                                         store->inst_right = sp [1];
7278                                         handle_loaded_temps (cfg, bblock, stack_start, sp);
7279                                         store->flags |= ins_flag;
7280                                         ins_flag = 0;
7281                                         if (store->opcode == CEE_STOBJ) {
7282                                                 handle_stobj (cfg, bblock, ins, sp [1], ip, 
7283                                                               mono_class_from_mono_type (field->type), FALSE, FALSE, TRUE);
7284                                         } else
7285                                                 MONO_ADD_INS (bblock, store);
7286                                 }
7287                         } else {
7288                                 if ((klass->marshalbyref && !MONO_CHECK_THIS (sp [0])) || klass->contextbound || klass == mono_defaults.marshalbyrefobject_class) {
7289                                         MonoMethod *wrapper = (*ip == CEE_LDFLDA) ? mono_marshal_get_ldflda_wrapper (field->type) : mono_marshal_get_ldfld_wrapper (field->type); 
7290                                         MonoInst *iargs [4];
7291                                         int temp;
7292                                         
7293                                         iargs [0] = sp [0];
7294                                         NEW_CLASSCONST (cfg, iargs [1], klass);
7295                                         NEW_FIELDCONST (cfg, iargs [2], field);
7296                                         NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset);
7297                                         if ((cfg->opt & MONO_OPT_INLINE) && !MONO_TYPE_ISSTRUCT (mono_method_signature (wrapper)->ret)) {
7298                                                 costs = inline_method (cfg, wrapper, mono_method_signature (wrapper), bblock, 
7299                                                                 iargs, ip, real_offset, dont_inline, &ebblock, TRUE);
7300                                                 g_assert (costs > 0);
7301                                                       
7302                                                 ip += 5;
7303                                                 real_offset += 5;
7304
7305                                                 GET_BBLOCK (cfg, bblock, ip);
7306                                                 ebblock->next_bb = bblock;
7307                                                 link_bblock (cfg, ebblock, bblock);
7308
7309                                                 temp = iargs [0]->inst_i0->inst_c0;
7310
7311                                                 NEW_TEMPLOAD (cfg, *sp, temp);
7312                                                 sp++;
7313
7314                                                 /* indicates start of a new block, and triggers a load of
7315                                                    all stack arguments at bb boundarie */
7316                                                 bblock = ebblock;
7317                                                 
7318                                                 inline_costs += costs;
7319                                                 break;
7320                                         } else {
7321                                                 temp = mono_emit_method_call_spilled (cfg, bblock, wrapper, mono_method_signature (wrapper), iargs, ip, NULL);
7322                                                 NEW_TEMPLOAD (cfg, *sp, temp);
7323                                                 sp++;
7324                                         }
7325                                 } else {
7326                                         NEW_ICONST (cfg, offset_ins, foffset);
7327                                         MONO_INST_NEW (cfg, ins, OP_PADD);
7328                                         ins->cil_code = ip;
7329                                         ins->inst_left = *sp;
7330                                         ins->inst_right = offset_ins;
7331                                         ins->type = STACK_MP;
7332
7333                                         if (*ip == CEE_LDFLDA) {
7334                                                 ins->klass = mono_class_from_mono_type (field->type);
7335                                                 *sp++ = ins;
7336                                         } else {
7337                                                 MonoInst *load;
7338                                                 MONO_INST_NEW (cfg, load, mini_type_to_ldind (cfg, field->type));
7339                                                 type_to_eval_stack_type (cfg, field->type, load);
7340                                                 load->cil_code = ip;
7341                                                 load->inst_left = ins;
7342                                                 load->flags |= ins_flag;
7343                                                 ins_flag = 0;
7344 #ifdef MONO_ARCH_SOFT_FLOAT
7345                                                 if (mini_type_to_ldind (cfg, field->type) == CEE_LDIND_R4) {
7346                                                         int temp;
7347                                                         temp = handle_load_float (cfg, bblock, ins, ip);
7348                                                         NEW_TEMPLOAD (cfg, *sp, temp);
7349                                                         sp++;
7350                                                 } else
7351 #endif
7352                                                 *sp++ = load;
7353                                         }
7354                                 }
7355                         }
7356                         ip += 5;
7357                         break;
7358                 }
7359                 case CEE_LDSFLD:
7360                 case CEE_LDSFLDA:
7361                 case CEE_STSFLD: {
7362                         MonoClassField *field;
7363                         gpointer addr = NULL;
7364                         gboolean shared_access = FALSE;
7365                         int relation = 0;
7366
7367                         CHECK_OPSIZE (5);
7368                         token = read32 (ip + 1);
7369                         if (method->wrapper_type != MONO_WRAPPER_NONE) {
7370                                 field = mono_method_get_wrapper_data (method, token);
7371                                 klass = field->parent;
7372                         }
7373                         else
7374                                 field = mono_field_from_token (image, token, &klass, generic_context);
7375                         if (!field)
7376                                 goto load_error;
7377                         mono_class_init (klass);
7378                         if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_field (method, field))
7379                                 FIELD_ACCESS_FAILURE;
7380
7381                         /*
7382                          * We can only support shared generic static
7383                          * field access on architectures where the
7384                          * trampoline code has been extended to handle
7385                          * the generic class init.
7386                          */
7387 #ifndef MONO_ARCH_VTABLE_REG
7388                         GENERIC_SHARING_FAILURE (*ip);
7389 #endif
7390
7391                         if (cfg->generic_sharing_context) {
7392                                 int context_used = mono_class_check_context_used (klass);
7393
7394                                 if (context_used & MONO_GENERIC_CONTEXT_USED_METHOD ||
7395                                                 klass->valuetype)
7396                                         GENERIC_SHARING_FAILURE (*ip);
7397
7398                                 if (context_used) {
7399                                         relation = mono_class_generic_class_relation (klass, MONO_RGCTX_INFO_VTABLE,
7400                                                 method->klass, generic_context, NULL);
7401                                         shared_access = TRUE;
7402                                 }
7403                         }
7404
7405                         g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
7406
7407                         if ((*ip) == CEE_STSFLD)
7408                                 handle_loaded_temps (cfg, bblock, stack_start, sp);
7409
7410                         /* The special_static_fields field is init'd in mono_class_vtable, so it needs
7411                          * to be called here.
7412                          */
7413                         if (!(cfg->opt & MONO_OPT_SHARED))
7414                                 mono_class_vtable (cfg->domain, klass);
7415                         mono_domain_lock (cfg->domain);
7416                         if (cfg->domain->special_static_fields)
7417                                 addr = g_hash_table_lookup (cfg->domain->special_static_fields, field);
7418                         mono_domain_unlock (cfg->domain);
7419
7420                         if (shared_access) {
7421                                 MonoInst *this, *rgctx, *static_data;
7422
7423                                 GENERIC_SHARING_FAILURE_IF_VALUETYPE_METHOD (*ip);
7424
7425                                 /*
7426                                 g_print ("sharing static field access in %s.%s.%s - depth %d offset %d\n",
7427                                         method->klass->name_space, method->klass->name, method->name,
7428                                         depth, field->offset);
7429                                 */
7430
7431                                 if (mono_class_needs_cctor_run (klass, method)) {
7432                                         MonoMethodSignature *sig = helper_sig_generic_class_init_trampoline;
7433                                         MonoCallInst *call;
7434                                         MonoInst *vtable;
7435
7436                                         if (!(method->flags & METHOD_ATTRIBUTE_STATIC))
7437                                                 NEW_ARGLOAD (cfg, this, 0);
7438                                         else
7439                                                 this = NULL;
7440
7441                                         if (relation == MINI_GENERIC_CLASS_RELATION_SELF && this) {
7442                                                 MONO_INST_NEW (cfg, vtable, CEE_LDIND_I);
7443                                                 vtable->cil_code = ip;
7444                                                 vtable->inst_left = this;
7445                                                 vtable->type = STACK_PTR;
7446                                                 vtable->klass = klass;
7447                                         } else {
7448                                                 MonoInst *rgctx = get_runtime_generic_context (cfg, method, this, ip);
7449
7450                                                 vtable = get_runtime_generic_context_ptr (cfg, method, bblock, klass,
7451                                                         token, MINI_TOKEN_SOURCE_FIELD, generic_context,
7452                                                         rgctx, MONO_RGCTX_INFO_VTABLE, ip);
7453                                         }
7454
7455                                         call = mono_emit_call_args (cfg, bblock, sig, NULL, FALSE, FALSE, ip, FALSE);
7456                                         call->inst.opcode = OP_TRAMPCALL_VTABLE;
7457                                         call->fptr = mono_get_trampoline_code (MONO_TRAMPOLINE_GENERIC_CLASS_INIT);
7458
7459                                         call->inst.inst_left = vtable;
7460
7461                                         mono_spill_call (cfg, bblock, call, sig, FALSE, ip, FALSE);
7462                                 }
7463
7464                                 /*
7465                                  * The pointer we're computing here is
7466                                  *
7467                                  *   super_info.static_data + field->offset
7468                                  */
7469
7470                                 if (!(method->flags & METHOD_ATTRIBUTE_STATIC))
7471                                         NEW_ARGLOAD (cfg, this, 0);
7472                                 else
7473                                         this = NULL;
7474                                 rgctx = get_runtime_generic_context (cfg, method, this, ip);
7475                                 static_data = get_runtime_generic_context_ptr (cfg, method, bblock, klass,
7476                                         token, MINI_TOKEN_SOURCE_FIELD, generic_context,
7477                                         rgctx, MONO_RGCTX_INFO_STATIC_DATA, ip);
7478
7479                                 if (field->offset == 0) {
7480                                         ins = static_data;
7481                                 } else {
7482                                         MonoInst *field_offset;
7483
7484                                         NEW_ICONST (cfg, field_offset, field->offset);
7485
7486                                         MONO_INST_NEW (cfg, ins, OP_PADD);
7487                                         ins->cil_code = ip;
7488                                         ins->inst_left = static_data;
7489                                         ins->inst_right = field_offset;
7490                                         ins->type = STACK_PTR;
7491                                         ins->klass = klass;
7492                                 }
7493                         } else if ((cfg->opt & MONO_OPT_SHARED) || (cfg->compile_aot && addr)) {
7494                                 int temp;
7495                                 MonoInst *iargs [2];
7496                                 MonoInst *domain_var;
7497                                 
7498                                 g_assert (field->parent);
7499                                 /* avoid depending on undefined C behavior in sequence points */
7500                                 domain_var = mono_get_domainvar (cfg);
7501                                 NEW_TEMPLOAD (cfg, iargs [0], domain_var->inst_c0);
7502                                 NEW_FIELDCONST (cfg, iargs [1], field);
7503                                 temp = mono_emit_jit_icall (cfg, bblock, mono_class_static_field_address, iargs, ip);
7504                                 NEW_TEMPLOAD (cfg, ins, temp);
7505                         } else {
7506                                 MonoVTable *vtable;
7507                                 vtable = mono_class_vtable (cfg->domain, klass);
7508                                 if (!addr) {
7509                                         if (mini_field_access_needs_cctor_run (cfg, method, vtable) && !(g_slist_find (class_inits, vtable))) {
7510                                                 guint8 *tramp = mono_create_class_init_trampoline (vtable);
7511                                                 mono_emit_native_call (cfg, bblock, tramp, 
7512                                                                                            helper_sig_class_init_trampoline,
7513                                                                                            NULL, ip, FALSE, FALSE);
7514                                                 if (cfg->verbose_level > 2)
7515                                                         g_print ("class %s.%s needs init call for %s\n", klass->name_space, klass->name, field->name);
7516                                                 class_inits = g_slist_prepend (class_inits, vtable);
7517                                         } else {
7518                                                 if (cfg->run_cctors) {
7519                                                         /* This makes so that inline cannot trigger */
7520                                                         /* .cctors: too many apps depend on them */
7521                                                         /* running with a specific order... */
7522                                                         if (! vtable->initialized)
7523                                                                 INLINE_FAILURE;
7524                                                         mono_runtime_class_init (vtable);
7525                                                 }
7526                                         }
7527                                         addr = (char*)vtable->data + field->offset;
7528
7529                                         if (cfg->compile_aot)
7530                                                 NEW_SFLDACONST (cfg, ins, field);
7531                                         else
7532                                                 NEW_PCONST (cfg, ins, addr);
7533                                         ins->cil_code = ip;
7534                                 } else {
7535                                         /* 
7536                                          * insert call to mono_threads_get_static_data (GPOINTER_TO_UINT (addr)) 
7537                                          * This could be later optimized to do just a couple of
7538                                          * memory dereferences with constant offsets.
7539                                          */
7540                                         int temp;
7541                                         MonoInst *iargs [1];
7542                                         NEW_ICONST (cfg, iargs [0], GPOINTER_TO_UINT (addr));
7543                                         temp = mono_emit_jit_icall (cfg, bblock, mono_get_special_static_data, iargs, ip);
7544                                         NEW_TEMPLOAD (cfg, ins, temp);
7545                                 }
7546                         }
7547
7548                         /* FIXME: mark instructions for use in SSA */
7549                         if (*ip == CEE_LDSFLDA) {
7550                                 ins->klass = mono_class_from_mono_type (field->type);
7551                                 *sp++ = ins;
7552                         } else if (*ip == CEE_STSFLD) {
7553                                 MonoInst *store;
7554                                 CHECK_STACK (1);
7555                                 sp--;
7556                                 MONO_INST_NEW (cfg, store, mini_type_to_stind (cfg, field->type));
7557                                 store->cil_code = ip;
7558                                 store->inst_left = ins;
7559                                 store->inst_right = sp [0];
7560                                 store->flags |= ins_flag;
7561                                 ins_flag = 0;
7562
7563 #ifdef MONO_ARCH_SOFT_FLOAT
7564                                 if (store->opcode == CEE_STIND_R4)
7565                                         handle_store_float (cfg, bblock, ins, sp [0], ip);
7566                                 else
7567 #endif
7568                                 if (store->opcode == CEE_STOBJ) {
7569                                         handle_stobj (cfg, bblock, ins, sp [0], ip, mono_class_from_mono_type (field->type), FALSE, FALSE, FALSE);
7570                                 } else
7571                                         MONO_ADD_INS (bblock, store);
7572                         } else {
7573                                 gboolean is_const = FALSE;
7574                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
7575                                 if (!shared_access && !((cfg->opt & MONO_OPT_SHARED) || cfg->compile_aot) && 
7576                                     vtable->initialized && (field->type->attrs & FIELD_ATTRIBUTE_INIT_ONLY)) {
7577                                         gpointer addr = (char*)vtable->data + field->offset;
7578                                         int ro_type = field->type->type;
7579                                         if (ro_type == MONO_TYPE_VALUETYPE && field->type->data.klass->enumtype) {
7580                                                 ro_type = field->type->data.klass->enum_basetype->type;
7581                                         }
7582                                         /* g_print ("RO-FIELD %s.%s:%s\n", klass->name_space, klass->name, field->name);*/
7583                                         is_const = TRUE;
7584                                         switch (ro_type) {
7585                                         case MONO_TYPE_BOOLEAN:
7586                                         case MONO_TYPE_U1:
7587                                                 NEW_ICONST (cfg, *sp, *((guint8 *)addr));
7588                                                 sp++;
7589                                                 break;
7590                                         case MONO_TYPE_I1:
7591                                                 NEW_ICONST (cfg, *sp, *((gint8 *)addr));
7592                                                 sp++;
7593                                                 break;                                          
7594                                         case MONO_TYPE_CHAR:
7595                                         case MONO_TYPE_U2:
7596                                                 NEW_ICONST (cfg, *sp, *((guint16 *)addr));
7597                                                 sp++;
7598                                                 break;
7599                                         case MONO_TYPE_I2:
7600                                                 NEW_ICONST (cfg, *sp, *((gint16 *)addr));
7601                                                 sp++;
7602                                                 break;
7603                                                 break;
7604                                         case MONO_TYPE_I4:
7605                                                 NEW_ICONST (cfg, *sp, *((gint32 *)addr));
7606                                                 sp++;
7607                                                 break;                                          
7608                                         case MONO_TYPE_U4:
7609                                                 NEW_ICONST (cfg, *sp, *((guint32 *)addr));
7610                                                 sp++;
7611                                                 break;
7612 #ifndef HAVE_MOVING_COLLECTOR
7613                                         case MONO_TYPE_I:
7614                                         case MONO_TYPE_U:
7615                                         case MONO_TYPE_STRING:
7616                                         case MONO_TYPE_OBJECT:
7617                                         case MONO_TYPE_CLASS:
7618                                         case MONO_TYPE_SZARRAY:
7619                                         case MONO_TYPE_PTR:
7620                                         case MONO_TYPE_FNPTR:
7621                                         case MONO_TYPE_ARRAY:
7622                                                 NEW_PCONST (cfg, *sp, *((gpointer *)addr));
7623                                                 type_to_eval_stack_type (cfg, field->type, *sp);
7624                                                 sp++;
7625                                                 break;
7626 #endif
7627                                         case MONO_TYPE_I8:
7628                                         case MONO_TYPE_U8:
7629                                                 MONO_INST_NEW (cfg, *sp, OP_I8CONST);
7630                                                 sp [0]->type = STACK_I8;
7631                                                 sp [0]->inst_l = *((gint64 *)addr);
7632                                                 sp++;
7633                                                 break;
7634                                         case MONO_TYPE_R4:
7635                                         case MONO_TYPE_R8:
7636                                         case MONO_TYPE_VALUETYPE:
7637                                         default:
7638                                                 is_const = FALSE;
7639                                                 break;
7640                                         }
7641                                 }
7642
7643                                 if (!is_const) {
7644                                         MonoInst *load;
7645                                         CHECK_STACK_OVF (1);
7646                                         MONO_INST_NEW (cfg, load, mini_type_to_ldind (cfg, field->type));
7647                                         type_to_eval_stack_type (cfg, field->type, load);
7648                                         load->cil_code = ip;
7649                                         load->inst_left = ins;
7650                                         load->flags |= ins_flag;
7651 #ifdef MONO_ARCH_SOFT_FLOAT
7652                                         if (load->opcode == CEE_LDIND_R4) {
7653                                                 int temp;
7654                                                 temp = handle_load_float (cfg, bblock, ins, ip);
7655                                                 NEW_TEMPLOAD (cfg, load, temp);
7656                                         }
7657 #endif
7658                                         *sp++ = load;
7659                                         ins_flag = 0;
7660                                 }
7661                         }
7662                         ip += 5;
7663                         break;
7664                 }
7665                 case CEE_STOBJ:
7666                         CHECK_STACK (2);
7667                         sp -= 2;
7668                         CHECK_OPSIZE (5);
7669                         token = read32 (ip + 1);
7670                         klass = mini_get_class (method, token, generic_context);
7671                         CHECK_TYPELOAD (klass);
7672                         n = mini_type_to_stind (cfg, &klass->byval_arg);
7673                         /* FIXME: handle CEE_STIND_R4 */
7674                         if (n == CEE_STOBJ) {
7675                                 handle_stobj (cfg, bblock, sp [0], sp [1], ip, klass, FALSE, FALSE, TRUE);
7676                         } else {
7677                                 /* FIXME: should check item at sp [1] is compatible with the type of the store. */
7678                                 MonoInst *store;
7679                                 MONO_INST_NEW (cfg, store, n);
7680                                 store->cil_code = ip;
7681                                 store->inst_left = sp [0];
7682                                 store->inst_right = sp [1];
7683                                 store->flags |= ins_flag;
7684                                 MONO_ADD_INS (bblock, store);
7685                         }
7686                         ins_flag = 0;
7687                         ip += 5;
7688                         inline_costs += 1;
7689                         break;
7690                 case CEE_BOX: {
7691                         MonoInst *val;
7692                         gboolean generic_shared = FALSE;
7693
7694                         CHECK_STACK (1);
7695                         --sp;
7696                         val = *sp;
7697                         CHECK_OPSIZE (5);
7698                         token = read32 (ip + 1);
7699                         klass = mini_get_class (method, token, generic_context);
7700                         CHECK_TYPELOAD (klass);
7701
7702                         if (cfg->generic_sharing_context && mono_class_check_context_used (klass)) {
7703                                 if (mono_class_is_nullable (klass))
7704                                         GENERIC_SHARING_FAILURE (CEE_BOX);
7705                                 else
7706                                         generic_shared = TRUE;
7707                         }
7708
7709                         if (generic_class_is_reference_type (cfg, klass)) {
7710                                 *sp++ = val;
7711                                 ip += 5;
7712                                 break;
7713                         }
7714                         if (klass == mono_defaults.void_class)
7715                                 UNVERIFIED;
7716                         if (target_type_is_incompatible (cfg, &klass->byval_arg, *sp))
7717                                 UNVERIFIED;
7718                         /* frequent check in generic code: box (struct), brtrue */
7719                         if (!mono_class_is_nullable (klass) &&
7720                             ip + 5 < end && ip_in_bb (cfg, bblock, ip + 5) && (ip [5] == CEE_BRTRUE || ip [5] == CEE_BRTRUE_S)) {
7721                                 /*g_print ("box-brtrue opt at 0x%04x in %s\n", real_offset, method->name);*/
7722                                 MONO_INST_NEW (cfg, ins, CEE_POP);
7723                                 MONO_ADD_INS (bblock, ins);
7724                                 ins->cil_code = ip;
7725                                 ins->inst_i0 = *sp;
7726                                 ip += 5;
7727                                 MONO_INST_NEW (cfg, ins, OP_BR);
7728                                 ins->cil_code = ip;
7729                                 MONO_ADD_INS (bblock, ins);
7730                                 if (*ip == CEE_BRTRUE_S) {
7731                                         CHECK_OPSIZE (2);
7732                                         ip++;
7733                                         target = ip + 1 + (signed char)(*ip);
7734                                         ip++;
7735                                 } else {
7736                                         CHECK_OPSIZE (5);
7737                                         ip++;
7738                                         target = ip + 4 + (gint)(read32 (ip));
7739                                         ip += 4;
7740                                 }
7741                                 GET_BBLOCK (cfg, tblock, target);
7742                                 link_bblock (cfg, bblock, tblock);
7743                                 CHECK_BBLOCK (target, ip, tblock);
7744                                 ins->inst_target_bb = tblock;
7745                                 GET_BBLOCK (cfg, tblock, ip);
7746                                 link_bblock (cfg, bblock, tblock);
7747                                 if (sp != stack_start) {
7748                                         handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
7749                                         sp = stack_start;
7750                                         CHECK_UNVERIFIABLE (cfg);
7751                                 }
7752                                 start_new_bblock = 1;
7753                                 break;
7754                         }
7755                         if (generic_shared) {
7756                                 MonoInst *this = NULL, *rgctx, *vtable;
7757
7758                                 GENERIC_SHARING_FAILURE_IF_VALUETYPE_METHOD (*ip);
7759
7760                                 if (!(method->flags & METHOD_ATTRIBUTE_STATIC))
7761                                         NEW_ARGLOAD (cfg, this, 0);
7762                                 rgctx = get_runtime_generic_context (cfg, method, this, ip);
7763                                 vtable = get_runtime_generic_context_ptr (cfg, method, bblock, klass,
7764                                         token, MINI_TOKEN_SOURCE_CLASS, generic_context,
7765                                         rgctx, MONO_RGCTX_INFO_VTABLE, ip);
7766
7767                                 *sp++ = handle_box_from_inst (cfg, bblock, val, ip, klass, vtable);
7768                         } else {
7769                                 *sp++ = handle_box (cfg, bblock, val, ip, klass);
7770                         }
7771                         ip += 5;
7772                         inline_costs += 1;
7773                         break;
7774                 }
7775                 case CEE_NEWARR: {
7776                         gboolean shared_access = FALSE;
7777
7778                         CHECK_STACK (1);
7779                         --sp;
7780
7781                         CHECK_OPSIZE (5);
7782                         token = read32 (ip + 1);
7783
7784                         /* allocate the domainvar - becaus this is used in decompose_foreach */
7785                         if (cfg->opt & MONO_OPT_SHARED) {
7786                                 mono_get_domainvar (cfg);
7787                                 /* LAME-IR: Mark it as used since otherwise it will be optimized away */
7788                                 cfg->domainvar->flags |= MONO_INST_VOLATILE;
7789                         }
7790
7791                         /* Ditto */
7792                         mono_get_got_var (cfg);
7793
7794                         klass = mini_get_class (method, token, generic_context);
7795                         CHECK_TYPELOAD (klass);
7796
7797                         if (cfg->generic_sharing_context) {
7798                                 int context_used = mono_class_check_context_used (klass);
7799
7800                                 if (context_used & MONO_GENERIC_CONTEXT_USED_METHOD || klass->valuetype)
7801                                         GENERIC_SHARING_FAILURE (CEE_NEWARR);
7802
7803                                 if (context_used)
7804                                         shared_access = TRUE;
7805                         }
7806
7807                         if (shared_access) {
7808                                 MonoInst *this = NULL, *rgctx;
7809                                 MonoInst *args [3];
7810                                 int temp;
7811
7812                                 GENERIC_SHARING_FAILURE_IF_VALUETYPE_METHOD (*ip);
7813
7814                                 /* domain */
7815                                 NEW_DOMAINCONST (cfg, args [0]);
7816
7817                                 /* klass */
7818                                 if (!(method->flags & METHOD_ATTRIBUTE_STATIC))
7819                                         NEW_ARGLOAD (cfg, this, 0);
7820                                 rgctx = get_runtime_generic_context (cfg, method, this, ip);
7821                                 args [1] = get_runtime_generic_context_ptr (cfg, method, bblock, klass,
7822                                         token, MINI_TOKEN_SOURCE_CLASS, generic_context, rgctx, MONO_RGCTX_INFO_KLASS, ip);
7823
7824                                 /* array len */
7825                                 args [2] = *sp;
7826
7827                                 temp = mono_emit_jit_icall (cfg, bblock, mono_array_new, args, ip);
7828                                 NEW_TEMPLOAD (cfg, ins, temp);
7829                         } else {
7830                                 MONO_INST_NEW (cfg, ins, *ip);
7831                                 ins->cil_code = ip;
7832                                 ins->inst_newa_class = klass;
7833                                 ins->inst_newa_len = *sp;
7834                                 ins->type = STACK_OBJ;
7835                                 ins->klass = mono_array_class_get (klass, 1);
7836                         }
7837
7838                         ip += 5;
7839                         *sp++ = ins;
7840                         /* 
7841                          * we store the object so calls to create the array are not interleaved
7842                          * with the arguments of other calls.
7843                          */
7844                         if (1) {
7845                                 MonoInst *store, *temp, *load;
7846                                 const char *data_ptr;
7847                                 int data_size = 0;
7848                                 --sp;
7849                                 temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
7850                                 NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
7851                                 store->cil_code = ins->cil_code;
7852                                 MONO_ADD_INS (bblock, store);
7853                                 /* 
7854                                  * we inline/optimize the initialization sequence if possible.
7855                                  * we should also allocate the array as not cleared, since we spend as much time clearing to 0 as initializing
7856                                  * for small sizes open code the memcpy
7857                                  * ensure the rva field is big enough
7858                                  */
7859                                 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))) {
7860                                         MonoMethod *memcpy_method = get_memcpy_method ();
7861                                         MonoInst *data_offset, *add;
7862                                         MonoInst *iargs [3];
7863                                         NEW_ICONST (cfg, iargs [2], data_size);
7864                                         NEW_TEMPLOAD (cfg, load, temp->inst_c0);
7865                                         load->cil_code = ins->cil_code;
7866                                         NEW_ICONST (cfg, data_offset, G_STRUCT_OFFSET (MonoArray, vector));
7867                                         MONO_INST_NEW (cfg, add, OP_PADD);
7868                                         add->inst_left = load;
7869                                         add->inst_right = data_offset;
7870                                         add->cil_code = ip;
7871                                         iargs [0] = add;
7872                                         if (cfg->compile_aot) {
7873                                                 NEW_AOTCONST_TOKEN (cfg, iargs [1], MONO_PATCH_INFO_RVA, method->klass->image, GPOINTER_TO_UINT(data_ptr), STACK_PTR, NULL);
7874                                         } else {
7875                                                 NEW_PCONST (cfg, iargs [1], (char*)data_ptr);
7876                                         }
7877                                         mono_emit_method_call_spilled (cfg, bblock, memcpy_method, memcpy_method->signature, iargs, ip, NULL);
7878                                         ip += 11;
7879                                 }
7880                                 NEW_TEMPLOAD (cfg, load, temp->inst_c0);
7881                                 load->cil_code = ins->cil_code;
7882                                 *sp++ = load;
7883                         }
7884                         inline_costs += 1;
7885                         break;
7886                 }
7887                 case CEE_LDLEN:
7888                         CHECK_STACK (1);
7889                         --sp;
7890                         if (sp [0]->type != STACK_OBJ)
7891                                 UNVERIFIED;
7892                         MONO_INST_NEW (cfg, ins, *ip);
7893                         ins->cil_code = ip++;
7894                         ins->inst_left = *sp;
7895                         ins->type = STACK_PTR;
7896                         *sp++ = ins;
7897                         break;
7898                 case CEE_LDELEMA:
7899                         CHECK_STACK (2);
7900                         sp -= 2;
7901                         CHECK_OPSIZE (5);
7902                         if (sp [0]->type != STACK_OBJ)
7903                                 UNVERIFIED;
7904
7905                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
7906                         CHECK_TYPELOAD (klass);
7907                         /* we need to make sure that this array is exactly the type it needs
7908                          * to be for correctness. the wrappers are lax with their usage
7909                          * so we need to ignore them here
7910                          */
7911                         if (!klass->valuetype && method->wrapper_type == MONO_WRAPPER_NONE && !readonly) {
7912                                 MonoInst* check;
7913
7914                                 /* Needed by the code generated in inssel.brg */
7915                                 mono_get_got_var (cfg);
7916
7917                                 MONO_INST_NEW (cfg, check, OP_CHECK_ARRAY_TYPE);
7918                                 check->cil_code = ip;
7919                                 check->klass = mono_array_class_get (klass, 1);
7920                                 check->inst_left = sp [0];
7921                                 check->type = STACK_OBJ;
7922                                 sp [0] = check;
7923                         }
7924                         
7925                         readonly = FALSE;
7926                         mono_class_init (klass);
7927                         NEW_LDELEMA (cfg, ins, sp, klass);
7928                         ins->cil_code = ip;
7929                         *sp++ = ins;
7930                         ip += 5;
7931                         break;
7932                 case CEE_LDELEM_ANY: {
7933                         MonoInst *load;
7934                         CHECK_STACK (2);
7935                         sp -= 2;
7936                         if (sp [0]->type != STACK_OBJ)
7937                                 UNVERIFIED;
7938                         CHECK_OPSIZE (5);
7939                         token = read32 (ip + 1);
7940                         klass = mini_get_class (method, token, generic_context);
7941                         CHECK_TYPELOAD (klass);
7942                         mono_class_init (klass);
7943                         NEW_LDELEMA (cfg, load, sp, klass);
7944                         load->cil_code = ip;
7945                         MONO_INST_NEW (cfg, ins, mini_type_to_ldind (cfg, &klass->byval_arg));
7946                         ins->cil_code = ip;
7947                         ins->inst_left = load;
7948                         *sp++ = ins;
7949                         type_to_eval_stack_type (cfg, &klass->byval_arg, ins);
7950                         ip += 5;
7951                         break;
7952                 }
7953                 case CEE_LDELEM_I1:
7954                 case CEE_LDELEM_U1:
7955                 case CEE_LDELEM_I2:
7956                 case CEE_LDELEM_U2:
7957                 case CEE_LDELEM_I4:
7958                 case CEE_LDELEM_U4:
7959                 case CEE_LDELEM_I8:
7960                 case CEE_LDELEM_I:
7961                 case CEE_LDELEM_R4:
7962                 case CEE_LDELEM_R8:
7963                 case CEE_LDELEM_REF: {
7964                         MonoInst *load;
7965                         /*
7966                          * translate to:
7967                          * ldind.x (ldelema (array, index))
7968                          * ldelema does the bounds check
7969                          */
7970                         CHECK_STACK (2);
7971                         sp -= 2;
7972                         if (sp [0]->type != STACK_OBJ)
7973                                 UNVERIFIED;
7974                         klass = array_access_to_klass (*ip, sp [0]);
7975                         NEW_LDELEMA (cfg, load, sp, klass);
7976                         load->cil_code = ip;
7977 #ifdef MONO_ARCH_SOFT_FLOAT
7978                         if (*ip == CEE_LDELEM_R4) {
7979                                 int temp;
7980                                 temp = handle_load_float (cfg, bblock, load, ip);
7981                                 NEW_TEMPLOAD (cfg, *sp, temp);
7982                                 sp++;
7983                                 ++ip;
7984                                 break;
7985                         }
7986 #endif
7987                         MONO_INST_NEW (cfg, ins, ldelem_to_ldind [*ip - CEE_LDELEM_I1]);
7988                         ins->cil_code = ip;
7989                         ins->inst_left = load;
7990                         *sp++ = ins;
7991                         ins->type = ldind_type [ins->opcode - CEE_LDIND_I1];
7992                         ins->klass = klass;
7993                         ++ip;
7994                         break;
7995                 }
7996                 case CEE_STELEM_I:
7997                 case CEE_STELEM_I1:
7998                 case CEE_STELEM_I2:
7999                 case CEE_STELEM_I4:
8000                 case CEE_STELEM_I8:
8001                 case CEE_STELEM_R4:
8002                 case CEE_STELEM_R8: {
8003                         MonoInst *load;
8004                         /*
8005                          * translate to:
8006                          * stind.x (ldelema (array, index), val)
8007                          * ldelema does the bounds check
8008                          */
8009                         CHECK_STACK (3);
8010                         sp -= 3;
8011                         if (sp [0]->type != STACK_OBJ)
8012                                 UNVERIFIED;
8013                         klass = array_access_to_klass (*ip, sp [0]);
8014                         NEW_LDELEMA (cfg, load, sp, klass);
8015                         load->cil_code = ip;
8016 #ifdef MONO_ARCH_SOFT_FLOAT
8017                         if (*ip == CEE_STELEM_R4) {
8018                                 handle_store_float (cfg, bblock, load, sp [2], ip);
8019                                 ip++;
8020                                 break;
8021                         }
8022 #endif
8023                         MONO_INST_NEW (cfg, ins, stelem_to_stind [*ip - CEE_STELEM_I]);
8024                         ins->cil_code = ip;
8025                         ins->inst_left = load;
8026                         ins->inst_right = sp [2];
8027                         ++ip;
8028                         handle_loaded_temps (cfg, bblock, stack_start, sp);
8029                         MONO_ADD_INS (bblock, ins);
8030                         inline_costs += 1;
8031                         break;
8032                 }
8033                 case CEE_STELEM_ANY: {
8034                         MonoInst *load;
8035                         /*
8036                          * translate to:
8037                          * stind.x (ldelema (array, index), val)
8038                          * ldelema does the bounds check
8039                          */
8040                         CHECK_STACK (3);
8041                         sp -= 3;
8042                         if (sp [0]->type != STACK_OBJ)
8043                                 UNVERIFIED;
8044                         CHECK_OPSIZE (5);
8045                         token = read32 (ip + 1);
8046                         klass = mini_get_class (method, token, generic_context);
8047                         CHECK_TYPELOAD (klass);
8048                         mono_class_init (klass);
8049                         if (generic_class_is_reference_type (cfg, klass)) {
8050                                 /* storing a NULL doesn't need any of the complex checks in stelemref */
8051                                 if (sp [2]->opcode == OP_PCONST && sp [2]->inst_p0 == NULL) {
8052                                         MonoInst *load;
8053                                         NEW_LDELEMA (cfg, load, sp, mono_defaults.object_class);
8054                                         load->cil_code = ip;
8055                                         MONO_INST_NEW (cfg, ins, stelem_to_stind [*ip - CEE_STELEM_I]);
8056                                         ins->cil_code = ip;
8057                                         ins->inst_left = load;
8058                                         ins->inst_right = sp [2];
8059                                         MONO_ADD_INS (bblock, ins);
8060                                 } else {
8061                                         MonoMethod* helper = mono_marshal_get_stelemref ();
8062                                         MonoInst *iargs [3];
8063                                         handle_loaded_temps (cfg, bblock, stack_start, sp);
8064
8065                                         iargs [2] = sp [2];
8066                                         iargs [1] = sp [1];
8067                                         iargs [0] = sp [0];
8068
8069                                         mono_emit_method_call_spilled (cfg, bblock, helper, mono_method_signature (helper), iargs, ip, NULL);
8070                                 }
8071                         } else {
8072                                 NEW_LDELEMA (cfg, load, sp, klass);
8073                                 load->cil_code = ip;
8074
8075                                 n = mini_type_to_stind (cfg, &klass->byval_arg);
8076                                 /* FIXME: CEE_STIND_R4 */
8077                                 if (n == CEE_STOBJ)
8078                                         handle_stobj (cfg, bblock, load, sp [2], ip, klass, FALSE, FALSE, TRUE);
8079                                 else {
8080                                         MONO_INST_NEW (cfg, ins, n);
8081                                         ins->cil_code = ip;
8082                                         ins->inst_left = load;
8083                                         ins->inst_right = sp [2];
8084                                         handle_loaded_temps (cfg, bblock, stack_start, sp);
8085                                         MONO_ADD_INS (bblock, ins);
8086                                 }
8087                         }
8088                         ip += 5;
8089                         inline_costs += 1;
8090                         break;
8091                 }
8092                 case CEE_STELEM_REF: {
8093                         MonoInst *iargs [3];
8094                         MonoMethod* helper = mono_marshal_get_stelemref ();
8095
8096                         CHECK_STACK (3);
8097                         sp -= 3;
8098                         if (sp [0]->type != STACK_OBJ)
8099                                 UNVERIFIED;
8100                         if (sp [2]->type != STACK_OBJ)
8101                                 UNVERIFIED;
8102
8103                         handle_loaded_temps (cfg, bblock, stack_start, sp);
8104
8105                         /* storing a NULL doesn't need any of the complex checks in stelemref */
8106                         if (sp [2]->opcode == OP_PCONST && sp [2]->inst_p0 == NULL) {
8107                                 MonoInst *load;
8108                                 NEW_LDELEMA (cfg, load, sp, mono_defaults.object_class);
8109                                 load->cil_code = ip;
8110                                 MONO_INST_NEW (cfg, ins, stelem_to_stind [*ip - CEE_STELEM_I]);
8111                                 ins->cil_code = ip;
8112                                 ins->inst_left = load;
8113                                 ins->inst_right = sp [2];
8114                                 MONO_ADD_INS (bblock, ins);
8115                         } else {
8116                                 iargs [2] = sp [2];
8117                                 iargs [1] = sp [1];
8118                                 iargs [0] = sp [0];
8119                         
8120                                 mono_emit_method_call_spilled (cfg, bblock, helper, mono_method_signature (helper), iargs, ip, NULL);
8121                                 inline_costs += 1;
8122                         }
8123
8124                         ++ip;
8125                         break;
8126                 }
8127                 case CEE_CKFINITE: {
8128                         MonoInst *store, *temp;
8129                         CHECK_STACK (1);
8130
8131                         /* this instr. can throw exceptions as side effect,
8132                          * so we cant eliminate dead code which contains CKFINITE opdodes.
8133                          * Spilling to memory makes sure that we always perform
8134                          * this check */
8135
8136                         
8137                         MONO_INST_NEW (cfg, ins, OP_CKFINITE);
8138                         ins->cil_code = ip;
8139                         ins->inst_left = sp [-1];
8140                         temp = mono_compile_create_var (cfg, &mono_defaults.double_class->byval_arg, OP_LOCAL);
8141
8142                         NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
8143                         store->cil_code = ip;
8144                         MONO_ADD_INS (bblock, store);
8145
8146                         NEW_TEMPLOAD (cfg, sp [-1], temp->inst_c0);
8147                        
8148                         ++ip;
8149                         break;
8150                 }
8151                 case CEE_REFANYVAL:
8152                         CHECK_STACK (1);
8153                         MONO_INST_NEW (cfg, ins, *ip);
8154                         --sp;
8155                         CHECK_OPSIZE (5);
8156                         klass = mono_class_get_full (image, read32 (ip + 1), generic_context);
8157                         CHECK_TYPELOAD (klass);
8158                         mono_class_init (klass);
8159                         ins->type = STACK_MP;
8160                         ins->inst_left = *sp;
8161                         ins->klass = klass;
8162                         ins->inst_newa_class = klass;
8163                         ins->cil_code = ip;
8164                         ip += 5;
8165                         *sp++ = ins;
8166                         break;
8167                 case CEE_MKREFANY: {
8168                         MonoInst *loc, *klassconst;
8169
8170                         CHECK_STACK (1);
8171                         MONO_INST_NEW (cfg, ins, *ip);
8172                         --sp;
8173                         CHECK_OPSIZE (5);
8174                         klass = mono_class_get_full (image, read32 (ip + 1), generic_context);
8175                         CHECK_TYPELOAD (klass);
8176                         mono_class_init (klass);
8177                         ins->cil_code = ip;
8178
8179                         if (cfg->generic_sharing_context && mono_class_check_context_used (klass))
8180                                 GENERIC_SHARING_FAILURE (CEE_MKREFANY);
8181
8182                         loc = mono_compile_create_var (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL);
8183                         NEW_TEMPLOADA (cfg, ins->inst_right, loc->inst_c0);
8184
8185                         NEW_PCONST (cfg, klassconst, klass);
8186                         NEW_GROUP (cfg, ins->inst_left, *sp, klassconst);
8187                         
8188                         MONO_ADD_INS (bblock, ins);
8189
8190                         NEW_TEMPLOAD (cfg, *sp, loc->inst_c0);
8191                         ++sp;
8192                         ip += 5;
8193                         break;
8194                 }
8195                 case CEE_LDTOKEN: {
8196                         gpointer handle;
8197                         MonoClass *handle_class;
8198                         int context_used = 0;
8199
8200                         CHECK_STACK_OVF (1);
8201
8202                         CHECK_OPSIZE (5);
8203                         n = read32 (ip + 1);
8204
8205                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
8206                                 handle = mono_method_get_wrapper_data (method, n);
8207                                 handle_class = mono_method_get_wrapper_data (method, n + 1);
8208                                 if (handle_class == mono_defaults.typehandle_class)
8209                                         handle = &((MonoClass*)handle)->byval_arg;
8210                         }
8211                         else {
8212                                 handle = mono_ldtoken (image, n, &handle_class, generic_context);
8213                         }
8214                         if (!handle)
8215                                 goto load_error;
8216                         mono_class_init (handle_class);
8217
8218                         if (cfg->generic_sharing_context) {
8219                                 if (handle_class == mono_defaults.typehandle_class) {
8220                                         /* If we get a MONO_TYPE_CLASS
8221                                            then we need to provide the
8222                                            open type, not an
8223                                            instantiation of it. */
8224                                         if (mono_type_get_type (handle) == MONO_TYPE_CLASS)
8225                                                 context_used = 0;
8226                                         else
8227                                                 context_used = mono_class_check_context_used (mono_class_from_mono_type (handle));
8228                                 } else if (handle_class == mono_defaults.fieldhandle_class)
8229                                         context_used = mono_class_check_context_used (((MonoClassField*)handle)->parent);
8230                                 else if (handle_class == mono_defaults.methodhandle_class)
8231                                         context_used = mono_method_check_context_used (handle);
8232                                 else
8233                                         g_assert_not_reached ();
8234
8235                                 if (context_used & MONO_GENERIC_CONTEXT_USED_METHOD)
8236                                         GENERIC_SHARING_FAILURE (CEE_LDTOKEN);
8237                         }
8238
8239                         if (cfg->opt & MONO_OPT_SHARED) {
8240                                 int temp;
8241                                 MonoInst *res, *store, *addr, *vtvar, *iargs [3];
8242
8243                                 GENERIC_SHARING_FAILURE (CEE_LDTOKEN);
8244
8245                                 vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL); 
8246
8247                                 NEW_IMAGECONST (cfg, iargs [0], image);
8248                                 NEW_ICONST (cfg, iargs [1], n);
8249                                 NEW_PCONST (cfg, iargs [2], generic_context);
8250                                 temp = mono_emit_jit_icall (cfg, bblock, mono_ldtoken_wrapper, iargs, ip);
8251                                 NEW_TEMPLOAD (cfg, res, temp);
8252                                 NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
8253                                 NEW_INDSTORE (cfg, store, addr, res, &mono_defaults.int_class->byval_arg);
8254                                 MONO_ADD_INS (bblock, store);
8255                                 NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
8256                         } else {
8257                                 if ((ip + 10 < end) && ip_in_bb (cfg, bblock, ip + 5) &&
8258                                         handle_class == mono_defaults.typehandle_class &&
8259                                         ((ip [5] == CEE_CALL) || (ip [5] == CEE_CALLVIRT)) && 
8260                                         (cmethod = mini_get_method (method, read32 (ip + 6), NULL, generic_context)) &&
8261                                         (cmethod->klass == mono_defaults.monotype_class->parent) &&
8262                                         (strcmp (cmethod->name, "GetTypeFromHandle") == 0)) {
8263                                         MonoClass *tclass = mono_class_from_mono_type (handle);
8264                                         mono_class_init (tclass);
8265                                         if (context_used) {
8266                                                 MonoInst *this, *rgctx;
8267
8268                                                 g_assert (!cfg->compile_aot);
8269                                                 if (!(method->flags & METHOD_ATTRIBUTE_STATIC))
8270                                                         NEW_ARGLOAD (cfg, this, 0);
8271                                                 rgctx = get_runtime_generic_context (cfg, method, this, ip);
8272                                                 ins = get_runtime_generic_context_ptr (cfg, method, bblock, tclass,
8273                                                         token, MINI_TOKEN_SOURCE_CLASS, generic_context,
8274                                                         rgctx, MONO_RGCTX_INFO_REFLECTION_TYPE, ip);
8275                                         } else if (cfg->compile_aot) {
8276                                                 NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, image, n);
8277                                         } else {
8278                                                 NEW_PCONST (cfg, ins, mono_type_get_object (cfg->domain, handle));
8279                                         }
8280                                         ins->type = STACK_OBJ;
8281                                         ins->klass = cmethod->klass;
8282                                         ip += 5;
8283                                 } else {
8284                                         MonoInst *store, *addr, *vtvar;
8285
8286                                         GENERIC_SHARING_FAILURE (CEE_LDTOKEN);
8287
8288                                         if (cfg->compile_aot)
8289                                                 NEW_LDTOKENCONST (cfg, ins, image, n);
8290                                         else
8291                                                 NEW_PCONST (cfg, ins, handle);
8292                                         vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL);
8293                                         NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
8294                                         NEW_INDSTORE (cfg, store, addr, ins, &mono_defaults.int_class->byval_arg);
8295                                         MONO_ADD_INS (bblock, store);
8296                                         NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
8297                                 }
8298                         }
8299
8300                         *sp++ = ins;
8301                         ip += 5;
8302                         break;
8303                 }
8304                 case CEE_CONV_U2:
8305                 case CEE_CONV_U1:
8306                 case CEE_CONV_I:
8307                         CHECK_STACK (1);
8308                         ADD_UNOP (*ip);
8309                         ip++;
8310                         break;
8311                 case CEE_ADD_OVF:
8312                 case CEE_ADD_OVF_UN:
8313                 case CEE_MUL_OVF:
8314                 case CEE_MUL_OVF_UN:
8315                 case CEE_SUB_OVF:
8316                 case CEE_SUB_OVF_UN:
8317                         CHECK_STACK (2);
8318                         ADD_BINOP (*ip);
8319                         if (mono_find_jit_opcode_emulation (ins->opcode)) {
8320                                 --sp;
8321                                 *sp++ = emit_tree (cfg, bblock, ins, ip + 1);
8322                         }
8323                         ip++;
8324                         break;
8325                 case CEE_ENDFINALLY:
8326                         MONO_INST_NEW (cfg, ins, OP_ENDFINALLY);
8327                         MONO_ADD_INS (bblock, ins);
8328                         ins->cil_code = ip++;
8329                         start_new_bblock = 1;
8330
8331                         /*
8332                          * Control will leave the method so empty the stack, otherwise
8333                          * the next basic block will start with a nonempty stack.
8334                          */
8335                         while (sp != stack_start) {
8336                                 MONO_INST_NEW (cfg, ins, CEE_POP);
8337                                 ins->cil_code = ip;
8338                                 sp--;
8339                                 ins->inst_i0 = *sp;
8340                                 MONO_ADD_INS (bblock, ins);
8341                         }
8342                         break;
8343                 case CEE_LEAVE:
8344                 case CEE_LEAVE_S: {
8345                         GList *handlers;
8346
8347                         if (*ip == CEE_LEAVE) {
8348                                 CHECK_OPSIZE (5);
8349                                 target = ip + 5 + (gint32)read32(ip + 1);
8350                         } else {
8351                                 CHECK_OPSIZE (2);
8352                                 target = ip + 2 + (signed char)(ip [1]);
8353                         }
8354
8355                         /* empty the stack */
8356                         while (sp != stack_start) {
8357                                 MONO_INST_NEW (cfg, ins, CEE_POP);
8358                                 ins->cil_code = ip;
8359                                 sp--;
8360                                 ins->inst_i0 = *sp;
8361                                 MONO_ADD_INS (bblock, ins);
8362                         }
8363
8364                         /* 
8365                          * If this leave statement is in a catch block, check for a
8366                          * pending exception, and rethrow it if necessary.
8367                          */
8368                         for (i = 0; i < header->num_clauses; ++i) {
8369                                 MonoExceptionClause *clause = &header->clauses [i];
8370
8371                                 /* 
8372                                  * Use <= in the final comparison to handle clauses with multiple
8373                                  * leave statements, like in bug #78024.
8374                                  * The ordering of the exception clauses guarantees that we find the
8375                                  * innermost clause.
8376                                  */
8377                                 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)) {
8378                                         int temp;
8379                                         MonoInst *load;
8380
8381                                         NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, clause->handler_offset)->inst_c0);
8382                                         load->cil_code = ip;
8383
8384                                         temp = mono_emit_jit_icall (cfg, bblock, mono_thread_get_undeniable_exception, NULL, ip);
8385                                         NEW_TEMPLOAD (cfg, *sp, temp);
8386                                 
8387                                         MONO_INST_NEW (cfg, ins, OP_THROW_OR_NULL);
8388                                         ins->inst_left = *sp;
8389                                         ins->inst_right = load;
8390                                         ins->cil_code = ip;
8391                                         MONO_ADD_INS (bblock, ins);
8392                                 }
8393                         }
8394
8395                         if ((handlers = mono_find_final_block (cfg, ip, target, MONO_EXCEPTION_CLAUSE_FINALLY))) {
8396                                 GList *tmp;
8397                                 for (tmp = handlers; tmp; tmp = tmp->next) {
8398                                         tblock = tmp->data;
8399                                         link_bblock (cfg, bblock, tblock);
8400                                         MONO_INST_NEW (cfg, ins, OP_CALL_HANDLER);
8401                                         ins->cil_code = ip;
8402                                         ins->inst_target_bb = tblock;
8403                                         MONO_ADD_INS (bblock, ins);
8404                                 }
8405                                 g_list_free (handlers);
8406                         } 
8407
8408                         MONO_INST_NEW (cfg, ins, OP_BR);
8409                         ins->cil_code = ip;
8410                         MONO_ADD_INS (bblock, ins);
8411                         GET_BBLOCK (cfg, tblock, target);
8412                         link_bblock (cfg, bblock, tblock);
8413                         CHECK_BBLOCK (target, ip, tblock);
8414                         ins->inst_target_bb = tblock;
8415                         start_new_bblock = 1;
8416
8417                         if (*ip == CEE_LEAVE)
8418                                 ip += 5;
8419                         else
8420                                 ip += 2;
8421
8422                         break;
8423                 }
8424                 case CEE_STIND_I:
8425                         CHECK_STACK (2);
8426                         MONO_INST_NEW (cfg, ins, *ip);
8427                         sp -= 2;
8428                         handle_loaded_temps (cfg, bblock, stack_start, sp);
8429                         MONO_ADD_INS (bblock, ins);
8430                         ins->cil_code = ip++;
8431                         ins->inst_i0 = sp [0];
8432                         ins->inst_i1 = sp [1];
8433                         inline_costs += 1;
8434                         break;
8435                 case CEE_CONV_U:
8436                         CHECK_STACK (1);
8437                         ADD_UNOP (*ip);
8438                         ip++;
8439                         break;
8440                 /* trampoline mono specific opcodes */
8441                 case MONO_CUSTOM_PREFIX: {
8442
8443                         g_assert (method->wrapper_type != MONO_WRAPPER_NONE);
8444
8445                         CHECK_OPSIZE (2);
8446                         switch (ip [1]) {
8447
8448                         case CEE_MONO_ICALL: {
8449                                 int temp;
8450                                 gpointer func;
8451                                 MonoJitICallInfo *info;
8452
8453                                 token = read32 (ip + 2);
8454                                 func = mono_method_get_wrapper_data (method, token);
8455                                 info = mono_find_jit_icall_by_addr (func);
8456                                 if (info == NULL){
8457                                         g_error ("An attempt has been made to perform an icall to address %p, "
8458                                                  "but the address has not been registered as an icall\n", info);
8459                                         g_assert_not_reached ();
8460                                 }
8461
8462                                 CHECK_STACK (info->sig->param_count);
8463                                 sp -= info->sig->param_count;
8464
8465                                 temp = mono_emit_jit_icall (cfg, bblock, info->func, sp, ip);
8466                                 if (!MONO_TYPE_IS_VOID (info->sig->ret)) {
8467                                         NEW_TEMPLOAD (cfg, *sp, temp);
8468                                         sp++;
8469                                 }
8470
8471                                 ip += 6;
8472                                 inline_costs += 10 * num_calls++;
8473
8474                                 break;
8475                         }
8476                         case CEE_MONO_LDPTR: {
8477                                 gpointer ptr;
8478
8479                                 CHECK_STACK_OVF (1);
8480                                 CHECK_OPSIZE (6);
8481                                 token = read32 (ip + 2);
8482
8483                                 ptr = mono_method_get_wrapper_data (method, token);
8484                                 if (cfg->compile_aot && cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
8485                                         MonoMethod *wrapped = mono_marshal_method_from_wrapper (cfg->method);
8486
8487                                         if (wrapped && ptr != NULL && mono_lookup_internal_call (wrapped) == ptr) {
8488                                                 NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_ICALL_ADDR, wrapped);
8489                                                 ins->cil_code = ip;
8490                                                 *sp++ = ins;
8491                                                 ip += 6;
8492                                                 break;
8493                                         }
8494                                 }
8495                                 NEW_PCONST (cfg, ins, ptr);
8496                                 ins->cil_code = ip;
8497                                 *sp++ = ins;
8498                                 ip += 6;
8499                                 inline_costs += 10 * num_calls++;
8500                                 /* Can't embed random pointers into AOT code */
8501                                 cfg->disable_aot = 1;
8502                                 break;
8503                         }
8504                         case CEE_MONO_VTADDR:
8505                                 CHECK_STACK (1);
8506                                 --sp;
8507                                 MONO_INST_NEW (cfg, ins, OP_VTADDR);
8508                                 ins->cil_code = ip;
8509                                 ins->type = STACK_MP;
8510                                 ins->inst_left = *sp;
8511                                 *sp++ = ins;
8512                                 ip += 2;
8513                                 break;
8514                         case CEE_MONO_NEWOBJ: {
8515                                 MonoInst *iargs [2];
8516                                 int temp;
8517                                 CHECK_STACK_OVF (1);
8518                                 CHECK_OPSIZE (6);
8519                                 token = read32 (ip + 2);
8520                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
8521                                 mono_class_init (klass);
8522                                 NEW_DOMAINCONST (cfg, iargs [0]);
8523                                 NEW_CLASSCONST (cfg, iargs [1], klass);
8524                                 temp = mono_emit_jit_icall (cfg, bblock, mono_object_new, iargs, ip);
8525                                 NEW_TEMPLOAD (cfg, *sp, temp);
8526                                 sp++;
8527                                 ip += 6;
8528                                 inline_costs += 10 * num_calls++;
8529                                 break;
8530                         }
8531                         case CEE_MONO_OBJADDR:
8532                                 CHECK_STACK (1);
8533                                 --sp;
8534                                 MONO_INST_NEW (cfg, ins, OP_OBJADDR);
8535                                 ins->cil_code = ip;
8536                                 ins->type = STACK_MP;
8537                                 ins->inst_left = *sp;
8538                                 *sp++ = ins;
8539                                 ip += 2;
8540                                 break;
8541                         case CEE_MONO_LDNATIVEOBJ:
8542                                 CHECK_STACK (1);
8543                                 CHECK_OPSIZE (6);
8544                                 token = read32 (ip + 2);
8545                                 klass = mono_method_get_wrapper_data (method, token);
8546                                 g_assert (klass->valuetype);
8547                                 mono_class_init (klass);
8548                                 NEW_INDLOAD (cfg, ins, sp [-1], &klass->byval_arg);
8549                                 sp [-1] = ins;
8550                                 ip += 6;
8551                                 break;
8552                         case CEE_MONO_RETOBJ:
8553                                 g_assert (cfg->ret);
8554                                 g_assert (mono_method_signature (method)->pinvoke); 
8555                                 CHECK_STACK (1);
8556                                 --sp;
8557                                 
8558                                 CHECK_OPSIZE (6);
8559                                 token = read32 (ip + 2);    
8560                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
8561
8562                                 NEW_RETLOADA (cfg, ins);
8563                                 handle_stobj (cfg, bblock, ins, *sp, ip, klass, FALSE, TRUE, FALSE);
8564                                 
8565                                 if (sp != stack_start)
8566                                         UNVERIFIED;
8567                                 
8568                                 MONO_INST_NEW (cfg, ins, OP_BR);
8569                                 ins->cil_code = ip;
8570                                 ins->inst_target_bb = end_bblock;
8571                                 MONO_ADD_INS (bblock, ins);
8572                                 link_bblock (cfg, bblock, end_bblock);
8573                                 start_new_bblock = 1;
8574                                 ip += 6;
8575                                 break;
8576                         case CEE_MONO_CISINST:
8577                         case CEE_MONO_CCASTCLASS: {
8578                                 int token;
8579                                 CHECK_STACK (1);
8580                                 --sp;
8581                                 CHECK_OPSIZE (6);
8582                                 token = read32 (ip + 2);
8583                                 /* Needed by the code generated in inssel.brg */
8584                                 mono_get_got_var (cfg);
8585                 
8586                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
8587                                 MONO_INST_NEW (cfg, ins, (ip [1] == CEE_MONO_CISINST) ? OP_CISINST : OP_CCASTCLASS);
8588                                 ins->type = STACK_I4;
8589                                 ins->inst_left = *sp;
8590                                 ins->inst_newa_class = klass;
8591                                 ins->cil_code = ip;
8592                                 *sp++ = emit_tree (cfg, bblock, ins, ip + 6);
8593                                 ip += 6;
8594                                 break;
8595                         }
8596                         case CEE_MONO_SAVE_LMF:
8597                         case CEE_MONO_RESTORE_LMF:
8598 #ifdef MONO_ARCH_HAVE_LMF_OPS
8599                                 MONO_INST_NEW (cfg, ins, (ip [1] == CEE_MONO_SAVE_LMF) ? OP_SAVE_LMF : OP_RESTORE_LMF);
8600                                 MONO_ADD_INS (bblock, ins);
8601                                 cfg->need_lmf_area = TRUE;
8602 #endif
8603                                 ip += 2;
8604                                 break;
8605                         case CEE_MONO_CLASSCONST:
8606                                 CHECK_STACK_OVF (1);
8607                                 CHECK_OPSIZE (6);
8608                                 token = read32 (ip + 2);
8609                                 NEW_CLASSCONST (cfg, ins, mono_method_get_wrapper_data (method, token));
8610                                 ins->cil_code = ip;
8611                                 *sp++ = ins;
8612                                 ip += 6;
8613                                 inline_costs += 10 * num_calls++;
8614                                 break;
8615                         case CEE_MONO_NOT_TAKEN:
8616                                 bblock->out_of_line = TRUE;
8617                                 ip += 2;
8618                                 break;
8619                         case CEE_MONO_TLS:
8620                                 CHECK_STACK_OVF (1);
8621                                 CHECK_OPSIZE (6);
8622                                 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
8623                                 ins->inst_offset = (gint32)read32 (ip + 2);
8624                                 ins->cil_code = ip;
8625                                 ins->type = STACK_PTR;
8626                                 *sp++ = ins;
8627                                 ip += 6;
8628                                 break;
8629                         default:
8630                                 g_error ("opcode 0x%02x 0x%02x not handled", MONO_CUSTOM_PREFIX, ip [1]);
8631                                 break;
8632                         }
8633                         break;
8634                 }
8635                 case CEE_PREFIX1: {
8636                         CHECK_OPSIZE (2);
8637                         switch (ip [1]) {
8638                         case CEE_ARGLIST: {
8639                                 /* somewhat similar to LDTOKEN */
8640                                 MonoInst *addr, *vtvar;
8641                                 CHECK_STACK_OVF (1);
8642                                 vtvar = mono_compile_create_var (cfg, &mono_defaults.argumenthandle_class->byval_arg, OP_LOCAL); 
8643
8644                                 NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
8645                                 addr->cil_code = ip;
8646                                 MONO_INST_NEW (cfg, ins, OP_ARGLIST);
8647                                 ins->cil_code = ip;
8648                                 ins->inst_left = addr;
8649                                 MONO_ADD_INS (bblock, ins);
8650                                 NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
8651                                 ins->cil_code = ip;
8652                                 *sp++ = ins;
8653                                 ip += 2;
8654                                 break;
8655                         }
8656                         case CEE_CEQ:
8657                         case CEE_CGT:
8658                         case CEE_CGT_UN:
8659                         case CEE_CLT:
8660                         case CEE_CLT_UN: {
8661                                 MonoInst *cmp;
8662                                 CHECK_STACK (2);
8663                                 /*
8664                                  * The following transforms:
8665                                  *    CEE_CEQ    into OP_CEQ
8666                                  *    CEE_CGT    into OP_CGT
8667                                  *    CEE_CGT_UN into OP_CGT_UN
8668                                  *    CEE_CLT    into OP_CLT
8669                                  *    CEE_CLT_UN into OP_CLT_UN
8670                                  */
8671                                 MONO_INST_NEW (cfg, cmp, (OP_CEQ - CEE_CEQ) + ip [1]);
8672                                 
8673                                 MONO_INST_NEW (cfg, ins, cmp->opcode);
8674                                 sp -= 2;
8675                                 cmp->inst_i0 = sp [0];
8676                                 cmp->inst_i1 = sp [1];
8677                                 cmp->cil_code = ip;
8678                                 type_from_op (cmp);
8679                                 CHECK_TYPE (cmp);
8680                                 ins->cil_code = ip;
8681                                 ins->type = STACK_I4;
8682                                 ins->inst_i0 = cmp;
8683 #if MONO_ARCH_SOFT_FLOAT
8684                                 if (sp [0]->type == STACK_R8) {
8685                                         cmp->type = STACK_I4;
8686                                         *sp++ = emit_tree (cfg, bblock, cmp, ip + 2);
8687                                         ip += 2;
8688                                         break;
8689                                 }
8690 #endif
8691                                 if ((sp [0]->type == STACK_I8) || ((sizeof (gpointer) == 8) && ((sp [0]->type == STACK_PTR) || (sp [0]->type == STACK_OBJ) || (sp [0]->type == STACK_MP))))
8692                                         cmp->opcode = OP_LCOMPARE;
8693                                 else
8694                                         cmp->opcode = OP_COMPARE;
8695                                 *sp++ = ins;
8696                                 /* spill it to reduce the expression complexity
8697                                  * and workaround bug 54209 
8698                                  */
8699                                 if (cmp->inst_left->type == STACK_I8) {
8700                                         --sp;
8701                                         *sp++ = emit_tree (cfg, bblock, ins, ip + 2);
8702                                 }
8703                                 ip += 2;
8704                                 break;
8705                         }
8706                         case CEE_LDFTN: {
8707                                 MonoInst *argconst;
8708                                 MonoMethod *cil_method, *ctor_method;
8709                                 int temp;
8710                                 gboolean is_shared;
8711
8712                                 CHECK_STACK_OVF (1);
8713                                 CHECK_OPSIZE (6);
8714                                 n = read32 (ip + 2);
8715                                 cmethod = mini_get_method (method, n, NULL, generic_context);
8716                                 if (!cmethod)
8717                                         goto load_error;
8718                                 mono_class_init (cmethod->klass);
8719
8720                                 if (cfg->generic_sharing_context && mono_method_check_context_used (cmethod))
8721                                         GENERIC_SHARING_FAILURE (CEE_LDFTN);
8722
8723                                 is_shared = (cmethod->flags & METHOD_ATTRIBUTE_STATIC) &&
8724                                         (cmethod->klass->generic_class || cmethod->klass->generic_container) &&
8725                                         mono_class_generic_sharing_enabled (cmethod->klass);
8726
8727                                 cil_method = cmethod;
8728                                 if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_method (method, cmethod))
8729                                         METHOD_ACCESS_FAILURE;
8730                                 if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS) {
8731                                         if (check_linkdemand (cfg, method, cmethod, bblock, ip))
8732                                                 INLINE_FAILURE;
8733                                         CHECK_CFG_EXCEPTION;
8734                                 } else if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR) {
8735                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod, bblock, ip);
8736                                 }
8737
8738                                 /* 
8739                                  * Optimize the common case of ldftn+delegate creation
8740                                  */
8741 #if defined(MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE) && !defined(HAVE_WRITE_BARRIERS)
8742                                 /* FIXME: SGEN support */
8743                                 /* FIXME: handle shared static generic methods */
8744                                 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 (method, read32 (ip + 7), NULL, generic_context)) && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
8745                                         MonoInst *target_ins;
8746
8747                                         ip += 6;
8748                                         if (cfg->verbose_level > 3)
8749                                                 g_print ("converting (in B%d: stack: %d) %s", bblock->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
8750                                         target_ins = sp [-1];
8751                                         sp --;
8752                                         *sp = handle_delegate_ctor (cfg, bblock, ctor_method->klass, target_ins, cmethod, ip);
8753                                         ip += 5;                                        
8754                                         sp ++;
8755                                         break;
8756                                 }
8757 #endif
8758
8759                                 handle_loaded_temps (cfg, bblock, stack_start, sp);
8760
8761                                 if (is_shared)
8762                                         NEW_METHODCONST (cfg, argconst, mono_marshal_get_static_rgctx_invoke (cmethod));
8763                                 else
8764                                         NEW_METHODCONST (cfg, argconst, cmethod);
8765                                 if (method->wrapper_type != MONO_WRAPPER_SYNCHRONIZED)
8766                                         temp = mono_emit_jit_icall (cfg, bblock, mono_ldftn, &argconst, ip);
8767                                 else
8768                                         temp = mono_emit_jit_icall (cfg, bblock, mono_ldftn_nosync, &argconst, ip);
8769                                 NEW_TEMPLOAD (cfg, *sp, temp);
8770                                 sp ++;
8771                                 
8772                                 ip += 6;
8773                                 inline_costs += 10 * num_calls++;
8774                                 break;
8775                         }
8776                         case CEE_LDVIRTFTN: {
8777                                 MonoInst *args [2];
8778                                 int temp;
8779
8780                                 CHECK_STACK (1);
8781                                 CHECK_OPSIZE (6);
8782                                 n = read32 (ip + 2);
8783                                 cmethod = mini_get_method (method, n, NULL, generic_context);
8784                                 if (!cmethod)
8785                                         goto load_error;
8786                                 mono_class_init (cmethod->klass);
8787
8788                                 if (cfg->generic_sharing_context && mono_method_check_context_used (cmethod))
8789                                         GENERIC_SHARING_FAILURE (CEE_LDVIRTFTN);
8790
8791                                 if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS) {
8792                                         if (check_linkdemand (cfg, method, cmethod, bblock, ip))
8793                                                 INLINE_FAILURE;
8794                                         CHECK_CFG_EXCEPTION;
8795                                 } else if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR) {
8796                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod, bblock, ip);
8797                                 }
8798
8799                                 handle_loaded_temps (cfg, bblock, stack_start, sp);
8800
8801                                 --sp;
8802                                 args [0] = *sp;
8803                                 NEW_METHODCONST (cfg, args [1], cmethod);
8804                                 temp = mono_emit_jit_icall (cfg, bblock, mono_ldvirtfn, args, ip);
8805                                 NEW_TEMPLOAD (cfg, *sp, temp);
8806                                 sp ++;
8807
8808                                 ip += 6;
8809                                 inline_costs += 10 * num_calls++;
8810                                 break;
8811                         }
8812                         case CEE_LDARG:
8813                                 CHECK_STACK_OVF (1);
8814                                 CHECK_OPSIZE (4);
8815                                 n = read16 (ip + 2);
8816                                 CHECK_ARG (n);
8817                                 NEW_ARGLOAD (cfg, ins, n);
8818                                 LDARG_SOFT_FLOAT (cfg, ins, n, ip);
8819                                 ins->cil_code = ip;
8820                                 *sp++ = ins;
8821                                 ip += 4;
8822                                 break;
8823                         case CEE_LDARGA:
8824                                 CHECK_STACK_OVF (1);
8825                                 CHECK_OPSIZE (4);
8826                                 n = read16 (ip + 2);
8827                                 CHECK_ARG (n);
8828                                 NEW_ARGLOADA (cfg, ins, n);
8829                                 ins->cil_code = ip;
8830                                 *sp++ = ins;
8831                                 ip += 4;
8832                                 break;
8833                         case CEE_STARG:
8834                                 CHECK_STACK (1);
8835                                 --sp;
8836                                 handle_loaded_temps (cfg, bblock, stack_start, sp);
8837                                 CHECK_OPSIZE (4);
8838                                 n = read16 (ip + 2);
8839                                 CHECK_ARG (n);
8840                                 NEW_ARGSTORE (cfg, ins, n, *sp);
8841                                 ins->cil_code = ip;
8842                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [n], *sp))
8843                                         UNVERIFIED;
8844                                 STARG_SOFT_FLOAT (cfg, ins, n, ip);
8845                                 if (ins->opcode == CEE_STOBJ) {
8846                                         NEW_ARGLOADA (cfg, ins, n);
8847                                         handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE, FALSE);
8848                                 } else
8849                                         MONO_ADD_INS (bblock, ins);
8850                                 ip += 4;
8851                                 break;
8852                         case CEE_LDLOC:
8853                                 CHECK_STACK_OVF (1);
8854                                 CHECK_OPSIZE (4);
8855                                 n = read16 (ip + 2);
8856                                 CHECK_LOCAL (n);
8857                                 NEW_LOCLOAD (cfg, ins, n);
8858                                 LDLOC_SOFT_FLOAT (cfg, ins, n, ip);
8859                                 ins->cil_code = ip;
8860                                 *sp++ = ins;
8861                                 ip += 4;
8862                                 break;
8863                         case CEE_LDLOCA:
8864                                 CHECK_STACK_OVF (1);
8865                                 CHECK_OPSIZE (4);
8866                                 n = read16 (ip + 2);
8867                                 CHECK_LOCAL (n);
8868                                 NEW_LOCLOADA (cfg, ins, n);
8869                                 ins->cil_code = ip;
8870                                 *sp++ = ins;
8871                                 ip += 4;
8872                                 break;
8873                         case CEE_STLOC:
8874                                 CHECK_STACK (1);
8875                                 --sp;
8876                                 CHECK_OPSIZE (4);
8877                                 n = read16 (ip + 2);
8878                                 CHECK_LOCAL (n);
8879                                 handle_loaded_temps (cfg, bblock, stack_start, sp);
8880                                 NEW_LOCSTORE (cfg, ins, n, *sp);
8881                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
8882                                         UNVERIFIED;
8883                                 ins->cil_code = ip;
8884                                 STLOC_SOFT_FLOAT (cfg, ins, n, ip);
8885                                 if (ins->opcode == CEE_STOBJ) {
8886                                         NEW_LOCLOADA (cfg, ins, n);
8887                                         handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE, FALSE);
8888                                 } else
8889                                         MONO_ADD_INS (bblock, ins);
8890                                 ip += 4;
8891                                 inline_costs += 1;
8892                                 break;
8893                         case CEE_LOCALLOC:
8894                                 CHECK_STACK (1);
8895                                 --sp;
8896                                 if (sp != stack_start) 
8897                                         UNVERIFIED;
8898                                 if (cfg->method != method) 
8899                                         /* 
8900                                          * Inlining this into a loop in a parent could lead to 
8901                                          * stack overflows which is different behavior than the
8902                                          * non-inlined case, thus disable inlining in this case.
8903                                          */
8904                                         goto inline_failure;
8905                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
8906                                 ins->inst_left = *sp;
8907                                 ins->cil_code = ip;
8908                                 ins->type = STACK_PTR;
8909
8910                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
8911                                 if (header->init_locals)
8912                                         ins->flags |= MONO_INST_INIT;
8913
8914                                 *sp++ = ins;
8915                                 ip += 2;
8916                                 /* FIXME: set init flag if locals init is set in this method */
8917                                 break;
8918                         case CEE_ENDFILTER: {
8919                                 MonoExceptionClause *clause, *nearest;
8920                                 int cc, nearest_num;
8921
8922                                 CHECK_STACK (1);
8923                                 --sp;
8924                                 if ((sp != stack_start) || (sp [0]->type != STACK_I4)) 
8925                                         UNVERIFIED;
8926                                 MONO_INST_NEW (cfg, ins, OP_ENDFILTER);
8927                                 ins->inst_left = *sp;
8928                                 ins->cil_code = ip;
8929                                 MONO_ADD_INS (bblock, ins);
8930                                 start_new_bblock = 1;
8931                                 ip += 2;
8932
8933                                 nearest = NULL;
8934                                 nearest_num = 0;
8935                                 for (cc = 0; cc < header->num_clauses; ++cc) {
8936                                         clause = &header->clauses [cc];
8937                                         if ((clause->flags & MONO_EXCEPTION_CLAUSE_FILTER) &&
8938                                                 ((ip - header->code) > clause->data.filter_offset && (ip - header->code) <= clause->handler_offset) &&
8939                                             (!nearest || (clause->data.filter_offset < nearest->data.filter_offset))) {
8940                                                 nearest = clause;
8941                                                 nearest_num = cc;
8942                                         }
8943                                 }
8944                                 g_assert (nearest);
8945                                 if ((ip - header->code) != nearest->handler_offset)
8946                                         UNVERIFIED;
8947
8948                                 break;
8949                         }
8950                         case CEE_UNALIGNED_:
8951                                 ins_flag |= MONO_INST_UNALIGNED;
8952                                 /* FIXME: record alignment? we can assume 1 for now */
8953                                 CHECK_OPSIZE (3);
8954                                 ip += 3;
8955                                 break;
8956                         case CEE_VOLATILE_:
8957                                 ins_flag |= MONO_INST_VOLATILE;
8958                                 ip += 2;
8959                                 break;
8960                         case CEE_TAIL_:
8961                                 ins_flag   |= MONO_INST_TAILCALL;
8962                                 cfg->flags |= MONO_CFG_HAS_TAIL;
8963                                 /* Can't inline tail calls at this time */
8964                                 inline_costs += 100000;
8965                                 ip += 2;
8966                                 break;
8967                         case CEE_INITOBJ:
8968                                 CHECK_STACK (1);
8969                                 --sp;
8970                                 CHECK_OPSIZE (6);
8971                                 token = read32 (ip + 2);
8972                                 klass = mini_get_class (method, token, generic_context);
8973                                 CHECK_TYPELOAD (klass);
8974
8975                                 if (generic_class_is_reference_type (cfg, klass)) {
8976                                         MonoInst *store, *load;
8977                                         NEW_PCONST (cfg, load, NULL);
8978                                         load->cil_code = ip;
8979                                         load->type = STACK_OBJ;
8980                                         load->klass = klass;
8981                                         MONO_INST_NEW (cfg, store, CEE_STIND_REF);
8982                                         store->cil_code = ip;
8983                                         handle_loaded_temps (cfg, bblock, stack_start, sp);
8984                                         MONO_ADD_INS (bblock, store);
8985                                         store->inst_i0 = sp [0];
8986                                         store->inst_i1 = load;
8987                                 } else {
8988                                         GENERIC_SHARING_FAILURE (CEE_INITOBJ);
8989                                         handle_initobj (cfg, bblock, *sp, NULL, klass, stack_start, sp);
8990                                 }
8991                                 ip += 6;
8992                                 inline_costs += 1;
8993                                 break;
8994                         case CEE_CONSTRAINED_:
8995                                 /* FIXME: implement */
8996                                 CHECK_OPSIZE (6);
8997                                 token = read32 (ip + 2);
8998                                 constrained_call = mono_class_get_full (image, token, generic_context);
8999                                 CHECK_TYPELOAD (constrained_call);
9000                                 ip += 6;
9001                                 break;
9002                         case CEE_CPBLK:
9003                         case CEE_INITBLK: {
9004                                 MonoInst *iargs [3];
9005                                 CHECK_STACK (3);
9006                                 sp -= 3;
9007                                 if ((cfg->opt & MONO_OPT_INTRINS) && (ip [1] == CEE_CPBLK) && (sp [2]->opcode == OP_ICONST) && ((n = sp [2]->inst_c0) <= sizeof (gpointer) * 5)) {
9008                                         MonoInst *copy;
9009                                         NEW_MEMCPY (cfg, copy, sp [0], sp [1], n, 0);
9010                                         MONO_ADD_INS (bblock, copy);
9011                                         ip += 2;
9012                                         break;
9013                                 }
9014                                 iargs [0] = sp [0];
9015                                 iargs [1] = sp [1];
9016                                 iargs [2] = sp [2];
9017                                 handle_loaded_temps (cfg, bblock, stack_start, sp);
9018                                 if (ip [1] == CEE_CPBLK) {
9019                                         MonoMethod *memcpy_method = get_memcpy_method ();
9020                                         mono_emit_method_call_spilled (cfg, bblock, memcpy_method, memcpy_method->signature, iargs, ip, NULL);
9021                                 } else {
9022                                         MonoMethod *memset_method = get_memset_method ();
9023                                         mono_emit_method_call_spilled (cfg, bblock, memset_method, memset_method->signature, iargs, ip, NULL);
9024                                 }
9025                                 ip += 2;
9026                                 inline_costs += 1;
9027                                 break;
9028                         }
9029                         case CEE_NO_:
9030                                 CHECK_OPSIZE (3);
9031                                 if (ip [2] & 0x1)
9032                                         ins_flag |= MONO_INST_NOTYPECHECK;
9033                                 if (ip [2] & 0x2)
9034                                         ins_flag |= MONO_INST_NORANGECHECK;
9035                                 /* we ignore the no-nullcheck for now since we
9036                                  * really do it explicitly only when doing callvirt->call
9037                                  */
9038                                 ip += 3;
9039                                 break;
9040                         case CEE_RETHROW: {
9041                                 MonoInst *load;
9042                                 int handler_offset = -1;
9043
9044                                 for (i = 0; i < header->num_clauses; ++i) {
9045                                         MonoExceptionClause *clause = &header->clauses [i];
9046                                         if (MONO_OFFSET_IN_HANDLER (clause, ip - header->code) && !(clause->flags & MONO_EXCEPTION_CLAUSE_FINALLY))
9047                                                 handler_offset = clause->handler_offset;
9048                                 }
9049
9050                                 bblock->flags |= BB_EXCEPTION_UNSAFE;
9051
9052                                 g_assert (handler_offset != -1);
9053
9054                                 NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, handler_offset)->inst_c0);
9055                                 load->cil_code = ip;
9056                                 MONO_INST_NEW (cfg, ins, OP_RETHROW);
9057                                 ins->inst_left = load;
9058                                 ins->cil_code = ip;
9059                                 MONO_ADD_INS (bblock, ins);
9060                                 sp = stack_start;
9061                                 link_bblock (cfg, bblock, end_bblock);
9062                                 start_new_bblock = 1;
9063                                 ip += 2;
9064                                 break;
9065                         }
9066                         case CEE_SIZEOF:
9067                                 GENERIC_SHARING_FAILURE (CEE_SIZEOF);
9068
9069                                 CHECK_STACK_OVF (1);
9070                                 CHECK_OPSIZE (6);
9071                                 token = read32 (ip + 2);
9072                                 /* FIXXME: handle generics. */
9073                                 if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC) {
9074                                         MonoType *type = mono_type_create_from_typespec (image, token);
9075                                         token = mono_type_size (type, &ialign);
9076                                 } else {
9077                                         MonoClass *klass = mono_class_get_full (image, token, generic_context);
9078                                         CHECK_TYPELOAD (klass);
9079                                         mono_class_init (klass);
9080                                         token = mono_class_value_size (klass, &align);
9081                                 }
9082                                 NEW_ICONST (cfg, ins, token);
9083                                 ins->cil_code = ip;
9084                                 *sp++= ins;
9085                                 ip += 6;
9086                                 break;
9087                         case CEE_REFANYTYPE:
9088                                 CHECK_STACK (1);
9089                                 MONO_INST_NEW (cfg, ins, OP_REFANYTYPE);
9090                                 --sp;
9091                                 ins->type = STACK_MP;
9092                                 ins->inst_left = *sp;
9093                                 ins->type = STACK_VTYPE;
9094                                 ins->klass = mono_defaults.typehandle_class;
9095                                 ins->cil_code = ip;
9096                                 ip += 2;
9097                                 *sp++ = ins;
9098                                 break;
9099                         case CEE_READONLY_:
9100                                 readonly = TRUE;
9101                                 ip += 2;
9102                                 break;
9103                         default:
9104                                 g_error ("opcode 0xfe 0x%02x not handled", ip [1]);
9105                         }
9106                         break;
9107                 }
9108                 default:
9109                         g_error ("opcode 0x%02x not handled", *ip);
9110                 }
9111         }
9112         if (start_new_bblock != 1)
9113                 UNVERIFIED;
9114
9115         bblock->cil_length = ip - bblock->cil_code;
9116         bblock->next_bb = end_bblock;
9117
9118         if (cfg->method == method && cfg->domainvar) {
9119                 MonoInst *store;
9120                 MonoInst *get_domain;
9121                 
9122                 if (! (get_domain = mono_arch_get_domain_intrinsic (cfg))) {
9123                         MonoCallInst *call;
9124                         
9125                         MONO_INST_NEW_CALL (cfg, call, OP_CALL);
9126                         call->signature = helper_sig_domain_get;
9127                         call->inst.type = STACK_PTR;
9128                         call->fptr = mono_domain_get;
9129                         get_domain = (MonoInst*)call;
9130                 }
9131                 
9132                 NEW_TEMPSTORE (cfg, store, cfg->domainvar->inst_c0, get_domain);
9133                 MONO_ADD_INS (init_localsbb, store);
9134         }
9135
9136         if (cfg->method == method && cfg->got_var)
9137                 mono_emit_load_got_addr (cfg);
9138
9139         if (header->init_locals) {
9140                 MonoInst *store;
9141                 cfg->ip = header->code;
9142                 for (i = 0; i < header->num_locals; ++i) {
9143                         MonoType *ptype = header->locals [i];
9144                         int t = ptype->type;
9145                         if (t == MONO_TYPE_VALUETYPE && ptype->data.klass->enumtype)
9146                                 t = ptype->data.klass->enum_basetype->type;
9147                         if (ptype->byref) {
9148                                 NEW_PCONST (cfg, ins, NULL);
9149                                 NEW_LOCSTORE (cfg, store, i, ins);
9150                                 MONO_ADD_INS (init_localsbb, store);
9151                         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
9152                                 NEW_ICONST (cfg, ins, 0);
9153                                 NEW_LOCSTORE (cfg, store, i, ins);
9154                                 MONO_ADD_INS (init_localsbb, store);
9155                         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
9156                                 MONO_INST_NEW (cfg, ins, OP_I8CONST);
9157                                 ins->type = STACK_I8;
9158                                 ins->inst_l = 0;
9159                                 NEW_LOCSTORE (cfg, store, i, ins);
9160                                 MONO_ADD_INS (init_localsbb, store);
9161                         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
9162 #ifdef MONO_ARCH_SOFT_FLOAT
9163                                 /* FIXME: handle init of R4 */
9164 #else
9165                                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
9166                                 ins->type = STACK_R8;
9167                                 ins->inst_p0 = (void*)&r8_0;
9168                                 NEW_LOCSTORE (cfg, store, i, ins);
9169                                 MONO_ADD_INS (init_localsbb, store);
9170 #endif
9171                         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
9172                                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (ptype))) {
9173                                 NEW_LOCLOADA (cfg, ins, i);
9174                                 handle_initobj (cfg, init_localsbb, ins, NULL, mono_class_from_mono_type (ptype), NULL, NULL);
9175                         } else {
9176                                 NEW_PCONST (cfg, ins, NULL);
9177                                 NEW_LOCSTORE (cfg, store, i, ins);
9178                                 MONO_ADD_INS (init_localsbb, store);
9179                         }
9180                 }
9181         }
9182
9183         cfg->ip = NULL;
9184
9185         /* resolve backward branches in the middle of an existing basic block */
9186         for (tmp = bb_recheck; tmp; tmp = tmp->next) {
9187                 bblock = tmp->data;
9188                 /*g_print ("need recheck in %s at IL_%04x\n", method->name, bblock->cil_code - header->code);*/
9189                 tblock = find_previous (cfg->cil_offset_to_bb, header->code_size, start_bblock, bblock->cil_code);
9190                 if (tblock != start_bblock) {
9191                         int l;
9192                         split_bblock (cfg, tblock, bblock);
9193                         l = bblock->cil_code - header->code;
9194                         bblock->cil_length = tblock->cil_length - l;
9195                         tblock->cil_length = l;
9196                 } else {
9197                         g_print ("recheck failed.\n");
9198                 }
9199         }
9200
9201         if (cfg->method == method) {
9202                 MonoBasicBlock *bb;
9203                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
9204                         bb->region = mono_find_block_region (cfg, bb->real_offset);
9205                         if (cfg->spvars)
9206                                 mono_create_spvar_for_region (cfg, bb->region);
9207                         if (cfg->verbose_level > 2)
9208                                 g_print ("REGION BB%d IL_%04x ID_%08X\n", bb->block_num, bb->real_offset, bb->region);
9209                 }
9210         }
9211
9212         g_slist_free (class_inits);
9213         dont_inline = g_list_remove (dont_inline, method);
9214
9215         if (inline_costs < 0) {
9216                 char *mname;
9217
9218                 /* Method is too large */
9219                 mname = mono_method_full_name (method, TRUE);
9220                 cfg->exception_type = MONO_EXCEPTION_INVALID_PROGRAM;
9221                 cfg->exception_message = g_strdup_printf ("Method %s is too complex.", mname);
9222                 g_free (mname);
9223                 return -1;
9224         }
9225
9226         return inline_costs;
9227
9228  exception_exit:
9229         g_assert (cfg->exception_type != MONO_EXCEPTION_NONE);
9230         g_slist_free (class_inits);
9231         dont_inline = g_list_remove (dont_inline, method);
9232         return -1;
9233
9234  inline_failure:
9235         g_slist_free (class_inits);
9236         dont_inline = g_list_remove (dont_inline, method);
9237         return -1;
9238
9239  load_error:
9240         g_slist_free (class_inits);
9241         dont_inline = g_list_remove (dont_inline, method);
9242         cfg->exception_type = MONO_EXCEPTION_TYPE_LOAD;
9243         return -1;
9244
9245  unverified:
9246         g_slist_free (class_inits);
9247         dont_inline = g_list_remove (dont_inline, method);
9248         set_exception_type_from_invalid_il (cfg, method, ip);
9249         return -1;
9250 }
9251
9252 void
9253 mono_print_tree (MonoInst *tree) {
9254         int arity;
9255
9256         if (!tree)
9257                 return;
9258
9259         arity = mono_burg_arity [tree->opcode];
9260
9261         printf (" %s%s", arity?"(":"",  mono_inst_name (tree->opcode));
9262
9263         switch (tree->opcode) {
9264         case OP_ICONST:
9265                 printf ("[%d]", (int)tree->inst_c0);
9266                 break;
9267         case OP_I8CONST:
9268                 printf ("[%lld]", (long long)tree->inst_l);
9269                 break;
9270         case OP_R8CONST:
9271                 printf ("[%f]", *(double*)tree->inst_p0);
9272                 break;
9273         case OP_R4CONST:
9274                 printf ("[%f]", *(float*)tree->inst_p0);
9275                 break;
9276         case OP_ARG:
9277         case OP_LOCAL:
9278                 printf ("[%d]", (int)tree->inst_c0);
9279                 break;
9280         case OP_REGOFFSET:
9281                 if (tree->inst_offset < 0)
9282                         printf ("[-0x%x(%s)]", (int)(-tree->inst_offset), mono_arch_regname (tree->inst_basereg));
9283                 else
9284                         printf ("[0x%x(%s)]", (int)(tree->inst_offset), mono_arch_regname (tree->inst_basereg));
9285                 break;
9286         case OP_REGVAR:
9287                 printf ("[%s]", mono_arch_regname (tree->dreg));
9288                 break;
9289         case CEE_NEWARR:
9290                 printf ("[%s]",  tree->inst_newa_class->name);
9291                 mono_print_tree (tree->inst_newa_len);
9292                 break;
9293         case OP_CALL:
9294         case OP_CALLVIRT:
9295         case OP_FCALL:
9296         case OP_FCALLVIRT:
9297         case OP_LCALL:
9298         case OP_LCALLVIRT:
9299         case OP_VCALL:
9300         case OP_VCALLVIRT:
9301         case OP_VOIDCALL:
9302         case OP_VOIDCALLVIRT:
9303         case OP_TRAMPCALL_VTABLE: {
9304                 MonoCallInst *call = (MonoCallInst*)tree;
9305                 if (call->method)
9306                         printf ("[%s]", call->method->name);
9307                 else if (call->fptr) {
9308                         MonoJitICallInfo *info = mono_find_jit_icall_by_addr (call->fptr);
9309                         if (info)
9310                                 printf ("[%s]", info->name);
9311                 }
9312                 break;
9313         }
9314         case OP_PHI: {
9315                 int i;
9316                 printf ("[%d (", (int)tree->inst_c0);
9317                 for (i = 0; i < tree->inst_phi_args [0]; i++) {
9318                         if (i)
9319                                 printf (", ");
9320                         printf ("%d", tree->inst_phi_args [i + 1]);
9321                 }
9322                 printf (")]");
9323                 break;
9324         }
9325         case OP_RENAME:
9326         case OP_RETARG:
9327         case OP_NOP:
9328         case OP_JMP:
9329         case OP_BREAK:
9330                 break;
9331         case OP_LOAD_MEMBASE:
9332         case OP_LOADI4_MEMBASE:
9333         case OP_LOADU4_MEMBASE:
9334         case OP_LOADU1_MEMBASE:
9335         case OP_LOADI1_MEMBASE:
9336         case OP_LOADU2_MEMBASE:
9337         case OP_LOADI2_MEMBASE:
9338                 printf ("[%s] <- [%s + 0x%x]", mono_arch_regname (tree->dreg), mono_arch_regname (tree->inst_basereg), (int)tree->inst_offset);
9339                 break;
9340         case OP_BR:
9341         case OP_CALL_HANDLER:
9342                 printf ("[B%d]", tree->inst_target_bb->block_num);
9343                 break;
9344         case OP_SWITCH:
9345         case CEE_ISINST:
9346         case CEE_CASTCLASS:
9347         case OP_OUTARG:
9348         case OP_CALL_REG:
9349         case OP_FCALL_REG:
9350         case OP_LCALL_REG:
9351         case OP_VCALL_REG:
9352         case OP_VOIDCALL_REG:
9353                 mono_print_tree (tree->inst_left);
9354                 break;
9355         case CEE_BNE_UN:
9356         case CEE_BEQ:
9357         case CEE_BLT:
9358         case CEE_BLT_UN:
9359         case CEE_BGT:
9360         case CEE_BGT_UN:
9361         case CEE_BGE:
9362         case CEE_BGE_UN:
9363         case CEE_BLE:
9364         case CEE_BLE_UN:
9365                 printf ("[B%dB%d]", tree->inst_true_bb->block_num, tree->inst_false_bb->block_num);
9366                 mono_print_tree (tree->inst_left);
9367                 break;
9368         default:
9369                 if (!mono_arch_print_tree(tree, arity)) {
9370                         if (arity) {
9371                                 mono_print_tree (tree->inst_left);
9372                                 if (arity > 1)
9373                                         mono_print_tree (tree->inst_right);
9374                         }
9375                 }
9376                 break;
9377         }
9378
9379         if (arity)
9380                 printf (")");
9381 }
9382
9383 void
9384 mono_print_tree_nl (MonoInst *tree)
9385 {
9386         mono_print_tree (tree);
9387         printf ("\n");
9388 }
9389
9390 static void
9391 create_helper_signature (void)
9392 {
9393         helper_sig_domain_get = mono_create_icall_signature ("ptr");
9394         helper_sig_class_init_trampoline = mono_create_icall_signature ("void");
9395         helper_sig_generic_class_init_trampoline = mono_create_icall_signature ("void");
9396         helper_sig_rgctx_lazy_fetch_trampoline = mono_create_icall_signature ("ptr ptr");
9397 }
9398
9399 gconstpointer
9400 mono_icall_get_wrapper (MonoJitICallInfo* callinfo)
9401 {
9402         char *name;
9403         MonoMethod *wrapper;
9404         gconstpointer trampoline;
9405         MonoDomain *domain = mono_get_root_domain ();
9406         
9407         if (callinfo->wrapper) {
9408                 return callinfo->wrapper;
9409         }
9410
9411         if (callinfo->trampoline)
9412                 return callinfo->trampoline;
9413
9414         /* 
9415          * We use the lock on the root domain instead of the JIT lock to protect 
9416          * callinfo->trampoline, since we do a lot of stuff inside the critical section.
9417          */
9418         mono_domain_lock (domain);
9419
9420         if (callinfo->trampoline) {
9421                 mono_domain_unlock (domain);
9422                 return callinfo->trampoline;
9423         }
9424
9425         name = g_strdup_printf ("__icall_wrapper_%s", callinfo->name);
9426         wrapper = mono_marshal_get_icall_wrapper (callinfo->sig, name, callinfo->func, check_for_pending_exc);
9427         g_free (name);
9428
9429         trampoline = mono_create_ftnptr (domain, mono_create_jit_trampoline_in_domain (domain, wrapper));
9430         mono_register_jit_icall_wrapper (callinfo, trampoline);
9431
9432         callinfo->trampoline = trampoline;
9433
9434         mono_domain_unlock (domain);
9435         
9436         return callinfo->trampoline;
9437 }
9438
9439 static void
9440 mono_dynamic_code_hash_insert (MonoDomain *domain, MonoMethod *method, MonoJitDynamicMethodInfo *ji)
9441 {
9442         if (!domain->dynamic_code_hash)
9443                 domain->dynamic_code_hash = g_hash_table_new (NULL, NULL);
9444         g_hash_table_insert (domain->dynamic_code_hash, method, ji);
9445 }
9446
9447 static MonoJitDynamicMethodInfo*
9448 mono_dynamic_code_hash_lookup (MonoDomain *domain, MonoMethod *method)
9449 {
9450         MonoJitDynamicMethodInfo *res;
9451
9452         if (domain->dynamic_code_hash)
9453                 res = g_hash_table_lookup (domain->dynamic_code_hash, method);
9454         else
9455                 res = NULL;
9456         return res;
9457 }
9458
9459 typedef struct {
9460         MonoClass *vtype;
9461         GList *active;
9462         GSList *slots;
9463 } StackSlotInfo;
9464
9465 static inline GSList*
9466 g_slist_prepend_mempool (MonoMemPool *mp, GSList   *list,
9467                                                  gpointer  data)
9468 {
9469   GSList *new_list;
9470
9471   new_list = mono_mempool_alloc (mp, sizeof (GSList));
9472   new_list->data = data;
9473   new_list->next = list;
9474
9475   return new_list;
9476 }
9477
9478 /*
9479  *  mono_allocate_stack_slots_full:
9480  *
9481  *  Allocate stack slots for all non register allocated variables using a
9482  * linear scan algorithm.
9483  * Returns: an array of stack offsets.
9484  * STACK_SIZE is set to the amount of stack space needed.
9485  * STACK_ALIGN is set to the alignment needed by the locals area.
9486  */
9487 gint32*
9488 mono_allocate_stack_slots_full (MonoCompile *cfg, gboolean backward, guint32 *stack_size, guint32 *stack_align)
9489 {
9490         int i, slot, offset, size;
9491         guint32 align;
9492         MonoMethodVar *vmv;
9493         MonoInst *inst;
9494         gint32 *offsets;
9495         GList *vars = NULL, *l;
9496         StackSlotInfo *scalar_stack_slots, *vtype_stack_slots, *slot_info;
9497         MonoType *t;
9498         int nvtypes;
9499
9500         scalar_stack_slots = mono_mempool_alloc0 (cfg->mempool, sizeof (StackSlotInfo) * MONO_TYPE_PINNED);
9501         vtype_stack_slots = NULL;
9502         nvtypes = 0;
9503
9504         offsets = mono_mempool_alloc (cfg->mempool, sizeof (gint32) * cfg->num_varinfo);
9505         for (i = 0; i < cfg->num_varinfo; ++i)
9506                 offsets [i] = -1;
9507
9508         for (i = cfg->locals_start; i < cfg->num_varinfo; i++) {
9509                 inst = cfg->varinfo [i];
9510                 vmv = MONO_VARINFO (cfg, i);
9511
9512                 if ((inst->flags & MONO_INST_IS_DEAD) || inst->opcode == OP_REGVAR || inst->opcode == OP_REGOFFSET)
9513                         continue;
9514
9515                 vars = g_list_prepend (vars, vmv);
9516         }
9517
9518         vars = mono_varlist_sort (cfg, vars, 0);
9519         offset = 0;
9520         *stack_align = 0;
9521         for (l = vars; l; l = l->next) {
9522                 vmv = l->data;
9523                 inst = cfg->varinfo [vmv->idx];
9524
9525                 /* inst->backend.is_pinvoke indicates native sized value types, this is used by the
9526                 * pinvoke wrappers when they call functions returning structures */
9527                 if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->inst_vtype->type != MONO_TYPE_TYPEDBYREF)
9528                         size = mono_class_native_size (inst->inst_vtype->data.klass, &align);
9529                 else {
9530                         int ialign;
9531
9532                         size = mono_type_size (inst->inst_vtype, &ialign);
9533                         align = ialign;
9534                 }
9535
9536                 t = mono_type_get_underlying_type (inst->inst_vtype);
9537                 if (t->byref) {
9538                         slot_info = &scalar_stack_slots [MONO_TYPE_I];
9539                 } else {
9540                         switch (t->type) {
9541                         case MONO_TYPE_GENERICINST:
9542                                 if (!mono_type_generic_inst_is_valuetype (t)) {
9543                                         slot_info = &scalar_stack_slots [t->type];
9544                                         break;
9545                                 }
9546                                 /* Fall through */
9547                         case MONO_TYPE_VALUETYPE:
9548                                 if (!vtype_stack_slots)
9549                                         vtype_stack_slots = mono_mempool_alloc0 (cfg->mempool, sizeof (StackSlotInfo) * 256);
9550                                 for (i = 0; i < nvtypes; ++i)
9551                                         if (t->data.klass == vtype_stack_slots [i].vtype)
9552                                                 break;
9553                                 if (i < nvtypes)
9554                                         slot_info = &vtype_stack_slots [i];
9555                                 else {
9556                                         g_assert (nvtypes < 256);
9557                                         vtype_stack_slots [nvtypes].vtype = t->data.klass;
9558                                         slot_info = &vtype_stack_slots [nvtypes];
9559                                         nvtypes ++;
9560                                 }
9561                                 break;
9562                         case MONO_TYPE_CLASS:
9563                         case MONO_TYPE_OBJECT:
9564                         case MONO_TYPE_ARRAY:
9565                         case MONO_TYPE_SZARRAY:
9566                         case MONO_TYPE_STRING:
9567                         case MONO_TYPE_PTR:
9568                         case MONO_TYPE_I:
9569                         case MONO_TYPE_U:
9570 #if SIZEOF_VOID_P == 4
9571                         case MONO_TYPE_I4:
9572 #else
9573                         case MONO_TYPE_I8:
9574 #endif
9575                                 /* Share non-float stack slots of the same size */
9576                                 slot_info = &scalar_stack_slots [MONO_TYPE_CLASS];
9577                                 break;
9578                         default:
9579                                 slot_info = &scalar_stack_slots [t->type];
9580                         }
9581                 }
9582
9583                 slot = 0xffffff;
9584                 if (cfg->comp_done & MONO_COMP_LIVENESS) {
9585                         //printf ("START  %2d %08x %08x\n",  vmv->idx, vmv->range.first_use.abs_pos, vmv->range.last_use.abs_pos);
9586                         
9587                         /* expire old intervals in active */
9588                         while (slot_info->active) {
9589                                 MonoMethodVar *amv = (MonoMethodVar *)slot_info->active->data;
9590
9591                                 if (amv->range.last_use.abs_pos > vmv->range.first_use.abs_pos)
9592                                         break;
9593
9594                                 //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);
9595
9596                                 slot_info->active = g_list_delete_link (slot_info->active, slot_info->active);
9597                                 slot_info->slots = g_slist_prepend_mempool (cfg->mempool, slot_info->slots, GINT_TO_POINTER (offsets [amv->idx]));
9598                         }
9599
9600                         /* 
9601                          * This also handles the case when the variable is used in an
9602                          * exception region, as liveness info is not computed there.
9603                          */
9604                         /* 
9605                          * FIXME: All valuetypes are marked as INDIRECT because of LDADDR
9606                          * opcodes.
9607                          */
9608                         if (! (inst->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT))) {
9609                                 if (slot_info->slots) {
9610                                         slot = GPOINTER_TO_INT (slot_info->slots->data);
9611
9612                                         slot_info->slots = slot_info->slots->next;
9613                                 }
9614
9615                                 slot_info->active = mono_varlist_insert_sorted (cfg, slot_info->active, vmv, TRUE);
9616                         }
9617                 }
9618
9619                 {
9620                         static int count = 0;
9621                         count ++;
9622
9623                         /*
9624                         if (count == atoi (getenv ("COUNT")))
9625                                 printf ("LAST: %s\n", mono_method_full_name (cfg->method, TRUE));
9626                         if (count > atoi (getenv ("COUNT")))
9627                                 slot = 0xffffff;
9628                         else {
9629                                 mono_print_tree_nl (inst);
9630                                 }
9631                         */
9632                 }
9633
9634                 if (cfg->disable_reuse_stack_slots)
9635                         slot = 0xffffff;
9636
9637                 if (slot == 0xffffff) {
9638                         /*
9639                          * Allways allocate valuetypes to sizeof (gpointer) to allow more
9640                          * efficient copying (and to work around the fact that OP_MEMCPY
9641                          * and OP_MEMSET ignores alignment).
9642                          */
9643                         if (MONO_TYPE_ISSTRUCT (t))
9644                                 align = sizeof (gpointer);
9645
9646                         if (backward) {
9647                                 offset += size;
9648                                 offset += align - 1;
9649                                 offset &= ~(align - 1);
9650                                 slot = offset;
9651                         }
9652                         else {
9653                                 offset += align - 1;
9654                                 offset &= ~(align - 1);
9655                                 slot = offset;
9656                                 offset += size;
9657                         }
9658
9659                         if (*stack_align == 0)
9660                                 *stack_align = align;
9661                 }
9662
9663                 offsets [vmv->idx] = slot;
9664         }
9665         g_list_free (vars);
9666         for (i = 0; i < MONO_TYPE_PINNED; ++i) {
9667                 if (scalar_stack_slots [i].active)
9668                         g_list_free (scalar_stack_slots [i].active);
9669         }
9670         for (i = 0; i < nvtypes; ++i) {
9671                 if (vtype_stack_slots [i].active)
9672                         g_list_free (vtype_stack_slots [i].active);
9673         }
9674
9675         mono_jit_stats.locals_stack_size += offset;
9676
9677         *stack_size = offset;
9678         return offsets;
9679 }
9680
9681 gint32*
9682 mono_allocate_stack_slots (MonoCompile *m, guint32 *stack_size, guint32 *stack_align)
9683 {
9684         return mono_allocate_stack_slots_full (m, TRUE, stack_size, stack_align);
9685 }
9686
9687 void
9688 mono_register_opcode_emulation (int opcode, const char *name, const char *sigstr, gpointer func, gboolean no_throw)
9689 {
9690         MonoJitICallInfo *info;
9691         MonoMethodSignature *sig = mono_create_icall_signature (sigstr);
9692
9693         if (!emul_opcode_map)
9694                 emul_opcode_map = g_new0 (MonoJitICallInfo*, OP_LAST + 1);
9695
9696         g_assert (!sig->hasthis);
9697         g_assert (sig->param_count < 3);
9698
9699         info = mono_register_jit_icall (func, name, sig, no_throw);
9700
9701         emul_opcode_map [opcode] = info;
9702 }
9703
9704 static void
9705 register_icall (gpointer func, const char *name, const char *sigstr, gboolean save)
9706 {
9707         MonoMethodSignature *sig;
9708
9709         if (sigstr)
9710                 sig = mono_create_icall_signature (sigstr);
9711         else
9712                 sig = NULL;
9713
9714         mono_register_jit_icall (func, name, sig, save);
9715 }
9716
9717 static void
9718 decompose_foreach (MonoInst *tree, gpointer data) 
9719 {
9720         static MonoJitICallInfo *newarr_info = NULL;
9721         static MonoJitICallInfo *newarr_specific_info = NULL;
9722         MonoJitICallInfo *info;
9723         int i;
9724
9725         switch (tree->opcode) {
9726         case CEE_NEWARR: {
9727                 MonoCompile *cfg = data;
9728                 MonoInst *iargs [3];
9729
9730                 if (!newarr_info) {
9731                         newarr_info = mono_find_jit_icall_by_addr (mono_array_new);
9732                         g_assert (newarr_info);
9733                         newarr_specific_info = mono_find_jit_icall_by_addr (mono_array_new_specific);
9734                         g_assert (newarr_specific_info);
9735                 }
9736
9737                 if (cfg->opt & MONO_OPT_SHARED) {
9738                         NEW_DOMAINCONST (cfg, iargs [0]);
9739                         NEW_CLASSCONST (cfg, iargs [1], tree->inst_newa_class);
9740                         iargs [2] = tree->inst_newa_len;
9741
9742                         info = newarr_info;
9743                 }
9744                 else {
9745                         MonoVTable *vtable = mono_class_vtable (cfg->domain, mono_array_class_get (tree->inst_newa_class, 1));
9746
9747                         NEW_VTABLECONST (cfg, iargs [0], vtable);
9748                         iargs [1] = tree->inst_newa_len;
9749
9750                         info = newarr_specific_info;
9751                 }
9752
9753                 mono_emulate_opcode (cfg, tree, iargs, info);
9754
9755                 /* Need to decompose arguments after the the opcode is decomposed */
9756                 for (i = 0; i < info->sig->param_count; ++i)
9757                         dec_foreach (iargs [i], cfg);
9758                 break;
9759         }
9760 #ifdef MONO_ARCH_SOFT_FLOAT
9761         case OP_FBEQ:
9762         case OP_FBGE:
9763         case OP_FBGT:
9764         case OP_FBLE:
9765         case OP_FBLT:
9766         case OP_FBNE_UN:
9767         case OP_FBGE_UN:
9768         case OP_FBGT_UN:
9769         case OP_FBLE_UN:
9770         case OP_FBLT_UN: {
9771                 if ((info = mono_find_jit_opcode_emulation (tree->opcode))) {
9772                         MonoCompile *cfg = data;
9773                         MonoInst *iargs [2];
9774                 
9775                         iargs [0] = tree->inst_i0;
9776                         iargs [1] = tree->inst_i1;
9777                 
9778                         mono_emulate_opcode (cfg, tree, iargs, info);
9779
9780                         dec_foreach (iargs [0], cfg);
9781                         dec_foreach (iargs [1], cfg);
9782                         break;
9783                 } else {
9784                         g_assert_not_reached ();
9785                 }
9786                 break;
9787         }
9788         case OP_FCEQ:
9789         case OP_FCGT:
9790         case OP_FCGT_UN:
9791         case OP_FCLT:
9792         case OP_FCLT_UN: {
9793                 if ((info = mono_find_jit_opcode_emulation (tree->opcode))) {
9794                         MonoCompile *cfg = data;
9795                         MonoInst *iargs [2];
9796
9797                         /* the args are in the compare opcode ... */
9798                         iargs [0] = tree->inst_i0;
9799                         iargs [1] = tree->inst_i1;
9800                 
9801                         mono_emulate_opcode (cfg, tree, iargs, info);
9802
9803                         dec_foreach (iargs [0], cfg);
9804                         dec_foreach (iargs [1], cfg);
9805                         break;
9806                 } else {
9807                         g_assert_not_reached ();
9808                 }
9809                 break;
9810         }
9811 #endif
9812
9813         default:
9814                 break;
9815         }
9816 }
9817
9818 void
9819 mono_inst_foreach (MonoInst *tree, MonoInstFunc func, gpointer data) {
9820
9821         switch (mono_burg_arity [tree->opcode]) {
9822         case 0: break;
9823         case 1: 
9824                 mono_inst_foreach (tree->inst_left, func, data);
9825                 break;
9826         case 2: 
9827                 mono_inst_foreach (tree->inst_left, func, data);
9828                 mono_inst_foreach (tree->inst_right, func, data);
9829                 break;
9830         default:
9831                 g_assert_not_reached ();
9832         }
9833         func (tree, data);
9834 }
9835
9836 G_GNUC_UNUSED
9837 static void
9838 mono_print_bb_code (MonoBasicBlock *bb)
9839 {
9840         MonoInst *c;
9841
9842         MONO_BB_FOR_EACH_INS (bb, c) {
9843                 mono_print_tree (c);
9844                 g_print ("\n");
9845         }
9846 }
9847
9848 static void
9849 print_dfn (MonoCompile *cfg) {
9850         int i, j;
9851         char *code;
9852         MonoBasicBlock *bb;
9853
9854         g_print ("IR code for method %s\n", mono_method_full_name (cfg->method, TRUE));
9855
9856         for (i = 0; i < cfg->num_bblocks; ++i) {
9857                 MonoInst *c;
9858
9859                 bb = cfg->bblocks [i];
9860                 /*if (bb->cil_code) {
9861                         char* code1, *code2;
9862                         code1 = mono_disasm_code_one (NULL, cfg->method, bb->cil_code, NULL);
9863                         if (bb->last_ins->cil_code)
9864                                 code2 = mono_disasm_code_one (NULL, cfg->method, bb->last_ins->cil_code, NULL);
9865                         else
9866                                 code2 = g_strdup ("");
9867
9868                         code1 [strlen (code1) - 1] = 0;
9869                         code = g_strdup_printf ("%s -> %s", code1, code2);
9870                         g_free (code1);
9871                         g_free (code2);
9872                 } else*/
9873                         code = g_strdup ("\n");
9874                 g_print ("\nBB%d DFN%d (len: %d): %s", bb->block_num, i, bb->cil_length, code);
9875                 MONO_BB_FOR_EACH_INS (bb, c) {
9876                         mono_print_tree (c);
9877                         g_print ("\n");
9878                 }
9879
9880                 g_print ("\tprev:");
9881                 for (j = 0; j < bb->in_count; ++j) {
9882                         g_print (" BB%d", bb->in_bb [j]->block_num);
9883                 }
9884                 g_print ("\t\tsucc:");
9885                 for (j = 0; j < bb->out_count; ++j) {
9886                         g_print (" BB%d", bb->out_bb [j]->block_num);
9887                 }
9888                 g_print ("\n\tidom: BB%d\n", bb->idom? bb->idom->block_num: -1);
9889
9890                 if (bb->idom)
9891                         g_assert (mono_bitset_test_fast (bb->dominators, bb->idom->dfn));
9892
9893                 if (bb->dominators)
9894                         mono_blockset_print (cfg, bb->dominators, "\tdominators", bb->idom? bb->idom->dfn: -1);
9895                 if (bb->dfrontier)
9896                         mono_blockset_print (cfg, bb->dfrontier, "\tdfrontier", -1);
9897                 g_free (code);
9898         }
9899
9900         g_print ("\n");
9901 }
9902
9903 void
9904 mono_bblock_add_inst (MonoBasicBlock *bb, MonoInst *inst)
9905 {
9906         MONO_ADD_INS (bb, inst);
9907 }
9908
9909 void
9910 mono_destroy_compile (MonoCompile *cfg)
9911 {
9912         //mono_mempool_stats (cfg->mempool);
9913         mono_free_loop_info (cfg);
9914         if (cfg->rs)
9915                 mono_regstate_free (cfg->rs);
9916         if (cfg->spvars)
9917                 g_hash_table_destroy (cfg->spvars);
9918         if (cfg->exvars)
9919                 g_hash_table_destroy (cfg->exvars);
9920         mono_mempool_destroy (cfg->mempool);
9921         g_list_free (cfg->ldstr_list);
9922         g_hash_table_destroy (cfg->token_info_hash);
9923
9924         g_free (cfg->varinfo);
9925         g_free (cfg->vars);
9926         g_free (cfg->exception_message);
9927         g_free (cfg);
9928 }
9929
9930 #ifdef HAVE_KW_THREAD
9931 static __thread gpointer mono_lmf_addr MONO_TLS_FAST;
9932 #ifdef MONO_ARCH_ENABLE_MONO_LMF_VAR
9933 /* 
9934  * When this is defined, the current lmf is stored in this tls variable instead of in 
9935  * jit_tls->lmf.
9936  */
9937 static __thread gpointer mono_lmf MONO_TLS_FAST;
9938 #endif
9939 #endif
9940
9941 guint32
9942 mono_get_jit_tls_key (void)
9943 {
9944         return mono_jit_tls_id;
9945 }
9946
9947 gint32
9948 mono_get_jit_tls_offset (void)
9949 {
9950 #ifdef HAVE_KW_THREAD
9951         int offset;
9952         MONO_THREAD_VAR_OFFSET (mono_jit_tls, offset);
9953         return offset;
9954 #else
9955         return -1;
9956 #endif
9957 }
9958
9959 gint32
9960 mono_get_lmf_tls_offset (void)
9961 {
9962 #if defined(HAVE_KW_THREAD) && defined(MONO_ARCH_ENABLE_MONO_LMF_VAR)
9963         int offset;
9964         MONO_THREAD_VAR_OFFSET(mono_lmf,offset);
9965         return offset;
9966 #else
9967         return -1;
9968 #endif
9969 }
9970
9971 gint32
9972 mono_get_lmf_addr_tls_offset (void)
9973 {
9974         int offset;
9975         MONO_THREAD_VAR_OFFSET(mono_lmf_addr,offset);
9976         return offset;
9977 }
9978
9979 MonoLMF *
9980 mono_get_lmf (void)
9981 {
9982 #if defined(HAVE_KW_THREAD) && defined(MONO_ARCH_ENABLE_MONO_LMF_VAR)
9983         return mono_lmf;
9984 #else
9985         MonoJitTlsData *jit_tls;
9986
9987         if ((jit_tls = TlsGetValue (mono_jit_tls_id)))
9988                 return jit_tls->lmf;
9989
9990         g_assert_not_reached ();
9991         return NULL;
9992 #endif
9993 }
9994
9995 MonoLMF **
9996 mono_get_lmf_addr (void)
9997 {
9998 #ifdef HAVE_KW_THREAD
9999         return mono_lmf_addr;
10000 #else
10001         MonoJitTlsData *jit_tls;
10002
10003         if ((jit_tls = TlsGetValue (mono_jit_tls_id)))
10004                 return &jit_tls->lmf;
10005
10006         g_assert_not_reached ();
10007         return NULL;
10008 #endif
10009 }
10010
10011 /* Called by native->managed wrappers */
10012 void
10013 mono_jit_thread_attach (MonoDomain *domain)
10014 {
10015 #ifdef HAVE_KW_THREAD
10016         if (!mono_lmf_addr) {
10017                 mono_thread_attach (domain);
10018         }
10019 #else
10020         if (!TlsGetValue (mono_jit_tls_id))
10021                 mono_thread_attach (domain);
10022 #endif
10023         if (mono_domain_get () != domain)
10024                 mono_domain_set (domain, TRUE);
10025 }       
10026
10027 /**
10028  * mono_thread_abort:
10029  * @obj: exception object
10030  *
10031  * abort the thread, print exception information and stack trace
10032  */
10033 static void
10034 mono_thread_abort (MonoObject *obj)
10035 {
10036         /* MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id); */
10037         
10038         /* handle_remove should be eventually called for this thread, too
10039         g_free (jit_tls);*/
10040
10041         if ((mono_runtime_unhandled_exception_policy_get () == MONO_UNHANLED_POLICY_LEGACY) ||
10042                         (obj->vtable->klass == mono_defaults.threadabortexception_class)) {
10043                 mono_thread_exit ();
10044         } else {
10045                 exit (mono_environment_exitcode_get ());
10046         }
10047 }
10048
10049 static void*
10050 setup_jit_tls_data (gpointer stack_start, gpointer abort_func)
10051 {
10052         MonoJitTlsData *jit_tls;
10053         MonoLMF *lmf;
10054
10055         jit_tls = TlsGetValue (mono_jit_tls_id);
10056         if (jit_tls)
10057                 return jit_tls;
10058
10059         jit_tls = g_new0 (MonoJitTlsData, 1);
10060
10061         TlsSetValue (mono_jit_tls_id, jit_tls);
10062
10063 #ifdef HAVE_KW_THREAD
10064         mono_jit_tls = jit_tls;
10065 #endif
10066
10067         jit_tls->abort_func = abort_func;
10068         jit_tls->end_of_stack = stack_start;
10069
10070         lmf = g_new0 (MonoLMF, 1);
10071 #ifdef MONO_ARCH_INIT_TOP_LMF_ENTRY
10072         MONO_ARCH_INIT_TOP_LMF_ENTRY (lmf);
10073 #else
10074         lmf->ebp = -1;
10075 #endif
10076
10077         jit_tls->first_lmf = lmf;
10078
10079 #if defined(HAVE_KW_THREAD) && defined(MONO_ARCH_ENABLE_MONO_LMF_VAR)
10080         /* jit_tls->lmf is unused */
10081         mono_lmf = lmf;
10082         mono_lmf_addr = &mono_lmf;
10083 #else
10084 #if defined(HAVE_KW_THREAD)
10085         mono_lmf_addr = &jit_tls->lmf;  
10086 #endif
10087
10088         jit_tls->lmf = lmf;
10089 #endif
10090
10091         mono_arch_setup_jit_tls_data (jit_tls);
10092         mono_setup_altstack (jit_tls);
10093
10094         return jit_tls;
10095 }
10096
10097 static void
10098 mono_thread_start_cb (gsize tid, gpointer stack_start, gpointer func)
10099 {
10100         MonoThread *thread;
10101         void *jit_tls = setup_jit_tls_data (stack_start, mono_thread_abort);
10102         thread = mono_thread_current ();
10103         mono_debugger_thread_created (tid, thread, jit_tls);
10104         if (thread)
10105                 thread->jit_data = jit_tls;
10106 }
10107
10108 void (*mono_thread_attach_aborted_cb ) (MonoObject *obj) = NULL;
10109
10110 static void
10111 mono_thread_abort_dummy (MonoObject *obj)
10112 {
10113   if (mono_thread_attach_aborted_cb)
10114     mono_thread_attach_aborted_cb (obj);
10115   else
10116     mono_thread_abort (obj);
10117 }
10118
10119 static void
10120 mono_thread_attach_cb (gsize tid, gpointer stack_start)
10121 {
10122         MonoThread *thread;
10123         void *jit_tls = setup_jit_tls_data (stack_start, mono_thread_abort_dummy);
10124         thread = mono_thread_current ();
10125         mono_debugger_thread_created (tid, thread, (MonoJitTlsData *) jit_tls);
10126         if (thread)
10127                 thread->jit_data = jit_tls;
10128         if (mono_profiler_get_events () & MONO_PROFILE_STATISTICAL)
10129                 setup_stat_profiler ();
10130 }
10131
10132 static void
10133 mini_thread_cleanup (MonoThread *thread)
10134 {
10135         MonoJitTlsData *jit_tls = thread->jit_data;
10136
10137         if (jit_tls) {
10138                 mono_debugger_thread_cleanup (jit_tls);
10139                 mono_arch_free_jit_tls_data (jit_tls);
10140
10141                 mono_free_altstack (jit_tls);
10142                 g_free (jit_tls->first_lmf);
10143                 g_free (jit_tls);
10144                 thread->jit_data = NULL;
10145                 TlsSetValue (mono_jit_tls_id, NULL);
10146         }
10147 }
10148
10149 static MonoInst*
10150 mono_create_tls_get (MonoCompile *cfg, int offset)
10151 {
10152 #ifdef MONO_ARCH_HAVE_TLS_GET
10153         MonoInst* ins;
10154         
10155         if (offset == -1)
10156                 return NULL;
10157         
10158         MONO_INST_NEW (cfg, ins, OP_TLS_GET);
10159         ins->dreg = mono_regstate_next_int (cfg->rs);
10160         ins->inst_offset = offset;
10161         return ins;
10162 #else
10163         return NULL;
10164 #endif
10165 }
10166
10167 MonoInst*
10168 mono_get_jit_tls_intrinsic (MonoCompile *cfg)
10169 {
10170         return mono_create_tls_get (cfg, mono_get_jit_tls_offset ());
10171 }
10172
10173 void
10174 mono_add_patch_info (MonoCompile *cfg, int ip, MonoJumpInfoType type, gconstpointer target)
10175 {
10176         MonoJumpInfo *ji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo));
10177
10178         ji->ip.i = ip;
10179         ji->type = type;
10180         ji->data.target = target;
10181         ji->next = cfg->patch_info;
10182
10183         cfg->patch_info = ji;
10184 }
10185
10186 void
10187 mono_remove_patch_info (MonoCompile *cfg, int ip)
10188 {
10189         MonoJumpInfo **ji = &cfg->patch_info;
10190
10191         while (*ji) {
10192                 if ((*ji)->ip.i == ip)
10193                         *ji = (*ji)->next;
10194                 else
10195                         ji = &((*ji)->next);
10196         }
10197 }
10198
10199 /**
10200  * mono_patch_info_dup_mp:
10201  *
10202  * Make a copy of PATCH_INFO, allocating memory from the mempool MP.
10203  */
10204 MonoJumpInfo*
10205 mono_patch_info_dup_mp (MonoMemPool *mp, MonoJumpInfo *patch_info)
10206 {
10207         MonoJumpInfo *res = mono_mempool_alloc (mp, sizeof (MonoJumpInfo));
10208         memcpy (res, patch_info, sizeof (MonoJumpInfo));
10209
10210         switch (patch_info->type) {
10211         case MONO_PATCH_INFO_RVA:
10212         case MONO_PATCH_INFO_LDSTR:
10213         case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
10214         case MONO_PATCH_INFO_LDTOKEN:
10215         case MONO_PATCH_INFO_DECLSEC:
10216                 res->data.token = mono_mempool_alloc (mp, sizeof (MonoJumpInfoToken));
10217                 memcpy (res->data.token, patch_info->data.token, sizeof (MonoJumpInfoToken));
10218                 break;
10219         case MONO_PATCH_INFO_SWITCH:
10220                 res->data.table = mono_mempool_alloc (mp, sizeof (MonoJumpInfoBBTable));
10221                 memcpy (res->data.table, patch_info->data.table, sizeof (MonoJumpInfoBBTable));
10222                 break;
10223         default:
10224                 break;
10225         }
10226
10227         return res;
10228 }
10229
10230 guint
10231 mono_patch_info_hash (gconstpointer data)
10232 {
10233         const MonoJumpInfo *ji = (MonoJumpInfo*)data;
10234
10235         switch (ji->type) {
10236         case MONO_PATCH_INFO_RVA:
10237         case MONO_PATCH_INFO_LDSTR:
10238         case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
10239         case MONO_PATCH_INFO_LDTOKEN:
10240         case MONO_PATCH_INFO_DECLSEC:
10241                 return (ji->type << 8) | ji->data.token->token;
10242         case MONO_PATCH_INFO_VTABLE:
10243         case MONO_PATCH_INFO_CLASS:
10244         case MONO_PATCH_INFO_IID:
10245         case MONO_PATCH_INFO_ADJUSTED_IID:
10246                 return (ji->type << 8) | (gssize)ji->data.klass;
10247         case MONO_PATCH_INFO_FIELD:
10248         case MONO_PATCH_INFO_SFLDA:
10249                 return (ji->type << 8) | (gssize)ji->data.field;
10250         case MONO_PATCH_INFO_METHODCONST:
10251         case MONO_PATCH_INFO_METHOD:
10252         case MONO_PATCH_INFO_METHOD_JUMP:
10253                 return (ji->type << 8) | (gssize)ji->data.method;
10254         case MONO_PATCH_INFO_IMAGE:
10255                 return (ji->type << 8) | (gssize)ji->data.image;                
10256         default:
10257                 return (ji->type << 8);
10258         }
10259 }
10260
10261 /* 
10262  * mono_patch_info_equal:
10263  * 
10264  * This might fail to recognize equivalent patches, i.e. floats, so its only
10265  * usable in those cases where this is not a problem, i.e. sharing GOT slots
10266  * in AOT.
10267  */
10268 gint
10269 mono_patch_info_equal (gconstpointer ka, gconstpointer kb)
10270 {
10271         const MonoJumpInfo *ji1 = (MonoJumpInfo*)ka;
10272         const MonoJumpInfo *ji2 = (MonoJumpInfo*)kb;
10273
10274         if (ji1->type != ji2->type)
10275                 return 0;
10276
10277         switch (ji1->type) {
10278         case MONO_PATCH_INFO_RVA:
10279         case MONO_PATCH_INFO_LDSTR:
10280         case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
10281         case MONO_PATCH_INFO_LDTOKEN:
10282         case MONO_PATCH_INFO_DECLSEC:
10283                 if ((ji1->data.token->image != ji2->data.token->image) ||
10284                         (ji1->data.token->token != ji2->data.token->token))
10285                         return 0;
10286                 break;
10287         default:
10288                 if (ji1->data.name != ji2->data.name)
10289                         return 0;
10290                 break;
10291         }
10292
10293         return 1;
10294 }
10295
10296 gpointer
10297 mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *patch_info, gboolean run_cctors)
10298 {
10299         unsigned char *ip = patch_info->ip.i + code;
10300         gconstpointer target = NULL;
10301
10302         switch (patch_info->type) {
10303         case MONO_PATCH_INFO_BB:
10304                 target = patch_info->data.bb->native_offset + code;
10305                 break;
10306         case MONO_PATCH_INFO_ABS:
10307                 target = patch_info->data.target;
10308                 break;
10309         case MONO_PATCH_INFO_LABEL:
10310                 target = patch_info->data.inst->inst_c0 + code;
10311                 break;
10312         case MONO_PATCH_INFO_IP:
10313                 target = ip;
10314                 break;
10315         case MONO_PATCH_INFO_METHOD_REL:
10316                 target = code + patch_info->data.offset;
10317                 break;
10318         case MONO_PATCH_INFO_INTERNAL_METHOD: {
10319                 MonoJitICallInfo *mi = mono_find_jit_icall_by_name (patch_info->data.name);
10320                 if (!mi) {
10321                         g_warning ("unknown MONO_PATCH_INFO_INTERNAL_METHOD %s", patch_info->data.name);
10322                         g_assert_not_reached ();
10323                 }
10324                 target = mono_icall_get_wrapper (mi);
10325                 break;
10326         }
10327         case MONO_PATCH_INFO_METHOD_JUMP: {
10328                 GSList *list;
10329
10330                 /* get the trampoline to the method from the domain */
10331                 target = mono_create_jump_trampoline (domain, patch_info->data.method, TRUE);
10332                 if (!domain->jump_target_hash)
10333                         domain->jump_target_hash = g_hash_table_new (NULL, NULL);
10334                 list = g_hash_table_lookup (domain->jump_target_hash, patch_info->data.method);
10335                 list = g_slist_prepend (list, ip);
10336                 g_hash_table_insert (domain->jump_target_hash, patch_info->data.method, list);
10337                 break;
10338         }
10339         case MONO_PATCH_INFO_METHOD:
10340                 if (patch_info->data.method == method) {
10341                         target = code;
10342                 } else {
10343                         /* get the trampoline to the method from the domain */
10344                         if (method && method->wrapper_type == MONO_WRAPPER_STATIC_RGCTX_INVOKE)
10345                                 target = mono_ldftn_nosync (patch_info->data.method);
10346                         else
10347                                 target = mono_create_jit_trampoline (patch_info->data.method);
10348                 }
10349                 break;
10350         case MONO_PATCH_INFO_SWITCH: {
10351                 gpointer *jump_table;
10352                 int i;
10353
10354                 if (method && method->dynamic) {
10355                         jump_table = mono_code_manager_reserve (mono_dynamic_code_hash_lookup (domain, method)->code_mp, sizeof (gpointer) * patch_info->data.table->table_size);
10356                 } else {
10357                         mono_domain_lock (domain);
10358                         jump_table = mono_code_manager_reserve (domain->code_mp, sizeof (gpointer) * patch_info->data.table->table_size);
10359                         mono_domain_unlock (domain);
10360                 }
10361
10362                 for (i = 0; i < patch_info->data.table->table_size; i++) {
10363                         jump_table [i] = code + GPOINTER_TO_INT (patch_info->data.table->table [i]);
10364                 }
10365                 target = jump_table;
10366                 break;
10367         }
10368         case MONO_PATCH_INFO_METHODCONST:
10369         case MONO_PATCH_INFO_CLASS:
10370         case MONO_PATCH_INFO_IMAGE:
10371         case MONO_PATCH_INFO_FIELD:
10372                 target = patch_info->data.target;
10373                 break;
10374         case MONO_PATCH_INFO_IID:
10375                 mono_class_init (patch_info->data.klass);
10376                 target = GINT_TO_POINTER ((int)patch_info->data.klass->interface_id);
10377                 break;
10378         case MONO_PATCH_INFO_ADJUSTED_IID:
10379                 mono_class_init (patch_info->data.klass);
10380                 target = GINT_TO_POINTER ((int)(-((patch_info->data.klass->interface_id + 1) * SIZEOF_VOID_P)));
10381                 break;
10382         case MONO_PATCH_INFO_VTABLE:
10383                 target = mono_class_vtable (domain, patch_info->data.klass);
10384                 break;
10385         case MONO_PATCH_INFO_CLASS_INIT:
10386                 target = mono_create_class_init_trampoline (mono_class_vtable (domain, patch_info->data.klass));
10387                 break;
10388         case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE:
10389                 target = mono_create_delegate_trampoline (patch_info->data.klass);
10390                 break;
10391         case MONO_PATCH_INFO_SFLDA: {
10392                 MonoVTable *vtable = mono_class_vtable (domain, patch_info->data.field->parent);
10393                 if (!vtable->initialized && !(vtable->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) && (method && mono_class_needs_cctor_run (vtable->klass, method)))
10394                         /* Done by the generated code */
10395                         ;
10396                 else {
10397                         if (run_cctors)
10398                                 mono_runtime_class_init (vtable);
10399                 }
10400                 target = (char*)vtable->data + patch_info->data.field->offset;
10401                 break;
10402         }
10403         case MONO_PATCH_INFO_RVA:
10404                 target = mono_image_rva_map (patch_info->data.token->image, patch_info->data.token->token);
10405                 break;
10406         case MONO_PATCH_INFO_R4:
10407         case MONO_PATCH_INFO_R8:
10408                 target = patch_info->data.target;
10409                 break;
10410         case MONO_PATCH_INFO_EXC_NAME:
10411                 target = patch_info->data.name;
10412                 break;
10413         case MONO_PATCH_INFO_LDSTR:
10414                 target =
10415                         mono_ldstr (domain, patch_info->data.token->image, 
10416                                                 mono_metadata_token_index (patch_info->data.token->token));
10417                 break;
10418         case MONO_PATCH_INFO_TYPE_FROM_HANDLE: {
10419                 gpointer handle;
10420                 MonoClass *handle_class;
10421
10422                 handle = mono_ldtoken (patch_info->data.token->image, 
10423                                        patch_info->data.token->token, &handle_class, NULL);
10424                 mono_class_init (handle_class);
10425                 mono_class_init (mono_class_from_mono_type (handle));
10426
10427                 target =
10428                         mono_type_get_object (domain, handle);
10429                 break;
10430         }
10431         case MONO_PATCH_INFO_LDTOKEN: {
10432                 gpointer handle;
10433                 MonoClass *handle_class;
10434                 
10435                 handle = mono_ldtoken (patch_info->data.token->image,
10436                                        patch_info->data.token->token, &handle_class, NULL);
10437                 mono_class_init (handle_class);
10438                 
10439                 target = handle;
10440                 break;
10441         }
10442         case MONO_PATCH_INFO_DECLSEC:
10443                 target = (mono_metadata_blob_heap (patch_info->data.token->image, patch_info->data.token->token) + 2);
10444                 break;
10445         case MONO_PATCH_INFO_ICALL_ADDR:
10446                 target = mono_lookup_internal_call (patch_info->data.method);
10447                 break;
10448         case MONO_PATCH_INFO_BB_OVF:
10449         case MONO_PATCH_INFO_EXC_OVF:
10450         case MONO_PATCH_INFO_GOT_OFFSET:
10451         case MONO_PATCH_INFO_NONE:
10452                 break;
10453         default:
10454                 g_assert_not_reached ();
10455         }
10456
10457         return (gpointer)target;
10458 }
10459
10460 static void
10461 dec_foreach (MonoInst *tree, MonoCompile *cfg) {
10462         MonoJitICallInfo *info;
10463
10464         decompose_foreach (tree, cfg);
10465
10466         switch (mono_burg_arity [tree->opcode]) {
10467         case 0: break;
10468         case 1: 
10469                 dec_foreach (tree->inst_left, cfg);
10470
10471                 if ((info = mono_find_jit_opcode_emulation (tree->opcode))) {
10472                         MonoInst *iargs [2];
10473                 
10474                         iargs [0] = tree->inst_left;
10475
10476                         mono_emulate_opcode (cfg, tree, iargs, info);
10477                         return;
10478                 }
10479
10480                 break;
10481         case 2:
10482 #ifdef MONO_ARCH_BIGMUL_INTRINS
10483                 if (tree->opcode == OP_LMUL
10484                                 && (cfg->opt & MONO_OPT_INTRINS)
10485                                 && (tree->inst_left->opcode == CEE_CONV_I8 
10486                                         || tree->inst_left->opcode == CEE_CONV_U8)
10487                                 && tree->inst_left->inst_left->type == STACK_I4
10488                                 && (tree->inst_right->opcode == CEE_CONV_I8 
10489                                         || tree->inst_right->opcode == CEE_CONV_U8)
10490                                 && tree->inst_right->inst_left->type == STACK_I4
10491                                 && tree->inst_left->opcode == tree->inst_right->opcode) {
10492                         tree->opcode = (tree->inst_left->opcode == CEE_CONV_I8 ? OP_BIGMUL: OP_BIGMUL_UN);
10493                         tree->inst_left = tree->inst_left->inst_left;
10494                         tree->inst_right = tree->inst_right->inst_left;
10495                         dec_foreach (tree, cfg);
10496                 } else 
10497 #endif
10498                         if ((info = mono_find_jit_opcode_emulation (tree->opcode))) {
10499                         MonoInst *iargs [2];
10500                 
10501                         iargs [0] = tree->inst_i0;
10502                         iargs [1] = tree->inst_i1;
10503                 
10504                         mono_emulate_opcode (cfg, tree, iargs, info);
10505
10506                         dec_foreach (iargs [0], cfg);
10507                         dec_foreach (iargs [1], cfg);
10508                         return;
10509                 } else {
10510                         dec_foreach (tree->inst_left, cfg);
10511                         dec_foreach (tree->inst_right, cfg);
10512                 }
10513                 break;
10514         default:
10515                 g_assert_not_reached ();
10516         }
10517 }
10518
10519 static void
10520 decompose_pass (MonoCompile *cfg) {
10521         MonoBasicBlock *bb;
10522
10523         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
10524                 MonoInst *tree;
10525                 cfg->cbb = bb;
10526                 cfg->prev_ins = NULL;
10527                 MONO_BB_FOR_EACH_INS (cfg->cbb, tree) {
10528                         dec_foreach (tree, cfg);
10529                         cfg->prev_ins = tree;
10530                 }
10531         }
10532 }
10533
10534 static void
10535 nullify_basic_block (MonoBasicBlock *bb) 
10536 {
10537         bb->in_count = 0;
10538         bb->out_count = 0;
10539         bb->in_bb = NULL;
10540         bb->out_bb = NULL;
10541         bb->next_bb = NULL;
10542         MONO_INST_LIST_INIT (&bb->ins_list);
10543         bb->cil_code = NULL;
10544 }
10545
10546 static void 
10547 replace_out_block (MonoBasicBlock *bb, MonoBasicBlock *orig,  MonoBasicBlock *repl)
10548 {
10549         int i;
10550
10551         for (i = 0; i < bb->out_count; i++) {
10552                 MonoBasicBlock *ob = bb->out_bb [i];
10553                 if (ob == orig) {
10554                         if (!repl) {
10555                                 if (bb->out_count > 1) {
10556                                         bb->out_bb [i] = bb->out_bb [bb->out_count - 1];
10557                                 }
10558                                 bb->out_count--;
10559                         } else {
10560                                 bb->out_bb [i] = repl;
10561                         }
10562                 }
10563         }
10564 }
10565
10566 static void 
10567 replace_in_block (MonoBasicBlock *bb, MonoBasicBlock *orig, MonoBasicBlock *repl)
10568 {
10569         int i;
10570
10571         for (i = 0; i < bb->in_count; i++) {
10572                 MonoBasicBlock *ib = bb->in_bb [i];
10573                 if (ib == orig) {
10574                         if (!repl) {
10575                                 if (bb->in_count > 1) {
10576                                         bb->in_bb [i] = bb->in_bb [bb->in_count - 1];
10577                                 }
10578                                 bb->in_count--;
10579                         } else {
10580                                 bb->in_bb [i] = repl;
10581                         }
10582                 }
10583         }
10584 }
10585
10586 static void
10587 replace_out_block_in_code (MonoBasicBlock *bb, MonoBasicBlock *orig, MonoBasicBlock *repl) {
10588         MonoInst *inst;
10589         
10590         MONO_BB_FOR_EACH_INS (bb, inst) {
10591                 if (inst->opcode == OP_CALL_HANDLER) {
10592                         if (inst->inst_target_bb == orig)
10593                                 inst->inst_target_bb = repl;
10594                 }
10595         }
10596
10597         inst = mono_inst_list_last (&bb->ins_list);
10598         if (!inst)
10599                 return;
10600
10601         switch (inst->opcode) {
10602         case OP_BR:
10603                 if (inst->inst_target_bb == orig)
10604                         inst->inst_target_bb = repl;
10605                 break;
10606         case OP_SWITCH: {
10607                 int i;
10608                 int n = GPOINTER_TO_INT (inst->klass);
10609                 for (i = 0; i < n; i++ ) {
10610                         if (inst->inst_many_bb [i] == orig)
10611                                 inst->inst_many_bb [i] = repl;
10612                 }
10613                 break;
10614         }
10615         case CEE_BNE_UN:
10616         case CEE_BEQ:
10617         case CEE_BLT:
10618         case CEE_BLT_UN:
10619         case CEE_BGT:
10620         case CEE_BGT_UN:
10621         case CEE_BGE:
10622         case CEE_BGE_UN:
10623         case CEE_BLE:
10624         case CEE_BLE_UN:
10625                 if (inst->inst_true_bb == orig)
10626                         inst->inst_true_bb = repl;
10627                 if (inst->inst_false_bb == orig)
10628                         inst->inst_false_bb = repl;
10629                 break;
10630         default:
10631                 break;
10632         }
10633 }
10634
10635 static void 
10636 replace_basic_block (MonoBasicBlock *bb, MonoBasicBlock *orig,  MonoBasicBlock *repl)
10637 {
10638         int i, j;
10639
10640         for (i = 0; i < bb->out_count; i++) {
10641                 MonoBasicBlock *ob = bb->out_bb [i];
10642                 for (j = 0; j < ob->in_count; j++) {
10643                         if (ob->in_bb [j] == orig) {
10644                                 ob->in_bb [j] = repl;
10645                         }
10646                 }
10647         }
10648
10649 }
10650
10651 /**
10652   * Check if a bb is useless (is just made of NOPs and ends with an
10653   * unconditional branch, or nothing).
10654   * If it is so, unlink it from the CFG and nullify it, and return TRUE.
10655   * Otherwise, return FALSE;
10656   */
10657 static gboolean
10658 remove_block_if_useless (MonoCompile *cfg, MonoBasicBlock *bb, MonoBasicBlock *previous_bb) {
10659         MonoBasicBlock *target_bb = NULL;
10660         MonoInst *inst;
10661         
10662         /* Do not touch handlers */
10663         if (bb->region != -1) {
10664                 bb->not_useless = TRUE;
10665                 return FALSE;
10666         }
10667         
10668         MONO_BB_FOR_EACH_INS (bb, inst) {
10669                 switch (inst->opcode) {
10670                 case OP_NOP:
10671                         break;
10672                 case OP_BR:
10673                         target_bb = inst->inst_target_bb;
10674                         break;
10675                 default:
10676                         bb->not_useless = TRUE;
10677                         return FALSE;
10678                 }
10679         }
10680         
10681         if (target_bb == NULL) {
10682                 if ((bb->out_count == 1) && (bb->out_bb [0] == bb->next_bb)) {
10683                         target_bb = bb->next_bb;
10684                 } else {
10685                         /* Do not touch empty BBs that do not "fall through" to their next BB (like the exit BB) */
10686                         return FALSE;
10687                 }
10688         }
10689         
10690         /* Do not touch BBs following a switch (they are the "default" branch) */
10691         inst = mono_inst_list_last (&previous_bb->ins_list);
10692         if (inst && inst->opcode == OP_SWITCH)
10693                 return FALSE;
10694         
10695         /* Do not touch BBs following the entry BB and jumping to something that is not */
10696         /* thiry "next" bb (the entry BB cannot contain the branch) */
10697         if ((previous_bb == cfg->bb_entry) && (bb->next_bb != target_bb)) {
10698                 return FALSE;
10699         }
10700
10701         /* 
10702          * Do not touch BBs following a try block as the code in 
10703          * mini_method_compile needs them to compute the length of the try block.
10704          */
10705         if (MONO_BBLOCK_IS_IN_REGION (previous_bb, MONO_REGION_TRY))
10706                 return FALSE;
10707         
10708         /* Check that there is a target BB, and that bb is not an empty loop (Bug 75061) */
10709         if ((target_bb != NULL) && (target_bb != bb)) {
10710                 MonoInst *last_ins;
10711                 int i;
10712
10713                 if (cfg->verbose_level > 1) {
10714                         printf ("remove_block_if_useless %s, removed BB%d\n", mono_method_full_name (cfg->method, TRUE), bb->block_num);
10715                 }
10716                 
10717                 /* unlink_bblock () modifies the bb->in_bb array so can't use a for loop here */
10718                 while (bb->in_count) {
10719                         MonoBasicBlock *in_bb = bb->in_bb [0];
10720                         mono_unlink_bblock (cfg, in_bb, bb);
10721                         link_bblock (cfg, in_bb, target_bb);
10722                         replace_out_block_in_code (in_bb, bb, target_bb);
10723                 }
10724                 
10725                 mono_unlink_bblock (cfg, bb, target_bb);
10726                 
10727                 last_ins = mono_inst_list_last (&previous_bb->ins_list);
10728
10729                 if ((previous_bb != cfg->bb_entry) &&
10730                                 (previous_bb->region == bb->region) &&
10731                                 ((last_ins == NULL) ||
10732                                 ((last_ins->opcode != OP_BR) &&
10733                                 (!(MONO_IS_COND_BRANCH_OP (last_ins))) &&
10734                                 (last_ins->opcode != OP_SWITCH)))) {
10735                         for (i = 0; i < previous_bb->out_count; i++) {
10736                                 if (previous_bb->out_bb [i] == target_bb) {
10737                                         MonoInst *jump;
10738                                         MONO_INST_NEW (cfg, jump, OP_BR);
10739                                         MONO_ADD_INS (previous_bb, jump);
10740                                         jump->cil_code = previous_bb->cil_code;
10741                                         jump->inst_target_bb = target_bb;
10742                                         break;
10743                                 }
10744                         }
10745                 }
10746                 
10747                 previous_bb->next_bb = bb->next_bb;
10748                 nullify_basic_block (bb);
10749                 
10750                 return TRUE;
10751         } else {
10752                 return FALSE;
10753         }
10754 }
10755
10756 static void
10757 merge_basic_blocks (MonoBasicBlock *bb, MonoBasicBlock *bbn) 
10758 {
10759         MonoInst *last_ins;
10760
10761         bb->out_count = bbn->out_count;
10762         bb->out_bb = bbn->out_bb;
10763
10764         replace_basic_block (bb, bbn, bb);
10765
10766         last_ins = mono_inst_list_last (&bb->ins_list);
10767
10768         /* Nullify branch at the end of bb */
10769         if (last_ins && MONO_IS_BRANCH_OP (last_ins))
10770                 last_ins->opcode = OP_NOP;
10771
10772         MONO_INST_LIST_SPLICE_TAIL_INIT (&bbn->ins_list, &bb->ins_list);
10773
10774         bb->next_bb = bbn->next_bb;
10775         nullify_basic_block (bbn);
10776 }
10777
10778 static void
10779 move_basic_block_to_end (MonoCompile *cfg, MonoBasicBlock *bb)
10780 {
10781         MonoBasicBlock *bbn, *next;
10782         MonoInst *last_ins;
10783
10784         next = bb->next_bb;
10785
10786         /* Find the previous */
10787         for (bbn = cfg->bb_entry; bbn->next_bb && bbn->next_bb != bb; bbn = bbn->next_bb)
10788                 ;
10789         if (bbn->next_bb) {
10790                 bbn->next_bb = bb->next_bb;
10791         }
10792
10793         /* Find the last */
10794         for (bbn = cfg->bb_entry; bbn->next_bb; bbn = bbn->next_bb)
10795                 ;
10796         bbn->next_bb = bb;
10797         bb->next_bb = NULL;
10798
10799         last_ins = mono_inst_list_last (&bb->ins_list);
10800
10801         /* Add a branch */
10802         if (next && (!last_ins || (last_ins->opcode != OP_NOT_REACHED))) {
10803                 MonoInst *ins;
10804
10805                 MONO_INST_NEW (cfg, ins, OP_BR);
10806                 MONO_ADD_INS (bb, ins);
10807                 link_bblock (cfg, bb, next);
10808                 ins->inst_target_bb = next;
10809         }               
10810 }
10811
10812 /* checks that a and b represent the same instructions, conservatively,
10813  * it can return FALSE also for two trees that are equal.
10814  * FIXME: also make sure there are no side effects.
10815  */
10816 static int
10817 same_trees (MonoInst *a, MonoInst *b)
10818 {
10819         int arity;
10820         if (a->opcode != b->opcode)
10821                 return FALSE;
10822         arity = mono_burg_arity [a->opcode];
10823         if (arity == 1) {
10824                 if (a->ssa_op == b->ssa_op && a->ssa_op == MONO_SSA_LOAD && a->inst_i0 == b->inst_i0)
10825                         return TRUE;
10826                 return same_trees (a->inst_left, b->inst_left);
10827         } else if (arity == 2) {
10828                 return same_trees (a->inst_left, b->inst_left) && same_trees (a->inst_right, b->inst_right);
10829         } else if (arity == 0) {
10830                 switch (a->opcode) {
10831                 case OP_ICONST:
10832                         return a->inst_c0 == b->inst_c0;
10833                 default:
10834                         return FALSE;
10835                 }
10836         }
10837         return FALSE;
10838 }
10839
10840 static int
10841 get_unsigned_condbranch (int opcode)
10842 {
10843         switch (opcode) {
10844         case CEE_BLE: return CEE_BLE_UN;
10845         case CEE_BLT: return CEE_BLT_UN;
10846         case CEE_BGE: return CEE_BGE_UN;
10847         case CEE_BGT: return CEE_BGT_UN;
10848         }
10849         g_assert_not_reached ();
10850         return 0;
10851 }
10852
10853 static int
10854 tree_is_unsigned (MonoInst* ins) {
10855         switch (ins->opcode) {
10856         case OP_ICONST:
10857                 return (int)ins->inst_c0 >= 0;
10858         /* array lengths are positive as are string sizes */
10859         case CEE_LDLEN:
10860         case OP_STRLEN:
10861                 return TRUE;
10862         case CEE_CONV_U1:
10863         case CEE_CONV_U2:
10864         case CEE_CONV_U4:
10865         case CEE_CONV_OVF_U1:
10866         case CEE_CONV_OVF_U2:
10867         case CEE_CONV_OVF_U4:
10868                 return TRUE;
10869         case CEE_LDIND_U1:
10870         case CEE_LDIND_U2:
10871         case CEE_LDIND_U4:
10872                 return TRUE;
10873         default:
10874                 return FALSE;
10875         }
10876 }
10877
10878 /* check if an unsigned compare can be used instead of two signed compares
10879  * for (val < 0 || val > limit) conditionals.
10880  * Returns TRUE if the optimization has been applied.
10881  * Note that this can't be applied if the second arg is not positive...
10882  */
10883 static int
10884 try_unsigned_compare (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *bb_last)
10885 {
10886         MonoBasicBlock *truet, *falset;
10887         MonoInst *cmp_inst = bb_last->inst_left;
10888         MonoInst *condb;
10889         if (!cmp_inst->inst_right->inst_c0 == 0)
10890                 return FALSE;
10891         truet = bb_last->inst_true_bb;
10892         falset = bb_last->inst_false_bb;
10893         if (falset->in_count != 1)
10894                 return FALSE;
10895         condb = mono_inst_list_last (&falset->ins_list);
10896         /* target bb must have one instruction */
10897         if (!condb || (condb->node.next != &falset->ins_list))
10898                 return FALSE;
10899         if ((((condb->opcode == CEE_BLE || condb->opcode == CEE_BLT) && (condb->inst_false_bb == truet))
10900                         || ((condb->opcode == CEE_BGE || condb->opcode == CEE_BGT) && (condb->inst_true_bb == truet)))
10901                         && same_trees (cmp_inst->inst_left, condb->inst_left->inst_left)) {
10902                 if (!tree_is_unsigned (condb->inst_left->inst_right))
10903                         return FALSE;
10904                 condb->opcode = get_unsigned_condbranch (condb->opcode);
10905                 /* change the original condbranch to just point to the new unsigned check */
10906                 bb_last->opcode = OP_BR;
10907                 bb_last->inst_target_bb = falset;
10908                 replace_out_block (bb, truet, NULL);
10909                 replace_in_block (truet, bb, NULL);
10910                 return TRUE;
10911         }
10912         return FALSE;
10913 }
10914
10915 /*
10916  * Optimizes the branches on the Control Flow Graph
10917  *
10918  */
10919 static void
10920 optimize_branches (MonoCompile *cfg)
10921 {
10922         int i, changed = FALSE;
10923         MonoBasicBlock *bb, *bbn;
10924         guint32 niterations;
10925
10926         /*
10927          * Some crazy loops could cause the code below to go into an infinite
10928          * loop, see bug #53003 for an example. To prevent this, we put an upper
10929          * bound on the number of iterations.
10930          */
10931         if (cfg->num_bblocks > 1000)
10932                 niterations = cfg->num_bblocks * 2;
10933         else
10934                 niterations = 1000;
10935
10936         do {
10937                 MonoBasicBlock *previous_bb;
10938                 changed = FALSE;
10939                 niterations --;
10940
10941                 /* we skip the entry block (exit is handled specially instead ) */
10942                 for (previous_bb = cfg->bb_entry, bb = cfg->bb_entry->next_bb; bb; previous_bb = bb, bb = bb->next_bb) {
10943                         MonoInst *last_ins;
10944
10945                         /* dont touch code inside exception clauses */
10946                         if (bb->region != -1)
10947                                 continue;
10948
10949                         if (!bb->not_useless && remove_block_if_useless (cfg, bb, previous_bb)) {
10950                                 changed = TRUE;
10951                                 continue;
10952                         }
10953
10954                         if ((bbn = bb->next_bb) && bbn->in_count == 0 && bb->region == bbn->region) {
10955                                 if (cfg->verbose_level > 2)
10956                                         g_print ("nullify block triggered %d\n", bbn->block_num);
10957
10958                                 bb->next_bb = bbn->next_bb;
10959
10960                                 for (i = 0; i < bbn->out_count; i++)
10961                                         replace_in_block (bbn->out_bb [i], bbn, NULL);
10962
10963                                 nullify_basic_block (bbn);                      
10964                                 changed = TRUE;
10965                         }
10966
10967                         last_ins = mono_inst_list_last (&bb->ins_list);
10968                         if (bb->out_count == 1) {
10969                                 bbn = bb->out_bb [0];
10970
10971                                 /* conditional branches where true and false targets are the same can be also replaced with OP_BR */
10972                                 if (last_ins && MONO_IS_COND_BRANCH_OP (last_ins)) {
10973                                         MonoInst *pop;
10974                                         MONO_INST_NEW (cfg, pop, CEE_POP);
10975                                         pop->inst_left = last_ins->inst_left->inst_left;
10976                                         mono_add_ins_to_end (bb, pop);
10977                                         MONO_INST_NEW (cfg, pop, CEE_POP);
10978                                         pop->inst_left = last_ins->inst_left->inst_right;
10979                                         mono_add_ins_to_end (bb, pop);
10980                                         last_ins->opcode = OP_BR;
10981                                         last_ins->inst_target_bb = last_ins->inst_true_bb;
10982                                         changed = TRUE;
10983                                         if (cfg->verbose_level > 2)
10984                                                 g_print ("cond branch removal triggered in %d %d\n", bb->block_num, bb->out_count);
10985                                 }
10986
10987                                 if (bb->region == bbn->region && bb->next_bb == bbn) {
10988                                         /* the block are in sequence anyway ... */
10989
10990                                         /* branches to the following block can be removed */
10991                                         if (last_ins && last_ins->opcode == OP_BR) {
10992                                                 last_ins->opcode = OP_NOP;
10993                                                 changed = TRUE;
10994                                                 if (cfg->verbose_level > 2)
10995                                                         g_print ("br removal triggered %d -> %d\n", bb->block_num, bbn->block_num);
10996                                         }
10997
10998                                         if (bbn->in_count == 1) {
10999
11000                                                 if (bbn != cfg->bb_exit) {
11001                                                         if (cfg->verbose_level > 2)
11002                                                                 g_print ("block merge triggered %d -> %d\n", bb->block_num, bbn->block_num);
11003                                                         merge_basic_blocks (bb, bbn);
11004                                                         changed = TRUE;
11005                                                         continue;
11006                                                 }
11007
11008                                                 //mono_print_bb_code (bb);
11009                                         }
11010                                 }
11011                         }
11012                         if ((bbn = bb->next_bb) && bbn->in_count == 0 && bb->region == bbn->region) {
11013                                 if (cfg->verbose_level > 2) {
11014                                         g_print ("nullify block triggered %d\n", bbn->block_num);
11015                                 }
11016                                 bb->next_bb = bbn->next_bb;
11017
11018                                 for (i = 0; i < bbn->out_count; i++)
11019                                         replace_in_block (bbn->out_bb [i], bbn, NULL);
11020
11021                                 nullify_basic_block (bbn);                      
11022                                 changed = TRUE;
11023                                 continue;
11024                         }
11025
11026                         if (bb->out_count == 1) {
11027                                 bbn = bb->out_bb [0];
11028
11029                                 if (last_ins && last_ins->opcode == OP_BR) {
11030                                         MonoInst *bbn_code;
11031
11032                                         bbn = last_ins->inst_target_bb;
11033                                         bbn_code = mono_inst_list_first (&bbn->ins_list);
11034                                         if (bb->region == bbn->region && bbn_code &&
11035                                                         bbn_code->opcode == OP_BR &&
11036                                                         bbn_code->inst_target_bb->region == bb->region) {
11037                                                 if (cfg->verbose_level > 2)
11038                                                         g_print ("in %s branch to branch triggered %d -> %d -> %d\n", cfg->method->name, 
11039                                                                  bb->block_num, bbn->block_num, bbn_code->inst_target_bb->block_num);
11040
11041                                                 replace_in_block (bbn, bb, NULL);
11042                                                 replace_out_block (bb, bbn, bbn_code->inst_target_bb);
11043                                                 link_bblock (cfg, bb, bbn_code->inst_target_bb);
11044                                                 last_ins->inst_target_bb = bbn_code->inst_target_bb;
11045                                                 changed = TRUE;
11046                                                 continue;
11047                                         }
11048                                 }
11049                         } else if (bb->out_count == 2) {
11050                                 if (last_ins && MONO_IS_COND_BRANCH_NOFP (last_ins)) {
11051                                         int branch_result = mono_eval_cond_branch (last_ins);
11052                                         MonoBasicBlock *taken_branch_target = NULL, *untaken_branch_target = NULL;
11053                                         MonoInst *bbn_code;
11054
11055                                         if (branch_result == BRANCH_TAKEN) {
11056                                                 taken_branch_target = last_ins->inst_true_bb;
11057                                                 untaken_branch_target = last_ins->inst_false_bb;
11058                                         } else if (branch_result == BRANCH_NOT_TAKEN) {
11059                                                 taken_branch_target = last_ins->inst_false_bb;
11060                                                 untaken_branch_target = last_ins->inst_true_bb;
11061                                         }
11062                                         if (taken_branch_target) {
11063                                                 /* if mono_eval_cond_branch () is ever taken to handle 
11064                                                  * non-constant values to compare, issue a pop here.
11065                                                  */
11066                                                 last_ins->opcode = OP_BR;
11067                                                 last_ins->inst_target_bb = taken_branch_target;
11068                                                 mono_unlink_bblock (cfg, bb, untaken_branch_target);
11069                                                 changed = TRUE;
11070                                                 continue;
11071                                         }
11072                                         bbn = last_ins->inst_true_bb;
11073                                         bbn_code = mono_inst_list_first (&bbn->ins_list);
11074                                         if (bb->region == bbn->region && bbn_code && bbn_code->opcode == OP_BR &&
11075                                                         bbn_code->inst_target_bb->region == bb->region) {
11076                                                 if (cfg->verbose_level > 2)             
11077                                                         g_print ("cbranch1 to branch triggered %d -> (%d) %d (0x%02x)\n", 
11078                                                                  bb->block_num, bbn->block_num, bbn_code->inst_target_bb->block_num, 
11079                                                                  bbn_code->opcode);
11080
11081                                                 /* 
11082                                                  * Unlink, then relink bblocks to avoid various
11083                                                  * tricky situations when the two targets of the branch
11084                                                  * are equal, or will become equal after the change.
11085                                                  */
11086                                                 mono_unlink_bblock (cfg, bb, last_ins->inst_true_bb);
11087                                                 mono_unlink_bblock (cfg, bb, last_ins->inst_false_bb);
11088
11089                                                 last_ins->inst_true_bb = bbn_code->inst_target_bb;
11090
11091                                                 link_bblock (cfg, bb, last_ins->inst_true_bb);
11092                                                 link_bblock (cfg, bb, last_ins->inst_false_bb);
11093
11094                                                 changed = TRUE;
11095                                                 continue;
11096                                         }
11097
11098                                         bbn = last_ins->inst_false_bb;
11099                                         bbn_code = mono_inst_list_first (&bbn->ins_list);
11100                                         if (bb->region == bbn->region && bbn_code && bbn_code->opcode == OP_BR &&
11101                                                         bbn_code->inst_target_bb->region == bb->region) {
11102                                                 if (cfg->verbose_level > 2)
11103                                                         g_print ("cbranch2 to branch triggered %d -> (%d) %d (0x%02x)\n", 
11104                                                                  bb->block_num, bbn->block_num, bbn_code->inst_target_bb->block_num, 
11105                                                                  bbn_code->opcode);
11106
11107                                                 mono_unlink_bblock (cfg, bb, last_ins->inst_true_bb);
11108                                                 mono_unlink_bblock (cfg, bb, last_ins->inst_false_bb);
11109
11110                                                 last_ins->inst_false_bb = bbn_code->inst_target_bb;
11111
11112                                                 link_bblock (cfg, bb, last_ins->inst_true_bb);
11113                                                 link_bblock (cfg, bb, last_ins->inst_false_bb);
11114
11115                                                 changed = TRUE;
11116                                                 continue;
11117                                         }
11118                                 }
11119
11120                                 /* detect and optimize to unsigned compares checks like: if (v < 0 || v > limit */
11121                                 if (last_ins && last_ins->opcode == CEE_BLT && last_ins->inst_left->inst_right->opcode == OP_ICONST) {
11122                                         if (try_unsigned_compare (cfg, bb, last_ins)) {
11123                                                 /*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));*/
11124                                                 changed = TRUE;
11125                                                 continue;
11126                                         }
11127                                 }
11128
11129                                 if (last_ins && MONO_IS_COND_BRANCH_NOFP (last_ins)) {
11130                                         if (last_ins->inst_false_bb->out_of_line && (bb->region == last_ins->inst_false_bb->region)) {
11131                                                 /* Reverse the branch */
11132                                                 last_ins->opcode = reverse_branch_op (last_ins->opcode);
11133                                                 bbn = last_ins->inst_false_bb;
11134                                                 last_ins->inst_false_bb = last_ins->inst_true_bb;
11135                                                 last_ins->inst_true_bb = bbn;
11136
11137                                                 move_basic_block_to_end (cfg, last_ins->inst_true_bb);
11138                                                 if (cfg->verbose_level > 2)
11139                                                         g_print ("cbranch to throw block triggered %d.\n", 
11140                                                                          bb->block_num);
11141                                         }
11142                                 }
11143                         }
11144                 }
11145         } while (changed && (niterations > 0));
11146
11147 }
11148
11149 static void
11150 mono_compile_create_vars (MonoCompile *cfg)
11151 {
11152         MonoMethodSignature *sig;
11153         MonoMethodHeader *header;
11154         int i;
11155
11156         header = mono_method_get_header (cfg->method);
11157
11158         sig = mono_method_signature (cfg->method);
11159         
11160         if (!MONO_TYPE_IS_VOID (sig->ret)) {
11161                 cfg->ret = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst));
11162                 cfg->ret->opcode = OP_RETARG;
11163                 cfg->ret->inst_vtype = sig->ret;
11164                 cfg->ret->klass = mono_class_from_mono_type (sig->ret);
11165         }
11166         if (cfg->verbose_level > 2)
11167                 g_print ("creating vars\n");
11168
11169         cfg->args = mono_mempool_alloc0 (cfg->mempool, (sig->param_count + sig->hasthis) * sizeof (MonoInst*));
11170
11171         if (sig->hasthis)
11172                 cfg->args [0] = mono_compile_create_var (cfg, &cfg->method->klass->this_arg, OP_ARG);
11173
11174         for (i = 0; i < sig->param_count; ++i) {
11175                 cfg->args [i + sig->hasthis] = mono_compile_create_var (cfg, sig->params [i], OP_ARG);
11176                 if (sig->params [i]->byref) {
11177                         cfg->disable_ssa = TRUE;
11178                 }
11179         }
11180
11181         cfg->locals_start = cfg->num_varinfo;
11182
11183         if (cfg->verbose_level > 2)
11184                 g_print ("creating locals\n");
11185
11186         for (i = 0; i < header->num_locals; ++i)
11187                 mono_compile_create_var (cfg, header->locals [i], OP_LOCAL);
11188         if (cfg->verbose_level > 2)
11189                 g_print ("locals done\n");
11190
11191         mono_arch_create_vars (cfg);
11192 }
11193
11194 void
11195 mono_print_code (MonoCompile *cfg)
11196 {
11197         MonoBasicBlock *bb;
11198         
11199         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
11200                 MonoInst *tree;
11201
11202                 if (!MONO_INST_LIST_EMPTY (&bb->ins_list))
11203                         g_print ("CODE BLOCK %d (nesting %d):\n",
11204                                  bb->block_num, bb->nesting);
11205
11206                 MONO_BB_FOR_EACH_INS (bb, tree) {
11207                         mono_print_tree (tree);
11208                         g_print ("\n");
11209                 }
11210         }
11211 }
11212
11213 extern const char * const mono_burg_rule_string [];
11214
11215 static void
11216 emit_state (MonoCompile *cfg, MBState *state, int goal)
11217 {
11218         MBState *kids [10];
11219         int ern = mono_burg_rule (state, goal);
11220         const guint16 *nts = mono_burg_nts_data + mono_burg_nts [ern];
11221
11222         //g_print ("rule: %s\n", mono_burg_rule_string [ern]);
11223         switch (goal) {
11224         case MB_NTERM_reg:
11225                 //if (state->reg2)
11226                 //      state->reg1 = state->reg2; /* chain rule */
11227                 //else
11228 #ifdef MONO_ARCH_ENABLE_EMIT_STATE_OPT
11229                 if (!state->reg1)
11230 #endif
11231                         state->reg1 = mono_regstate_next_int (cfg->rs);
11232                 //g_print ("alloc symbolic R%d (reg2: R%d) in block %d\n", state->reg1, state->reg2, cfg->cbb->block_num);
11233                 break;
11234         case MB_NTERM_lreg:
11235                 state->reg1 = mono_regstate_next_int (cfg->rs);
11236                 state->reg2 = mono_regstate_next_int (cfg->rs);
11237                 break;
11238         case MB_NTERM_freg:
11239 #ifdef MONO_ARCH_SOFT_FLOAT
11240                 state->reg1 = mono_regstate_next_int (cfg->rs);
11241                 state->reg2 = mono_regstate_next_int (cfg->rs);
11242 #else
11243                 state->reg1 = mono_regstate_next_float (cfg->rs);
11244 #endif
11245                 break;
11246         default:
11247 #ifdef MONO_ARCH_ENABLE_EMIT_STATE_OPT
11248                 /*
11249                  * Enabling this might cause bugs to surface in the local register
11250                  * allocators on some architectures like x86.
11251                  */
11252                 if ((state->tree->ssa_op == MONO_SSA_STORE) && (state->left->tree->opcode == OP_REGVAR)) {
11253                         /* Do not optimize away reg-reg moves */
11254                         if (! ((state->right->tree->ssa_op == MONO_SSA_LOAD) && (state->right->left->tree->opcode == OP_REGVAR))) {
11255                                 state->right->reg1 = state->left->tree->dreg;
11256                         }
11257                 }
11258 #endif
11259
11260                 /* do nothing */
11261                 break;
11262         }
11263         if (nts [0]) {
11264                 mono_burg_kids (state, ern, kids);
11265
11266                 emit_state (cfg, kids [0], nts [0]);
11267                 if (nts [1]) {
11268                         emit_state (cfg, kids [1], nts [1]);
11269                         if (nts [2]) {
11270                                 g_assert (!nts [3]);
11271                                 emit_state (cfg, kids [2], nts [2]);
11272                         }
11273                 }
11274         }
11275
11276 //      g_print ("emit: %s (%p)\n", mono_burg_rule_string [ern], state);
11277         mono_burg_emit (ern, state, state->tree, cfg);
11278 }
11279
11280 #define DEBUG_SELECTION
11281
11282 static void 
11283 mini_select_instructions (MonoCompile *cfg)
11284 {
11285         MonoBasicBlock *bb;
11286         
11287         cfg->state_pool = mono_mempool_new ();
11288         cfg->rs = mono_regstate_new ();
11289
11290         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
11291                 MonoInst *last_ins = mono_inst_list_last (&bb->ins_list);
11292
11293                 if (last_ins && MONO_IS_COND_BRANCH_OP (last_ins) &&
11294                                 bb->next_bb != last_ins->inst_false_bb) {
11295
11296                         /* we are careful when inverting, since bugs like #59580
11297                          * could show up when dealing with NaNs.
11298                          */
11299                         if (MONO_IS_COND_BRANCH_NOFP(last_ins) && bb->next_bb == last_ins->inst_true_bb) {
11300                                 MonoBasicBlock *tmp =  last_ins->inst_true_bb;
11301                                 last_ins->inst_true_bb = last_ins->inst_false_bb;
11302                                 last_ins->inst_false_bb = tmp;
11303
11304                                 last_ins->opcode = reverse_branch_op (last_ins->opcode);
11305                         } else {                        
11306                                 MonoInst *inst = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst));
11307                                 inst->opcode = OP_BR;
11308                                 inst->inst_target_bb = last_ins->inst_false_bb;
11309                                 mono_bblock_add_inst (bb, inst);
11310                         }
11311                 }
11312         }
11313
11314 #ifdef DEBUG_SELECTION
11315         if (cfg->verbose_level >= 4) {
11316         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
11317                 MonoInst *tree; 
11318                 g_print ("DUMP BLOCK %d:\n", bb->block_num);
11319
11320                 MONO_BB_FOR_EACH_INS (bb, tree) {
11321                         mono_print_tree (tree);
11322                         g_print ("\n");
11323                 }
11324         }
11325         }
11326 #endif
11327
11328         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
11329                 MonoInst *tree, *n;     
11330                 MonoInstList head;
11331                 MBState *mbstate;
11332
11333                 MONO_INST_LIST_INIT (&head);
11334                 if (MONO_INST_LIST_EMPTY (&bb->ins_list))
11335                         continue;
11336                 MONO_INST_LIST_SPLICE_INIT (&bb->ins_list, &head);
11337                 
11338                 cfg->cbb = bb;
11339                 mono_regstate_reset (cfg->rs);
11340
11341 #ifdef DEBUG_SELECTION
11342                 if (cfg->verbose_level >= 3)
11343                         g_print ("LABEL BLOCK %d:\n", bb->block_num);
11344 #endif
11345                 MONO_INST_LIST_FOR_EACH_ENTRY_SAFE (tree, n, &head, node) {
11346 #ifdef DEBUG_SELECTION
11347                         if (cfg->verbose_level >= 3) {
11348                                 mono_print_tree (tree);
11349                                 g_print ("\n");
11350                         }
11351 #endif
11352
11353                         cfg->ip = tree->cil_code;
11354                         if (!(mbstate = mono_burg_label (tree, cfg))) {
11355                                 g_warning ("unable to label tree %p", tree);
11356                                 mono_print_tree (tree);
11357                                 g_print ("\n");                         
11358                                 g_assert_not_reached ();
11359                         }
11360                         emit_state (cfg, mbstate, MB_NTERM_stmt);
11361                 }
11362                 bb->max_vreg = cfg->rs->next_vreg;
11363
11364                 mono_mempool_empty (cfg->state_pool); 
11365         }
11366         mono_mempool_destroy (cfg->state_pool); 
11367
11368         cfg->ip = NULL;
11369 }
11370
11371 /*
11372  * mono_normalize_opcodes:
11373  *
11374  *   Replace CEE_ and OP_ opcodes with the corresponding OP_I or OP_L opcodes.
11375  */
11376
11377 static gint16 *remap_table;
11378
11379 #if SIZEOF_VOID_P == 8
11380 #define REMAP_OPCODE(opcode) OP_L ## opcode
11381 #else
11382 #define REMAP_OPCODE(opcode) OP_I ## opcode
11383 #endif
11384
11385 static G_GNUC_UNUSED void
11386 mono_normalize_opcodes (MonoCompile *cfg, MonoBasicBlock *bb)
11387 {
11388         MonoInst *ins;
11389
11390         if (!remap_table) {
11391                 remap_table = g_new0 (gint16, OP_LAST);
11392
11393 #if SIZEOF_VOID_P == 8
11394                 remap_table [CEE_CONV_U8] = OP_ZEXT_I4;
11395                 remap_table [CEE_CONV_U] = OP_ZEXT_I4;
11396                 remap_table [CEE_CONV_I8] = OP_SEXT_I4;
11397                 remap_table [CEE_CONV_I] = OP_SEXT_I4;
11398                 remap_table [CEE_CONV_OVF_U4] = OP_LCONV_TO_OVF_U4;
11399                 remap_table [CEE_CONV_OVF_I4_UN] = OP_LCONV_TO_OVF_I4_UN;
11400 #else
11401 #endif
11402                 remap_table [CEE_CONV_R4] = OP_ICONV_TO_R4;
11403                 remap_table [CEE_CONV_R8] = OP_ICONV_TO_R8;
11404                 remap_table [CEE_CONV_I4] = OP_MOVE;
11405                 remap_table [CEE_CONV_U4] = OP_MOVE;
11406                 remap_table [CEE_CONV_I1] = REMAP_OPCODE (CONV_TO_I1);
11407                 remap_table [CEE_CONV_I2] = REMAP_OPCODE (CONV_TO_I2);
11408                 remap_table [CEE_CONV_U1] = REMAP_OPCODE (CONV_TO_U1);
11409                 remap_table [CEE_CONV_U2] = REMAP_OPCODE (CONV_TO_U2);
11410                 remap_table [CEE_CONV_R_UN] = REMAP_OPCODE (CONV_TO_R_UN);
11411                 remap_table [CEE_ADD] = REMAP_OPCODE (ADD);
11412                 remap_table [CEE_SUB] = REMAP_OPCODE (SUB);
11413                 remap_table [CEE_MUL] = REMAP_OPCODE (MUL);
11414                 remap_table [CEE_DIV] = REMAP_OPCODE (DIV);
11415                 remap_table [CEE_REM] = REMAP_OPCODE (REM);
11416                 remap_table [CEE_DIV_UN] = REMAP_OPCODE (DIV_UN);
11417                 remap_table [CEE_REM_UN] = REMAP_OPCODE (REM_UN);
11418                 remap_table [CEE_AND] = REMAP_OPCODE (AND);
11419                 remap_table [CEE_OR] = REMAP_OPCODE (OR);
11420                 remap_table [CEE_XOR] = REMAP_OPCODE (XOR);
11421                 remap_table [CEE_SHL] = REMAP_OPCODE (SHL);
11422                 remap_table [CEE_SHR] = REMAP_OPCODE (SHR);
11423                 remap_table [CEE_SHR_UN] = REMAP_OPCODE (SHR_UN);
11424                 remap_table [CEE_NOT] = REMAP_OPCODE (NOT);
11425                 remap_table [CEE_NEG] = REMAP_OPCODE (NEG);
11426                 remap_table [CEE_CALL] = OP_CALL;
11427                 remap_table [CEE_BEQ] = REMAP_OPCODE (BEQ);
11428                 remap_table [CEE_BNE_UN] = REMAP_OPCODE (BNE_UN);
11429                 remap_table [CEE_BLT] = REMAP_OPCODE (BLT);
11430                 remap_table [CEE_BLT_UN] = REMAP_OPCODE (BLT_UN);
11431                 remap_table [CEE_BGT] = REMAP_OPCODE (BGT);
11432                 remap_table [CEE_BGT_UN] = REMAP_OPCODE (BGT_UN);
11433                 remap_table [CEE_BGE] = REMAP_OPCODE (BGE);
11434                 remap_table [CEE_BGE_UN] = REMAP_OPCODE (BGE_UN);
11435                 remap_table [CEE_BLE] = REMAP_OPCODE (BLE);
11436                 remap_table [CEE_BLE_UN] = REMAP_OPCODE (BLE_UN);
11437                 remap_table [CEE_ADD_OVF] = REMAP_OPCODE (ADD_OVF);
11438                 remap_table [CEE_ADD_OVF_UN] = REMAP_OPCODE (ADD_OVF_UN);
11439                 remap_table [CEE_SUB_OVF] = REMAP_OPCODE (SUB_OVF);
11440                 remap_table [CEE_SUB_OVF_UN] = REMAP_OPCODE (SUB_OVF_UN);
11441                 remap_table [CEE_MUL_OVF] = REMAP_OPCODE (MUL_OVF);
11442                 remap_table [CEE_MUL_OVF_UN] = REMAP_OPCODE (MUL_OVF_UN);
11443         }
11444
11445         MONO_BB_FOR_EACH_INS (bb, ins) {
11446                 int remapped = remap_table [ins->opcode];
11447                 if (remapped)
11448                         ins->opcode = remapped;
11449         }
11450 }
11451
11452 void
11453 mono_codegen (MonoCompile *cfg)
11454 {
11455         MonoJumpInfo *patch_info;
11456         MonoBasicBlock *bb;
11457         int i, max_epilog_size;
11458         guint8 *code;
11459
11460         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
11461                 cfg->spill_count = 0;
11462                 /* we reuse dfn here */
11463                 /* bb->dfn = bb_count++; */
11464 #ifdef MONO_ARCH_ENABLE_NORMALIZE_OPCODES
11465                 mono_normalize_opcodes (cfg, bb);
11466 #endif
11467
11468                 mono_arch_lowering_pass (cfg, bb);
11469
11470                 if (cfg->opt & MONO_OPT_PEEPHOLE)
11471                         mono_arch_peephole_pass_1 (cfg, bb);
11472
11473                 mono_local_regalloc (cfg, bb);
11474
11475                 if (cfg->opt & MONO_OPT_PEEPHOLE)
11476                         mono_arch_peephole_pass_2 (cfg, bb);
11477         }
11478
11479         if (cfg->prof_options & MONO_PROFILE_COVERAGE)
11480                 cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, cfg->num_bblocks);
11481
11482         code = mono_arch_emit_prolog (cfg);
11483
11484         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
11485                 code = mono_arch_instrument_prolog (cfg, mono_profiler_method_enter, code, FALSE);
11486
11487         cfg->code_len = code - cfg->native_code;
11488         cfg->prolog_end = cfg->code_len;
11489
11490         mono_debug_open_method (cfg);
11491
11492         /* emit code all basic blocks */
11493         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
11494                 bb->native_offset = cfg->code_len;
11495                 mono_arch_output_basic_block (cfg, bb);
11496
11497                 if (bb == cfg->bb_exit) {
11498                         cfg->epilog_begin = cfg->code_len;
11499
11500                         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE) {
11501                                 code = cfg->native_code + cfg->code_len;
11502                                 code = mono_arch_instrument_epilog (cfg, mono_profiler_method_leave, code, FALSE);
11503                                 cfg->code_len = code - cfg->native_code;
11504                                 g_assert (cfg->code_len < cfg->code_size);
11505                         }
11506
11507                         mono_arch_emit_epilog (cfg);
11508                 }
11509         }
11510
11511         mono_arch_emit_exceptions (cfg);
11512
11513         max_epilog_size = 0;
11514
11515         code = cfg->native_code + cfg->code_len;
11516
11517         /* we always allocate code in cfg->domain->code_mp to increase locality */
11518         cfg->code_size = cfg->code_len + max_epilog_size;
11519         /* fixme: align to MONO_ARCH_CODE_ALIGNMENT */
11520
11521         if (cfg->method->dynamic) {
11522                 /* Allocate the code into a separate memory pool so it can be freed */
11523                 cfg->dynamic_info = g_new0 (MonoJitDynamicMethodInfo, 1);
11524                 cfg->dynamic_info->code_mp = mono_code_manager_new_dynamic ();
11525                 mono_domain_lock (cfg->domain);
11526                 mono_dynamic_code_hash_insert (cfg->domain, cfg->method, cfg->dynamic_info);
11527                 mono_domain_unlock (cfg->domain);
11528
11529                 code = mono_code_manager_reserve (cfg->dynamic_info->code_mp, cfg->code_size);
11530         } else {
11531                 mono_domain_lock (cfg->domain);
11532                 code = mono_code_manager_reserve (cfg->domain->code_mp, cfg->code_size);
11533                 mono_domain_unlock (cfg->domain);
11534         }
11535
11536         memcpy (code, cfg->native_code, cfg->code_len);
11537         g_free (cfg->native_code);
11538         cfg->native_code = code;
11539         code = cfg->native_code + cfg->code_len;
11540   
11541         /* g_assert (((int)cfg->native_code & (MONO_ARCH_CODE_ALIGNMENT - 1)) == 0); */
11542         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
11543                 switch (patch_info->type) {
11544                 case MONO_PATCH_INFO_ABS: {
11545                         MonoJitICallInfo *info = mono_find_jit_icall_by_addr (patch_info->data.target);
11546                         if (info) {
11547                                 //printf ("TEST %s %p\n", info->name, patch_info->data.target);
11548                                 if ((cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) && 
11549                                         strstr (cfg->method->name, info->name))
11550                                         /*
11551                                          * This is an icall wrapper, and this is a call to the
11552                                          * wrapped function.
11553                                          */
11554                                         ;
11555                                 else {
11556                                         /* for these array methods we currently register the same function pointer
11557                                          * since it's a vararg function. But this means that mono_find_jit_icall_by_addr ()
11558                                          * will return the incorrect one depending on the order they are registered.
11559                                          * See tests/test-arr.cs
11560                                          */
11561                                         if (strstr (info->name, "ves_array_new_va_") == NULL && strstr (info->name, "ves_array_element_address_") == NULL) {
11562                                                 patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
11563                                                 patch_info->data.name = info->name;
11564                                         }
11565                                 }
11566                         }
11567                         else {
11568                                 MonoVTable *vtable = mono_find_class_init_trampoline_by_addr (patch_info->data.target);
11569                                 if (vtable) {
11570                                         patch_info->type = MONO_PATCH_INFO_CLASS_INIT;
11571                                         patch_info->data.klass = vtable->klass;
11572                                 } else {
11573                                         MonoClass *klass = mono_find_delegate_trampoline_by_addr (patch_info->data.target);
11574                                         if (klass) {
11575                                                 patch_info->type = MONO_PATCH_INFO_DELEGATE_TRAMPOLINE;
11576                                                 patch_info->data.klass = klass;
11577                                         }
11578                                 }
11579                         }
11580                         break;
11581                 }
11582                 case MONO_PATCH_INFO_SWITCH: {
11583                         gpointer *table;
11584                         if (cfg->method->dynamic) {
11585                                 table = mono_code_manager_reserve (cfg->dynamic_info->code_mp, sizeof (gpointer) * patch_info->data.table->table_size);
11586                         } else {
11587                                 mono_domain_lock (cfg->domain);
11588                                 table = mono_code_manager_reserve (cfg->domain->code_mp, sizeof (gpointer) * patch_info->data.table->table_size);
11589                                 mono_domain_unlock (cfg->domain);
11590                         }
11591
11592                         if (!cfg->compile_aot)
11593                                 /* In the aot case, the patch already points to the correct location */
11594                                 patch_info->ip.i = patch_info->ip.label->inst_c0;
11595                         for (i = 0; i < patch_info->data.table->table_size; i++) {
11596                                 table [i] = GINT_TO_POINTER (patch_info->data.table->table [i]->native_offset);
11597                         }
11598                         patch_info->data.table->table = (MonoBasicBlock**)table;
11599                         break;
11600                 }
11601                 default:
11602                         /* do nothing */
11603                         break;
11604                 }
11605         }
11606
11607 #ifdef VALGRIND_JIT_REGISTER_MAP
11608 if (valgrind_register){
11609                 char* nm = mono_method_full_name (cfg->method, TRUE);
11610                 VALGRIND_JIT_REGISTER_MAP (nm, cfg->native_code, cfg->native_code + cfg->code_len);
11611                 g_free (nm);
11612         }
11613 #endif
11614  
11615         if (cfg->verbose_level > 0) {
11616                 char* nm = mono_method_full_name (cfg->method, TRUE);
11617                 g_print ("Method %s emitted at %p to %p (code length %d) [%s]\n", 
11618                                  nm, 
11619                                  cfg->native_code, cfg->native_code + cfg->code_len, cfg->code_len, cfg->domain->friendly_name);
11620                 g_free (nm);
11621         }
11622
11623 #ifdef MONO_ARCH_HAVE_SAVE_UNWIND_INFO
11624         mono_arch_save_unwind_info (cfg);
11625 #endif
11626         
11627         mono_arch_patch_code (cfg->method, cfg->domain, cfg->native_code, cfg->patch_info, cfg->run_cctors);
11628
11629         if (cfg->method->dynamic) {
11630                 mono_code_manager_commit (cfg->dynamic_info->code_mp, cfg->native_code, cfg->code_size, cfg->code_len);
11631         } else {
11632                 mono_domain_lock (cfg->domain);
11633                 mono_code_manager_commit (cfg->domain->code_mp, cfg->native_code, cfg->code_size, cfg->code_len);
11634                 mono_domain_unlock (cfg->domain);
11635         }
11636         
11637         mono_arch_flush_icache (cfg->native_code, cfg->code_len);
11638
11639         mono_debug_close_method (cfg);
11640 }
11641
11642
11643
11644 static void
11645 remove_critical_edges (MonoCompile *cfg) {
11646         MonoBasicBlock *bb;
11647         MonoBasicBlock *previous_bb;
11648         
11649         if (cfg->verbose_level > 3) {
11650                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
11651                         MonoInst *last_ins;
11652                         int i;
11653                         printf ("remove_critical_edges %s, BEFORE BB%d (in:", mono_method_full_name (cfg->method, TRUE), bb->block_num);
11654                         for (i = 0; i < bb->in_count; i++) {
11655                                 printf (" %d", bb->in_bb [i]->block_num);
11656                         }
11657                         printf (") (out:");
11658                         for (i = 0; i < bb->out_count; i++) {
11659                                 printf (" %d", bb->out_bb [i]->block_num);
11660                         }
11661                         printf (")");
11662                         last_ins = mono_inst_list_last (&bb->ins_list);
11663                         if (last_ins) {
11664                                 printf (" ");
11665                                 mono_print_tree (last_ins);
11666                         }
11667                         printf ("\n");
11668                 }
11669         }
11670         
11671         for (previous_bb = cfg->bb_entry, bb = previous_bb->next_bb; bb != NULL; previous_bb = previous_bb->next_bb, bb = bb->next_bb) {
11672                 if (bb->in_count > 1) {
11673                         int in_bb_index;
11674                         for (in_bb_index = 0; in_bb_index < bb->in_count; in_bb_index++) {
11675                                 MonoBasicBlock *in_bb = bb->in_bb [in_bb_index];
11676                                 if (in_bb->out_count > 1) {
11677                                         MonoBasicBlock *new_bb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
11678                                         MONO_INST_LIST_INIT (&new_bb->ins_list);
11679                                         new_bb->block_num = cfg->num_bblocks++;
11680 //                                      new_bb->real_offset = bb->real_offset;
11681                                         new_bb->region = bb->region;
11682                                         
11683                                         /* Do not alter the CFG while altering the BB list */
11684                                         if (previous_bb->region == bb->region) {
11685                                                 if (previous_bb != cfg->bb_entry) {
11686                                                         MonoInst *last_ins;
11687                                                         /* If previous_bb "followed through" to bb, */
11688                                                         /* keep it linked with a OP_BR */
11689                                                         last_ins = mono_inst_list_last (&previous_bb->ins_list);
11690                                                         if ((last_ins == NULL) ||
11691                                                                         ((last_ins->opcode != OP_BR) &&
11692                                                                         (!(MONO_IS_COND_BRANCH_OP (last_ins))) &&
11693                                                                         (last_ins->opcode != OP_SWITCH))) {
11694                                                                 int i;
11695                                                                 /* Make sure previous_bb really falls through bb */
11696                                                                 for (i = 0; i < previous_bb->out_count; i++) {
11697                                                                         if (previous_bb->out_bb [i] == bb) {
11698                                                                                 MonoInst *jump;
11699                                                                                 MONO_INST_NEW (cfg, jump, OP_BR);
11700                                                                                 MONO_ADD_INS (previous_bb, jump);
11701                                                                                 jump->cil_code = previous_bb->cil_code;
11702                                                                                 jump->inst_target_bb = bb;
11703                                                                                 break;
11704                                                                         }
11705                                                                 }
11706                                                         }
11707                                                 } else {
11708                                                         /* We cannot add any inst to the entry BB, so we must */
11709                                                         /* put a new BB in the middle to hold the OP_BR */
11710                                                         MonoInst *jump;
11711                                                         MonoBasicBlock *new_bb_after_entry = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
11712                                                         MONO_INST_LIST_INIT (&new_bb_after_entry->ins_list);
11713                                                         new_bb_after_entry->block_num = cfg->num_bblocks++;
11714 //                                                      new_bb_after_entry->real_offset = bb->real_offset;
11715                                                         new_bb_after_entry->region = bb->region;
11716                                                         
11717                                                         MONO_INST_NEW (cfg, jump, OP_BR);
11718                                                         MONO_ADD_INS (new_bb_after_entry, jump);
11719                                                         jump->cil_code = bb->cil_code;
11720                                                         jump->inst_target_bb = bb;
11721                                                         
11722                                                         previous_bb->next_bb = new_bb_after_entry;
11723                                                         previous_bb = new_bb_after_entry;
11724                                                         
11725                                                         if (cfg->verbose_level > 2) {
11726                                                                 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);
11727                                                         }
11728                                                 }
11729                                         }
11730                                         
11731                                         /* Insert new_bb in the BB list */
11732                                         previous_bb->next_bb = new_bb;
11733                                         new_bb->next_bb = bb;
11734                                         previous_bb = new_bb;
11735                                         
11736                                         /* Setup in_bb and out_bb */
11737                                         new_bb->in_bb = mono_mempool_alloc ((cfg)->mempool, sizeof (MonoBasicBlock*));
11738                                         new_bb->in_bb [0] = in_bb;
11739                                         new_bb->in_count = 1;
11740                                         new_bb->out_bb = mono_mempool_alloc ((cfg)->mempool, sizeof (MonoBasicBlock*));
11741                                         new_bb->out_bb [0] = bb;
11742                                         new_bb->out_count = 1;
11743                                         
11744                                         /* Relink in_bb and bb to (from) new_bb */
11745                                         replace_out_block (in_bb, bb, new_bb);
11746                                         replace_out_block_in_code (in_bb, bb, new_bb);
11747                                         replace_in_block (bb, in_bb, new_bb);
11748                                         
11749                                         if (cfg->verbose_level > 2) {
11750                                                 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);
11751                                         }
11752                                 }
11753                         }
11754                 }
11755         }
11756         
11757         if (cfg->verbose_level > 3) {
11758                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
11759                         MonoInst *last_ins;
11760                         int i;
11761                         printf ("remove_critical_edges %s, AFTER BB%d (in:", mono_method_full_name (cfg->method, TRUE), bb->block_num);
11762                         for (i = 0; i < bb->in_count; i++) {
11763                                 printf (" %d", bb->in_bb [i]->block_num);
11764                         }
11765                         printf (") (out:");
11766                         for (i = 0; i < bb->out_count; i++) {
11767                                 printf (" %d", bb->out_bb [i]->block_num);
11768                         }
11769                         printf (")");
11770                         last_ins = mono_inst_list_last (&bb->ins_list);
11771                         if (last_ins) {
11772                                 printf (" ");
11773                                 mono_print_tree (last_ins);
11774                         }
11775                         printf ("\n");
11776                 }
11777         }
11778 }
11779
11780 /*
11781  * mini_method_compile:
11782  * @method: the method to compile
11783  * @opts: the optimization flags to use
11784  * @domain: the domain where the method will be compiled in
11785  * @run_cctors: whether we should run type ctors if possible
11786  * @compile_aot: whether this is an AOT compilation
11787  * @parts: debug flag
11788  *
11789  * Returns: a MonoCompile* pointer. Caller must check the exception_type
11790  * field in the returned struct to see if compilation succeded.
11791  */
11792 MonoCompile*
11793 mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gboolean run_cctors, gboolean compile_aot, int parts)
11794 {
11795         MonoMethodHeader *header;
11796         guint8 *ip;
11797         MonoCompile *cfg;
11798         MonoJitInfo *jinfo;
11799         int dfn = 0, i, code_size_ratio;
11800         gboolean deadce_has_run = FALSE;
11801         gboolean try_generic_shared;
11802         MonoMethod *method_to_compile;
11803         int generic_info_size;
11804
11805         mono_jit_stats.methods_compiled++;
11806         if (mono_profiler_get_events () & MONO_PROFILE_JIT_COMPILATION)
11807                 mono_profiler_method_jit (method);
11808  
11809         if (compile_aot)
11810                 /* We are passed the original generic method definition */
11811                 try_generic_shared = mono_class_generic_sharing_enabled (method->klass) &&
11812                         (opts & MONO_OPT_GSHARED) && (method->generic_container || method->klass->generic_container);
11813         else
11814                 try_generic_shared = mono_class_generic_sharing_enabled (method->klass) &&
11815                         (opts & MONO_OPT_GSHARED) && mono_method_is_generic_sharable_impl (method);
11816
11817         if (opts & MONO_OPT_GSHARED) {
11818                 if (try_generic_shared)
11819                         mono_stats.generics_sharable_methods++;
11820                 else if (mono_method_is_generic_impl (method))
11821                         mono_stats.generics_unsharable_methods++;
11822         }
11823
11824  restart_compile:
11825         if (try_generic_shared) {
11826                 MonoMethod *declaring_method;
11827                 MonoGenericContext *shared_context;
11828
11829                 if (compile_aot) {
11830                         declaring_method = method;
11831                 } else {
11832                         declaring_method = mono_method_get_declaring_generic_method (method);
11833                         g_assert (method->klass->generic_class->container_class == declaring_method->klass);
11834                 }
11835
11836                 if (declaring_method->generic_container)
11837                         shared_context = &declaring_method->generic_container->context;
11838                 else
11839                         shared_context = &declaring_method->klass->generic_container->context;
11840
11841                 method_to_compile = mono_class_inflate_generic_method (declaring_method, shared_context);
11842                 g_assert (method_to_compile);
11843         } else {
11844                 method_to_compile = method;
11845         }
11846
11847         cfg = g_new0 (MonoCompile, 1);
11848         cfg->method = method_to_compile;
11849         cfg->mempool = mono_mempool_new ();
11850         cfg->opt = opts;
11851         cfg->prof_options = mono_profiler_get_events ();
11852         cfg->run_cctors = run_cctors;
11853         cfg->domain = domain;
11854         cfg->verbose_level = mini_verbose;
11855         cfg->compile_aot = compile_aot;
11856         cfg->skip_visibility = method->skip_visibility;
11857         if (try_generic_shared)
11858                 cfg->generic_sharing_context = (MonoGenericSharingContext*)&cfg->generic_sharing_context;
11859         cfg->token_info_hash = g_hash_table_new (NULL, NULL);
11860
11861         /* The debugger has no liveness information, so avoid sharing registers/stack slots */
11862         if (mono_debug_using_mono_debugger ()) {
11863                 cfg->disable_reuse_registers = TRUE;
11864                 cfg->disable_reuse_stack_slots = TRUE;
11865                 /* 
11866                  * This decreases the change the debugger will read registers/stack slots which are
11867                  * not yet initialized.
11868                  */
11869                 cfg->disable_initlocals_opt = TRUE;
11870
11871                 /* Temporarily disable this when running in the debugger until we have support
11872                  * for this in the debugger. */
11873                 cfg->disable_omit_fp = TRUE;
11874
11875                 // cfg->opt |= MONO_OPT_SHARED;
11876                 cfg->opt &= ~MONO_OPT_INLINE;
11877                 cfg->opt &= ~MONO_OPT_COPYPROP;
11878                 cfg->opt &= ~MONO_OPT_CONSPROP;
11879         }
11880
11881         header = mono_method_get_header (method_to_compile);
11882         if (!header) {
11883                 cfg->exception_type = MONO_EXCEPTION_INVALID_PROGRAM;
11884                 cfg->exception_message = g_strdup_printf ("Missing or incorrect header for method %s", cfg->method->name);
11885                 if (cfg->prof_options & MONO_PROFILE_JIT_COMPILATION)
11886                         mono_profiler_method_end_jit (method, NULL, MONO_PROFILE_FAILED);
11887                 return cfg;
11888         }
11889
11890         ip = (guint8 *)header->code;
11891
11892         if (cfg->verbose_level > 2) {
11893                 if (cfg->generic_sharing_context)
11894                         g_print ("converting shared method %s\n", mono_method_full_name (method, TRUE));
11895                 else
11896                         g_print ("converting method %s\n", mono_method_full_name (method, TRUE));
11897         }
11898
11899         /*
11900          * create MonoInst* which represents arguments and local variables
11901          */
11902         mono_compile_create_vars (cfg);
11903
11904         if ((i = mono_method_to_ir (cfg, method_to_compile, NULL, NULL, cfg->locals_start, NULL, NULL, NULL, 0, FALSE)) < 0) {
11905                 if (try_generic_shared && cfg->exception_type == MONO_EXCEPTION_GENERIC_SHARING_FAILED) {
11906                         if (compile_aot)
11907                                 return cfg;
11908                         mono_destroy_compile (cfg);
11909                         try_generic_shared = FALSE;
11910                         goto restart_compile;
11911                 }
11912                 g_assert (cfg->exception_type != MONO_EXCEPTION_GENERIC_SHARING_FAILED);
11913
11914                 if (cfg->prof_options & MONO_PROFILE_JIT_COMPILATION)
11915                         mono_profiler_method_end_jit (method, NULL, MONO_PROFILE_FAILED);
11916                 /* cfg contains the details of the failure, so let the caller cleanup */
11917                 return cfg;
11918         }
11919
11920         mono_jit_stats.basic_blocks += cfg->num_bblocks;
11921         mono_jit_stats.max_basic_blocks = MAX (cfg->num_bblocks, mono_jit_stats.max_basic_blocks);
11922
11923         if ((cfg->num_varinfo > 2000) && !cfg->compile_aot) {
11924                 /* 
11925                  * we disable some optimizations if there are too many variables
11926                  * because JIT time may become too expensive. The actual number needs 
11927                  * to be tweaked and eventually the non-linear algorithms should be fixed.
11928                  */
11929                 cfg->opt &= ~ (MONO_OPT_LINEARS | MONO_OPT_COPYPROP | MONO_OPT_CONSPROP);
11930                 cfg->disable_ssa = TRUE;
11931         }
11932
11933         /*g_print ("numblocks = %d\n", cfg->num_bblocks);*/
11934
11935         if (cfg->opt & MONO_OPT_BRANCH)
11936                 optimize_branches (cfg);
11937
11938         if (cfg->opt & MONO_OPT_SSAPRE) {
11939                 remove_critical_edges (cfg);
11940         }
11941
11942         /* Depth-first ordering on basic blocks */
11943         cfg->bblocks = mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * (cfg->num_bblocks + 1));
11944
11945         df_visit (cfg->bb_entry, &dfn, cfg->bblocks);
11946         if (cfg->num_bblocks != dfn + 1) {
11947                 MonoBasicBlock *bb;
11948
11949                 cfg->num_bblocks = dfn + 1;
11950
11951                 if (!header->clauses) {
11952                         /* remove unreachable code, because the code in them may be 
11953                          * inconsistent  (access to dead variables for example) */
11954                         for (bb = cfg->bb_entry; bb;) {
11955                                 MonoBasicBlock *bbn = bb->next_bb;
11956
11957                                 if (bbn && bbn->region == -1 && !bbn->dfn) {
11958                                         if (cfg->verbose_level > 1)
11959                                                 g_print ("found unreachable code in BB%d\n", bbn->block_num);
11960                                         bb->next_bb = bbn->next_bb;
11961                                         nullify_basic_block (bbn);                      
11962                                 } else {
11963                                         bb = bb->next_bb;
11964                                 }
11965                         }
11966                 }
11967         }
11968
11969         if (cfg->opt & MONO_OPT_LOOP) {
11970                 mono_compile_dominator_info (cfg, MONO_COMP_DOM | MONO_COMP_IDOM);
11971                 mono_compute_natural_loops (cfg);
11972         }
11973
11974         /* after method_to_ir */
11975         if (parts == 1)
11976                 return cfg;
11977
11978 //#define DEBUGSSA "logic_run"
11979 #define DEBUGSSA_CLASS "Tests"
11980 #ifdef DEBUGSSA
11981
11982         if (!header->num_clauses && !cfg->disable_ssa) {
11983                 mono_local_cprop (cfg);
11984 #ifndef DISABLE_SSA
11985                 mono_ssa_compute (cfg);
11986 #endif
11987         }
11988 #else 
11989
11990         /* fixme: add all optimizations which requires SSA */
11991         if (cfg->opt & (MONO_OPT_SSA | MONO_OPT_ABCREM | MONO_OPT_SSAPRE)) {
11992                 if (!(cfg->comp_done & MONO_COMP_SSA) && !header->num_clauses && !cfg->disable_ssa) {
11993                         mono_local_cprop (cfg);
11994 #ifndef DISABLE_SSA
11995                         mono_ssa_compute (cfg);
11996 #endif
11997
11998                         if (cfg->verbose_level >= 2) {
11999                                 print_dfn (cfg);
12000                         }
12001                 }
12002         }
12003 #endif
12004
12005         /* after SSA translation */
12006         if (parts == 2)
12007                 return cfg;
12008
12009         if ((cfg->opt & MONO_OPT_CONSPROP) || (cfg->opt & MONO_OPT_COPYPROP)) {
12010                 if (cfg->comp_done & MONO_COMP_SSA) {
12011 #ifndef DISABLE_SSA
12012                         mono_ssa_cprop (cfg);
12013 #endif
12014                 } else {
12015                         mono_local_cprop (cfg);
12016                 }
12017         }
12018
12019 #ifndef DISABLE_SSA
12020         if (cfg->comp_done & MONO_COMP_SSA) {                   
12021                 //mono_ssa_deadce (cfg);
12022
12023                 //mono_ssa_strength_reduction (cfg);
12024
12025                 if (cfg->opt & MONO_OPT_SSAPRE) {
12026                         mono_perform_ssapre (cfg);
12027                         //mono_local_cprop (cfg);
12028                 }
12029                 
12030                 if (cfg->opt & MONO_OPT_DEADCE) {
12031                         mono_ssa_deadce (cfg);
12032                         deadce_has_run = TRUE;
12033                 }
12034                 
12035                 if ((cfg->flags & MONO_CFG_HAS_LDELEMA) && (cfg->opt & MONO_OPT_ABCREM))
12036                         mono_perform_abc_removal (cfg);
12037                 
12038                 mono_ssa_remove (cfg);
12039
12040                 if (cfg->opt & MONO_OPT_BRANCH)
12041                         optimize_branches (cfg);
12042         }
12043 #endif
12044
12045         /* after SSA removal */
12046         if (parts == 3)
12047                 return cfg;
12048
12049         if (cfg->verbose_level > 4) {
12050                 printf ("BEFORE DECOMPSE START\n");
12051                 mono_print_code (cfg);
12052                 printf ("BEFORE DECOMPSE END\n");
12053         }
12054         
12055         decompose_pass (cfg);
12056
12057         if (cfg->got_var) {
12058                 GList *regs;
12059
12060                 g_assert (cfg->got_var_allocated);
12061
12062                 /* 
12063                  * Allways allocate the GOT var to a register, because keeping it
12064                  * in memory will increase the number of live temporaries in some
12065                  * code created by inssel.brg, leading to the well known spills+
12066                  * branches problem. Testcase: mcs crash in 
12067                  * System.MonoCustomAttrs:GetCustomAttributes.
12068                  */
12069                 regs = mono_arch_get_global_int_regs (cfg);
12070                 g_assert (regs);
12071                 cfg->got_var->opcode = OP_REGVAR;
12072                 cfg->got_var->dreg = GPOINTER_TO_INT (regs->data);
12073                 cfg->used_int_regs |= 1LL << cfg->got_var->dreg;
12074                 
12075                 g_list_free (regs);
12076         }
12077
12078         /* todo: remove code when we have verified that the liveness for try/catch blocks
12079          * works perfectly 
12080          */
12081         /* 
12082          * Currently, this can't be commented out since exception blocks are not
12083          * processed during liveness analysis.
12084          */
12085         mono_liveness_handle_exception_clauses (cfg);
12086
12087         if (cfg->opt & MONO_OPT_LINEARS) {
12088                 GList *vars, *regs;
12089                 
12090                 /* For now, compute aliasing info only if needed for deadce... */
12091                 if ((cfg->opt & MONO_OPT_DEADCE) && (! deadce_has_run) && (header->num_clauses == 0)) {
12092                         cfg->aliasing_info = mono_build_aliasing_information (cfg);
12093                 }
12094
12095                 /* fixme: maybe we can avoid to compute livenesss here if already computed ? */
12096                 cfg->comp_done &= ~MONO_COMP_LIVENESS;
12097                 if (!(cfg->comp_done & MONO_COMP_LIVENESS))
12098                         mono_analyze_liveness (cfg);
12099
12100                 if (cfg->aliasing_info != NULL) {
12101                         mono_aliasing_deadce (cfg->aliasing_info);
12102                         deadce_has_run = TRUE;
12103                 }
12104                 
12105                 if ((vars = mono_arch_get_allocatable_int_vars (cfg))) {
12106                         regs = mono_arch_get_global_int_regs (cfg);
12107                         if (cfg->got_var)
12108                                 regs = g_list_delete_link (regs, regs);
12109                         mono_linear_scan (cfg, vars, regs, &cfg->used_int_regs);
12110                 }
12111                 
12112                 if (cfg->aliasing_info != NULL) {
12113                         mono_destroy_aliasing_information (cfg->aliasing_info);
12114                         cfg->aliasing_info = NULL;
12115                 }
12116         }
12117
12118         //mono_print_code (cfg);
12119
12120     //print_dfn (cfg);
12121         
12122         /* variables are allocated after decompose, since decompose could create temps */
12123         mono_arch_allocate_vars (cfg);
12124
12125         if (cfg->opt & MONO_OPT_CFOLD)
12126                 mono_constant_fold (cfg);
12127
12128         mini_select_instructions (cfg);
12129
12130         mono_codegen (cfg);
12131         if (cfg->verbose_level >= 2) {
12132                 char *id =  mono_method_full_name (cfg->method, FALSE);
12133                 mono_disassemble_code (cfg, cfg->native_code, cfg->code_len, id + 3);
12134                 g_free (id);
12135         }
12136
12137         if (cfg->generic_sharing_context)
12138                 generic_info_size = sizeof (MonoGenericJitInfo);
12139         else
12140                 generic_info_size = 0;
12141
12142         if (cfg->method->dynamic) {
12143                 jinfo = g_malloc0 (sizeof (MonoJitInfo) + (header->num_clauses * sizeof (MonoJitExceptionInfo)) +
12144                                 generic_info_size);
12145         } else {
12146                 /* we access cfg->domain->mp */
12147                 mono_domain_lock (cfg->domain);
12148                 jinfo = mono_mempool_alloc0 (cfg->domain->mp, sizeof (MonoJitInfo) +
12149                                 (header->num_clauses * sizeof (MonoJitExceptionInfo)) +
12150                                 generic_info_size);
12151                 mono_domain_unlock (cfg->domain);
12152         }
12153
12154         jinfo->method = method;
12155         jinfo->code_start = cfg->native_code;
12156         jinfo->code_size = cfg->code_len;
12157         jinfo->used_regs = cfg->used_int_regs;
12158         jinfo->domain_neutral = (cfg->opt & MONO_OPT_SHARED) != 0;
12159         jinfo->cas_inited = FALSE; /* initialization delayed at the first stalk walk using this method */
12160         jinfo->num_clauses = header->num_clauses;
12161
12162         /*
12163          * Static methods only get a generic JIT info if they use the
12164          * rgctx variable (which they are forced to if they have any
12165          * open catch clauses).
12166          */
12167         if (cfg->generic_sharing_context &&
12168                         (cfg->rgctx_var || !(method_to_compile->flags & METHOD_ATTRIBUTE_STATIC))) {
12169                 MonoInst *inst;
12170                 MonoGenericJitInfo *gi;
12171
12172                 jinfo->has_generic_jit_info = 1;
12173
12174                 gi = mono_jit_info_get_generic_jit_info (jinfo);
12175                 g_assert (gi);
12176
12177                 gi->generic_sharing_context = cfg->generic_sharing_context;
12178
12179                 if (method_to_compile->flags & METHOD_ATTRIBUTE_STATIC) {
12180                         inst = cfg->rgctx_var;
12181                         g_assert (inst->opcode == OP_REGOFFSET);
12182                 } else {
12183                         inst = cfg->varinfo [0];
12184                 }
12185
12186                 if (inst->opcode == OP_REGVAR) {
12187                         gi->this_in_reg = 1;
12188                         gi->this_reg = inst->dreg;
12189
12190                         //g_print ("this in reg %d\n", inst->dreg);
12191                 } else {
12192                         g_assert (inst->opcode == OP_REGOFFSET);
12193 #ifdef __i386__
12194                         g_assert (inst->inst_basereg == X86_EBP);
12195 #elif defined(__x86_64__)
12196                         g_assert (inst->inst_basereg == X86_EBP || inst->inst_basereg == X86_ESP);
12197 #endif
12198                         g_assert (inst->inst_offset >= G_MININT32 && inst->inst_offset <= G_MAXINT32);
12199
12200                         gi->this_in_reg = 0;
12201                         gi->this_reg = inst->inst_basereg;
12202                         gi->this_offset = inst->inst_offset;
12203
12204                         //g_print ("this at offset %d\n", inst->inst_offset);
12205                 }
12206         }
12207
12208         if (header->num_clauses) {
12209                 int i;
12210
12211                 for (i = 0; i < header->num_clauses; i++) {
12212                         MonoExceptionClause *ec = &header->clauses [i];
12213                         MonoJitExceptionInfo *ei = &jinfo->clauses [i];
12214                         MonoBasicBlock *tblock;
12215                         MonoInst *exvar;
12216
12217                         ei->flags = ec->flags;
12218
12219                         exvar = mono_find_exvar_for_offset (cfg, ec->handler_offset);
12220                         ei->exvar_offset = exvar ? exvar->inst_offset : 0;
12221
12222                         if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
12223                                 tblock = cfg->cil_offset_to_bb [ec->data.filter_offset];
12224                                 g_assert (tblock);
12225                                 ei->data.filter = cfg->native_code + tblock->native_offset;
12226                         } else {
12227                                 ei->data.catch_class = ec->data.catch_class;
12228                         }
12229
12230                         tblock = cfg->cil_offset_to_bb [ec->try_offset];
12231                         g_assert (tblock);
12232                         ei->try_start = cfg->native_code + tblock->native_offset;
12233                         g_assert (tblock->native_offset);
12234                         tblock = cfg->cil_offset_to_bb [ec->try_offset + ec->try_len];
12235                         g_assert (tblock);
12236                         ei->try_end = cfg->native_code + tblock->native_offset;
12237                         g_assert (tblock->native_offset);
12238                         tblock = cfg->cil_offset_to_bb [ec->handler_offset];
12239                         g_assert (tblock);
12240                         ei->handler_start = cfg->native_code + tblock->native_offset;
12241                 }
12242         }
12243
12244         cfg->jit_info = jinfo;
12245 #if defined(__arm__)
12246         mono_arch_fixup_jinfo (cfg);
12247 #endif
12248
12249         mono_domain_lock (cfg->domain);
12250         mono_jit_info_table_add (cfg->domain, jinfo);
12251
12252         if (cfg->method->dynamic)
12253                 mono_dynamic_code_hash_lookup (cfg->domain, cfg->method)->ji = jinfo;
12254         mono_domain_unlock (cfg->domain);
12255
12256         /* collect statistics */
12257         mono_jit_stats.allocated_code_size += cfg->code_len;
12258         code_size_ratio = cfg->code_len;
12259         if (code_size_ratio > mono_jit_stats.biggest_method_size) {
12260                         mono_jit_stats.biggest_method_size = code_size_ratio;
12261                         mono_jit_stats.biggest_method = method;
12262         }
12263         code_size_ratio = (code_size_ratio * 100) / mono_method_get_header (method)->code_size;
12264         if (code_size_ratio > mono_jit_stats.max_code_size_ratio) {
12265                 mono_jit_stats.max_code_size_ratio = code_size_ratio;
12266                 mono_jit_stats.max_ratio_method = method;
12267         }
12268         mono_jit_stats.native_code_size += cfg->code_len;
12269
12270         if (cfg->prof_options & MONO_PROFILE_JIT_COMPILATION)
12271                 mono_profiler_method_end_jit (method, jinfo, MONO_PROFILE_OK);
12272
12273         return cfg;
12274 }
12275
12276 static MonoJitInfo*
12277 lookup_generic_method (MonoDomain *domain, MonoMethod *method)
12278 {
12279         MonoMethod *open_method;
12280
12281         if (!mono_method_is_generic_sharable_impl (method))
12282                 return NULL;
12283
12284         open_method = mono_method_get_declaring_generic_method (method);
12285
12286         return mono_domain_lookup_shared_generic (domain, open_method);
12287 }
12288
12289 static MonoJitInfo*
12290 lookup_method (MonoDomain *domain, MonoMethod *method)
12291 {
12292         MonoJitInfo *ji = mono_internal_hash_table_lookup (&domain->jit_code_hash, method);
12293
12294         if (ji != NULL)
12295                 return ji;
12296
12297         return lookup_generic_method (domain, method);
12298 }
12299
12300 static gpointer
12301 mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, int opt)
12302 {
12303         MonoCompile *cfg;
12304         gpointer code = NULL;
12305         MonoJitInfo *info;
12306
12307 #ifdef MONO_USE_AOT_COMPILER
12308         if ((opt & MONO_OPT_AOT) && !(mono_profiler_get_events () & MONO_PROFILE_JIT_COMPILATION)) {
12309                 MonoDomain *domain = mono_domain_get ();
12310
12311                 mono_class_init (method->klass);
12312
12313                 mono_domain_lock (domain);
12314                 if ((code = mono_aot_get_method (domain, method))) {
12315                         mono_domain_unlock (domain);
12316                         mono_runtime_class_init (mono_class_vtable (domain, method->klass));
12317                         return code;
12318                 }
12319
12320                 mono_domain_unlock (domain);
12321         }
12322 #endif
12323
12324         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
12325             (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
12326                 MonoMethod *nm;
12327                 MonoMethodPInvoke* piinfo = (MonoMethodPInvoke *) method;
12328
12329                 if (method->iflags & METHOD_IMPL_ATTRIBUTE_NATIVE && !MONO_CLASS_IS_IMPORT(method->klass))
12330                         g_error ("Method '%s' in assembly '%s' contains native code and mono can't run it. The assembly was probably created by Managed C++.\n", mono_method_full_name (method, TRUE), method->klass->image->name);
12331
12332                 if (!piinfo->addr) {
12333                         if (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL)
12334                                 piinfo->addr = mono_lookup_internal_call (method);
12335                         else
12336                                 if (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
12337                                         mono_lookup_pinvoke_call (method, NULL, NULL);
12338                 }
12339                         nm = mono_marshal_get_native_wrapper (method, check_for_pending_exc);
12340                         return mono_get_addr_from_ftnptr (mono_compile_method (nm));
12341
12342                         //if (mono_debug_format != MONO_DEBUG_FORMAT_NONE) 
12343                         //mono_debug_add_wrapper (method, nm);
12344         } else if ((method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME)) {
12345                 const char *name = method->name;
12346                 MonoMethod *nm;
12347
12348                 if (method->klass->parent == mono_defaults.multicastdelegate_class) {
12349                         if (*name == '.' && (strcmp (name, ".ctor") == 0)) {
12350                                 MonoJitICallInfo *mi = mono_find_jit_icall_by_name ("mono_delegate_ctor");
12351                                 g_assert (mi);
12352                                 return mono_get_addr_from_ftnptr ((gpointer)mono_icall_get_wrapper (mi));
12353                         } else if (*name == 'I' && (strcmp (name, "Invoke") == 0)) {
12354 #ifdef MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE
12355                                 return mono_create_delegate_trampoline (method->klass);
12356 #else
12357                                 nm = mono_marshal_get_delegate_invoke (method, NULL);
12358                                 return mono_get_addr_from_ftnptr (mono_compile_method (nm));
12359 #endif
12360                         } else if (*name == 'B' && (strcmp (name, "BeginInvoke") == 0)) {
12361                                 nm = mono_marshal_get_delegate_begin_invoke (method);
12362                                 return mono_get_addr_from_ftnptr (mono_compile_method (nm));
12363                         } else if (*name == 'E' && (strcmp (name, "EndInvoke") == 0)) {
12364                                 nm = mono_marshal_get_delegate_end_invoke (method);
12365                                 return mono_get_addr_from_ftnptr (mono_compile_method (nm));
12366                         }
12367                 }
12368                 return NULL;
12369         }
12370
12371         cfg = mini_method_compile (method, opt, target_domain, TRUE, FALSE, 0);
12372
12373         switch (cfg->exception_type) {
12374         case MONO_EXCEPTION_NONE: break;
12375         case MONO_EXCEPTION_TYPE_LOAD:
12376         case MONO_EXCEPTION_MISSING_FIELD:
12377         case MONO_EXCEPTION_MISSING_METHOD:
12378         case MONO_EXCEPTION_FILE_NOT_FOUND: {
12379                 /* Throw a type load exception if needed */
12380                 MonoLoaderError *error = mono_loader_get_last_error ();
12381                 MonoException *ex;
12382
12383                 if (error) {
12384                         ex = mono_loader_error_prepare_exception (error);
12385                 } else {
12386                         if (cfg->exception_ptr) {
12387                                 ex = mono_class_get_exception_for_failure (cfg->exception_ptr);
12388                         } else {
12389                                 if (cfg->exception_type == MONO_EXCEPTION_MISSING_FIELD)
12390                                         ex = mono_exception_from_name_msg (mono_defaults.corlib, "System", "MissingFieldException", cfg->exception_message);
12391                                 else if (cfg->exception_type == MONO_EXCEPTION_MISSING_METHOD)
12392                                         ex = mono_exception_from_name_msg (mono_defaults.corlib, "System", "MissingMethodException", cfg->exception_message);
12393                                 else if (cfg->exception_type == MONO_EXCEPTION_TYPE_LOAD)
12394                                         ex = mono_exception_from_name_msg (mono_defaults.corlib, "System", "TypeLoadException", cfg->exception_message);
12395                                 else if (cfg->exception_type == MONO_EXCEPTION_FILE_NOT_FOUND)
12396                                         ex = mono_exception_from_name_msg (mono_defaults.corlib, "System", "FileNotFoundException", cfg->exception_message);
12397                                 else
12398                                         g_assert_not_reached ();
12399                         }
12400                 }
12401                 mono_destroy_compile (cfg);
12402                 mono_raise_exception (ex);
12403                 break;
12404         }
12405         case MONO_EXCEPTION_INVALID_PROGRAM: {
12406                 MonoException *ex = mono_exception_from_name_msg (mono_defaults.corlib, "System", "InvalidProgramException", cfg->exception_message);
12407                 mono_destroy_compile (cfg);
12408                 mono_raise_exception (ex);
12409                 break;
12410         }
12411         case MONO_EXCEPTION_UNVERIFIABLE_IL: {
12412                 MonoException *ex = mono_exception_from_name_msg (mono_defaults.corlib, "System.Security", "VerificationException", cfg->exception_message);
12413                 mono_destroy_compile (cfg);
12414                 mono_raise_exception (ex);
12415                 break;
12416         }
12417         case MONO_EXCEPTION_METHOD_ACCESS: {
12418                 MonoException *ex = mono_exception_from_name_msg (mono_defaults.corlib, "System", "MethodAccessException", cfg->exception_message);
12419                 mono_destroy_compile (cfg);
12420                 mono_raise_exception (ex);
12421                 break;
12422         }
12423         case MONO_EXCEPTION_FIELD_ACCESS: {
12424                 MonoException *ex = mono_exception_from_name_msg (mono_defaults.corlib, "System", "FieldAccessException", cfg->exception_message);
12425                 mono_destroy_compile (cfg);
12426                 mono_raise_exception (ex);
12427                 break;
12428         }
12429         /* this can only be set if the security manager is active */
12430         case MONO_EXCEPTION_SECURITY_LINKDEMAND: {
12431                 MonoSecurityManager* secman = mono_security_manager_get_methods ();
12432                 MonoObject *exc = NULL;
12433                 gpointer args [2];
12434
12435                 args [0] = &cfg->exception_data;
12436                 args [1] = &method;
12437                 mono_runtime_invoke (secman->linkdemandsecurityexception, NULL, args, &exc);
12438
12439                 mono_destroy_compile (cfg);
12440                 cfg = NULL;
12441
12442                 mono_raise_exception ((MonoException*)exc);
12443         }
12444         default:
12445                 g_assert_not_reached ();
12446         }
12447
12448         mono_domain_lock (target_domain);
12449
12450         /* Check if some other thread already did the job. In this case, we can
12451        discard the code this thread generated. */
12452
12453         if ((info = lookup_method (target_domain, method))) {
12454                 /* We can't use a domain specific method in another domain */
12455                 if ((target_domain == mono_domain_get ()) || info->domain_neutral) {
12456                         code = info->code_start;
12457 //                      printf("Discarding code for method %s\n", method->name);
12458                 }
12459         }
12460         
12461         if (code == NULL) {
12462                 mono_internal_hash_table_insert (&target_domain->jit_code_hash, method, cfg->jit_info);
12463                 code = cfg->native_code;
12464
12465                 if (cfg->generic_sharing_context && mono_method_is_generic_sharable_impl (method)) {
12466                         /* g_print ("inserting method %s.%s.%s\n", method->klass->name_space, method->klass->name, method->name); */
12467                         mono_domain_register_shared_generic (target_domain, 
12468                                 mono_method_get_declaring_generic_method (method), cfg->jit_info);
12469                         mono_stats.generics_shared_methods++;
12470                 }
12471         }
12472
12473         mono_destroy_compile (cfg);
12474
12475         if (target_domain->jump_target_hash) {
12476                 MonoJumpInfo patch_info;
12477                 GSList *list, *tmp;
12478                 list = g_hash_table_lookup (target_domain->jump_target_hash, method);
12479                 if (list) {
12480                         patch_info.next = NULL;
12481                         patch_info.ip.i = 0;
12482                         patch_info.type = MONO_PATCH_INFO_METHOD_JUMP;
12483                         patch_info.data.method = method;
12484                         g_hash_table_remove (target_domain->jump_target_hash, method);
12485                 }
12486                 for (tmp = list; tmp; tmp = tmp->next)
12487                         mono_arch_patch_code (NULL, target_domain, tmp->data, &patch_info, TRUE);
12488                 g_slist_free (list);
12489         }
12490
12491         mono_domain_unlock (target_domain);
12492
12493         mono_runtime_class_init (mono_class_vtable (target_domain, method->klass));
12494         return code;
12495 }
12496
12497 static gpointer
12498 mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt)
12499 {
12500         MonoDomain *target_domain, *domain = mono_domain_get ();
12501         MonoJitInfo *info;
12502         gpointer p;
12503         MonoJitICallInfo *callinfo = NULL;
12504
12505         /*
12506          * ICALL wrappers are handled specially, since there is only one copy of them
12507          * shared by all appdomains.
12508          */
12509         if ((method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) && (strstr (method->name, "__icall_wrapper_") == method->name)) {
12510                 const char *icall_name;
12511
12512                 icall_name = method->name + strlen ("__icall_wrapper_");
12513                 g_assert (icall_name);
12514                 callinfo = mono_find_jit_icall_by_name (icall_name);
12515                 g_assert (callinfo);
12516
12517                 /* Must be domain neutral since there is only one copy */
12518                 opt |= MONO_OPT_SHARED;
12519         }
12520
12521         if (opt & MONO_OPT_SHARED)
12522                 target_domain = mono_get_root_domain ();
12523         else 
12524                 target_domain = domain;
12525
12526         mono_domain_lock (target_domain);
12527
12528         if ((info = lookup_method (target_domain, method))) {
12529                 /* We can't use a domain specific method in another domain */
12530                 if (! ((domain != target_domain) && !info->domain_neutral)) {
12531                         mono_domain_unlock (target_domain);
12532                         mono_jit_stats.methods_lookups++;
12533                         mono_runtime_class_init (mono_class_vtable (domain, method->klass));
12534                         return mono_create_ftnptr (target_domain, info->code_start);
12535                 }
12536         }
12537
12538         mono_domain_unlock (target_domain);
12539         p = mono_create_ftnptr (target_domain, mono_jit_compile_method_inner (method, target_domain, opt));
12540
12541         if (callinfo) {
12542                 mono_jit_lock ();
12543                 if (!callinfo->wrapper) {
12544                         callinfo->wrapper = p;
12545                         mono_register_jit_icall_wrapper (callinfo, p);
12546                         mono_debug_add_icall_wrapper (method, callinfo);
12547                 }
12548                 mono_jit_unlock ();
12549         }
12550
12551         return p;
12552 }
12553
12554 static gpointer
12555 mono_jit_compile_method (MonoMethod *method)
12556 {
12557         return mono_jit_compile_method_with_opt (method, default_opt);
12558 }
12559
12560 static void
12561 invalidated_delegate_trampoline (char *desc)
12562 {
12563         g_error ("Unmanaged code called delegate of type %s which was already garbage collected.\n"
12564                  "See http://www.go-mono.com/delegate.html for an explanation and ways to fix this.",
12565                  desc);
12566 }
12567
12568 /*
12569  * mono_jit_free_method:
12570  *
12571  *  Free all memory allocated by the JIT for METHOD.
12572  */
12573 static void
12574 mono_jit_free_method (MonoDomain *domain, MonoMethod *method)
12575 {
12576         MonoJitDynamicMethodInfo *ji;
12577         gboolean destroy = TRUE;
12578
12579         g_assert (method->dynamic);
12580
12581         mono_domain_lock (domain);
12582         ji = mono_dynamic_code_hash_lookup (domain, method);
12583         mono_domain_unlock (domain);
12584
12585         if (!ji)
12586                 return;
12587         mono_domain_lock (domain);
12588         g_hash_table_remove (domain->dynamic_code_hash, method);
12589         mono_internal_hash_table_remove (&domain->jit_code_hash, method);
12590         g_hash_table_remove (domain->jump_trampoline_hash, method);
12591         mono_domain_unlock (domain);
12592
12593 #ifdef MONO_ARCH_HAVE_INVALIDATE_METHOD
12594         if (debug_options.keep_delegates && method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
12595                 /*
12596                  * Instead of freeing the code, change it to call an error routine
12597                  * so people can fix their code.
12598                  */
12599                 char *type = mono_type_full_name (&method->klass->byval_arg);
12600                 char *type_and_method = g_strdup_printf ("%s.%s", type, method->name);
12601
12602                 g_free (type);
12603                 mono_arch_invalidate_method (ji->ji, invalidated_delegate_trampoline, type_and_method);
12604                 destroy = FALSE;
12605         }
12606 #endif
12607
12608         /* 
12609          * This needs to be done before freeing code_mp, since the code address is the
12610          * key in the table, so if we free the code_mp first, another thread can grab the
12611          * same code address and replace our entry in the table.
12612          */
12613         mono_jit_info_table_remove (domain, ji->ji);
12614
12615         if (destroy)
12616                 mono_code_manager_destroy (ji->code_mp);
12617         mono_thread_hazardous_free_or_queue (ji->ji, g_free);
12618         g_free (ji);
12619 }
12620
12621 gpointer
12622 mono_jit_find_compiled_method (MonoDomain *domain, MonoMethod *method)
12623 {
12624         MonoDomain *target_domain;
12625         MonoJitInfo *info;
12626
12627         if (default_opt & MONO_OPT_SHARED)
12628                 target_domain = mono_get_root_domain ();
12629         else 
12630                 target_domain = domain;
12631
12632         mono_domain_lock (target_domain);
12633
12634         if ((info = lookup_method (target_domain, method))) {
12635                 /* We can't use a domain specific method in another domain */
12636                 if (! ((domain != target_domain) && !info->domain_neutral)) {
12637                         mono_domain_unlock (target_domain);
12638                         mono_jit_stats.methods_lookups++;
12639                         return info->code_start;
12640                 }
12641         }
12642
12643         mono_domain_unlock (target_domain);
12644
12645         return NULL;
12646 }
12647
12648 /**
12649  * mono_jit_runtime_invoke:
12650  * @method: the method to invoke
12651  * @obj: this pointer
12652  * @params: array of parameter values.
12653  * @exc: used to catch exceptions objects
12654  */
12655 static MonoObject*
12656 mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
12657 {
12658         MonoMethod *to_compile;
12659         MonoMethod *invoke;
12660         MonoObject *(*runtime_invoke) (MonoObject *this, void **params, MonoObject **exc, void* compiled_method);
12661         void* compiled_method;
12662
12663         if (obj == NULL && !(method->flags & METHOD_ATTRIBUTE_STATIC) && !method->string_ctor && (method->wrapper_type == 0)) {
12664                 g_warning ("Ignoring invocation of an instance method on a NULL instance.\n");
12665                 return NULL;
12666         }
12667
12668         if ((method->flags & METHOD_ATTRIBUTE_STATIC) &&
12669                         mono_class_generic_sharing_enabled (method->klass) &&
12670                         mono_method_is_generic_sharable_impl (method)) {
12671                 to_compile = mono_marshal_get_static_rgctx_invoke (method);
12672         } else {
12673                 to_compile = method;
12674         }
12675
12676         invoke = mono_marshal_get_runtime_invoke (method);
12677         runtime_invoke = mono_jit_compile_method (invoke);
12678         
12679         /* We need this here becuase mono_marshal_get_runtime_invoke can be place 
12680          * the helper method in System.Object and not the target class
12681          */
12682         mono_runtime_class_init (mono_class_vtable (mono_domain_get (), method->klass));
12683
12684         if (method->klass->rank && (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) &&
12685                 (method->iflags & METHOD_IMPL_ATTRIBUTE_NATIVE)) {
12686                 /* 
12687                  * Array Get/Set/Address methods. The JIT implements them using inline code 
12688                  * inside the runtime invoke wrappers, so no need to compile them.
12689                  */
12690                 compiled_method = NULL;
12691         } else {
12692                 compiled_method = mono_jit_compile_method (to_compile);
12693         }
12694         return runtime_invoke (obj, params, exc, compiled_method);
12695 }
12696
12697 #ifdef MONO_GET_CONTEXT
12698 #define GET_CONTEXT MONO_GET_CONTEXT
12699 #endif
12700
12701 #ifndef GET_CONTEXT
12702 #ifdef PLATFORM_WIN32
12703 #define GET_CONTEXT \
12704         struct sigcontext *ctx = (struct sigcontext*)_dummy;
12705 #else
12706 #ifdef MONO_ARCH_USE_SIGACTION
12707 #define GET_CONTEXT \
12708     void *ctx = context;
12709 #elif defined(__sparc__)
12710 #define GET_CONTEXT \
12711     void *ctx = sigctx;
12712 #else
12713 #define GET_CONTEXT \
12714         void **_p = (void **)&_dummy; \
12715         struct sigcontext *ctx = (struct sigcontext *)++_p;
12716 #endif
12717 #endif
12718 #endif
12719
12720 #ifdef MONO_ARCH_USE_SIGACTION
12721 #define SIG_HANDLER_SIGNATURE(ftn) ftn (int _dummy, siginfo_t *info, void *context)
12722 #elif defined(__sparc__)
12723 #define SIG_HANDLER_SIGNATURE(ftn) ftn (int _dummy, void *sigctx)
12724 #else
12725 #define SIG_HANDLER_SIGNATURE(ftn) ftn (int _dummy)
12726 #endif
12727
12728 static void
12729 SIG_HANDLER_SIGNATURE (sigfpe_signal_handler)
12730 {
12731         MonoException *exc = NULL;
12732 #ifndef MONO_ARCH_USE_SIGACTION
12733         void *info = NULL;
12734 #endif
12735         GET_CONTEXT;
12736
12737 #if defined(MONO_ARCH_HAVE_IS_INT_OVERFLOW)
12738         if (mono_arch_is_int_overflow (ctx, info))
12739                 exc = mono_get_exception_arithmetic ();
12740         else
12741                 exc = mono_get_exception_divide_by_zero ();
12742 #else
12743         exc = mono_get_exception_divide_by_zero ();
12744 #endif
12745         
12746         mono_arch_handle_exception (ctx, exc, FALSE);
12747 }
12748
12749 static void
12750 SIG_HANDLER_SIGNATURE (sigill_signal_handler)
12751 {
12752         MonoException *exc;
12753         GET_CONTEXT;
12754
12755         exc = mono_get_exception_execution_engine ("SIGILL");
12756         
12757         mono_arch_handle_exception (ctx, exc, FALSE);
12758 }
12759
12760 static void
12761 SIG_HANDLER_SIGNATURE (sigsegv_signal_handler)
12762 {
12763 #ifndef MONO_ARCH_SIGSEGV_ON_ALTSTACK
12764         MonoException *exc = NULL;
12765 #endif
12766         MonoJitInfo *ji;
12767
12768 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
12769         MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
12770 #endif
12771         GET_CONTEXT;
12772
12773 #ifdef MONO_ARCH_USE_SIGACTION
12774         if (debug_options.collect_pagefault_stats) {
12775                 if (mono_raw_buffer_is_pagefault (info->si_addr)) {
12776                         mono_raw_buffer_handle_pagefault (info->si_addr);
12777                         return;
12778                 }
12779                 if (mono_aot_is_pagefault (info->si_addr)) {
12780                         mono_aot_handle_pagefault (info->si_addr);
12781                         return;
12782                 }
12783         }
12784 #endif
12785
12786         ji = mono_jit_info_table_find (mono_domain_get (), mono_arch_ip_from_context (ctx));
12787
12788 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
12789         /* we got a stack overflow in the soft-guard pages
12790          * There are two cases:
12791          * 1) managed code caused the overflow: we unprotect the soft-guard page
12792          * and let the arch-specific code trigger the exception handling mechanism
12793          * in the thread stack. The soft-guard pages will be protected again as the stack is unwound.
12794          * 2) unmanaged code caused the overflow: we unprotect the soft-guard page
12795          * and hope we can continue with those enabled, at least until the hard-guard page
12796          * is hit. The alternative to continuing here is to just print a message and abort.
12797          * We may add in the future the code to protect the pages again in the codepath
12798          * when we return from unmanaged to managed code.
12799          */
12800         if (jit_tls->stack_ovf_guard_size && (guint8*)info->si_addr >= (guint8*)jit_tls->stack_ovf_guard_base &&
12801                         (guint8*)info->si_addr < (guint8*)jit_tls->stack_ovf_guard_base + jit_tls->stack_ovf_guard_size) {
12802                 mono_mprotect (jit_tls->stack_ovf_guard_base, jit_tls->stack_ovf_guard_size, MONO_MMAP_READ|MONO_MMAP_WRITE|MONO_MMAP_EXEC);
12803                 if (ji) {
12804                         mono_arch_handle_altstack_exception (ctx, info->si_addr, TRUE);
12805                 } else {
12806                         /* We print a message: after this even managed stack overflows
12807                          * may crash the runtime
12808                          */
12809                         fprintf (stderr, "Stack overflow in unmanaged: IP: %p, fault addr: %p\n", mono_arch_ip_from_context (ctx), (gpointer)info->si_addr);
12810                 }
12811                 return;
12812         }
12813         /* The hard-guard page has been hit: there is not much we can do anymore
12814          * Print a hopefully clear message and abort.
12815          */
12816         if (jit_tls->stack_size && 
12817                         ABS ((guint8*)info->si_addr - ((guint8*)jit_tls->end_of_stack - jit_tls->stack_size)) < 32768) {
12818                 const char *method;
12819                 /* we don't do much now, but we can warn the user with a useful message */
12820                 fprintf (stderr, "Stack overflow: IP: %p, fault addr: %p\n", mono_arch_ip_from_context (ctx), (gpointer)info->si_addr);
12821                 if (ji && ji->method)
12822                         method = mono_method_full_name (ji->method, TRUE);
12823                 else
12824                         method = "Unmanaged";
12825                 fprintf (stderr, "At %s\n", method);
12826                 abort ();
12827         } else {
12828                 mono_arch_handle_altstack_exception (ctx, info->si_addr, FALSE);
12829         }
12830 #else
12831
12832         if (!ji) {
12833                 mono_handle_native_sigsegv (SIGSEGV, ctx);
12834         }
12835                         
12836         mono_arch_handle_exception (ctx, exc, FALSE);
12837 #endif
12838 }
12839
12840 #ifndef PLATFORM_WIN32
12841
12842 static void
12843 SIG_HANDLER_SIGNATURE (sigabrt_signal_handler)
12844 {
12845         MonoJitInfo *ji;
12846         GET_CONTEXT;
12847
12848         ji = mono_jit_info_table_find (mono_domain_get (), mono_arch_ip_from_context(ctx));
12849         if (!ji) {
12850                 mono_handle_native_sigsegv (SIGABRT, ctx);
12851         }
12852 }
12853
12854 static void
12855 SIG_HANDLER_SIGNATURE (sigusr1_signal_handler)
12856 {
12857         gboolean running_managed;
12858         MonoException *exc;
12859         MonoThread *thread = mono_thread_current ();
12860         void *ji;
12861         
12862         GET_CONTEXT;
12863
12864         if (thread->thread_dump_requested) {
12865                 thread->thread_dump_requested = FALSE;
12866
12867                 mono_print_thread_dump (ctx);
12868         }
12869
12870         /*
12871          * FIXME:
12872          * This is an async signal, so the code below must not call anything which
12873          * is not async safe. That includes the pthread locking functions. If we
12874          * know that we interrupted managed code, then locking is safe.
12875          */
12876         ji = mono_jit_info_table_find (mono_domain_get (), mono_arch_ip_from_context(ctx));
12877         running_managed = ji != NULL;
12878         
12879         exc = mono_thread_request_interruption (running_managed); 
12880         if (!exc) return;
12881
12882         mono_arch_handle_exception (ctx, exc, FALSE);
12883 }
12884
12885 static void
12886 SIG_HANDLER_SIGNATURE (sigprof_signal_handler)
12887 {
12888         GET_CONTEXT;
12889
12890         mono_profiler_stat_hit (mono_arch_ip_from_context (ctx), ctx);
12891 }
12892
12893 static void
12894 SIG_HANDLER_SIGNATURE (sigquit_signal_handler)
12895 {
12896         GET_CONTEXT;
12897
12898         printf ("Full thread dump:\n");
12899
12900         mono_threads_request_thread_dump ();
12901
12902         /*
12903          * print_thread_dump () skips the current thread, since sending a signal
12904          * to it would invoke the signal handler below the sigquit signal handler,
12905          * and signal handlers don't create an lmf, so the stack walk could not
12906          * be performed.
12907          */
12908         mono_print_thread_dump (ctx);
12909 }
12910
12911 static void
12912 SIG_HANDLER_SIGNATURE (sigusr2_signal_handler)
12913 {
12914         gboolean enabled = mono_trace_is_enabled ();
12915
12916         mono_trace_enable (!enabled);
12917 }
12918
12919 #endif
12920
12921 static void
12922 SIG_HANDLER_SIGNATURE (sigint_signal_handler)
12923 {
12924         MonoException *exc;
12925         GET_CONTEXT;
12926
12927         exc = mono_get_exception_execution_engine ("Interrupted (SIGINT).");
12928         
12929         mono_arch_handle_exception (ctx, exc, FALSE);
12930 }
12931
12932 #ifdef PLATFORM_MACOSX
12933
12934 /*
12935  * This code disables the CrashReporter of MacOS X by installing
12936  * a dummy Mach exception handler.
12937  */
12938
12939 /*
12940  * http://darwinsource.opendarwin.org/10.4.3/xnu-792.6.22/osfmk/man/exc_server.html
12941  */
12942 extern
12943 boolean_t
12944 exc_server (mach_msg_header_t *request_msg,
12945             mach_msg_header_t *reply_msg);
12946
12947 /*
12948  * The exception message
12949  */
12950 typedef struct {
12951         mach_msg_base_t msg;  /* common mach message header */
12952         char payload [1024];  /* opaque */
12953 } mach_exception_msg_t;
12954
12955 /* The exception port */
12956 static mach_port_t mach_exception_port = VM_MAP_NULL;
12957
12958 /*
12959  * Implicitly called by exc_server. Must be public.
12960  *
12961  * http://darwinsource.opendarwin.org/10.4.3/xnu-792.6.22/osfmk/man/catch_exception_raise.html
12962  */
12963 kern_return_t
12964 catch_exception_raise (
12965         mach_port_t exception_port,
12966         mach_port_t thread,
12967         mach_port_t task,
12968         exception_type_t exception,
12969         exception_data_t code,
12970         mach_msg_type_number_t code_count)
12971 {
12972         /* consume the exception */
12973         return KERN_FAILURE;
12974 }
12975
12976 /*
12977  * Exception thread handler.
12978  */
12979 static
12980 void *
12981 mach_exception_thread (void *arg)
12982 {
12983         for (;;) {
12984                 mach_exception_msg_t request;
12985                 mach_exception_msg_t reply;
12986                 mach_msg_return_t result;
12987
12988                 /* receive from "mach_exception_port" */
12989                 result = mach_msg (&request.msg.header,
12990                                    MACH_RCV_MSG | MACH_RCV_LARGE,
12991                                    0,
12992                                    sizeof (request),
12993                                    mach_exception_port,
12994                                    MACH_MSG_TIMEOUT_NONE,
12995                                    MACH_PORT_NULL);
12996
12997                 g_assert (result == MACH_MSG_SUCCESS);
12998
12999                 /* dispatch to catch_exception_raise () */
13000                 exc_server (&request.msg.header, &reply.msg.header);
13001
13002                 /* send back to sender */
13003                 result = mach_msg (&reply.msg.header,
13004                                    MACH_SEND_MSG,
13005                                    reply.msg.header.msgh_size,
13006                                    0,
13007                                    MACH_PORT_NULL,
13008                                    MACH_MSG_TIMEOUT_NONE,
13009                                    MACH_PORT_NULL);
13010
13011                 g_assert (result == MACH_MSG_SUCCESS);
13012         }
13013         return NULL;
13014 }
13015
13016 static void
13017 macosx_register_exception_handler ()
13018 {
13019         mach_port_t task;
13020         pthread_attr_t attr;
13021         pthread_t thread;
13022
13023         if (mach_exception_port != VM_MAP_NULL)
13024                 return;
13025
13026         task = mach_task_self ();
13027
13028         /* create the "mach_exception_port" with send & receive rights */
13029         g_assert (mach_port_allocate (task, MACH_PORT_RIGHT_RECEIVE,
13030                                       &mach_exception_port) == KERN_SUCCESS);
13031         g_assert (mach_port_insert_right (task, mach_exception_port, mach_exception_port,
13032                                           MACH_MSG_TYPE_MAKE_SEND) == KERN_SUCCESS);
13033
13034         /* create the exception handler thread */
13035         g_assert (!pthread_attr_init (&attr));
13036         g_assert (!pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED));
13037         g_assert (!pthread_create (&thread, &attr, mach_exception_thread, NULL));
13038         pthread_attr_destroy (&attr);
13039
13040         /*
13041          * register "mach_exception_port" as a receiver for the
13042          * EXC_BAD_ACCESS exception
13043          *
13044          * http://darwinsource.opendarwin.org/10.4.3/xnu-792.6.22/osfmk/man/task_set_exception_ports.html
13045          */
13046         g_assert (task_set_exception_ports (task, EXC_MASK_BAD_ACCESS,
13047                                             mach_exception_port,
13048                                             EXCEPTION_DEFAULT,
13049                                             MACHINE_THREAD_STATE) == KERN_SUCCESS);
13050 }
13051 #endif
13052
13053 #ifndef PLATFORM_WIN32
13054 static void
13055 add_signal_handler (int signo, gpointer handler)
13056 {
13057         struct sigaction sa;
13058
13059 #ifdef MONO_ARCH_USE_SIGACTION
13060         sa.sa_sigaction = handler;
13061         sigemptyset (&sa.sa_mask);
13062         sa.sa_flags = SA_SIGINFO;
13063 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
13064         if (signo == SIGSEGV)
13065                 sa.sa_flags |= SA_ONSTACK;
13066 #endif
13067 #else
13068         sa.sa_handler = handler;
13069         sigemptyset (&sa.sa_mask);
13070         sa.sa_flags = 0;
13071 #endif
13072         g_assert (sigaction (signo, &sa, NULL) != -1);
13073 }
13074
13075 static void
13076 remove_signal_handler (int signo)
13077 {
13078         struct sigaction sa;
13079
13080         sa.sa_handler = SIG_DFL;
13081         sigemptyset (&sa.sa_mask);
13082         sa.sa_flags = 0;
13083
13084         g_assert (sigaction (signo, &sa, NULL) != -1);
13085 }
13086 #endif
13087
13088 static void
13089 mono_runtime_install_handlers (void)
13090 {
13091 #ifdef PLATFORM_WIN32
13092         win32_seh_init();
13093         win32_seh_set_handler(SIGFPE, sigfpe_signal_handler);
13094         win32_seh_set_handler(SIGILL, sigill_signal_handler);
13095         win32_seh_set_handler(SIGSEGV, sigsegv_signal_handler);
13096         if (debug_options.handle_sigint)
13097                 win32_seh_set_handler(SIGINT, sigint_signal_handler);
13098
13099 #else /* !PLATFORM_WIN32 */
13100
13101
13102 #ifdef PLATFORM_MACOSX
13103         macosx_register_exception_handler ();
13104 #endif
13105
13106         if (debug_options.handle_sigint)
13107                 add_signal_handler (SIGINT, sigint_signal_handler);
13108
13109         add_signal_handler (SIGFPE, sigfpe_signal_handler);
13110         add_signal_handler (SIGQUIT, sigquit_signal_handler);
13111         add_signal_handler (SIGILL, sigill_signal_handler);
13112         add_signal_handler (SIGBUS, sigsegv_signal_handler);
13113         if (mono_jit_trace_calls != NULL)
13114                 add_signal_handler (SIGUSR2, sigusr2_signal_handler);
13115
13116         add_signal_handler (mono_thread_get_abort_signal (), sigusr1_signal_handler);
13117         signal (SIGPIPE, SIG_IGN);
13118
13119         add_signal_handler (SIGABRT, sigabrt_signal_handler);
13120
13121         /* catch SIGSEGV */
13122         add_signal_handler (SIGSEGV, sigsegv_signal_handler);
13123 #endif /* PLATFORM_WIN32 */
13124 }
13125
13126 static void
13127 mono_runtime_cleanup_handlers (void)
13128 {
13129 #ifdef PLATFORM_WIN32
13130         win32_seh_cleanup();
13131 #else
13132         if (debug_options.handle_sigint)
13133                 remove_signal_handler (SIGINT);
13134
13135         remove_signal_handler (SIGFPE);
13136         remove_signal_handler (SIGQUIT);
13137         remove_signal_handler (SIGILL);
13138         remove_signal_handler (SIGBUS);
13139         if (mono_jit_trace_calls != NULL)
13140                 remove_signal_handler (SIGUSR2);
13141
13142         remove_signal_handler (mono_thread_get_abort_signal ());
13143
13144         remove_signal_handler (SIGABRT);
13145
13146         remove_signal_handler (SIGSEGV);
13147 #endif /* PLATFORM_WIN32 */
13148 }
13149
13150
13151 #ifdef HAVE_LINUX_RTC_H
13152 #include <linux/rtc.h>
13153 #include <sys/ioctl.h>
13154 #include <fcntl.h>
13155 static int rtc_fd = -1;
13156
13157 static int
13158 enable_rtc_timer (gboolean enable)
13159 {
13160         int flags;
13161         flags = fcntl (rtc_fd, F_GETFL);
13162         if (flags < 0) {
13163                 perror ("getflags");
13164                 return 0;
13165         }
13166         if (enable)
13167                 flags |= FASYNC;
13168         else
13169                 flags &= ~FASYNC;
13170         if (fcntl (rtc_fd, F_SETFL, flags) == -1) {
13171                 perror ("setflags");
13172                 return 0;
13173         }
13174         return 1;
13175 }
13176 #endif
13177
13178 #ifdef PLATFORM_WIN32
13179 static HANDLE win32_main_thread;
13180 static MMRESULT win32_timer;
13181
13182 static void CALLBACK
13183 win32_time_proc (UINT uID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2)
13184 {
13185         CONTEXT context;
13186
13187         context.ContextFlags = CONTEXT_CONTROL;
13188         if (GetThreadContext (win32_main_thread, &context)) {
13189 #ifdef _WIN64
13190                 mono_profiler_stat_hit ((guchar *) context.Rip, &context);
13191 #else
13192                 mono_profiler_stat_hit ((guchar *) context.Eip, &context);
13193 #endif
13194         }
13195 }
13196 #endif
13197
13198 static void
13199 setup_stat_profiler (void)
13200 {
13201 #ifdef ITIMER_PROF
13202         struct itimerval itval;
13203         static int inited = 0;
13204 #ifdef HAVE_LINUX_RTC_H
13205         const char *rtc_freq;
13206         if (!inited && (rtc_freq = g_getenv ("MONO_RTC"))) {
13207                 int freq = 0;
13208                 inited = 1;
13209                 if (*rtc_freq)
13210                         freq = atoi (rtc_freq);
13211                 if (!freq)
13212                         freq = 1024;
13213                 rtc_fd = open ("/dev/rtc", O_RDONLY);
13214                 if (rtc_fd == -1) {
13215                         perror ("open /dev/rtc");
13216                         return;
13217                 }
13218                 add_signal_handler (SIGPROF, sigprof_signal_handler);
13219                 if (ioctl (rtc_fd, RTC_IRQP_SET, freq) == -1) {
13220                         perror ("set rtc freq");
13221                         return;
13222                 }
13223                 if (ioctl (rtc_fd, RTC_PIE_ON, 0) == -1) {
13224                         perror ("start rtc");
13225                         return;
13226                 }
13227                 if (fcntl (rtc_fd, F_SETSIG, SIGPROF) == -1) {
13228                         perror ("setsig");
13229                         return;
13230                 }
13231                 if (fcntl (rtc_fd, F_SETOWN, getpid ()) == -1) {
13232                         perror ("setown");
13233                         return;
13234                 }
13235                 enable_rtc_timer (TRUE);
13236                 return;
13237         }
13238         if (rtc_fd >= 0)
13239                 return;
13240 #endif
13241
13242         itval.it_interval.tv_usec = 999;
13243         itval.it_interval.tv_sec = 0;
13244         itval.it_value = itval.it_interval;
13245         setitimer (ITIMER_PROF, &itval, NULL);
13246         if (inited)
13247                 return;
13248         inited = 1;
13249         add_signal_handler (SIGPROF, sigprof_signal_handler);
13250 #elif defined (PLATFORM_WIN32)
13251         static int inited = 0;
13252         TIMECAPS timecaps;
13253
13254         if (inited)
13255                 return;
13256
13257         inited = 1;
13258         if (timeGetDevCaps (&timecaps, sizeof (timecaps)) != TIMERR_NOERROR)
13259                 return;
13260
13261         if ((win32_main_thread = OpenThread (READ_CONTROL | THREAD_GET_CONTEXT, FALSE, GetCurrentThreadId ())) == NULL)
13262                 return;
13263
13264         if (timeBeginPeriod (1) != TIMERR_NOERROR)
13265                 return;
13266
13267         if ((win32_timer = timeSetEvent (1, 0, win32_time_proc, 0, TIME_PERIODIC)) == 0) {
13268                 timeEndPeriod (1);
13269                 return;
13270         }
13271 #endif
13272 }
13273
13274 /* mono_jit_create_remoting_trampoline:
13275  * @method: pointer to the method info
13276  *
13277  * Creates a trampoline which calls the remoting functions. This
13278  * is used in the vtable of transparent proxies.
13279  * 
13280  * Returns: a pointer to the newly created code 
13281  */
13282 static gpointer
13283 mono_jit_create_remoting_trampoline (MonoMethod *method, MonoRemotingTarget target)
13284 {
13285         MonoMethod *nm;
13286         guint8 *addr = NULL;
13287
13288         if ((method->flags & METHOD_ATTRIBUTE_ABSTRACT) || 
13289             (mono_method_signature (method)->hasthis && (method->klass->marshalbyref || method->klass == mono_defaults.object_class))) {
13290                 nm = mono_marshal_get_remoting_invoke_for_target (method, target);
13291                 addr = mono_compile_method (nm);
13292         } else {
13293                 addr = mono_compile_method (method);
13294         }
13295         return mono_get_addr_from_ftnptr (addr);
13296 }
13297
13298 #ifdef MONO_ARCH_HAVE_IMT
13299 static gpointer
13300 mini_get_imt_trampoline (void)
13301 {
13302         static gpointer tramp = NULL;
13303         if (!tramp)
13304                 tramp =  mono_arch_create_specific_trampoline (MONO_FAKE_IMT_METHOD, MONO_TRAMPOLINE_GENERIC, mono_get_root_domain (), NULL);
13305         return tramp;
13306 }
13307 #endif
13308
13309 #ifdef MONO_ARCH_COMMON_VTABLE_TRAMPOLINE
13310 gpointer
13311 mini_get_vtable_trampoline (void)
13312 {
13313         static gpointer tramp = NULL;
13314         if (!tramp)
13315                 tramp =  mono_arch_create_specific_trampoline (MONO_FAKE_VTABLE_METHOD, MONO_TRAMPOLINE_GENERIC, mono_get_root_domain (), NULL);
13316         return tramp;
13317 }
13318 #endif
13319
13320 static void
13321 mini_parse_debug_options (void)
13322 {
13323         char *options = getenv ("MONO_DEBUG");
13324         gchar **args, **ptr;
13325         
13326         if (!options)
13327                 return;
13328
13329         args = g_strsplit (options, ",", -1);
13330
13331         for (ptr = args; ptr && *ptr; ptr++) {
13332                 const char *arg = *ptr;
13333
13334                 if (!strcmp (arg, "handle-sigint"))
13335                         debug_options.handle_sigint = TRUE;
13336                 else if (!strcmp (arg, "keep-delegates"))
13337                         debug_options.keep_delegates = TRUE;
13338                 else if (!strcmp (arg, "collect-pagefault-stats"))
13339                         debug_options.collect_pagefault_stats = TRUE;
13340                 else if (!strcmp (arg, "break-on-unverified"))
13341                         debug_options.break_on_unverified = TRUE;
13342                 else {
13343                         fprintf (stderr, "Invalid option for the MONO_DEBUG env variable: %s\n", arg);
13344                         fprintf (stderr, "Available options: 'handle-sigint', 'keep-delegates', 'collect-pagefault-stats', 'break-on-unverified'\n");
13345                         exit (1);
13346                 }
13347         }
13348 }
13349
13350 MonoDebugOptions *
13351 mini_get_debug_options (void)
13352 {
13353         return &debug_options;
13354 }
13355
13356 MonoDomain *
13357 mini_init (const char *filename, const char *runtime_version)
13358 {
13359         MonoDomain *domain;
13360
13361 #ifdef __linux__
13362         if (access ("/proc/self/maps", F_OK) != 0) {
13363                 g_print ("Mono requires /proc to be mounted.\n");
13364                 exit (1);
13365         }
13366 #endif
13367
13368         /* Happens when using the embedding interface */
13369         if (!default_opt_set)
13370                 default_opt = mono_parse_default_optimizations (NULL);
13371
13372         InitializeCriticalSection (&jit_mutex);
13373
13374         if (!global_codeman)
13375                 global_codeman = mono_code_manager_new ();
13376         jit_icall_name_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
13377
13378         mono_arch_cpu_init ();
13379
13380         mono_arch_init ();
13381
13382         mono_trampolines_init ();
13383
13384         mono_exceptions_init ();
13385
13386         if (!g_thread_supported ())
13387                 g_thread_init (NULL);
13388
13389         if (getenv ("MONO_DEBUG") != NULL)
13390                 mini_parse_debug_options ();
13391
13392         mono_gc_base_init ();
13393
13394         mono_jit_tls_id = TlsAlloc ();
13395         setup_jit_tls_data ((gpointer)-1, mono_thread_abort);
13396
13397         mono_burg_init ();
13398
13399         if (default_opt & MONO_OPT_AOT)
13400                 mono_aot_init ();
13401
13402         mono_runtime_install_handlers ();
13403         mono_threads_install_cleanup (mini_thread_cleanup);
13404
13405 #ifdef MONO_ARCH_HAVE_NOTIFY_PENDING_EXC
13406         // This is experimental code so provide an env var to switch it off
13407         if (getenv ("MONO_DISABLE_PENDING_EXCEPTIONS")) {
13408                 printf ("MONO_DISABLE_PENDING_EXCEPTIONS env var set.\n");
13409         } else {
13410                 check_for_pending_exc = FALSE;
13411                 mono_threads_install_notify_pending_exc (mono_arch_notify_pending_exc);
13412         }
13413 #endif
13414
13415 #define JIT_TRAMPOLINES_WORK
13416 #ifdef JIT_TRAMPOLINES_WORK
13417         mono_install_compile_method (mono_jit_compile_method);
13418         mono_install_free_method (mono_jit_free_method);
13419         mono_install_trampoline (mono_create_jit_trampoline);
13420         mono_install_jump_trampoline (mono_create_jump_trampoline);
13421         mono_install_remoting_trampoline (mono_jit_create_remoting_trampoline);
13422         mono_install_delegate_trampoline (mono_create_delegate_trampoline);
13423 #endif
13424 #define JIT_INVOKE_WORKS
13425 #ifdef JIT_INVOKE_WORKS
13426         mono_install_runtime_invoke (mono_jit_runtime_invoke);
13427         mono_install_handler (mono_arch_get_throw_exception ());
13428 #endif
13429         mono_install_stack_walk (mono_jit_walk_stack);
13430         mono_install_init_vtable (mono_aot_init_vtable);
13431         mono_install_get_cached_class_info (mono_aot_get_cached_class_info);
13432         mono_install_get_class_from_name (mono_aot_get_class_from_name);
13433         mono_install_jit_info_find_in_aot (mono_aot_find_jit_info);
13434
13435         if (debug_options.collect_pagefault_stats) {
13436                 mono_raw_buffer_set_make_unreadable (TRUE);
13437                 mono_aot_set_make_unreadable (TRUE);
13438         }
13439
13440         if (runtime_version)
13441                 domain = mono_init_version (filename, runtime_version);
13442         else
13443                 domain = mono_init_from_assembly (filename, filename);
13444 #ifdef MONO_ARCH_HAVE_IMT
13445         mono_install_imt_thunk_builder (mono_arch_build_imt_thunk);
13446         mono_install_imt_trampoline (mini_get_imt_trampoline ());
13447 #if MONO_ARCH_COMMON_VTABLE_TRAMPOLINE
13448         mono_install_vtable_trampoline (mini_get_vtable_trampoline ());
13449 #endif
13450 #endif
13451         mono_icall_init ();
13452
13453         mono_add_internal_call ("System.Diagnostics.StackFrame::get_frame_info", 
13454                                 ves_icall_get_frame_info);
13455         mono_add_internal_call ("System.Diagnostics.StackTrace::get_trace", 
13456                                 ves_icall_get_trace);
13457         mono_add_internal_call ("System.Exception::get_trace", 
13458                                 ves_icall_System_Exception_get_trace);
13459         mono_add_internal_call ("System.Security.SecurityFrame::_GetSecurityFrame",
13460                                 ves_icall_System_Security_SecurityFrame_GetSecurityFrame);
13461         mono_add_internal_call ("System.Security.SecurityFrame::_GetSecurityStack",
13462                                 ves_icall_System_Security_SecurityFrame_GetSecurityStack);
13463         mono_add_internal_call ("Mono.Runtime::mono_runtime_install_handlers", 
13464                                 mono_runtime_install_handlers);
13465
13466
13467         create_helper_signature ();
13468
13469 #define JIT_CALLS_WORK
13470 #ifdef JIT_CALLS_WORK
13471         /* Needs to be called here since register_jit_icall depends on it */
13472         mono_marshal_init ();
13473
13474         mono_arch_register_lowlevel_calls ();
13475         register_icall (mono_profiler_method_enter, "mono_profiler_method_enter", NULL, TRUE);
13476         register_icall (mono_profiler_method_leave, "mono_profiler_method_leave", NULL, TRUE);
13477         register_icall (mono_trace_enter_method, "mono_trace_enter_method", NULL, TRUE);
13478         register_icall (mono_trace_leave_method, "mono_trace_leave_method", NULL, TRUE);
13479         register_icall (mono_get_lmf_addr, "mono_get_lmf_addr", "ptr", TRUE);
13480         register_icall (mono_jit_thread_attach, "mono_jit_thread_attach", "void", TRUE);
13481         register_icall (mono_domain_get, "mono_domain_get", "ptr", TRUE);
13482
13483         register_icall (mono_arch_get_throw_exception (), "mono_arch_throw_exception", "void object", TRUE);
13484         register_icall (mono_arch_get_rethrow_exception (), "mono_arch_rethrow_exception", "void object", TRUE);
13485         register_icall (mono_arch_get_throw_exception_by_name (), "mono_arch_throw_exception_by_name", "void ptr", TRUE); 
13486 #if MONO_ARCH_HAVE_THROW_CORLIB_EXCEPTION
13487         register_icall (mono_arch_get_throw_corlib_exception (), "mono_arch_throw_corlib_exception", 
13488                                  "void ptr", TRUE);
13489 #endif
13490         register_icall (mono_thread_get_undeniable_exception, "mono_thread_get_undeniable_exception", "object", FALSE);
13491         register_icall (mono_thread_interruption_checkpoint, "mono_thread_interruption_checkpoint", "void", FALSE);
13492         register_icall (mono_thread_force_interruption_checkpoint, "mono_thread_force_interruption_checkpoint", "void", FALSE);
13493         register_icall (mono_load_remote_field_new, "mono_load_remote_field_new", "object object ptr ptr", FALSE);
13494         register_icall (mono_store_remote_field_new, "mono_store_remote_field_new", "void object ptr ptr object", FALSE);
13495
13496         /* 
13497          * NOTE, NOTE, NOTE, NOTE:
13498          * when adding emulation for some opcodes, remember to also add a dummy
13499          * rule to the burg files, because we need the arity information to be correct.
13500          */
13501 #ifndef MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS
13502         mono_register_opcode_emulation (OP_LMUL, "__emul_lmul", "long long long", mono_llmult, TRUE);
13503         mono_register_opcode_emulation (OP_LDIV, "__emul_ldiv", "long long long", mono_lldiv, FALSE);
13504         mono_register_opcode_emulation (OP_LDIV_UN, "__emul_ldiv_un", "long long long", mono_lldiv_un, FALSE);
13505         mono_register_opcode_emulation (OP_LREM, "__emul_lrem", "long long long", mono_llrem, FALSE);
13506         mono_register_opcode_emulation (OP_LREM_UN, "__emul_lrem_un", "long long long", mono_llrem_un, FALSE);
13507         mono_register_opcode_emulation (OP_LMUL_OVF_UN, "__emul_lmul_ovf_un", "long long long", mono_llmult_ovf_un, FALSE);
13508         mono_register_opcode_emulation (OP_LMUL_OVF, "__emul_lmul_ovf", "long long long", mono_llmult_ovf, FALSE);
13509 #endif
13510
13511 #ifndef MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
13512         mono_register_opcode_emulation (OP_LSHL, "__emul_lshl", "long long int32", mono_lshl, TRUE);
13513         mono_register_opcode_emulation (OP_LSHR, "__emul_lshr", "long long int32", mono_lshr, TRUE);
13514         mono_register_opcode_emulation (OP_LSHR_UN, "__emul_lshr_un", "long long int32", mono_lshr_un, TRUE);
13515 #endif
13516
13517 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
13518         mono_register_opcode_emulation (CEE_DIV, "__emul_idiv", "int32 int32 int32", mono_idiv, FALSE);
13519         mono_register_opcode_emulation (CEE_DIV_UN, "__emul_idiv_un", "int32 int32 int32", mono_idiv_un, FALSE);
13520         mono_register_opcode_emulation (CEE_REM, "__emul_irem", "int32 int32 int32", mono_irem, FALSE);
13521         mono_register_opcode_emulation (CEE_REM_UN, "__emul_irem_un", "int32 int32 int32", mono_irem_un, FALSE);
13522 #endif
13523
13524 #ifdef MONO_ARCH_EMULATE_MUL_DIV
13525         mono_register_opcode_emulation (CEE_MUL_OVF, "__emul_imul_ovf", "int32 int32 int32", mono_imul_ovf, FALSE);
13526         mono_register_opcode_emulation (CEE_MUL_OVF_UN, "__emul_imul_ovf_un", "int32 int32 int32", mono_imul_ovf_un, FALSE);
13527         mono_register_opcode_emulation (CEE_MUL, "__emul_imul", "int32 int32 int32", mono_imul, TRUE);
13528 #endif
13529 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_SOFT_FLOAT)
13530         mono_register_opcode_emulation (OP_FDIV, "__emul_fdiv", "double double double", mono_fdiv, FALSE);
13531 #endif
13532
13533         mono_register_opcode_emulation (OP_FCONV_TO_U8, "__emul_fconv_to_u8", "ulong double", mono_fconv_u8, FALSE);
13534         mono_register_opcode_emulation (OP_FCONV_TO_U4, "__emul_fconv_to_u4", "uint32 double", mono_fconv_u4, FALSE);
13535         mono_register_opcode_emulation (OP_FCONV_TO_OVF_I8, "__emul_fconv_to_ovf_i8", "long double", mono_fconv_ovf_i8, FALSE);
13536         mono_register_opcode_emulation (OP_FCONV_TO_OVF_U8, "__emul_fconv_to_ovf_u8", "ulong double", mono_fconv_ovf_u8, FALSE);
13537
13538 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
13539         mono_register_opcode_emulation (OP_FCONV_TO_I8, "__emul_fconv_to_i8", "long double", mono_fconv_i8, FALSE);
13540 #endif
13541 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
13542         mono_register_opcode_emulation (CEE_CONV_R_UN, "__emul_conv_r_un", "double int32", mono_conv_to_r8_un, FALSE);
13543 #endif
13544 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
13545         mono_register_opcode_emulation (OP_LCONV_TO_R8, "__emul_lconv_to_r8", "double long", mono_lconv_to_r8, FALSE);
13546 #endif
13547 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
13548         mono_register_opcode_emulation (OP_LCONV_TO_R4, "__emul_lconv_to_r4", "float long", mono_lconv_to_r4, FALSE);
13549 #endif
13550 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
13551         mono_register_opcode_emulation (OP_LCONV_TO_R_UN, "__emul_lconv_to_r8_un", "double long", mono_lconv_to_r8_un, FALSE);
13552 #endif
13553 #ifdef MONO_ARCH_EMULATE_FREM
13554         mono_register_opcode_emulation (OP_FREM, "__emul_frem", "double double double", fmod, FALSE);
13555 #endif
13556
13557 #ifdef MONO_ARCH_SOFT_FLOAT
13558         mono_register_opcode_emulation (OP_FSUB, "__emul_fsub", "double double double", mono_fsub, FALSE);
13559         mono_register_opcode_emulation (OP_FADD, "__emul_fadd", "double double double", mono_fadd, FALSE);
13560         mono_register_opcode_emulation (OP_FMUL, "__emul_fmul", "double double double", mono_fmul, FALSE);
13561         mono_register_opcode_emulation (OP_FNEG, "__emul_fneg", "double double", mono_fneg, FALSE);
13562         mono_register_opcode_emulation (CEE_CONV_R8, "__emul_conv_r8", "double int32", mono_conv_to_r8, FALSE);
13563         mono_register_opcode_emulation (CEE_CONV_R4, "__emul_conv_r4", "double int32", mono_conv_to_r4, FALSE);
13564         mono_register_opcode_emulation (OP_FCONV_TO_R4, "__emul_fconv_to_r4", "double double", mono_fconv_r4, FALSE);
13565         mono_register_opcode_emulation (OP_FCONV_TO_I1, "__emul_fconv_to_i1", "int8 double", mono_fconv_i1, FALSE);
13566         mono_register_opcode_emulation (OP_FCONV_TO_I2, "__emul_fconv_to_i2", "int16 double", mono_fconv_i2, FALSE);
13567         mono_register_opcode_emulation (OP_FCONV_TO_I4, "__emul_fconv_to_i4", "int32 double", mono_fconv_i4, FALSE);
13568         mono_register_opcode_emulation (OP_FCONV_TO_U1, "__emul_fconv_to_u1", "uint8 double", mono_fconv_u1, FALSE);
13569         mono_register_opcode_emulation (OP_FCONV_TO_U2, "__emul_fconv_to_u2", "uint16 double", mono_fconv_u2, FALSE);
13570
13571         mono_register_opcode_emulation (OP_FBEQ, "__emul_fcmp_eq", "uint32 double double", mono_fcmp_eq, FALSE);
13572         mono_register_opcode_emulation (OP_FBLT, "__emul_fcmp_lt", "uint32 double double", mono_fcmp_lt, FALSE);
13573         mono_register_opcode_emulation (OP_FBGT, "__emul_fcmp_gt", "uint32 double double", mono_fcmp_gt, FALSE);
13574         mono_register_opcode_emulation (OP_FBLE, "__emul_fcmp_le", "uint32 double double", mono_fcmp_le, FALSE);
13575         mono_register_opcode_emulation (OP_FBGE, "__emul_fcmp_ge", "uint32 double double", mono_fcmp_ge, FALSE);
13576         mono_register_opcode_emulation (OP_FBNE_UN, "__emul_fcmp_ne_un", "uint32 double double", mono_fcmp_ne_un, FALSE);
13577         mono_register_opcode_emulation (OP_FBLT_UN, "__emul_fcmp_lt_un", "uint32 double double", mono_fcmp_lt_un, FALSE);
13578         mono_register_opcode_emulation (OP_FBGT_UN, "__emul_fcmp_gt_un", "uint32 double double", mono_fcmp_gt_un, FALSE);
13579         mono_register_opcode_emulation (OP_FBLE_UN, "__emul_fcmp_le_un", "uint32 double double", mono_fcmp_le_un, FALSE);
13580         mono_register_opcode_emulation (OP_FBGE_UN, "__emul_fcmp_ge_un", "uint32 double double", mono_fcmp_ge_un, FALSE);
13581
13582         mono_register_opcode_emulation (OP_FCEQ, "__emul_fcmp_ceq", "uint32 double double", mono_fceq, FALSE);
13583         mono_register_opcode_emulation (OP_FCGT, "__emul_fcmp_cgt", "uint32 double double", mono_fcgt, FALSE);
13584         mono_register_opcode_emulation (OP_FCGT_UN, "__emul_fcmp_cgt_un", "uint32 double double", mono_fcgt_un, FALSE);
13585         mono_register_opcode_emulation (OP_FCLT, "__emul_fcmp_clt", "uint32 double double", mono_fclt, FALSE);
13586         mono_register_opcode_emulation (OP_FCLT_UN, "__emul_fcmp_clt_un", "uint32 double double", mono_fclt_un, FALSE);
13587
13588         register_icall (mono_fload_r4, "mono_fload_r4", "double ptr", FALSE);
13589         register_icall (mono_fstore_r4, "mono_fstore_r4", "void double ptr", FALSE);
13590         register_icall (mono_fload_r4_arg, "mono_fload_r4_arg", "uint32 double", FALSE);
13591 #endif
13592
13593 #if SIZEOF_VOID_P == 4
13594         mono_register_opcode_emulation (OP_FCONV_TO_U, "__emul_fconv_to_u", "uint32 double", mono_fconv_u4, TRUE);
13595 #endif
13596
13597         /* other jit icalls */
13598         register_icall (mono_delegate_ctor, "mono_delegate_ctor", "void object object ptr", FALSE);
13599         register_icall (mono_class_static_field_address , "mono_class_static_field_address", 
13600                                  "ptr ptr ptr", FALSE);
13601         register_icall (mono_ldtoken_wrapper, "mono_ldtoken_wrapper", "ptr ptr ptr ptr", FALSE);
13602         register_icall (mono_get_special_static_data, "mono_get_special_static_data", "ptr int", FALSE);
13603         register_icall (mono_ldstr, "mono_ldstr", "object ptr ptr int32", FALSE);
13604         register_icall (mono_helper_stelem_ref_check, "helper_stelem_ref_check", "void object object", FALSE);
13605         register_icall (mono_object_new, "mono_object_new", "object ptr ptr", FALSE);
13606         register_icall (mono_object_new_specific, "mono_object_new_specific", "object ptr", FALSE);
13607         register_icall (mono_array_new, "mono_array_new", "object ptr ptr int32", FALSE);
13608         register_icall (mono_array_new_specific, "mono_array_new_specific", "object ptr int32", FALSE);
13609         register_icall (mono_runtime_class_init, "mono_runtime_class_init", "void ptr", FALSE);
13610         register_icall (mono_ldftn, "mono_ldftn", "ptr ptr", FALSE);
13611         register_icall (mono_ldftn_nosync, "mono_ldftn_nosync", "ptr ptr", FALSE);
13612         register_icall (mono_ldvirtfn, "mono_ldvirtfn", "ptr object ptr", FALSE);
13613         register_icall (mono_helper_compile_generic_method, "compile_generic_method", "ptr object ptr ptr ptr", FALSE);
13614         register_icall (mono_helper_ldstr, "helper_ldstr", "object ptr int", FALSE);
13615         register_icall (mono_helper_ldstr_mscorlib, "helper_ldstr_mscorlib", "object int", FALSE);
13616         register_icall (mono_helper_newobj_mscorlib, "helper_newobj_mscorlib", "object int", FALSE);
13617         register_icall (mono_value_copy, "mono_value_copy", "void ptr ptr ptr", FALSE);
13618         register_icall (mono_helper_get_rgctx_other_ptr, "get_rgctx_other_ptr", "ptr ptr ptr int32 int32 int32 int32", FALSE);
13619         register_icall (mono_break, "mono_break", NULL, TRUE);
13620         register_icall (mono_create_corlib_exception_0, "mono_create_corlib_exception_0", "object int", TRUE);
13621         register_icall (mono_create_corlib_exception_1, "mono_create_corlib_exception_1", "object int object", TRUE);
13622         register_icall (mono_create_corlib_exception_2, "mono_create_corlib_exception_2", "object int object object", TRUE);
13623 #endif
13624
13625 #define JIT_RUNTIME_WORKS
13626 #ifdef JIT_RUNTIME_WORKS
13627         mono_install_runtime_cleanup ((MonoDomainFunc)mini_cleanup);
13628         mono_runtime_init (domain, mono_thread_start_cb, mono_thread_attach_cb);
13629 #endif
13630
13631         mono_generic_sharing_init ();
13632
13633         mono_thread_attach (domain);
13634         return domain;
13635 }
13636
13637 MonoJitStats mono_jit_stats = {0};
13638
13639 static void 
13640 print_jit_stats (void)
13641 {
13642         if (mono_jit_stats.enabled) {
13643                 g_print ("Mono Jit statistics\n");
13644                 g_print ("Compiled methods:       %ld\n", mono_jit_stats.methods_compiled);
13645                 g_print ("Methods from AOT:       %ld\n", mono_jit_stats.methods_aot);
13646                 g_print ("Methods cache lookup:   %ld\n", mono_jit_stats.methods_lookups);
13647                 g_print ("Method trampolines:     %ld\n", mono_jit_stats.method_trampolines);
13648                 g_print ("Basic blocks:           %ld\n", mono_jit_stats.basic_blocks);
13649                 g_print ("Max basic blocks:       %ld\n", mono_jit_stats.max_basic_blocks);
13650                 g_print ("Allocated vars:         %ld\n", mono_jit_stats.allocate_var);
13651                 g_print ("Analyze stack repeat:   %ld\n", mono_jit_stats.analyze_stack_repeat);
13652                 g_print ("Compiled CIL code size: %ld\n", mono_jit_stats.cil_code_size);
13653                 g_print ("Native code size:       %ld\n", mono_jit_stats.native_code_size);
13654                 g_print ("Max code size ratio:    %.2f (%s::%s)\n", mono_jit_stats.max_code_size_ratio/100.0,
13655                                 mono_jit_stats.max_ratio_method->klass->name, mono_jit_stats.max_ratio_method->name);
13656                 g_print ("Biggest method:         %ld (%s::%s)\n", mono_jit_stats.biggest_method_size,
13657                                 mono_jit_stats.biggest_method->klass->name, mono_jit_stats.biggest_method->name);
13658                 g_print ("Code reallocs:          %ld\n", mono_jit_stats.code_reallocs);
13659                 g_print ("Allocated code size:    %ld\n", mono_jit_stats.allocated_code_size);
13660                 g_print ("Inlineable methods:     %ld\n", mono_jit_stats.inlineable_methods);
13661                 g_print ("Inlined methods:        %ld\n", mono_jit_stats.inlined_methods);
13662                 g_print ("Locals stack size:      %ld\n", mono_jit_stats.locals_stack_size);
13663
13664                 g_print ("\nCreated object count:   %ld\n", mono_stats.new_object_count);
13665                 g_print ("Delegates created:      %ld\n", mono_stats.delegate_creations);
13666                 g_print ("Initialized classes:    %ld\n", mono_stats.initialized_class_count);
13667                 g_print ("Used classes:           %ld\n", mono_stats.used_class_count);
13668                 g_print ("Generic vtables:        %ld\n", mono_stats.generic_vtable_count);
13669                 g_print ("Methods:                %ld\n", mono_stats.method_count);
13670                 g_print ("Static data size:       %ld\n", mono_stats.class_static_data_size);
13671                 g_print ("VTable data size:       %ld\n", mono_stats.class_vtable_size);
13672                 g_print ("Mscorlib mempool size:  %d\n", mono_mempool_get_allocated (mono_defaults.corlib->mempool));
13673
13674                 g_print ("\nGeneric instances:      %ld\n", mono_stats.generic_instance_count);
13675                 g_print ("Initialized classes:    %ld\n", mono_stats.generic_class_count);
13676                 g_print ("Inflated methods:       %ld / %ld\n", mono_stats.inflated_method_count_2,
13677                          mono_stats.inflated_method_count);
13678                 g_print ("Inflated types:         %ld\n", mono_stats.inflated_type_count);
13679                 g_print ("Generics metadata size: %ld\n", mono_stats.generics_metadata_size);
13680                 g_print ("Generics virtual invokes: %ld\n", mono_jit_stats.generic_virtual_invocations);
13681
13682                 g_print ("Sharable generic methods: %ld\n", mono_stats.generics_sharable_methods);
13683                 g_print ("Unsharable generic methods: %ld\n", mono_stats.generics_unsharable_methods);
13684                 g_print ("Shared generic methods: %ld\n", mono_stats.generics_shared_methods);
13685
13686                 g_print ("Dynamic code allocs:    %ld\n", mono_stats.dynamic_code_alloc_count);
13687                 g_print ("Dynamic code bytes:     %ld\n", mono_stats.dynamic_code_bytes_count);
13688                 g_print ("Dynamic code frees:     %ld\n", mono_stats.dynamic_code_frees_count);
13689
13690                 g_print ("IMT tables size:        %ld\n", mono_stats.imt_tables_size);
13691                 g_print ("IMT number of tables:   %ld\n", mono_stats.imt_number_of_tables);
13692                 g_print ("IMT number of methods:  %ld\n", mono_stats.imt_number_of_methods);
13693                 g_print ("IMT used slots:         %ld\n", mono_stats.imt_used_slots);
13694                 g_print ("IMT colliding slots:    %ld\n", mono_stats.imt_slots_with_collisions);
13695                 g_print ("IMT max collisions:     %ld\n", mono_stats.imt_max_collisions_in_slot);
13696                 g_print ("IMT methods at max col: %ld\n", mono_stats.imt_method_count_when_max_collisions);
13697                 g_print ("IMT thunks size:        %ld\n", mono_stats.imt_thunks_size);
13698
13699                 g_print ("JIT info table inserts: %ld\n", mono_stats.jit_info_table_insert_count);
13700                 g_print ("JIT info table removes: %ld\n", mono_stats.jit_info_table_remove_count);
13701                 g_print ("JIT info table lookups: %ld\n", mono_stats.jit_info_table_lookup_count);
13702
13703                 g_print ("Hazardous pointers:     %ld\n", mono_stats.hazardous_pointer_count);
13704 #ifdef HAVE_SGEN_GC
13705                 g_print ("Minor GC collections:   %ld\n", mono_stats.minor_gc_count);
13706                 g_print ("Major GC collections:   %ld\n", mono_stats.major_gc_count);
13707                 g_print ("Minor GC time in msecs: %lf\n", (double)mono_stats.minor_gc_time_usecs / 1000.0);
13708                 g_print ("Major GC time in msecs: %lf\n", (double)mono_stats.major_gc_time_usecs / 1000.0);
13709 #endif
13710                 if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS) {
13711                         g_print ("\nDecl security check   : %ld\n", mono_jit_stats.cas_declsec_check);
13712                         g_print ("LinkDemand (user)     : %ld\n", mono_jit_stats.cas_linkdemand);
13713                         g_print ("LinkDemand (icall)    : %ld\n", mono_jit_stats.cas_linkdemand_icall);
13714                         g_print ("LinkDemand (pinvoke)  : %ld\n", mono_jit_stats.cas_linkdemand_pinvoke);
13715                         g_print ("LinkDemand (aptc)     : %ld\n", mono_jit_stats.cas_linkdemand_aptc);
13716                         g_print ("Demand (code gen)     : %ld\n", mono_jit_stats.cas_demand_generation);
13717                 }
13718                 if (debug_options.collect_pagefault_stats) {
13719                         g_print ("Metadata pagefaults   : %d\n", mono_raw_buffer_get_n_pagefaults ());
13720                         g_print ("AOT pagefaults        : %d\n", mono_aot_get_n_pagefaults ());
13721                 }
13722         }
13723 }
13724
13725 void
13726 mini_cleanup (MonoDomain *domain)
13727 {
13728 #ifdef HAVE_LINUX_RTC_H
13729         if (rtc_fd >= 0)
13730                 enable_rtc_timer (FALSE);
13731 #endif
13732
13733         /* 
13734          * mono_runtime_cleanup() and mono_domain_finalize () need to
13735          * be called early since they need the execution engine still
13736          * fully working (mono_domain_finalize may invoke managed finalizers
13737          * and mono_runtime_cleanup will wait for other threads to finish).
13738          */
13739         mono_domain_finalize (domain, 2000);
13740
13741         /* This accesses metadata so needs to be called before runtime shutdown */
13742         print_jit_stats ();
13743
13744         mono_runtime_cleanup (domain);
13745
13746         mono_profiler_shutdown ();
13747
13748         mono_icall_cleanup ();
13749
13750         mono_runtime_cleanup_handlers ();
13751
13752         mono_domain_free (domain, TRUE);
13753
13754         mono_debugger_cleanup ();
13755
13756         mono_trampolines_cleanup ();
13757
13758         mono_code_manager_destroy (global_codeman);
13759         g_hash_table_destroy (jit_icall_name_hash);
13760         g_free (emul_opcode_map);
13761
13762         mono_arch_cleanup ();
13763
13764         mono_cleanup ();
13765
13766         mono_trace_cleanup ();
13767
13768         mono_counters_dump (-1, stdout);
13769
13770         if (mono_inject_async_exc_method)
13771                 mono_method_desc_free (mono_inject_async_exc_method);
13772
13773         TlsFree(mono_jit_tls_id);
13774
13775         DeleteCriticalSection (&jit_mutex);
13776
13777         DeleteCriticalSection (&mono_delegate_section);
13778 }
13779
13780 void
13781 mono_set_defaults (int verbose_level, guint32 opts)
13782 {
13783         mini_verbose = verbose_level;
13784         default_opt = opts;
13785         default_opt_set = TRUE;
13786 }
13787
13788 static void
13789 mono_precompile_assembly (MonoAssembly *ass, void *user_data)
13790 {
13791         GHashTable *assemblies = (GHashTable*)user_data;
13792         MonoImage *image = mono_assembly_get_image (ass);
13793         MonoMethod *method, *invoke;
13794         int i, count = 0;
13795
13796         if (g_hash_table_lookup (assemblies, ass))
13797                 return;
13798
13799         g_hash_table_insert (assemblies, ass, ass);
13800
13801         if (mini_verbose > 0)
13802                 printf ("PRECOMPILE: %s.\n", mono_image_get_filename (image));
13803
13804         for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_METHOD); ++i) {
13805                 method = mono_get_method (image, MONO_TOKEN_METHOD_DEF | (i + 1), NULL);
13806                 if (method->flags & METHOD_ATTRIBUTE_ABSTRACT)
13807                         continue;
13808
13809                 count++;
13810                 if (mini_verbose > 1) {
13811                         char * desc = mono_method_full_name (method, TRUE);
13812                         g_print ("Compiling %d %s\n", count, desc);
13813                         g_free (desc);
13814                 }
13815                 mono_compile_method (method);
13816                 if (strcmp (method->name, "Finalize") == 0) {
13817                         invoke = mono_marshal_get_runtime_invoke (method);
13818                         mono_compile_method (invoke);
13819                 }
13820                 if (method->klass->marshalbyref && mono_method_signature (method)->hasthis) {
13821                         invoke = mono_marshal_get_remoting_invoke_with_check (method);
13822                         mono_compile_method (invoke);
13823                 }
13824         }
13825
13826         /* Load and precompile referenced assemblies as well */
13827         for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_ASSEMBLYREF); ++i) {
13828                 mono_assembly_load_reference (image, i);
13829                 if (image->references [i])
13830                         mono_precompile_assembly (image->references [i], assemblies);
13831         }
13832 }
13833
13834 void mono_precompile_assemblies ()
13835 {
13836         GHashTable *assemblies = g_hash_table_new (NULL, NULL);
13837
13838         mono_assembly_foreach ((GFunc)mono_precompile_assembly, assemblies);
13839
13840         g_hash_table_destroy (assemblies);
13841 }