Mark tests as not working under TARGET_JVM
[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 #include <unistd.h>
14 #include <math.h>
15 #include <sys/time.h>
16
17 #ifdef PLATFORM_MACOSX
18 #include <mach/mach.h>
19 #include <mach/mach_error.h>
20 #include <mach/exception.h>
21 #include <mach/task.h>
22 #include <pthread.h>
23 #endif
24
25 #ifdef PLATFORM_WIN32
26 #define _WIN32_WINNT 0x0500
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/cil-coff.h>
36 #include <mono/metadata/tabledefs.h>
37 #include <mono/metadata/class.h>
38 #include <mono/metadata/object.h>
39 #include <mono/metadata/exception.h>
40 #include <mono/metadata/opcodes.h>
41 #include <mono/metadata/mono-endian.h>
42 #include <mono/metadata/tokentype.h>
43 #include <mono/metadata/tabledefs.h>
44 #include <mono/metadata/threads.h>
45 #include <mono/metadata/marshal.h>
46 #include <mono/metadata/socket-io.h>
47 #include <mono/metadata/appdomain.h>
48 #include <mono/metadata/debug-helpers.h>
49 #include <mono/io-layer/io-layer.h>
50 #include "mono/metadata/profiler.h"
51 #include <mono/metadata/profiler-private.h>
52 #include <mono/metadata/mono-config.h>
53 #include <mono/metadata/environment.h>
54 #include <mono/metadata/mono-debug.h>
55 #include <mono/metadata/monitor.h>
56 #include <mono/metadata/security-manager.h>
57 #include <mono/metadata/threads-types.h>
58 #include <mono/metadata/rawbuffer.h>
59 #include <mono/utils/mono-math.h>
60 #include <mono/utils/mono-compiler.h>
61 #include <mono/utils/mono-counters.h>
62 #include <mono/utils/mono-logger.h>
63 #include <mono/os/gc_wrapper.h>
64
65 #include "mini.h"
66 #include <string.h>
67 #include <ctype.h>
68 #include "inssel.h"
69 #include "trace.h"
70
71 #include "jit-icalls.h"
72
73 #include "aliasing.h"
74
75 #define BRANCH_COST 100
76 #define INLINE_LENGTH_LIMIT 20
77 #define INLINE_FAILURE do {\
78                 if ((cfg->method != method) && (method->wrapper_type == MONO_WRAPPER_NONE))\
79                         goto inline_failure;\
80         } while (0)
81
82 /* 
83  * this is used to determine when some branch optimizations are possible: we exclude FP compares
84  * because they have weird semantics with NaNs.
85  */
86 #define MONO_IS_COND_BRANCH_OP(ins) (((ins)->opcode >= CEE_BEQ && (ins)->opcode <= CEE_BLT_UN) || ((ins)->opcode >= OP_LBEQ && (ins)->opcode <= OP_LBLT_UN) || ((ins)->opcode >= OP_FBEQ && (ins)->opcode <= OP_FBLT_UN) || ((ins)->opcode >= OP_IBEQ && (ins)->opcode <= OP_IBLT_UN))
87 #define MONO_IS_COND_BRANCH_NOFP(ins) (MONO_IS_COND_BRANCH_OP(ins) && (ins)->inst_left->inst_left->type != STACK_R8)
88
89 #define MONO_IS_BRANCH_OP(ins) (MONO_IS_COND_BRANCH_OP(ins) || ((ins)->opcode == CEE_BR) || ((ins)->opcode == OP_BR_REG) || ((ins)->opcode == CEE_SWITCH))
90
91 #define MONO_CHECK_THIS(ins) (mono_method_signature (cfg->method)->hasthis && (ins)->ssa_op == MONO_SSA_LOAD && (ins)->inst_left->inst_c0 == 0)
92
93 static void setup_stat_profiler (void);
94 gboolean  mono_arch_print_tree(MonoInst *tree, int arity);
95 static gpointer mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt);
96 static gpointer mono_jit_compile_method (MonoMethod *method);
97 static gpointer mono_jit_find_compiled_method (MonoDomain *domain, MonoMethod *method);
98 static gpointer mono_create_jit_trampoline_in_domain (MonoDomain *domain, MonoMethod *method);
99 inline static int mono_emit_jit_icall (MonoCompile *cfg, MonoBasicBlock *bblock, gconstpointer func, MonoInst **args, const guint8 *ip);
100
101 static void handle_stobj (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *dest, MonoInst *src, 
102                           const unsigned char *ip, MonoClass *klass, gboolean to_end, gboolean native, gboolean write_barrier);
103
104 static void dec_foreach (MonoInst *tree, MonoCompile *cfg);
105
106 static int mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock, 
107                    int locals_offset, MonoInst *return_var, GList *dont_inline, MonoInst **inline_args, 
108                    guint inline_offset, gboolean is_virtual_call);
109
110 /* helper methods signature */
111 static MonoMethodSignature *helper_sig_class_init_trampoline = NULL;
112 static MonoMethodSignature *helper_sig_domain_get = NULL;
113
114 static guint32 default_opt = 0;
115 static gboolean default_opt_set = FALSE;
116
117 guint32 mono_jit_tls_id = -1;
118 MonoTraceSpec *mono_jit_trace_calls = NULL;
119 gboolean mono_break_on_exc = FALSE;
120 #ifndef DISABLE_AOT
121 gboolean mono_compile_aot = FALSE;
122 #endif
123 gboolean mono_use_security_manager = FALSE;
124
125 static int mini_verbose = 0;
126
127 #define mono_jit_lock() EnterCriticalSection (&jit_mutex)
128 #define mono_jit_unlock() LeaveCriticalSection (&jit_mutex)
129 static CRITICAL_SECTION jit_mutex;
130
131 static GHashTable *class_init_hash_addr = NULL;
132
133 static MonoCodeManager *global_codeman = NULL;
134
135 static GHashTable *jit_icall_name_hash = NULL;
136
137 static MonoDebugOptions debug_options;
138
139 /*
140  * Address of the trampoline code.  This is used by the debugger to check
141  * whether a method is a trampoline.
142  */
143 guint8* mono_trampoline_code [MONO_TRAMPOLINE_NUM];
144
145 gboolean
146 mono_running_on_valgrind (void)
147 {
148 #ifdef HAVE_VALGRIND_MEMCHECK_H
149                 if (RUNNING_ON_VALGRIND)
150                         return TRUE;
151                 else
152                         return FALSE;
153 #else
154                 return FALSE;
155 #endif
156 }
157
158 /*
159  * mono_create_ftnptr:
160  *
161  *   Given a function address, create a function descriptor for it.
162  * This is only needed on IA64.
163  */
164 gpointer
165 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
166 {
167 #ifdef __ia64__
168         gpointer *desc;
169
170         mono_domain_lock (domain);
171         desc = mono_code_manager_reserve (domain->code_mp, 2 * sizeof (gpointer));
172         mono_domain_unlock (domain);
173
174         desc [0] = addr;
175         desc [1] = NULL;
176
177         return desc;
178 #else
179         return addr;
180 #endif
181 }
182
183 typedef struct {
184         void *ip;
185         MonoMethod *method;
186 } FindTrampUserData;
187
188 static void
189 find_tramp (gpointer key, gpointer value, gpointer user_data)
190 {
191         FindTrampUserData *ud = (FindTrampUserData*)user_data;
192
193         if (value == ud->ip)
194                 ud->method = (MonoMethod*)key;
195 }
196
197 /* debug function */
198 G_GNUC_UNUSED static char*
199 get_method_from_ip (void *ip)
200 {
201         MonoJitInfo *ji;
202         char *method;
203         char *res;
204         MonoDomain *domain = mono_domain_get ();
205         MonoDebugSourceLocation *location;
206         FindTrampUserData user_data;
207         
208         ji = mono_jit_info_table_find (domain, ip);
209         if (!ji) {
210                 user_data.ip = ip;
211                 user_data.method = NULL;
212                 mono_domain_lock (domain);
213                 g_hash_table_foreach (domain->jit_trampoline_hash, find_tramp, &user_data);
214                 mono_domain_unlock (domain);
215                 if (user_data.method) {
216                         char *mname = mono_method_full_name (user_data.method, TRUE);
217                         res = g_strdup_printf ("<%p - JIT trampoline for %s>", ip, mname);
218                         g_free (mname);
219                         return res;
220                 }
221                 else
222                         return NULL;
223         }
224         method = mono_method_full_name (ji->method, TRUE);
225         /* FIXME: unused ? */
226         location = mono_debug_lookup_source_location (ji->method, (guint32)((guint8*)ip - (guint8*)ji->code_start), domain);
227
228         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);
229
230         mono_debug_free_source_location (location);
231         g_free (method);
232
233         return res;
234 }
235
236 /** 
237  * mono_pmip:
238  * @ip: an instruction pointer address
239  *
240  * This method is used from a debugger to get the name of the
241  * method at address @ip.   This routine is typically invoked from
242  * a debugger like this:
243  *
244  * (gdb) print mono_pmip ($pc)
245  *
246  * Returns: the name of the method at address @ip.
247  */
248 G_GNUC_UNUSED char *
249 mono_pmip (void *ip)
250 {
251         return get_method_from_ip (ip);
252 }
253
254 /** 
255  * mono_print_method_from_ip
256  * @ip: an instruction pointer address
257  *
258  * This method is used from a debugger to get the name of the
259  * method at address @ip.
260  *
261  * This prints the name of the method at address @ip in the standard
262  * output.  Unlike mono_pmip which returns a string, this routine
263  * prints the value on the standard output. 
264  */
265 void
266 mono_print_method_from_ip (void *ip)
267 {
268         MonoJitInfo *ji;
269         char *method;
270         MonoDebugSourceLocation *source;
271         MonoDomain *domain = mono_domain_get ();
272         FindTrampUserData user_data;
273         
274         ji = mono_jit_info_table_find (domain, ip);
275         if (!ji) {
276                 user_data.ip = ip;
277                 user_data.method = NULL;
278                 mono_domain_lock (domain);
279                 g_hash_table_foreach (domain->jit_trampoline_hash, find_tramp, &user_data);
280                 mono_domain_unlock (domain);
281                 if (user_data.method) {
282                         char *mname = mono_method_full_name (user_data.method, TRUE);
283                         printf ("IP %p is a JIT trampoline for %s\n", ip, mname);
284                         g_free (mname);
285                 }
286                 else
287                         g_print ("No method at %p\n", ip);
288                 return;
289         }
290         method = mono_method_full_name (ji->method, TRUE);
291         source = mono_debug_lookup_source_location (ji->method, (guint32)((guint8*)ip - (guint8*)ji->code_start), domain);
292
293         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);
294
295         if (source)
296                 g_print ("%s:%d\n", source->source_file, source->row);
297
298         mono_debug_free_source_location (source);
299         g_free (method);
300 }
301         
302 /* 
303  * mono_method_same_domain:
304  *
305  * Determine whenever two compiled methods are in the same domain, thus
306  * the address of the callee can be embedded in the caller.
307  */
308 gboolean mono_method_same_domain (MonoJitInfo *caller, MonoJitInfo *callee)
309 {
310         if (!caller || !callee)
311                 return FALSE;
312
313         /*
314          * If the call was made from domain-neutral to domain-specific 
315          * code, we can't patch the call site.
316          */
317         if (caller->domain_neutral && !callee->domain_neutral)
318                 return FALSE;
319
320         if ((caller->method->klass == mono_defaults.appdomain_class) &&
321                 (strstr (caller->method->name, "InvokeInDomain"))) {
322                  /* The InvokeInDomain methods change the current appdomain */
323                 return FALSE;
324         }
325
326         return TRUE;
327 }
328
329 /*
330  * mono_global_codeman_reserve:
331  *
332  *  Allocate code memory from the global code manager.
333  */
334 void *mono_global_codeman_reserve (int size)
335 {
336         void *ptr;
337
338         if (!global_codeman) {
339                 /* This can happen during startup */
340                 global_codeman = mono_code_manager_new ();
341                 return mono_code_manager_reserve (global_codeman, size);
342         }
343         else {
344                 mono_jit_lock ();
345                 ptr = mono_code_manager_reserve (global_codeman, size);
346                 mono_jit_unlock ();
347                 return ptr;
348         }
349 }
350
351 MonoJumpInfoToken *
352 mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
353 {
354         MonoJumpInfoToken *res = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoToken));
355         res->image = image;
356         res->token = token;
357
358         return res;
359 }
360
361 #define MONO_INIT_VARINFO(vi,id) do { \
362         (vi)->range.first_use.pos.bid = 0xffff; \
363         (vi)->reg = -1; \
364         (vi)->idx = (id); \
365 } while (0)
366
367 //#define UNVERIFIED do { G_BREAKPOINT (); goto unverified; } while (0)
368 #define UNVERIFIED do { if (debug_options.break_on_unverified) G_BREAKPOINT (); else goto unverified; } while (0)
369
370 /*
371  * Basic blocks have two numeric identifiers:
372  * dfn: Depth First Number
373  * block_num: unique ID assigned at bblock creation
374  */
375 #define NEW_BBLOCK(cfg) (mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock)))
376 #define ADD_BBLOCK(cfg,bbhash,b) do {   \
377                 g_hash_table_insert (bbhash, (b)->cil_code, (b));       \
378                 (b)->block_num = cfg->num_bblocks++;    \
379                 (b)->real_offset = real_offset; \
380         } while (0)
381
382 #define GET_BBLOCK(cfg,bbhash,tblock,ip) do {   \
383                 (tblock) = g_hash_table_lookup (bbhash, (ip));  \
384                 if (!(tblock)) {        \
385                         if ((ip) >= end || (ip) < header->code) UNVERIFIED; \
386                         (tblock) = NEW_BBLOCK (cfg);    \
387                         (tblock)->cil_code = (ip);      \
388                         ADD_BBLOCK (cfg, (bbhash), (tblock));   \
389                 } \
390         } while (0)
391
392 #define CHECK_BBLOCK(target,ip,tblock) do {     \
393                 if ((target) < (ip) && !(tblock)->code) {       \
394                         bb_recheck = g_list_prepend (bb_recheck, (tblock));     \
395                         if (cfg->verbose_level > 2) g_print ("queued block %d for check at IL%04x from IL%04x\n", (tblock)->block_num, (int)((target) - header->code), (int)((ip) - header->code));     \
396                 }       \
397         } while (0)
398
399 #define NEW_ICONST(cfg,dest,val) do {   \
400                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
401                 (dest)->opcode = OP_ICONST;     \
402                 (dest)->inst_c0 = (val);        \
403                 (dest)->type = STACK_I4;        \
404         } while (0)
405
406 #define NEW_PCONST(cfg,dest,val) do {   \
407                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
408                 (dest)->opcode = OP_PCONST;     \
409                 (dest)->inst_p0 = (val);        \
410                 (dest)->type = STACK_PTR;       \
411         } while (0)
412
413
414 #ifdef MONO_ARCH_NEED_GOT_VAR
415
416 #define NEW_PATCH_INFO(cfg,dest,el1,el2) do {   \
417                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
418                 (dest)->opcode = OP_PATCH_INFO; \
419                 (dest)->inst_left = (gpointer)(el1);    \
420                 (dest)->inst_right = (gpointer)(el2);   \
421         } while (0)
422
423 #define NEW_AOTCONST(cfg,dest,patch_type,cons) do {                     \
424                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
425                 (dest)->opcode = cfg->compile_aot ? OP_GOT_ENTRY : OP_PCONST; \
426                 if (cfg->compile_aot) {                                 \
427                         MonoInst *group, *got_var, *got_loc;            \
428                         got_loc = mono_get_got_var (cfg);               \
429                         NEW_TEMPLOAD ((cfg), got_var, got_loc->inst_c0); \
430                         NEW_PATCH_INFO ((cfg), group, cons, patch_type); \
431                         (dest)->inst_p0 = got_var;                      \
432                         (dest)->inst_p1 = group;                        \
433                 } else {                                                \
434                         (dest)->inst_p0 = (cons);                       \
435                         (dest)->inst_i1 = (gpointer)(patch_type);       \
436                 }                                                       \
437                 (dest)->type = STACK_PTR;                               \
438         } while (0)
439
440 #define NEW_AOTCONST_TOKEN(cfg,dest,patch_type,image,token,stack_type,stack_class) do { \
441                 MonoInst *group, *got_var, *got_loc;                    \
442                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
443                 (dest)->opcode = OP_GOT_ENTRY;                          \
444                 got_loc = mono_get_got_var (cfg);                       \
445                 NEW_TEMPLOAD ((cfg), got_var, got_loc->inst_c0);        \
446                 NEW_PATCH_INFO ((cfg), group, NULL, patch_type);        \
447                 group->inst_p0 = mono_jump_info_token_new ((cfg)->mempool, (image), (token)); \
448                 (dest)->inst_p0 = got_var;                              \
449                 (dest)->inst_p1 = group;                                \
450                 (dest)->type = (stack_type);                    \
451         (dest)->klass = (stack_class);          \
452         } while (0)
453
454 #else
455
456 #define NEW_AOTCONST(cfg,dest,patch_type,cons) do {    \
457                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
458                 (dest)->opcode = cfg->compile_aot ? OP_AOTCONST : OP_PCONST;    \
459                 (dest)->inst_p0 = (cons);       \
460                 (dest)->inst_i1 = (gpointer)(patch_type); \
461                 (dest)->type = STACK_PTR;       \
462     } while (0)
463
464 #define NEW_AOTCONST_TOKEN(cfg,dest,patch_type,image,token,stack_type,stack_class) do { \
465                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
466                 (dest)->opcode = OP_AOTCONST;   \
467                 (dest)->inst_p0 = mono_jump_info_token_new ((cfg)->mempool, (image), (token));  \
468                 (dest)->inst_p1 = (gpointer)(patch_type); \
469                 (dest)->type = (stack_type);    \
470         (dest)->klass = (stack_class);          \
471     } while (0)
472
473 #endif
474
475 #define NEW_CLASSCONST(cfg,dest,val) NEW_AOTCONST ((cfg), (dest), MONO_PATCH_INFO_CLASS, (val))
476
477 #define NEW_IMAGECONST(cfg,dest,val) NEW_AOTCONST ((cfg), (dest), MONO_PATCH_INFO_IMAGE, (val))
478
479 #define NEW_FIELDCONST(cfg,dest,val) NEW_AOTCONST ((cfg), (dest), MONO_PATCH_INFO_FIELD, (val))
480
481 #define NEW_METHODCONST(cfg,dest,val) NEW_AOTCONST ((cfg), (dest), MONO_PATCH_INFO_METHODCONST, (val))
482
483 #define NEW_VTABLECONST(cfg,dest,vtable) NEW_AOTCONST ((cfg), (dest), MONO_PATCH_INFO_VTABLE, cfg->compile_aot ? (gpointer)((vtable)->klass) : (vtable))
484
485 #define NEW_SFLDACONST(cfg,dest,val) NEW_AOTCONST ((cfg), (dest), MONO_PATCH_INFO_SFLDA, (val))
486
487 #define NEW_LDSTRCONST(cfg,dest,image,token) NEW_AOTCONST_TOKEN ((cfg), (dest), MONO_PATCH_INFO_LDSTR, (image), (token), STACK_OBJ, mono_defaults.string_class)
488
489 #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)
490
491 #define NEW_LDTOKENCONST(cfg,dest,image,token) NEW_AOTCONST_TOKEN ((cfg), (dest), MONO_PATCH_INFO_LDTOKEN, (image), (token), STACK_PTR, NULL)
492
493 #define NEW_DECLSECCONST(cfg,dest,image,entry) do { \
494                 if (cfg->compile_aot) { \
495                         NEW_AOTCONST_TOKEN (cfg, dest, MONO_PATCH_INFO_DECLSEC, image, (entry).index, STACK_OBJ, NULL); \
496                 } else { \
497                         NEW_PCONST (cfg, args [0], (entry).blob); \
498                 } \
499         } while (0)
500
501 #define NEW_DOMAINCONST(cfg,dest) do { \
502                 if (cfg->opt & MONO_OPT_SHARED) { \
503                         /* avoid depending on undefined C behavior in sequence points */ \
504                         MonoInst* __domain_var = mono_get_domainvar (cfg); \
505                         NEW_TEMPLOAD (cfg, dest, __domain_var->inst_c0); \
506                 } else { \
507                         NEW_PCONST (cfg, dest, (cfg)->domain); \
508                 } \
509         } while (0)
510
511 #define GET_VARINFO_INST(cfg,num) ((cfg)->varinfo [(num)]->inst)
512
513 #define NEW_ARGLOAD(cfg,dest,num) do {  \
514                 if (arg_array [(num)]->opcode == OP_ICONST) (dest) = arg_array [(num)]; else { \
515                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
516                 (dest)->ssa_op = MONO_SSA_LOAD; \
517                 (dest)->inst_i0 = arg_array [(num)];    \
518                 (dest)->opcode = mono_type_to_ldind ((dest)->inst_i0->inst_vtype);      \
519                 type_to_eval_stack_type (param_types [(num)], (dest));  \
520                 (dest)->klass = (dest)->inst_i0->klass; \
521         }} while (0)
522
523 #define NEW_LOCLOAD(cfg,dest,num) do {  \
524                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
525                 (dest)->ssa_op = MONO_SSA_LOAD; \
526                 (dest)->inst_i0 = (cfg)->varinfo [locals_offset + (num)];       \
527                 (dest)->opcode = mono_type_to_ldind ((dest)->inst_i0->inst_vtype);      \
528                 type_to_eval_stack_type (header->locals [(num)], (dest));       \
529                 (dest)->klass = (dest)->inst_i0->klass; \
530         } while (0)
531
532 #define NEW_LOCLOADA(cfg,dest,num) do { \
533                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
534                 (dest)->ssa_op = MONO_SSA_ADDRESS_TAKEN;        \
535                 (dest)->inst_i0 = (cfg)->varinfo [locals_offset + (num)];       \
536                 (dest)->inst_i0->flags |= MONO_INST_INDIRECT;   \
537                 (dest)->opcode = OP_LDADDR;     \
538                 (dest)->type = STACK_MP;        \
539                 (dest)->klass = (dest)->inst_i0->klass; \
540         if (!MONO_TYPE_ISSTRUCT (header->locals [(num)])) \
541            (cfg)->disable_ssa = TRUE; \
542         } while (0)
543
544 #define NEW_RETLOADA(cfg,dest) do {     \
545                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
546                 (dest)->ssa_op = MONO_SSA_ADDRESS_TAKEN;        \
547                 (dest)->inst_i0 = (cfg)->ret;   \
548                 (dest)->inst_i0->flags |= MONO_INST_INDIRECT;   \
549                 (dest)->opcode = cfg->ret_var_is_local ? OP_LDADDR : CEE_LDIND_I;       \
550                 (dest)->type = STACK_MP;        \
551                 (dest)->klass = (dest)->inst_i0->klass; \
552                 (cfg)->disable_ssa = TRUE; \
553         } while (0)
554
555 #define NEW_ARGLOADA(cfg,dest,num) do { \
556                 if (arg_array [(num)]->opcode == OP_ICONST) goto inline_failure; \
557                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
558                 (dest)->ssa_op = MONO_SSA_ADDRESS_TAKEN;        \
559                 (dest)->inst_i0 = arg_array [(num)];    \
560                 (dest)->inst_i0->flags |= MONO_INST_INDIRECT;   \
561                 (dest)->opcode = OP_LDADDR;     \
562                 (dest)->type = STACK_MP;        \
563                 (dest)->klass = (dest)->inst_i0->klass; \
564                 (cfg)->disable_ssa = TRUE; \
565         } while (0)
566
567 #define NEW_TEMPLOAD(cfg,dest,num) do { \
568                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
569                 (dest)->ssa_op = MONO_SSA_LOAD; \
570                 (dest)->inst_i0 = (cfg)->varinfo [(num)];       \
571                 (dest)->opcode = mono_type_to_ldind ((dest)->inst_i0->inst_vtype);      \
572                 type_to_eval_stack_type ((dest)->inst_i0->inst_vtype, (dest));  \
573                 (dest)->klass = (dest)->inst_i0->klass; \
574         } while (0)
575
576 #define NEW_TEMPLOADA(cfg,dest,num) do {        \
577                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
578                 (dest)->ssa_op = MONO_SSA_ADDRESS_TAKEN;        \
579                 (dest)->inst_i0 = (cfg)->varinfo [(num)];       \
580                 (dest)->inst_i0->flags |= MONO_INST_INDIRECT;   \
581                 (dest)->opcode = OP_LDADDR;     \
582                 (dest)->type = STACK_MP;        \
583                 (dest)->klass = (dest)->inst_i0->klass; \
584         if (!MONO_TYPE_ISSTRUCT (cfg->varinfo [(num)]->inst_vtype)) \
585            (cfg)->disable_ssa = TRUE; \
586         } while (0)
587
588
589 #define NEW_INDLOAD(cfg,dest,addr,vtype) do {   \
590                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
591                 (dest)->inst_left = addr;       \
592                 (dest)->opcode = mono_type_to_ldind (vtype);    \
593                 type_to_eval_stack_type (vtype, (dest));        \
594                 /* FIXME: (dest)->klass = (dest)->inst_i0->klass;*/     \
595         } while (0)
596
597 #define NEW_INDSTORE(cfg,dest,addr,value,vtype) do {    \
598                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
599                 (dest)->inst_i0 = addr; \
600                 (dest)->opcode = mono_type_to_stind (vtype);    \
601                 (dest)->inst_i1 = (value);      \
602                 /* FIXME: (dest)->klass = (dest)->inst_i0->klass;*/     \
603         } while (0)
604
605 #define NEW_TEMPSTORE(cfg,dest,num,inst) do {   \
606                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
607                 (dest)->ssa_op = MONO_SSA_STORE;        \
608                 (dest)->inst_i0 = (cfg)->varinfo [(num)];       \
609                 (dest)->opcode = mono_type_to_stind ((dest)->inst_i0->inst_vtype);      \
610                 (dest)->inst_i1 = (inst);       \
611                 (dest)->klass = (dest)->inst_i0->klass; \
612         } while (0)
613
614 #define NEW_LOCSTORE(cfg,dest,num,inst) do {    \
615                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
616                 (dest)->opcode = mono_type_to_stind (header->locals [(num)]);   \
617                 (dest)->ssa_op = MONO_SSA_STORE;        \
618                 (dest)->inst_i0 = (cfg)->varinfo [locals_offset + (num)];       \
619                 (dest)->inst_i1 = (inst);       \
620                 (dest)->klass = (dest)->inst_i0->klass; \
621         } while (0)
622
623 #define NEW_ARGSTORE(cfg,dest,num,inst) do {    \
624                 if (arg_array [(num)]->opcode == OP_ICONST) goto inline_failure; \
625                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
626                 (dest)->opcode = mono_type_to_stind (param_types [(num)]);      \
627                 (dest)->ssa_op = MONO_SSA_STORE;        \
628                 (dest)->inst_i0 = arg_array [(num)];    \
629                 (dest)->inst_i1 = (inst);       \
630                 (dest)->klass = (dest)->inst_i0->klass; \
631         } while (0)
632
633 #define NEW_DUMMY_USE(cfg,dest,load) do { \
634                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
635                 (dest)->opcode = OP_DUMMY_USE; \
636                 (dest)->inst_left = (load); \
637     } while (0)
638
639 #define NEW_DUMMY_STORE(cfg,dest,num) do { \
640                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
641                 (dest)->inst_i0 = (cfg)->varinfo [(num)];       \
642                 (dest)->opcode = OP_DUMMY_STORE; \
643                 (dest)->klass = (dest)->inst_i0->klass; \
644         } while (0)
645
646 #define ADD_BINOP(op) do {      \
647                 MONO_INST_NEW (cfg, ins, (op)); \
648                 ins->cil_code = ip;     \
649                 sp -= 2;        \
650                 ins->inst_i0 = sp [0];  \
651                 ins->inst_i1 = sp [1];  \
652                 *sp++ = ins;    \
653                 type_from_op (ins);     \
654                 CHECK_TYPE (ins);       \
655         } while (0)
656
657 #define ADD_UNOP(op) do {       \
658                 MONO_INST_NEW (cfg, ins, (op)); \
659                 ins->cil_code = ip;     \
660                 sp--;   \
661                 ins->inst_i0 = sp [0];  \
662                 *sp++ = ins;    \
663                 type_from_op (ins);     \
664                 CHECK_TYPE (ins);       \
665         } while (0)
666
667 #define ADD_BINCOND(next_block) do {    \
668                 MonoInst *cmp;  \
669                 sp -= 2;                \
670                 MONO_INST_NEW(cfg, cmp, OP_COMPARE);    \
671                 cmp->inst_i0 = sp [0];  \
672                 cmp->inst_i1 = sp [1];  \
673                 cmp->cil_code = ins->cil_code;  \
674                 type_from_op (cmp);     \
675                 CHECK_TYPE (cmp);       \
676                 ins->inst_i0 = cmp;     \
677                 MONO_ADD_INS (bblock, ins);     \
678                 ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);      \
679                 GET_BBLOCK (cfg, bbhash, tblock, target);               \
680                 link_bblock (cfg, bblock, tblock);      \
681                 ins->inst_true_bb = tblock;     \
682                 CHECK_BBLOCK (target, ip, tblock);      \
683                 if ((next_block)) {     \
684                         link_bblock (cfg, bblock, (next_block));        \
685                         ins->inst_false_bb = (next_block);      \
686                         start_new_bblock = 1;   \
687                 } else {        \
688                         GET_BBLOCK (cfg, bbhash, tblock, ip);           \
689                         link_bblock (cfg, bblock, tblock);      \
690                         ins->inst_false_bb = tblock;    \
691                         start_new_bblock = 2;   \
692                 }       \
693         } while (0)
694
695 /* FIXME: handle float, long ... */
696 #define ADD_UNCOND(istrue) do { \
697                 MonoInst *cmp;  \
698                 sp--;           \
699                 MONO_INST_NEW(cfg, cmp, OP_COMPARE);    \
700                 cmp->inst_i0 = sp [0];  \
701                 switch (cmp->inst_i0->type) { \
702                 case STACK_I8: \
703                         cmp->inst_i1 = zero_int64; break; \
704                 case STACK_R8: \
705                         cmp->inst_i1 = zero_r8; break; \
706                 case STACK_PTR: \
707                 case STACK_MP: \
708                         cmp->inst_i1 = zero_ptr; break; \
709                 case STACK_OBJ: \
710                         cmp->inst_i1 = zero_obj; break; \
711                 default: \
712                         cmp->inst_i1 = zero_int32;  \
713                 }  \
714                 cmp->cil_code = ins->cil_code;  \
715                 type_from_op (cmp);     \
716                 CHECK_TYPE (cmp);       \
717                 ins->inst_i0 = cmp;     \
718                 ins->opcode = (istrue)? CEE_BNE_UN: CEE_BEQ;    \
719                 MONO_ADD_INS (bblock, ins);     \
720                 ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);      \
721                 GET_BBLOCK (cfg, bbhash, tblock, target);               \
722                 link_bblock (cfg, bblock, tblock);      \
723                 ins->inst_true_bb = tblock;     \
724                 CHECK_BBLOCK (target, ip, tblock);      \
725                 GET_BBLOCK (cfg, bbhash, tblock, ip);           \
726                 link_bblock (cfg, bblock, tblock);      \
727                 ins->inst_false_bb = tblock;    \
728                 start_new_bblock = 2;   \
729         } while (0)
730
731 #define NEW_LDELEMA(cfg,dest,sp,k) do { \
732                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
733                 (dest)->opcode = CEE_LDELEMA;   \
734                 (dest)->inst_left = (sp) [0];   \
735                 (dest)->inst_right = (sp) [1];  \
736                 (dest)->type = STACK_MP;        \
737                 (dest)->klass = (k);    \
738                 (cfg)->flags |= MONO_CFG_HAS_LDELEMA; \
739         } while (0)
740
741 #define NEW_GROUP(cfg,dest,el1,el2) do {        \
742                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
743                 (dest)->opcode = OP_GROUP;      \
744                 (dest)->inst_left = (el1);      \
745                 (dest)->inst_right = (el2);     \
746         } while (0)
747
748 #if 0
749 static gint
750 compare_bblock (gconstpointer a, gconstpointer b)
751 {
752         const MonoBasicBlock *b1 = a;
753         const MonoBasicBlock *b2 = b;
754
755         return b2->cil_code - b1->cil_code;
756 }
757 #endif
758
759 /* *
760  * link_bblock: Links two basic blocks
761  *
762  * links two basic blocks in the control flow graph, the 'from'
763  * argument is the starting block and the 'to' argument is the block
764  * the control flow ends to after 'from'.
765  */
766 static void
767 link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
768 {
769         MonoBasicBlock **newa;
770         int i, found;
771
772 #if 0
773         if (from->cil_code) {
774                 if (to->cil_code)
775                         g_print ("edge from IL%04x to IL_%04x\n", from->cil_code - cfg->cil_code, to->cil_code - cfg->cil_code);
776                 else
777                         g_print ("edge from IL%04x to exit\n", from->cil_code - cfg->cil_code);
778         } else {
779                 if (to->cil_code)
780                         g_print ("edge from entry to IL_%04x\n", to->cil_code - cfg->cil_code);
781                 else
782                         g_print ("edge from entry to exit\n");
783         }
784 #endif
785         found = FALSE;
786         for (i = 0; i < from->out_count; ++i) {
787                 if (to == from->out_bb [i]) {
788                         found = TRUE;
789                         break;
790                 }
791         }
792         if (!found) {
793                 newa = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (from->out_count + 1));
794                 for (i = 0; i < from->out_count; ++i) {
795                         newa [i] = from->out_bb [i];
796                 }
797                 newa [i] = to;
798                 from->out_count++;
799                 from->out_bb = newa;
800         }
801
802         found = FALSE;
803         for (i = 0; i < to->in_count; ++i) {
804                 if (from == to->in_bb [i]) {
805                         found = TRUE;
806                         break;
807                 }
808         }
809         if (!found) {
810                 newa = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (to->in_count + 1));
811                 for (i = 0; i < to->in_count; ++i) {
812                         newa [i] = to->in_bb [i];
813                 }
814                 newa [i] = from;
815                 to->in_count++;
816                 to->in_bb = newa;
817         }
818 }
819
820 /**
821  * mono_unlink_bblock:
822  *
823  *   Unlink two basic blocks.
824  */
825 static void
826 mono_unlink_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
827 {
828         int i, pos;
829         gboolean found;
830
831         found = FALSE;
832         for (i = 0; i < from->out_count; ++i) {
833                 if (to == from->out_bb [i]) {
834                         found = TRUE;
835                         break;
836                 }
837         }
838         if (found) {
839                 pos = 0;
840                 for (i = 0; i < from->out_count; ++i) {
841                         if (from->out_bb [i] != to)
842                                 from->out_bb [pos ++] = from->out_bb [i];
843                 }
844                 g_assert (pos == from->out_count - 1);
845                 from->out_count--;
846         }
847
848         found = FALSE;
849         for (i = 0; i < to->in_count; ++i) {
850                 if (from == to->in_bb [i]) {
851                         found = TRUE;
852                         break;
853                 }
854         }
855         if (found) {
856                 pos = 0;
857                 for (i = 0; i < to->in_count; ++i) {
858                         if (to->in_bb [i] != from)
859                                 to->in_bb [pos ++] = to->in_bb [i];
860                 }
861                 g_assert (pos == to->in_count - 1);
862                 to->in_count--;
863         }
864 }
865
866 /**
867  * mono_find_block_region:
868  *
869  *   We mark each basic block with a region ID. We use that to avoid BB
870  *   optimizations when blocks are in different regions.
871  *
872  * Returns:
873  *   A region token that encodes where this region is, and information
874  *   about the clause owner for this block.
875  *
876  *   The region encodes the try/catch/filter clause that owns this block
877  *   as well as the type.  -1 is a special value that represents a block
878  *   that is in none of try/catch/filter.
879  */
880 static int
881 mono_find_block_region (MonoCompile *cfg, int offset)
882 {
883         MonoMethod *method = cfg->method;
884         MonoMethodHeader *header = mono_method_get_header (method);
885         MonoExceptionClause *clause;
886         int i;
887
888         /* first search for handlers and filters */
889         for (i = 0; i < header->num_clauses; ++i) {
890                 clause = &header->clauses [i];
891                 if ((clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) && (offset >= clause->data.filter_offset) &&
892                     (offset < (clause->handler_offset)))
893                         return ((i + 1) << 8) | MONO_REGION_FILTER | clause->flags;
894                            
895                 if (MONO_OFFSET_IN_HANDLER (clause, offset)) {
896                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY)
897                                 return ((i + 1) << 8) | MONO_REGION_FINALLY | clause->flags;
898                         else if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
899                                 return ((i + 1) << 8) | MONO_REGION_FAULT | clause->flags;
900                         else if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE)
901                                 return ((i + 1) << 8) | MONO_REGION_CATCH | clause->flags;
902                 }
903         }
904
905         /* search the try blocks */
906         for (i = 0; i < header->num_clauses; ++i) {
907                 clause = &header->clauses [i];
908                 if (MONO_OFFSET_IN_CLAUSE (clause, offset))
909                         return ((i + 1) << 8) | clause->flags;
910         }
911
912         return -1;
913 }
914
915 static GList*
916 mono_find_final_block (MonoCompile *cfg, unsigned char *ip, unsigned char *target, int type)
917 {
918         MonoMethod *method = cfg->method;
919         MonoMethodHeader *header = mono_method_get_header (method);
920         MonoExceptionClause *clause;
921         MonoBasicBlock *handler;
922         int i;
923         GList *res = NULL;
924
925         for (i = 0; i < header->num_clauses; ++i) {
926                 clause = &header->clauses [i];
927                 if (MONO_OFFSET_IN_CLAUSE (clause, (ip - header->code)) && 
928                     (!MONO_OFFSET_IN_CLAUSE (clause, (target - header->code)))) {
929                         if (clause->flags == type) {
930                                 handler = g_hash_table_lookup (cfg->bb_hash, header->code + clause->handler_offset);
931                                 g_assert (handler);
932                                 res = g_list_append (res, handler);
933                         }
934                 }
935         }
936         return res;
937 }
938
939 MonoInst *
940 mono_find_spvar_for_region (MonoCompile *cfg, int region)
941 {
942         return g_hash_table_lookup (cfg->spvars, GINT_TO_POINTER (region));
943 }
944
945 static void
946 mono_create_spvar_for_region (MonoCompile *cfg, int region)
947 {
948         MonoInst *var;
949
950         var = g_hash_table_lookup (cfg->spvars, GINT_TO_POINTER (region));
951         if (var)
952                 return;
953
954         var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
955         /* prevent it from being register allocated */
956         var->flags |= MONO_INST_INDIRECT;
957
958         g_hash_table_insert (cfg->spvars, GINT_TO_POINTER (region), var);
959 }
960
961 static MonoInst *
962 mono_find_exvar_for_offset (MonoCompile *cfg, int offset)
963 {
964         return g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
965 }
966
967 static MonoInst*
968 mono_create_exvar_for_offset (MonoCompile *cfg, int offset)
969 {
970         MonoInst *var;
971
972         var = g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
973         if (var)
974                 return var;
975
976         var = mono_compile_create_var (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL);
977         /* prevent it from being register allocated */
978         var->flags |= MONO_INST_INDIRECT;
979
980         g_hash_table_insert (cfg->exvars, GINT_TO_POINTER (offset), var);
981
982         return var;
983 }
984
985 static void
986 df_visit (MonoBasicBlock *start, int *dfn, MonoBasicBlock **array)
987 {
988         int i;
989
990         array [*dfn] = start;
991         /*g_print ("visit %d at %p (BB%ld)\n", *dfn, start->cil_code, start->block_num);*/
992         for (i = 0; i < start->out_count; ++i) {
993                 if (start->out_bb [i]->dfn)
994                         continue;
995                 (*dfn)++;
996                 start->out_bb [i]->dfn = *dfn;
997                 start->out_bb [i]->df_parent = start;
998                 array [*dfn] = start->out_bb [i];
999                 df_visit (start->out_bb [i], dfn, array);
1000         }
1001 }
1002
1003 typedef struct {
1004         const guchar *code;
1005         MonoBasicBlock *best;
1006 } PrevStruct;
1007
1008 static void
1009 previous_foreach (gconstpointer key, gpointer val, gpointer data)
1010 {
1011         PrevStruct *p = data;
1012         MonoBasicBlock *bb = val;
1013         //printf ("FIDPREV %d %p  %p %p %p %p %d %d %d\n", bb->block_num, p->code, bb, p->best, bb->cil_code, p->best->cil_code,
1014         //bb->method == p->best->method, bb->cil_code < p->code, bb->cil_code > p->best->cil_code);
1015
1016         if (bb->cil_code && bb->cil_code < p->code && bb->cil_code > p->best->cil_code)
1017                 p->best = bb;
1018 }
1019
1020 static MonoBasicBlock*
1021 find_previous (GHashTable *bb_hash, MonoBasicBlock *start, const guchar *code) {
1022         PrevStruct p;
1023
1024         p.code = code;
1025         p.best = start;
1026
1027         g_hash_table_foreach (bb_hash, (GHFunc)previous_foreach, &p);
1028         return p.best;
1029 }
1030
1031 static void
1032 split_bblock (MonoCompile *cfg, MonoBasicBlock *first, MonoBasicBlock *second) {
1033         int i, j;
1034         MonoInst *inst;
1035         MonoBasicBlock *bb;
1036
1037         if (second->code)
1038                 return;
1039         
1040         /* 
1041          * FIXME: take into account all the details:
1042          * second may have been the target of more than one bblock
1043          */
1044         second->out_count = first->out_count;
1045         second->out_bb = first->out_bb;
1046
1047         for (i = 0; i < first->out_count; ++i) {
1048                 bb = first->out_bb [i];
1049                 for (j = 0; j < bb->in_count; ++j) {
1050                         if (bb->in_bb [j] == first)
1051                                 bb->in_bb [j] = second;
1052                 }
1053         }
1054
1055         first->out_count = 0;
1056         first->out_bb = NULL;
1057         link_bblock (cfg, first, second);
1058
1059         second->last_ins = first->last_ins;
1060
1061         /*g_print ("start search at %p for %p\n", first->cil_code, second->cil_code);*/
1062         for (inst = first->code; inst && inst->next; inst = inst->next) {
1063                 /*char *code = mono_disasm_code_one (NULL, cfg->method, inst->next->cil_code, NULL);
1064                 g_print ("found %p: %s", inst->next->cil_code, code);
1065                 g_free (code);*/
1066                 if (inst->cil_code < second->cil_code && inst->next->cil_code >= second->cil_code) {
1067                         second->code = inst->next;
1068                         inst->next = NULL;
1069                         first->last_ins = inst;
1070                         second->next_bb = first->next_bb;
1071                         first->next_bb = second;
1072                         return;
1073                 }
1074         }
1075         if (!second->code) {
1076                 g_warning ("bblock split failed in %s::%s\n", cfg->method->klass->name, cfg->method->name);
1077                 //G_BREAKPOINT ();
1078         }
1079 }
1080
1081 static guint32
1082 reverse_branch_op (guint32 opcode)
1083 {
1084         static const int reverse_map [] = {
1085                 CEE_BNE_UN, CEE_BLT, CEE_BLE, CEE_BGT, CEE_BGE,
1086                 CEE_BEQ, CEE_BLT_UN, CEE_BLE_UN, CEE_BGT_UN, CEE_BGE_UN
1087         };
1088         static const int reverse_fmap [] = {
1089                 OP_FBNE_UN, OP_FBLT, OP_FBLE, OP_FBGT, OP_FBGE,
1090                 OP_FBEQ, OP_FBLT_UN, OP_FBLE_UN, OP_FBGT_UN, OP_FBGE_UN
1091         };
1092         static const int reverse_lmap [] = {
1093                 OP_LBNE_UN, OP_LBLT, OP_LBLE, OP_LBGT, OP_LBGE,
1094                 OP_LBEQ, OP_LBLT_UN, OP_LBLE_UN, OP_LBGT_UN, OP_LBGE_UN
1095         };
1096         static const int reverse_imap [] = {
1097                 OP_IBNE_UN, OP_IBLT, OP_IBLE, OP_IBGT, OP_IBGE,
1098                 OP_IBEQ, OP_IBLT_UN, OP_IBLE_UN, OP_IBGT_UN, OP_IBGE_UN
1099         };
1100                                 
1101         if (opcode >= CEE_BEQ && opcode <= CEE_BLT_UN) {
1102                 opcode = reverse_map [opcode - CEE_BEQ];
1103         } else if (opcode >= OP_FBEQ && opcode <= OP_FBLT_UN) {
1104                 opcode = reverse_fmap [opcode - OP_FBEQ];
1105         } else if (opcode >= OP_LBEQ && opcode <= OP_LBLT_UN) {
1106                 opcode = reverse_lmap [opcode - OP_LBEQ];
1107         } else if (opcode >= OP_IBEQ && opcode <= OP_IBLT_UN) {
1108                 opcode = reverse_imap [opcode - OP_IBEQ];
1109         } else
1110                 g_assert_not_reached ();
1111
1112         return opcode;
1113 }
1114
1115 #ifdef MONO_ARCH_SOFT_FLOAT
1116 static int
1117 condbr_to_fp_br (int opcode)
1118 {
1119         switch (opcode) {
1120         case CEE_BEQ: return OP_FBEQ;
1121         case CEE_BGE: return OP_FBGE;
1122         case CEE_BGT: return OP_FBGT;
1123         case CEE_BLE: return OP_FBLE;
1124         case CEE_BLT: return OP_FBLT;
1125         case CEE_BNE_UN: return OP_FBNE_UN;
1126         case CEE_BGE_UN: return OP_FBGE_UN;
1127         case CEE_BGT_UN: return OP_FBGT_UN;
1128         case CEE_BLE_UN: return OP_FBLE_UN;
1129         case CEE_BLT_UN: return OP_FBLT_UN;
1130         }
1131         g_assert_not_reached ();
1132         return 0;
1133 }
1134 #endif
1135
1136 /*
1137  * Returns the type used in the eval stack when @type is loaded.
1138  * FIXME: return a MonoType/MonoClass for the byref and VALUETYPE cases.
1139  */
1140 static void
1141 type_to_eval_stack_type (MonoType *type, MonoInst *inst)
1142 {
1143         MonoClass *klass;
1144
1145         inst->klass = klass = mono_class_from_mono_type (type);
1146         if (type->byref) {
1147                 inst->type = STACK_MP;
1148                 return;
1149         }
1150
1151 handle_enum:
1152         switch (type->type) {
1153         case MONO_TYPE_VOID:
1154                 inst->type = STACK_INV;
1155                 return;
1156         case MONO_TYPE_I1:
1157         case MONO_TYPE_U1:
1158         case MONO_TYPE_BOOLEAN:
1159         case MONO_TYPE_I2:
1160         case MONO_TYPE_U2:
1161         case MONO_TYPE_CHAR:
1162         case MONO_TYPE_I4:
1163         case MONO_TYPE_U4:
1164                 inst->type = STACK_I4;
1165                 return;
1166         case MONO_TYPE_I:
1167         case MONO_TYPE_U:
1168         case MONO_TYPE_PTR:
1169         case MONO_TYPE_FNPTR:
1170                 inst->type = STACK_PTR;
1171                 return;
1172         case MONO_TYPE_CLASS:
1173         case MONO_TYPE_STRING:
1174         case MONO_TYPE_OBJECT:
1175         case MONO_TYPE_SZARRAY:
1176         case MONO_TYPE_ARRAY:    
1177                 inst->type = STACK_OBJ;
1178                 return;
1179         case MONO_TYPE_I8:
1180         case MONO_TYPE_U8:
1181                 inst->type = STACK_I8;
1182                 return;
1183         case MONO_TYPE_R4:
1184         case MONO_TYPE_R8:
1185                 inst->type = STACK_R8;
1186                 return;
1187         case MONO_TYPE_VALUETYPE:
1188                 if (type->data.klass->enumtype) {
1189                         type = type->data.klass->enum_basetype;
1190                         goto handle_enum;
1191                 } else {
1192                         inst->klass = klass;
1193                         inst->type = STACK_VTYPE;
1194                         return;
1195                 }
1196         case MONO_TYPE_TYPEDBYREF:
1197                 inst->klass = mono_defaults.typed_reference_class;
1198                 inst->type = STACK_VTYPE;
1199                 return;
1200         case MONO_TYPE_GENERICINST:
1201                 type = &type->data.generic_class->container_class->byval_arg;
1202                 goto handle_enum;
1203         default:
1204                 g_error ("unknown type 0x%02x in eval stack type", type->type);
1205         }
1206 }
1207
1208 /*
1209  * The following tables are used to quickly validate the IL code in type_from_op ().
1210  */
1211 static const char
1212 bin_num_table [STACK_MAX] [STACK_MAX] = {
1213         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1214         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
1215         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1216         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
1217         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_R8,  STACK_INV, STACK_INV, STACK_INV},
1218         {STACK_INV, STACK_MP,  STACK_INV, STACK_MP,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV},
1219         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1220         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
1221 };
1222
1223 static const char 
1224 neg_table [] = {
1225         STACK_INV, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_INV, STACK_INV, STACK_INV
1226 };
1227
1228 /* reduce the size of this table */
1229 static const char
1230 bin_int_table [STACK_MAX] [STACK_MAX] = {
1231         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1232         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1233         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1234         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1235         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1236         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1237         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1238         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
1239 };
1240
1241 static const char
1242 bin_comp_table [STACK_MAX] [STACK_MAX] = {
1243 /*      Inv i  L  p  F  &  O  vt */
1244         {0},
1245         {0, 1, 0, 1, 0, 0, 0, 0}, /* i, int32 */
1246         {0, 0, 1, 0, 0, 0, 0, 0}, /* L, int64 */
1247         {0, 1, 0, 1, 0, 2, 4, 0}, /* p, ptr */
1248         {0, 0, 0, 0, 1, 0, 0, 0}, /* F, R8 */
1249         {0, 0, 0, 2, 0, 1, 0, 0}, /* &, managed pointer */
1250         {0, 0, 0, 4, 0, 0, 3, 0}, /* O, reference */
1251         {0, 0, 0, 0, 0, 0, 0, 0}, /* vt value type */
1252 };
1253
1254 /* reduce the size of this table */
1255 static const char
1256 shift_table [STACK_MAX] [STACK_MAX] = {
1257         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1258         {STACK_INV, STACK_I4,  STACK_INV, STACK_I4,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1259         {STACK_INV, STACK_I8,  STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1260         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1261         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1262         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1263         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1264         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
1265 };
1266
1267 /*
1268  * Tables to map from the non-specific opcode to the matching
1269  * type-specific opcode.
1270  */
1271 /* handles from CEE_ADD to CEE_SHR_UN (CEE_REM_UN for floats) */
1272 static const guint16
1273 binops_op_map [STACK_MAX] = {
1274         0, 0, OP_LADD-CEE_ADD, OP_PADD-CEE_ADD, OP_FADD-CEE_ADD, OP_PADD-CEE_ADD
1275 };
1276
1277 /* handles from CEE_NEG to CEE_CONV_U8 */
1278 static const guint16
1279 unops_op_map [STACK_MAX] = {
1280         0, 0, OP_LNEG-CEE_NEG, OP_PNEG-CEE_NEG, OP_FNEG-CEE_NEG, OP_PNEG-CEE_NEG
1281 };
1282
1283 /* handles from CEE_CONV_U2 to CEE_SUB_OVF_UN */
1284 static const guint16
1285 ovfops_op_map [STACK_MAX] = {
1286         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
1287 };
1288
1289 /* handles from CEE_CONV_OVF_I1_UN to CEE_CONV_OVF_U_UN */
1290 static const guint16
1291 ovf2ops_op_map [STACK_MAX] = {
1292         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
1293 };
1294
1295 /* handles from CEE_CONV_OVF_I1 to CEE_CONV_OVF_U8 */
1296 static const guint16
1297 ovf3ops_op_map [STACK_MAX] = {
1298         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
1299 };
1300
1301 /* handles from CEE_CEQ to CEE_CLT_UN */
1302 static const guint16
1303 ceqops_op_map [STACK_MAX] = {
1304         0, 0, OP_LCEQ-OP_CEQ, OP_PCEQ-OP_CEQ, OP_FCEQ-OP_CEQ, OP_LCEQ-OP_CEQ
1305 };
1306
1307 /*
1308  * Sets ins->type (the type on the eval stack) according to the
1309  * type of the opcode and the arguments to it.
1310  * Invalid IL code is marked by setting ins->type to the invalid value STACK_INV.
1311  *
1312  * FIXME: this function sets ins->type unconditionally in some cases, but
1313  * it should set it to invalid for some types (a conv.x on an object)
1314  */
1315 static void
1316 type_from_op (MonoInst *ins) {
1317         switch (ins->opcode) {
1318         /* binops */
1319         case CEE_ADD:
1320         case CEE_SUB:
1321         case CEE_MUL:
1322         case CEE_DIV:
1323         case CEE_REM:
1324                 /* FIXME: check unverifiable args for STACK_MP */
1325                 ins->type = bin_num_table [ins->inst_i0->type] [ins->inst_i1->type];
1326                 ins->opcode += binops_op_map [ins->type];
1327                 return;
1328         case CEE_DIV_UN:
1329         case CEE_REM_UN:
1330         case CEE_AND:
1331         case CEE_OR:
1332         case CEE_XOR:
1333                 ins->type = bin_int_table [ins->inst_i0->type] [ins->inst_i1->type];
1334                 ins->opcode += binops_op_map [ins->type];
1335                 return;
1336         case CEE_SHL:
1337         case CEE_SHR:
1338         case CEE_SHR_UN:
1339                 ins->type = shift_table [ins->inst_i0->type] [ins->inst_i1->type];
1340                 ins->opcode += binops_op_map [ins->type];
1341                 return;
1342         case OP_COMPARE:
1343         case OP_LCOMPARE:
1344                 /* FIXME: handle some specifics with ins->next->type */
1345                 ins->type = bin_comp_table [ins->inst_i0->type] [ins->inst_i1->type] ? STACK_I4: STACK_INV;
1346                 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))))
1347                         ins->opcode = OP_LCOMPARE;
1348                 return;
1349         case OP_CEQ:
1350                 ins->type = bin_comp_table [ins->inst_i0->type] [ins->inst_i1->type] ? STACK_I4: STACK_INV;
1351                 ins->opcode += ceqops_op_map [ins->inst_i0->type];
1352                 return;
1353                 
1354         case OP_CGT:
1355         case OP_CGT_UN:
1356         case OP_CLT:
1357         case OP_CLT_UN:
1358                 ins->type = (bin_comp_table [ins->inst_i0->type] [ins->inst_i1->type] & 1) ? STACK_I4: STACK_INV;
1359                 ins->opcode += ceqops_op_map [ins->inst_i0->type];
1360                 return;
1361         /* unops */
1362         case CEE_NEG:
1363                 ins->type = neg_table [ins->inst_i0->type];
1364                 ins->opcode += unops_op_map [ins->type];
1365                 return;
1366         case CEE_NOT:
1367                 if (ins->inst_i0->type >= STACK_I4 && ins->inst_i0->type <= STACK_PTR)
1368                         ins->type = ins->inst_i0->type;
1369                 else
1370                         ins->type = STACK_INV;
1371                 ins->opcode += unops_op_map [ins->type];
1372                 return;
1373         case CEE_CONV_I1:
1374         case CEE_CONV_I2:
1375         case CEE_CONV_I4:
1376         case CEE_CONV_U4:
1377                 ins->type = STACK_I4;
1378                 ins->opcode += unops_op_map [ins->inst_i0->type];
1379                 return;
1380         case CEE_CONV_R_UN:
1381                 ins->type = STACK_R8;
1382                 switch (ins->inst_i0->type) {
1383                 case STACK_I4:
1384                 case STACK_PTR:
1385                         break;
1386                 case STACK_I8:
1387                         ins->opcode = OP_LCONV_TO_R_UN; 
1388                         break;
1389                 }
1390                 return;
1391         case CEE_CONV_OVF_I1:
1392         case CEE_CONV_OVF_U1:
1393         case CEE_CONV_OVF_I2:
1394         case CEE_CONV_OVF_U2:
1395         case CEE_CONV_OVF_I4:
1396         case CEE_CONV_OVF_U4:
1397                 ins->type = STACK_I4;
1398                 ins->opcode += ovf3ops_op_map [ins->inst_i0->type];
1399                 return;
1400         case CEE_CONV_OVF_I_UN:
1401         case CEE_CONV_OVF_U_UN:
1402                 ins->type = STACK_PTR;
1403                 ins->opcode += ovf2ops_op_map [ins->inst_i0->type];
1404                 return;
1405         case CEE_CONV_OVF_I1_UN:
1406         case CEE_CONV_OVF_I2_UN:
1407         case CEE_CONV_OVF_I4_UN:
1408         case CEE_CONV_OVF_U1_UN:
1409         case CEE_CONV_OVF_U2_UN:
1410         case CEE_CONV_OVF_U4_UN:
1411                 ins->type = STACK_I4;
1412                 ins->opcode += ovf2ops_op_map [ins->inst_i0->type];
1413                 return;
1414         case CEE_CONV_U:
1415                 ins->type = STACK_PTR;
1416                 switch (ins->inst_i0->type) {
1417                 case STACK_I4:
1418                         break;
1419                 case STACK_PTR:
1420                 case STACK_MP:
1421 #if SIZEOF_VOID_P == 8
1422                         ins->opcode = OP_LCONV_TO_U;
1423 #endif
1424                         break;
1425                 case STACK_I8:
1426                         ins->opcode = OP_LCONV_TO_U;
1427                         break;
1428                 case STACK_R8:
1429                         ins->opcode = OP_FCONV_TO_U;
1430                         break;
1431                 }
1432                 return;
1433         case CEE_CONV_I8:
1434         case CEE_CONV_U8:
1435                 ins->type = STACK_I8;
1436                 ins->opcode += unops_op_map [ins->inst_i0->type];
1437                 return;
1438         case CEE_CONV_OVF_I8:
1439         case CEE_CONV_OVF_U8:
1440                 ins->type = STACK_I8;
1441                 ins->opcode += ovf3ops_op_map [ins->inst_i0->type];
1442                 return;
1443         case CEE_CONV_OVF_U8_UN:
1444         case CEE_CONV_OVF_I8_UN:
1445                 ins->type = STACK_I8;
1446                 ins->opcode += ovf2ops_op_map [ins->inst_i0->type];
1447                 return;
1448         case CEE_CONV_R4:
1449         case CEE_CONV_R8:
1450                 ins->type = STACK_R8;
1451                 ins->opcode += unops_op_map [ins->inst_i0->type];
1452                 return;
1453         case CEE_CKFINITE:
1454                 ins->type = STACK_R8;           
1455                 return;
1456         case CEE_CONV_U2:
1457         case CEE_CONV_U1:
1458                 ins->type = STACK_I4;
1459                 ins->opcode += ovfops_op_map [ins->inst_i0->type];
1460                 break;
1461         case CEE_CONV_I:
1462         case CEE_CONV_OVF_I:
1463         case CEE_CONV_OVF_U:
1464                 ins->type = STACK_PTR;
1465                 ins->opcode += ovfops_op_map [ins->inst_i0->type];
1466                 return;
1467         case CEE_ADD_OVF:
1468         case CEE_ADD_OVF_UN:
1469         case CEE_MUL_OVF:
1470         case CEE_MUL_OVF_UN:
1471         case CEE_SUB_OVF:
1472         case CEE_SUB_OVF_UN:
1473                 ins->type = bin_num_table [ins->inst_i0->type] [ins->inst_i1->type];
1474                 ins->opcode += ovfops_op_map [ins->inst_i0->type];
1475                 return;
1476         default:
1477                 g_error ("opcode 0x%04x not handled in type from op", ins->opcode);
1478                 break;
1479         }
1480 }
1481
1482 static const char 
1483 ldind_type [] = {
1484         STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_R8, STACK_OBJ
1485 };
1486
1487 /* map ldelem.x to the matching ldind.x opcode */
1488 static const guchar
1489 ldelem_to_ldind [] = {
1490         CEE_LDIND_I1,
1491         CEE_LDIND_U1,
1492         CEE_LDIND_I2,
1493         CEE_LDIND_U2,
1494         CEE_LDIND_I4,
1495         CEE_LDIND_U4,
1496         CEE_LDIND_I8,
1497         CEE_LDIND_I,
1498         CEE_LDIND_R4,
1499         CEE_LDIND_R8,
1500         CEE_LDIND_REF
1501 };
1502
1503 /* map stelem.x to the matching stind.x opcode */
1504 static const guchar
1505 stelem_to_stind [] = {
1506         CEE_STIND_I,
1507         CEE_STIND_I1,
1508         CEE_STIND_I2,
1509         CEE_STIND_I4,
1510         CEE_STIND_I8,
1511         CEE_STIND_R4,
1512         CEE_STIND_R8,
1513         CEE_STIND_REF
1514 };
1515
1516 #if 0
1517
1518 static const char
1519 param_table [STACK_MAX] [STACK_MAX] = {
1520         {0},
1521 };
1522
1523 static int
1524 check_values_to_signature (MonoInst *args, MonoType *this, MonoMethodSignature *sig) {
1525         int i;
1526
1527         if (sig->hasthis) {
1528                 switch (args->type) {
1529                 case STACK_I4:
1530                 case STACK_I8:
1531                 case STACK_R8:
1532                 case STACK_VTYPE:
1533                 case STACK_INV:
1534                         return 0;
1535                 }
1536                 args++;
1537         }
1538         for (i = 0; i < sig->param_count; ++i) {
1539                 switch (args [i].type) {
1540                 case STACK_INV:
1541                         return 0;
1542                 case STACK_MP:
1543                         if (!sig->params [i]->byref)
1544                                 return 0;
1545                         continue;
1546                 case STACK_OBJ:
1547                         if (sig->params [i]->byref)
1548                                 return 0;
1549                         switch (sig->params [i]->type) {
1550                         case MONO_TYPE_CLASS:
1551                         case MONO_TYPE_STRING:
1552                         case MONO_TYPE_OBJECT:
1553                         case MONO_TYPE_SZARRAY:
1554                         case MONO_TYPE_ARRAY:
1555                                 break;
1556                         default:
1557                                 return 0;
1558                         }
1559                         continue;
1560                 case STACK_R8:
1561                         if (sig->params [i]->byref)
1562                                 return 0;
1563                         if (sig->params [i]->type != MONO_TYPE_R4 && sig->params [i]->type != MONO_TYPE_R8)
1564                                 return 0;
1565                         continue;
1566                 case STACK_PTR:
1567                 case STACK_I4:
1568                 case STACK_I8:
1569                 case STACK_VTYPE:
1570                         break;
1571                 }
1572                 /*if (!param_table [args [i].type] [sig->params [i]->type])
1573                         return 0;*/
1574         }
1575         return 1;
1576 }
1577 #endif
1578
1579 /*
1580  * When we need a pointer to the current domain many times in a method, we
1581  * call mono_domain_get() once and we store the result in a local variable.
1582  * This function returns the variable that represents the MonoDomain*.
1583  */
1584 inline static MonoInst *
1585 mono_get_domainvar (MonoCompile *cfg)
1586 {
1587         if (!cfg->domainvar)
1588                 cfg->domainvar = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1589         return cfg->domainvar;
1590 }
1591
1592 /*
1593  * The got_var contains the address of the Global Offset Table when AOT 
1594  * compiling.
1595  */
1596 inline static MonoInst *
1597 mono_get_got_var (MonoCompile *cfg)
1598 {
1599 #ifdef MONO_ARCH_NEED_GOT_VAR
1600         if (!cfg->compile_aot)
1601                 return NULL;
1602         if (!cfg->got_var) {
1603                 cfg->got_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1604         }
1605         return cfg->got_var;
1606 #else
1607         return NULL;
1608 #endif
1609 }
1610
1611 MonoInst*
1612 mono_compile_create_var (MonoCompile *cfg, MonoType *type, int opcode)
1613 {
1614         MonoInst *inst;
1615         int num = cfg->num_varinfo;
1616
1617         if ((num + 1) >= cfg->varinfo_count) {
1618                 cfg->varinfo_count = (cfg->varinfo_count + 2) * 2;
1619                 cfg->varinfo = (MonoInst **)g_realloc (cfg->varinfo, sizeof (MonoInst*) * cfg->varinfo_count);
1620                 cfg->vars = (MonoMethodVar **)g_realloc (cfg->vars, sizeof (MonoMethodVar*) * cfg->varinfo_count);      
1621         }
1622
1623         /*g_print ("created temp %d of type 0x%x\n", num, type->type);*/
1624         mono_jit_stats.allocate_var++;
1625
1626         MONO_INST_NEW (cfg, inst, opcode);
1627         inst->inst_c0 = num;
1628         inst->inst_vtype = type;
1629         inst->klass = mono_class_from_mono_type (type);
1630         /* if set to 1 the variable is native */
1631         inst->backend.is_pinvoke = 0;
1632
1633         cfg->varinfo [num] = inst;
1634
1635         cfg->vars [num] = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoMethodVar));
1636         MONO_INIT_VARINFO (cfg->vars [num], num);
1637
1638         cfg->num_varinfo++;
1639         if (cfg->verbose_level > 2)
1640                 g_print ("created temp %d of type %s\n", num, mono_type_get_name (type));
1641         return inst;
1642 }
1643
1644 /*
1645  * Transform a MonoInst into a load from the variable of index var_index.
1646  */
1647 void
1648 mono_compile_make_var_load (MonoCompile *cfg, MonoInst *dest, gssize var_index) {
1649         memset (dest, 0, sizeof (MonoInst));
1650         dest->ssa_op = MONO_SSA_LOAD;
1651         dest->inst_i0 = cfg->varinfo [var_index];
1652         dest->opcode = mono_type_to_ldind (dest->inst_i0->inst_vtype);
1653         type_to_eval_stack_type (dest->inst_i0->inst_vtype, dest);
1654         dest->klass = dest->inst_i0->klass;
1655 }
1656
1657 /*
1658  * Create a MonoInst that is a load from the variable of index var_index.
1659  */
1660 MonoInst*
1661 mono_compile_create_var_load (MonoCompile *cfg, gssize var_index) {
1662         MonoInst *dest;
1663         NEW_TEMPLOAD (cfg,dest,var_index);
1664         return dest;
1665 }
1666
1667 /*
1668  * Create a MonoInst that is a store of the given value into the variable of index var_index.
1669  */
1670 MonoInst*
1671 mono_compile_create_var_store (MonoCompile *cfg, gssize var_index, MonoInst *value) {
1672         MonoInst *dest;
1673         NEW_TEMPSTORE (cfg, dest, var_index, value);
1674         return dest;
1675 }
1676
1677 static MonoType*
1678 type_from_stack_type (MonoInst *ins) {
1679         switch (ins->type) {
1680         case STACK_I4: return &mono_defaults.int32_class->byval_arg;
1681         case STACK_I8: return &mono_defaults.int64_class->byval_arg;
1682         case STACK_PTR: return &mono_defaults.int_class->byval_arg;
1683         case STACK_R8: return &mono_defaults.double_class->byval_arg;
1684         case STACK_MP:
1685                 /* 
1686                  * this if used to be commented without any specific reason, but
1687                  * it breaks #80235 when commented
1688                  */
1689                 if (ins->klass)
1690                         return &ins->klass->this_arg;
1691                 else
1692                         return &mono_defaults.object_class->this_arg;
1693         case STACK_OBJ:
1694                 /* ins->klass may not be set for ldnull.
1695                  * Also, if we have a boxed valuetype, we want an object lass,
1696                  * not the valuetype class
1697                  */
1698                 if (ins->klass && !ins->klass->valuetype)
1699                         return &ins->klass->byval_arg;
1700                 return &mono_defaults.object_class->byval_arg;
1701         case STACK_VTYPE: return &ins->klass->byval_arg;
1702         default:
1703                 g_error ("stack type %d to montype not handled\n", ins->type);
1704         }
1705         return NULL;
1706 }
1707
1708 MonoType*
1709 mono_type_from_stack_type (MonoInst *ins) {
1710         return type_from_stack_type (ins);
1711 }
1712
1713 static MonoClass*
1714 array_access_to_klass (int opcode, MonoInst *array_obj)
1715 {
1716         switch (opcode) {
1717         case CEE_LDELEM_U1:
1718                 return mono_defaults.byte_class;
1719         case CEE_LDELEM_U2:
1720                 return mono_defaults.uint16_class;
1721         case CEE_LDELEM_I:
1722         case CEE_STELEM_I:
1723                 return mono_defaults.int_class;
1724         case CEE_LDELEM_I1:
1725         case CEE_STELEM_I1:
1726                 return mono_defaults.sbyte_class;
1727         case CEE_LDELEM_I2:
1728         case CEE_STELEM_I2:
1729                 return mono_defaults.int16_class;
1730         case CEE_LDELEM_I4:
1731         case CEE_STELEM_I4:
1732                 return mono_defaults.int32_class;
1733         case CEE_LDELEM_U4:
1734                 return mono_defaults.uint32_class;
1735         case CEE_LDELEM_I8:
1736         case CEE_STELEM_I8:
1737                 return mono_defaults.int64_class;
1738         case CEE_LDELEM_R4:
1739         case CEE_STELEM_R4:
1740                 return mono_defaults.single_class;
1741         case CEE_LDELEM_R8:
1742         case CEE_STELEM_R8:
1743                 return mono_defaults.double_class;
1744         case CEE_LDELEM_REF:
1745         case CEE_STELEM_REF: {
1746                 MonoClass *klass = array_obj->klass;
1747                 /* FIXME: add assert */
1748                 if (klass && klass->rank)
1749                         return klass->element_class;
1750                 return mono_defaults.object_class;
1751         }
1752         default:
1753                 g_assert_not_reached ();
1754         }
1755         return NULL;
1756 }
1757
1758 void
1759 mono_add_ins_to_end (MonoBasicBlock *bb, MonoInst *inst)
1760 {
1761         MonoInst *prev;
1762         if (!bb->code) {
1763                 MONO_ADD_INS (bb, inst);
1764                 return;
1765         }
1766         switch (bb->last_ins->opcode) {
1767         case CEE_BEQ:
1768         case CEE_BGE:
1769         case CEE_BGT:
1770         case CEE_BLE:
1771         case CEE_BLT:
1772         case CEE_BNE_UN:
1773         case CEE_BGE_UN:
1774         case CEE_BGT_UN:
1775         case CEE_BLE_UN:
1776         case CEE_BLT_UN:
1777         case CEE_BR:
1778         case CEE_SWITCH:
1779                 prev = bb->code;
1780                 while (prev->next && prev->next != bb->last_ins)
1781                         prev = prev->next;
1782                 if (prev == bb->code) {
1783                         if (bb->last_ins == bb->code) {
1784                                 inst->next = bb->code;
1785                                 bb->code = inst;
1786                         } else {
1787                                 inst->next = prev->next;
1788                                 prev->next = inst;
1789                         }
1790                 } else {
1791                         inst->next = bb->last_ins;
1792                         prev->next = inst;
1793                 }
1794                 break;
1795         //      g_warning ("handle conditional jump in add_ins_to_end ()\n");
1796         default:
1797                 MONO_ADD_INS (bb, inst);
1798                 break;
1799         }
1800 }
1801
1802 void
1803 mono_add_varcopy_to_end (MonoCompile *cfg, MonoBasicBlock *bb, int src, int dest)
1804 {
1805         MonoInst *inst, *load;
1806
1807         NEW_TEMPLOAD (cfg, load, src);
1808
1809         NEW_TEMPSTORE (cfg, inst, dest, load);
1810         if (inst->opcode == CEE_STOBJ) {
1811                 NEW_TEMPLOADA (cfg, inst, dest);
1812                 handle_stobj (cfg, bb, inst, load, NULL, inst->klass, TRUE, FALSE, FALSE);
1813         } else {
1814                 inst->cil_code = NULL;
1815                 mono_add_ins_to_end (bb, inst);
1816         }
1817 }
1818
1819 /*
1820  * We try to share variables when possible
1821  */
1822 static MonoInst *
1823 mono_compile_get_interface_var (MonoCompile *cfg, int slot, MonoInst *ins)
1824 {
1825         MonoInst *res;
1826         int pos, vnum;
1827
1828         /* inlining can result in deeper stacks */ 
1829         if (slot >= mono_method_get_header (cfg->method)->max_stack)
1830                 return mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1831
1832         pos = ins->type - 1 + slot * STACK_MAX;
1833
1834         switch (ins->type) {
1835         case STACK_I4:
1836         case STACK_I8:
1837         case STACK_R8:
1838         case STACK_PTR:
1839         case STACK_MP:
1840         case STACK_OBJ:
1841                 if ((vnum = cfg->intvars [pos]))
1842                         return cfg->varinfo [vnum];
1843                 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1844                 cfg->intvars [pos] = res->inst_c0;
1845                 break;
1846         default:
1847                 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1848         }
1849         return res;
1850 }
1851
1852 /*
1853  * merge_stacks:
1854  *
1855  * Merge stack state between two basic blocks according to Ecma 335, Partition III,
1856  * section 1.8.1.1. Store the resulting stack state into stack_2.
1857  * Returns: TRUE, if verification succeeds, FALSE otherwise.
1858  * FIXME: We should store the stack state in a dedicated structure instead of in
1859  * MonoInst's.
1860  */
1861 static gboolean
1862 merge_stacks (MonoCompile *cfg, MonoStackSlot *state_1, MonoStackSlot *state_2, guint32 size)
1863 {
1864         int i;
1865
1866         if (cfg->dont_verify_stack_merge)
1867                 return TRUE;
1868
1869         /* FIXME: Implement all checks from the spec */
1870
1871         for (i = 0; i < size; ++i) {
1872                 MonoStackSlot *slot1 = &state_1 [i];
1873                 MonoStackSlot *slot2 = &state_2 [i];
1874
1875                 if (slot1->type != slot2->type)
1876                         return FALSE;
1877
1878                 switch (slot1->type) {
1879                 case STACK_PTR:
1880                         /* FIXME: Perform merge ? */
1881                         /* klass == NULL means a native int */
1882                         if (slot1->klass && slot2->klass) {
1883                                 if (slot1->klass != slot2->klass)
1884                                         return FALSE;
1885                         }
1886                         break;
1887                 case STACK_MP:
1888                         /* FIXME: Change this to an assert and fix the JIT to allways fill this */
1889                         if (slot1->klass && slot2->klass) {
1890                                 if (slot1->klass != slot2->klass)
1891                                         return FALSE;
1892                         }
1893                         break;
1894                 case STACK_OBJ: {
1895                         MonoClass *klass1 = slot1->klass;
1896                         MonoClass *klass2 = slot2->klass;
1897
1898                         if (!klass1) {
1899                                 /* slot1 is ldnull */
1900                         } else if (!klass2) {
1901                                 /* slot2 is ldnull */
1902                                 slot2->klass = slot1->klass;
1903                         }
1904                         break;
1905                 }
1906                 }
1907         }
1908
1909         return TRUE;
1910 }
1911
1912 /*
1913  * This function is called to handle items that are left on the evaluation stack
1914  * at basic block boundaries. What happens is that we save the values to local variables
1915  * and we reload them later when first entering the target basic block (with the
1916  * handle_loaded_temps () function).
1917  * It is also used to handle items on the stack in store opcodes, since it is
1918  * possible that the variable to be stored into is already on the stack, in
1919  * which case its old value should be used.
1920  * A single joint point will use the same variables (stored in the array bb->out_stack or
1921  * bb->in_stack, if the basic block is before or after the joint point).
1922  * If the stack merge fails at a join point, cfg->unverifiable is set.
1923  */
1924 static int
1925 handle_stack_args (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst **sp, int count) {
1926         int i, bindex;
1927         MonoBasicBlock *outb;
1928         MonoInst *inst, **locals;
1929         MonoStackSlot *stack_state;
1930         gboolean found;
1931
1932         if (!count)
1933                 return 0;
1934         if (cfg->verbose_level > 3)
1935                 g_print ("%d item(s) on exit from B%d\n", count, bb->block_num);
1936
1937         stack_state = mono_mempool_alloc (cfg->mempool, sizeof (MonoStackSlot) * count);
1938         for (i = 0; i < count; ++i) {
1939                 stack_state [i].type = sp [i]->type;
1940                 stack_state [i].klass = sp [i]->klass;
1941
1942                 /* Check that instructions other than ldnull have ins->klass set */
1943                 if (!cfg->dont_verify_stack_merge && (sp [i]->type == STACK_OBJ) && !((sp [i]->opcode == OP_PCONST) && sp [i]->inst_c0 == 0))
1944                         g_assert (sp [i]->klass);
1945         }
1946
1947         /* Perform verification and stack state merge */
1948         for (i = 0; i < bb->out_count; ++i) {
1949                 outb = bb->out_bb [i];
1950
1951                 /* exception handlers are linked, but they should not be considered for stack args */
1952                 if (outb->flags & BB_EXCEPTION_HANDLER)
1953                         continue;
1954                 if (outb->stack_state) {
1955                         gboolean verified;
1956
1957                         if (count != outb->in_scount) {
1958                                 cfg->unverifiable = TRUE;
1959                                 return 0;
1960                         }
1961                         verified = merge_stacks (cfg, stack_state, outb->stack_state, count);
1962                         if (!verified) {
1963                                 cfg->unverifiable = TRUE;
1964                                 return 0;
1965                         }
1966
1967                         if (cfg->verbose_level > 3) {
1968                                 int j;
1969
1970                                 for (j = 0; j < count; ++j)
1971                                         printf ("\tStack state of BB%d, slot %d=%d\n", outb->block_num, j, outb->stack_state [j].type);
1972                         }
1973                 } else {
1974                         /* Make a copy of the stack state */
1975                         outb->stack_state = mono_mempool_alloc (cfg->mempool, sizeof (MonoStackSlot) * count);
1976                         memcpy (outb->stack_state, stack_state, sizeof (MonoStackSlot) * count);
1977                 }
1978         }
1979
1980         if (!bb->out_scount) {
1981                 bb->out_scount = count;
1982                 //g_print ("bblock %d has out:", bb->block_num);
1983                 found = FALSE;
1984                 for (i = 0; i < bb->out_count; ++i) {
1985                         outb = bb->out_bb [i];
1986                         /* exception handlers are linked, but they should not be considered for stack args */
1987                         if (outb->flags & BB_EXCEPTION_HANDLER)
1988                                 continue;
1989                         //g_print (" %d", outb->block_num);
1990                         if (outb->in_stack) {
1991                                 found = TRUE;
1992                                 bb->out_stack = outb->in_stack;
1993                                 break;
1994                         }
1995                 }
1996                 //g_print ("\n");
1997                 if (!found) {
1998                         bb->out_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * count);
1999                         for (i = 0; i < count; ++i) {
2000                                 /* 
2001                                  * try to reuse temps already allocated for this purpouse, if they occupy the same
2002                                  * stack slot and if they are of the same type.
2003                                  * This won't cause conflicts since if 'local' is used to 
2004                                  * store one of the values in the in_stack of a bblock, then
2005                                  * the same variable will be used for the same outgoing stack 
2006                                  * slot as well. 
2007                                  * This doesn't work when inlining methods, since the bblocks
2008                                  * in the inlined methods do not inherit their in_stack from
2009                                  * the bblock they are inlined to. See bug #58863 for an
2010                                  * example.
2011                                  * This hack is disabled since it also prevents proper tracking of types.
2012                                  */
2013 #if 1
2014                                 bb->out_stack [i] = mono_compile_create_var (cfg, type_from_stack_type (sp [i]), OP_LOCAL);
2015 #else
2016                                 if (cfg->inlined_method)
2017                                         bb->out_stack [i] = mono_compile_create_var (cfg, type_from_stack_type (sp [i]), OP_LOCAL);
2018                                 else
2019                                         bb->out_stack [i] = mono_compile_get_interface_var (cfg, i, sp [i]);
2020 #endif
2021                         }
2022                 }
2023         }
2024
2025         for (i = 0; i < bb->out_count; ++i) {
2026                 outb = bb->out_bb [i];
2027                 /* exception handlers are linked, but they should not be considered for stack args */
2028                 if (outb->flags & BB_EXCEPTION_HANDLER)
2029                         continue;
2030                 if (outb->in_scount) {
2031                         if (outb->in_scount != bb->out_scount)
2032                                 G_BREAKPOINT ();
2033                         continue; /* check they are the same locals */
2034                 }
2035                 outb->in_scount = count;
2036                 outb->in_stack = bb->out_stack;
2037         }
2038
2039         locals = bb->out_stack;
2040         for (i = 0; i < count; ++i) {
2041                 /* add store ops at the end of the bb, before the branch */
2042                 NEW_TEMPSTORE (cfg, inst, locals [i]->inst_c0, sp [i]);
2043                 if (inst->opcode == CEE_STOBJ) {
2044                         NEW_TEMPLOADA (cfg, inst, locals [i]->inst_c0);
2045                         handle_stobj (cfg, bb, inst, sp [i], sp [i]->cil_code, inst->klass, TRUE, FALSE, FALSE);
2046                 } else {
2047                         inst->cil_code = sp [i]->cil_code;
2048                         mono_add_ins_to_end (bb, inst);
2049                 }
2050                 if (cfg->verbose_level > 3)
2051                         g_print ("storing %d to temp %d\n", i, (int)locals [i]->inst_c0);
2052         }
2053
2054         /*
2055          * It is possible that the out bblocks already have in_stack assigned, and
2056          * the in_stacks differ. In this case, we will store to all the different 
2057          * in_stacks.
2058          */
2059
2060         found = TRUE;
2061         bindex = 0;
2062         while (found) {
2063                 /* Find a bblock which has a different in_stack */
2064                 found = FALSE;
2065                 while (bindex < bb->out_count) {
2066                         outb = bb->out_bb [bindex];
2067                         /* exception handlers are linked, but they should not be considered for stack args */
2068                         if (outb->flags & BB_EXCEPTION_HANDLER) {
2069                                 bindex++;
2070                                 continue;
2071                         }
2072                         if (outb->in_stack != locals) {
2073                                 /* 
2074                                  * Instead of storing sp [i] to locals [i], we need to store
2075                                  * locals [i] to <new locals>[i], since the sp [i] tree can't
2076                                  * be shared between trees.
2077                                  */
2078                                 for (i = 0; i < count; ++i)
2079                                         mono_add_varcopy_to_end (cfg, bb, locals [i]->inst_c0, outb->in_stack [i]->inst_c0);
2080                                 locals = outb->in_stack;
2081                                 found = TRUE;
2082                                 break;
2083                         }
2084                         bindex ++;
2085                 }
2086         }
2087         
2088         return 0;
2089 }
2090
2091 static int
2092 ret_type_to_call_opcode (MonoType *type, int calli, int virt)
2093 {
2094         if (type->byref)
2095                 return calli? OP_CALL_REG: virt? CEE_CALLVIRT: CEE_CALL;
2096
2097 handle_enum:
2098         switch (type->type) {
2099         case MONO_TYPE_VOID:
2100                 return calli? OP_VOIDCALL_REG: virt? OP_VOIDCALLVIRT: OP_VOIDCALL;
2101         case MONO_TYPE_I1:
2102         case MONO_TYPE_U1:
2103         case MONO_TYPE_BOOLEAN:
2104         case MONO_TYPE_I2:
2105         case MONO_TYPE_U2:
2106         case MONO_TYPE_CHAR:
2107         case MONO_TYPE_I4:
2108         case MONO_TYPE_U4:
2109                 return calli? OP_CALL_REG: virt? CEE_CALLVIRT: CEE_CALL;
2110         case MONO_TYPE_I:
2111         case MONO_TYPE_U:
2112         case MONO_TYPE_PTR:
2113         case MONO_TYPE_FNPTR:
2114                 return calli? OP_CALL_REG: virt? CEE_CALLVIRT: CEE_CALL;
2115         case MONO_TYPE_CLASS:
2116         case MONO_TYPE_STRING:
2117         case MONO_TYPE_OBJECT:
2118         case MONO_TYPE_SZARRAY:
2119         case MONO_TYPE_ARRAY:    
2120                 return calli? OP_CALL_REG: virt? CEE_CALLVIRT: CEE_CALL;
2121         case MONO_TYPE_I8:
2122         case MONO_TYPE_U8:
2123                 return calli? OP_LCALL_REG: virt? OP_LCALLVIRT: OP_LCALL;
2124         case MONO_TYPE_R4:
2125         case MONO_TYPE_R8:
2126                 return calli? OP_FCALL_REG: virt? OP_FCALLVIRT: OP_FCALL;
2127         case MONO_TYPE_VALUETYPE:
2128                 if (type->data.klass->enumtype) {
2129                         type = type->data.klass->enum_basetype;
2130                         goto handle_enum;
2131                 } else
2132                         return calli? OP_VCALL_REG: virt? OP_VCALLVIRT: OP_VCALL;
2133         case MONO_TYPE_TYPEDBYREF:
2134                 return calli? OP_VCALL_REG: virt? OP_VCALLVIRT: OP_VCALL;
2135         case MONO_TYPE_GENERICINST:
2136                 type = &type->data.generic_class->container_class->byval_arg;
2137                 goto handle_enum;
2138         default:
2139                 g_error ("unknown type 0x%02x in ret_type_to_call_opcode", type->type);
2140         }
2141         return -1;
2142 }
2143
2144 void
2145 mono_create_jump_table (MonoCompile *cfg, MonoInst *label, MonoBasicBlock **bbs, int num_blocks)
2146 {
2147         MonoJumpInfo *ji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo));
2148         MonoJumpInfoBBTable *table;
2149
2150         table = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfoBBTable));
2151         table->table = bbs;
2152         table->table_size = num_blocks;
2153         
2154         ji->ip.label = label;
2155         ji->type = MONO_PATCH_INFO_SWITCH;
2156         ji->data.table = table;
2157         ji->next = cfg->patch_info;
2158         cfg->patch_info = ji;
2159 }
2160
2161 /*
2162  * When we add a tree of instructions, we need to ensure the instructions currently
2163  * on the stack are executed before (like, if we load a value from a local).
2164  * We ensure this by saving the currently loaded values to temps and rewriting the
2165  * instructions to load the values.
2166  * This is not done for opcodes that terminate a basic block (because it's handled already
2167  * by handle_stack_args ()) and for opcodes that can't change values, like POP.
2168  */
2169 static void
2170 handle_loaded_temps (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst **stack, MonoInst **sp)
2171 {
2172         MonoInst *load, *store, *temp, *ins;
2173
2174         while (stack < sp) {
2175                 ins = *stack;
2176                 /* handle also other constants */
2177                 if ((ins->opcode != OP_ICONST) &&
2178                     /* temps never get written to again, so we can safely avoid duplicating them */
2179                     !(ins->ssa_op == MONO_SSA_LOAD && ins->inst_i0->opcode == OP_LOCAL && ins->inst_i0->flags & MONO_INST_IS_TEMP)) {
2180                         temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
2181                         temp->flags |= MONO_INST_IS_TEMP;
2182                         NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
2183                         store->cil_code = ins->cil_code;
2184                         if (store->opcode == CEE_STOBJ) {
2185                                 NEW_TEMPLOADA (cfg, store, temp->inst_c0);
2186                                 handle_stobj (cfg, bblock, store, ins, ins->cil_code, temp->klass, FALSE, FALSE, FALSE);
2187                         } else
2188                                 MONO_ADD_INS (bblock, store);
2189                         NEW_TEMPLOAD (cfg, load, temp->inst_c0);
2190                         load->cil_code = ins->cil_code;
2191                         *stack = load;
2192                 }
2193                 stack++;
2194         }
2195 }
2196
2197 /*
2198  * target_type_is_incompatible:
2199  * @cfg: MonoCompile context
2200  *
2201  * Check that the item @arg on the evaluation stack can be stored
2202  * in the target type (can be a local, or field, etc).
2203  * The cfg arg can be used to check if we need verification or just
2204  * validity checks.
2205  *
2206  * Returns: non-0 value if arg can't be stored on a target.
2207  */
2208 static int
2209 target_type_is_incompatible (MonoCompile *cfg, MonoType *target, MonoInst *arg)
2210 {
2211         MonoType *simple_type;
2212         MonoClass *klass;
2213
2214         if (target->byref) {
2215                 /* FIXME: check that the pointed to types match */
2216                 if (arg->type == STACK_MP)
2217                         return arg->klass != mono_class_from_mono_type (target);
2218                 if (arg->type == STACK_PTR)
2219                         return 0;
2220                 return 1;
2221         }
2222         simple_type = mono_type_get_underlying_type (target);
2223         switch (simple_type->type) {
2224         case MONO_TYPE_VOID:
2225                 return 1;
2226         case MONO_TYPE_I1:
2227         case MONO_TYPE_U1:
2228         case MONO_TYPE_BOOLEAN:
2229         case MONO_TYPE_I2:
2230         case MONO_TYPE_U2:
2231         case MONO_TYPE_CHAR:
2232         case MONO_TYPE_I4:
2233         case MONO_TYPE_U4:
2234                 if (arg->type != STACK_I4 && arg->type != STACK_PTR)
2235                         return 1;
2236                 return 0;
2237         case MONO_TYPE_PTR:
2238                 /* STACK_MP is needed when setting pinned locals */
2239                 if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
2240                         return 1;
2241                 return 0;
2242         case MONO_TYPE_I:
2243         case MONO_TYPE_U:
2244         case MONO_TYPE_FNPTR:
2245                 if (arg->type != STACK_I4 && arg->type != STACK_PTR)
2246                         return 1;
2247                 return 0;
2248         case MONO_TYPE_OBJECT:
2249                 if (arg->type != STACK_OBJ)
2250                         return 1;
2251                 return 0;
2252         case MONO_TYPE_STRING:
2253                 if (arg->type != STACK_OBJ)
2254                         return 1;
2255                 /* ldnull has arg->klass unset */
2256                 /*if (arg->klass && arg->klass != mono_defaults.string_class) {
2257                         G_BREAKPOINT ();
2258                         return 1;
2259                 }*/
2260                 return 0;
2261         case MONO_TYPE_CLASS:
2262         case MONO_TYPE_SZARRAY:
2263         case MONO_TYPE_ARRAY:    
2264                 if (arg->type != STACK_OBJ)
2265                         return 1;
2266                 /* FIXME: check type compatibility */
2267                 return 0;
2268         case MONO_TYPE_I8:
2269         case MONO_TYPE_U8:
2270                 if (arg->type != STACK_I8)
2271                         return 1;
2272                 return 0;
2273         case MONO_TYPE_R4:
2274         case MONO_TYPE_R8:
2275                 if (arg->type != STACK_R8)
2276                         return 1;
2277                 return 0;
2278         case MONO_TYPE_VALUETYPE:
2279                 if (arg->type != STACK_VTYPE)
2280                         return 1;
2281                 klass = mono_class_from_mono_type (simple_type);
2282                 if (klass != arg->klass)
2283                         return 1;
2284                 return 0;
2285         case MONO_TYPE_TYPEDBYREF:
2286                 if (arg->type != STACK_VTYPE)
2287                         return 1;
2288                 klass = mono_class_from_mono_type (simple_type);
2289                 if (klass != arg->klass)
2290                         return 1;
2291                 return 0;
2292         case MONO_TYPE_GENERICINST:
2293                 if (mono_type_generic_inst_is_valuetype (simple_type)) {
2294                         klass = mono_class_from_mono_type (simple_type);
2295                         if (klass->enumtype)
2296                                 return target_type_is_incompatible (cfg, klass->enum_basetype, arg);
2297                         if (arg->type != STACK_VTYPE)
2298                                 return 1;
2299                         if (klass != arg->klass)
2300                                 return 1;
2301                         return 0;
2302                 } else {
2303                         if (arg->type != STACK_OBJ)
2304                                 return 1;
2305                         /* FIXME: check type compatibility */
2306                         return 0;
2307                 }
2308         default:
2309                 g_error ("unknown type 0x%02x in target_type_is_incompatible", simple_type->type);
2310         }
2311         return 1;
2312 }
2313
2314 /*
2315  * Prepare arguments for passing to a function call.
2316  * Return a non-zero value if the arguments can't be passed to the given
2317  * signature.
2318  * The type checks are not yet complete and some conversions may need
2319  * casts on 32 or 64 bit architectures.
2320  *
2321  * FIXME: implement this using target_type_is_incompatible ()
2322  */
2323 static int
2324 check_call_signature (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args)
2325 {
2326         MonoType *simple_type;
2327         int i;
2328
2329         if (sig->hasthis) {
2330                 if (args [0]->type != STACK_OBJ && args [0]->type != STACK_MP && args [0]->type != STACK_PTR)
2331                         return 1;
2332                 args++;
2333         }
2334         for (i = 0; i < sig->param_count; ++i) {
2335                 if (sig->params [i]->byref) {
2336                         if (args [i]->type != STACK_MP && args [i]->type != STACK_PTR)
2337                                 return 1;
2338                         continue;
2339                 }
2340                 simple_type = sig->params [i];
2341 handle_enum:
2342                 switch (simple_type->type) {
2343                 case MONO_TYPE_VOID:
2344                         return 1;
2345                         continue;
2346                 case MONO_TYPE_I1:
2347                 case MONO_TYPE_U1:
2348                 case MONO_TYPE_BOOLEAN:
2349                 case MONO_TYPE_I2:
2350                 case MONO_TYPE_U2:
2351                 case MONO_TYPE_CHAR:
2352                 case MONO_TYPE_I4:
2353                 case MONO_TYPE_U4:
2354                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR)
2355                                 return 1;
2356                         continue;
2357                 case MONO_TYPE_I:
2358                 case MONO_TYPE_U:
2359                 case MONO_TYPE_PTR:
2360                 case MONO_TYPE_FNPTR:
2361                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR && args [i]->type != STACK_MP && args [i]->type != STACK_OBJ)
2362                                 return 1;
2363                         continue;
2364                 case MONO_TYPE_CLASS:
2365                 case MONO_TYPE_STRING:
2366                 case MONO_TYPE_OBJECT:
2367                 case MONO_TYPE_SZARRAY:
2368                 case MONO_TYPE_ARRAY:    
2369                         if (args [i]->type != STACK_OBJ)
2370                                 return 1;
2371                         continue;
2372                 case MONO_TYPE_I8:
2373                 case MONO_TYPE_U8:
2374                         if (args [i]->type != STACK_I8)
2375                                 return 1;
2376                         continue;
2377                 case MONO_TYPE_R4:
2378                 case MONO_TYPE_R8:
2379                         if (args [i]->type != STACK_R8)
2380                                 return 1;
2381                         continue;
2382                 case MONO_TYPE_VALUETYPE:
2383                         if (simple_type->data.klass->enumtype) {
2384                                 simple_type = simple_type->data.klass->enum_basetype;
2385                                 goto handle_enum;
2386                         }
2387                         if (args [i]->type != STACK_VTYPE)
2388                                 return 1;
2389                         continue;
2390                 case MONO_TYPE_TYPEDBYREF:
2391                         if (args [i]->type != STACK_VTYPE)
2392                                 return 1;
2393                         continue;
2394                 case MONO_TYPE_GENERICINST:
2395                         simple_type = &simple_type->data.generic_class->container_class->byval_arg;
2396                         goto handle_enum;
2397
2398                 default:
2399                         g_error ("unknown type 0x%02x in check_call_signature",
2400                                  simple_type->type);
2401                 }
2402         }
2403         return 0;
2404 }
2405
2406 inline static int
2407 mono_spill_call (MonoCompile *cfg, MonoBasicBlock *bblock, MonoCallInst *call, MonoMethodSignature *sig, gboolean ret_object, 
2408                  const guint8 *ip, gboolean to_end)
2409 {
2410         MonoInst *temp, *store, *ins = (MonoInst*)call;
2411         MonoType *ret = sig->ret;
2412
2413         if (!MONO_TYPE_IS_VOID (ret) || ret_object) {
2414                 if (ret_object) {
2415                         call->inst.type = STACK_OBJ;
2416                         call->inst.opcode = CEE_CALL;
2417                         temp = mono_compile_create_var (cfg, &mono_defaults.string_class->byval_arg, OP_LOCAL);
2418                 } else {
2419                         type_to_eval_stack_type (ret, ins);
2420                         temp = mono_compile_create_var (cfg, ret, OP_LOCAL);
2421                 }
2422                 
2423                 temp->flags |= MONO_INST_IS_TEMP;
2424
2425                 if (MONO_TYPE_ISSTRUCT (ret)) {
2426                         MonoInst *loada, *dummy_store;
2427
2428                         /* 
2429                          * Emit a dummy store to the local holding the result so the
2430                          * liveness info remains correct.
2431                          */
2432                         NEW_DUMMY_STORE (cfg, dummy_store, temp->inst_c0);
2433                         if (to_end)
2434                                 mono_add_ins_to_end (bblock, dummy_store);
2435                         else
2436                                 MONO_ADD_INS (bblock, dummy_store);
2437
2438                         /* we use this to allocate native sized structs */
2439                         temp->backend.is_pinvoke = sig->pinvoke;
2440
2441                         NEW_TEMPLOADA (cfg, loada, temp->inst_c0);
2442                         if (call->inst.opcode == OP_VCALL)
2443                                 ins->inst_left = loada;
2444                         else
2445                                 ins->inst_right = loada; /* a virtual or indirect call */
2446
2447                         if (to_end)
2448                                 mono_add_ins_to_end (bblock, ins);
2449                         else
2450                                 MONO_ADD_INS (bblock, ins);
2451                 } else {
2452                         NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
2453                         store->cil_code = ip;
2454                         if (to_end)
2455                                 mono_add_ins_to_end (bblock, store);
2456                         else
2457                                 MONO_ADD_INS (bblock, store);
2458                 }
2459                 return temp->inst_c0;
2460         } else {
2461                 if (to_end)
2462                         mono_add_ins_to_end (bblock, ins);
2463                 else
2464                         MONO_ADD_INS (bblock, ins);
2465                 return -1;
2466         }
2467 }
2468
2469 inline static MonoCallInst *
2470 mono_emit_call_args (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethodSignature *sig, 
2471                      MonoInst **args, int calli, int virtual, const guint8 *ip, gboolean to_end)
2472 {
2473         MonoCallInst *call;
2474         MonoInst *arg;
2475
2476         MONO_INST_NEW_CALL (cfg, call, ret_type_to_call_opcode (sig->ret, calli, virtual));
2477
2478 #ifdef MONO_ARCH_SOFT_FLOAT
2479         /* we need to convert the r4 value to an int value */
2480         {
2481                 int i;
2482                 for (i = 0; i < sig->param_count; ++i) {
2483                         if (sig->params [i]->type == MONO_TYPE_R4) {
2484                                 MonoInst *iargs [1];
2485                                 int temp;
2486                                 iargs [0] = args [i + sig->hasthis];
2487
2488                                 temp = mono_emit_jit_icall (cfg, bblock, mono_fload_r4_arg, iargs, ip);
2489                                 NEW_TEMPLOAD (cfg, arg, temp);
2490                                 args [i + sig->hasthis] = arg;
2491                         }
2492                 }
2493         }
2494 #endif
2495
2496         call->inst.cil_code = ip;
2497         call->args = args;
2498         call->signature = sig;
2499         call = mono_arch_call_opcode (cfg, bblock, call, virtual);
2500         type_to_eval_stack_type (sig->ret, &call->inst);
2501
2502         for (arg = call->out_args; arg;) {
2503                 MonoInst *narg = arg->next;
2504                 arg->next = NULL;
2505                 if (!arg->cil_code)
2506                         arg->cil_code = ip;
2507                 if (to_end)
2508                         mono_add_ins_to_end (bblock, arg);
2509                 else
2510                         MONO_ADD_INS (bblock, arg);
2511                 arg = narg;
2512         }
2513         return call;
2514 }
2515
2516 inline static int
2517 mono_emit_calli (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethodSignature *sig, 
2518                  MonoInst **args, MonoInst *addr, const guint8 *ip)
2519 {
2520         MonoCallInst *call = mono_emit_call_args (cfg, bblock, sig, args, TRUE, FALSE, ip, FALSE);
2521
2522         call->inst.inst_i0 = addr;
2523
2524         return mono_spill_call (cfg, bblock, call, sig, FALSE, ip, FALSE);
2525 }
2526
2527 static MonoCallInst*
2528 mono_emit_method_call_full (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *method, MonoMethodSignature *sig,
2529                        MonoInst **args, const guint8 *ip, MonoInst *this, gboolean to_end)
2530 {
2531         gboolean virtual = this != NULL;
2532         MonoCallInst *call;
2533
2534         call = mono_emit_call_args (cfg, bblock, sig, args, FALSE, virtual, ip, to_end);
2535
2536         if (this && sig->hasthis && 
2537             (method->klass->marshalbyref || method->klass == mono_defaults.object_class) && 
2538             !(method->flags & METHOD_ATTRIBUTE_VIRTUAL) && !MONO_CHECK_THIS (this)) {
2539                 call->method = mono_marshal_get_remoting_invoke_with_check (method);
2540         } else {
2541                 call->method = method;
2542         }
2543         call->inst.flags |= MONO_INST_HAS_METHOD;
2544         call->inst.inst_left = this;
2545
2546         if (call->method->klass->flags & TYPE_ATTRIBUTE_INTERFACE)
2547                 /* Needed by the code generated in inssel.brg */
2548                 mono_get_got_var (cfg);
2549
2550         return call;
2551 }
2552
2553 static MonoCallInst*
2554 mono_emit_method_call (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *method, MonoMethodSignature *sig,
2555                        MonoInst **args, const guint8 *ip, MonoInst *this)
2556 {
2557         return mono_emit_method_call_full (cfg, bblock, method, sig, args, ip, this, FALSE);
2558 }
2559
2560 inline static int
2561 mono_emit_method_call_spilled (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *method,  
2562                        MonoMethodSignature *signature, MonoInst **args, const guint8 *ip, MonoInst *this)
2563 {
2564         MonoCallInst *call = mono_emit_method_call (cfg, bblock, method, signature, args, ip, this);
2565
2566         return mono_spill_call (cfg, bblock, call, signature, method->string_ctor, ip, FALSE);
2567 }
2568
2569 inline static int
2570 mono_emit_method_call_spilled_full (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *method,  
2571                        MonoMethodSignature *signature, MonoInst **args, const guint8 *ip, MonoInst *this,
2572                        gboolean ret_object, gboolean to_end)
2573 {
2574         MonoCallInst *call = mono_emit_method_call_full (cfg, bblock, method, signature, args, ip, this, to_end);
2575
2576         return mono_spill_call (cfg, bblock, call, signature, ret_object, ip, to_end);
2577 }
2578
2579 inline static int
2580 mono_emit_native_call (MonoCompile *cfg, MonoBasicBlock *bblock, gconstpointer func, MonoMethodSignature *sig,
2581                        MonoInst **args, const guint8 *ip, gboolean ret_object, gboolean to_end)
2582 {
2583         MonoCallInst *call;
2584
2585         g_assert (sig);
2586
2587         call = mono_emit_call_args (cfg, bblock, sig, args, FALSE, FALSE, ip, to_end);
2588         call->fptr = func;
2589
2590         return mono_spill_call (cfg, bblock, call, sig, ret_object, ip, to_end);
2591 }
2592
2593 inline static int
2594 mono_emit_jit_icall (MonoCompile *cfg, MonoBasicBlock *bblock, gconstpointer func, MonoInst **args, const guint8 *ip)
2595 {
2596         MonoJitICallInfo *info = mono_find_jit_icall_by_addr (func);
2597         
2598         if (!info) {
2599                 g_warning ("unregistered JIT ICall");
2600                 g_assert_not_reached ();
2601         }
2602
2603         return mono_emit_native_call (cfg, bblock, mono_icall_get_wrapper (info), info->sig, args, ip, FALSE, FALSE);
2604 }
2605
2606 static void
2607 mono_emulate_opcode (MonoCompile *cfg, MonoInst *tree, MonoInst **iargs, MonoJitICallInfo *info)
2608 {
2609         MonoInst *ins, *temp = NULL, *store, *load, *begin;
2610         MonoInst *last_arg = NULL;
2611         int nargs;
2612         MonoCallInst *call;
2613
2614         //g_print ("emulating: ");
2615         //mono_print_tree_nl (tree);
2616         MONO_INST_NEW_CALL (cfg, call, ret_type_to_call_opcode (info->sig->ret, FALSE, FALSE));
2617         ins = (MonoInst*)call;
2618         
2619         call->inst.cil_code = tree->cil_code;
2620         call->args = iargs;
2621         call->signature = info->sig;
2622
2623         call = mono_arch_call_opcode (cfg, cfg->cbb, call, FALSE);
2624
2625         if (!MONO_TYPE_IS_VOID (info->sig->ret)) {
2626                 temp = mono_compile_create_var (cfg, info->sig->ret, OP_LOCAL);
2627                 temp->flags |= MONO_INST_IS_TEMP;
2628                 NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
2629                 store->cil_code = tree->cil_code;
2630         } else {
2631                 store = ins;
2632         }
2633
2634         nargs = info->sig->param_count + info->sig->hasthis;
2635
2636         for (last_arg = call->out_args; last_arg && last_arg->next; last_arg = last_arg->next) ;
2637
2638         if (nargs)
2639                 last_arg->next = store;
2640
2641         if (nargs)
2642                 begin = call->out_args;
2643         else
2644                 begin = store;
2645
2646         if (cfg->prev_ins) {
2647                 /* 
2648                  * This assumes that that in a tree, emulate_opcode is called for a
2649                  * node before it is called for its children. dec_foreach needs to
2650                  * take this into account.
2651                  */
2652                 store->next = cfg->prev_ins->next;
2653                 cfg->prev_ins->next = begin;
2654         } else {
2655                 store->next = cfg->cbb->code;
2656                 cfg->cbb->code = begin;
2657         }
2658
2659         call->fptr = mono_icall_get_wrapper (info);
2660
2661         if (!MONO_TYPE_IS_VOID (info->sig->ret)) {
2662                 NEW_TEMPLOAD (cfg, load, temp->inst_c0);
2663                 *tree = *load;
2664         }
2665 }
2666
2667 static MonoMethodSignature *
2668 mono_get_array_new_va_signature (int arity)
2669 {
2670         static GHashTable *sighash = NULL;
2671         MonoMethodSignature *res;
2672         int i;
2673
2674         mono_jit_lock ();
2675         if (!sighash) {
2676                 sighash = g_hash_table_new (NULL, NULL);
2677         }
2678         else if ((res = g_hash_table_lookup (sighash, GINT_TO_POINTER (arity)))) {
2679                 mono_jit_unlock ();
2680                 return res;
2681         }
2682
2683         res = mono_metadata_signature_alloc (mono_defaults.corlib, arity + 1);
2684
2685         res->pinvoke = 1;
2686 #ifdef MONO_ARCH_VARARG_ICALLS
2687         /* Only set this only some archs since not all backends can handle varargs+pinvoke */
2688         res->call_convention = MONO_CALL_VARARG;
2689 #endif
2690
2691 #ifdef PLATFORM_WIN32
2692         res->call_convention = MONO_CALL_C;
2693 #endif
2694
2695         res->params [0] = &mono_defaults.int_class->byval_arg;  
2696         for (i = 0; i < arity; i++)
2697                 res->params [i + 1] = &mono_defaults.int_class->byval_arg;
2698
2699         res->ret = &mono_defaults.int_class->byval_arg;
2700
2701         g_hash_table_insert (sighash, GINT_TO_POINTER (arity), res);
2702         mono_jit_unlock ();
2703
2704         return res;
2705 }
2706
2707 #ifdef MONO_ARCH_SOFT_FLOAT
2708 static void
2709 handle_store_float (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *ptr, MonoInst *val, const unsigned char *ip)
2710 {
2711         MonoInst *iargs [2];
2712         iargs [0] = val;
2713         iargs [1] = ptr;
2714
2715         mono_emit_jit_icall (cfg, bblock, mono_fstore_r4, iargs, ip);
2716 }
2717
2718 static int
2719 handle_load_float (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *ptr, const unsigned char *ip)
2720 {
2721         MonoInst *iargs [1];
2722         iargs [0] = ptr;
2723
2724         return mono_emit_jit_icall (cfg, bblock, mono_fload_r4, iargs, ip);
2725 }
2726
2727 #define LDLOC_SOFT_FLOAT(cfg,ins,idx,ip) do {\
2728                 if (header->locals [(idx)]->type == MONO_TYPE_R4 && !header->locals [(idx)]->byref) {   \
2729                         int temp;       \
2730                         NEW_LOCLOADA (cfg, (ins), (idx));       \
2731                         temp = handle_load_float (cfg, bblock, (ins), (ip));    \
2732                         NEW_TEMPLOAD (cfg, (ins), temp);        \
2733                 }       \
2734         } while (0)
2735 #define STLOC_SOFT_FLOAT(cfg,ins,idx,ip) do {\
2736                 if (header->locals [(idx)]->type == MONO_TYPE_R4 && !header->locals [(idx)]->byref) {   \
2737                         int temp;       \
2738                         NEW_LOCLOADA (cfg, (ins), (idx));       \
2739                         handle_store_float (cfg, bblock, (ins), *sp, (ip));     \
2740                         MONO_INST_NEW (cfg, (ins), CEE_NOP);    \
2741                 }       \
2742         } while (0)
2743 #define LDARG_SOFT_FLOAT(cfg,ins,idx,ip) do {\
2744                 if (param_types [(idx)]->type == MONO_TYPE_R4 && !param_types [(idx)]->byref) { \
2745                         int temp;       \
2746                         NEW_ARGLOADA (cfg, (ins), (idx));       \
2747                         temp = handle_load_float (cfg, bblock, (ins), (ip));    \
2748                         NEW_TEMPLOAD (cfg, (ins), temp);        \
2749                 }       \
2750         } while (0)
2751 #define STARG_SOFT_FLOAT(cfg,ins,idx,ip) do {\
2752                 if (param_types [(idx)]->type == MONO_TYPE_R4 && !param_types [(idx)]->byref) { \
2753                         int temp;       \
2754                         NEW_ARGLOADA (cfg, (ins), (idx));       \
2755                         handle_store_float (cfg, bblock, (ins), *sp, (ip));     \
2756                         MONO_INST_NEW (cfg, (ins), CEE_NOP);    \
2757                 }       \
2758         } while (0)
2759 #else
2760 #define LDLOC_SOFT_FLOAT(cfg,ins,idx,ip)
2761 #define STLOC_SOFT_FLOAT(cfg,ins,idx,ip)
2762 #define LDARG_SOFT_FLOAT(cfg,ins,idx,ip)
2763 #define STARG_SOFT_FLOAT(cfg,ins,idx,ip)
2764 #endif
2765
2766 static MonoMethod*
2767 get_memcpy_method (void)
2768 {
2769         static MonoMethod *memcpy_method = NULL;
2770         if (!memcpy_method) {
2771                 memcpy_method = mono_class_get_method_from_name (mono_defaults.string_class, "memcpy", 3);
2772                 if (!memcpy_method)
2773                         g_error ("Old corlib found. Install a new one");
2774         }
2775         return memcpy_method;
2776 }
2777
2778 static void
2779 handle_stobj (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *dest, MonoInst *src, const unsigned char *ip, MonoClass *klass, gboolean to_end, gboolean native, gboolean write_barrier) {
2780         MonoInst *iargs [3];
2781         int n;
2782         guint32 align = 0;
2783         MonoMethod *memcpy_method;
2784
2785         g_assert (klass);
2786         /*
2787          * This check breaks with spilled vars... need to handle it during verification anyway.
2788          * g_assert (klass && klass == src->klass && klass == dest->klass);
2789          */
2790
2791         if (native)
2792                 n = mono_class_native_size (klass, &align);
2793         else
2794                 n = mono_class_value_size (klass, &align);
2795
2796 #if HAVE_WRITE_BARRIERS
2797         /* if native is true there should be no references in the struct */
2798         if (write_barrier && klass->has_references && !native) {
2799                 iargs [0] = dest;
2800                 iargs [1] = src;
2801                 NEW_PCONST (cfg, iargs [2], klass);
2802
2803                 mono_emit_jit_icall (cfg, bblock, mono_value_copy, iargs, ip);
2804                 return;
2805         }
2806 #endif
2807
2808         /* FIXME: add write barrier handling */
2809         if ((cfg->opt & MONO_OPT_INTRINS) && !to_end && n <= sizeof (gpointer) * 5) {
2810                 MonoInst *inst;
2811                 if (dest->opcode == OP_LDADDR) {
2812                         /* Keep liveness info correct */
2813                         NEW_DUMMY_STORE (cfg, inst, dest->inst_i0->inst_c0);
2814                         MONO_ADD_INS (bblock, inst);
2815                 }
2816                 MONO_INST_NEW (cfg, inst, OP_MEMCPY);
2817                 inst->inst_left = dest;
2818                 inst->inst_right = src;
2819                 inst->cil_code = ip;
2820                 inst->backend.size = n;
2821                 MONO_ADD_INS (bblock, inst);
2822                 return;
2823         }
2824         iargs [0] = dest;
2825         iargs [1] = src;
2826         NEW_ICONST (cfg, iargs [2], n);
2827
2828         memcpy_method = get_memcpy_method ();
2829         mono_emit_method_call_spilled_full (cfg, bblock, memcpy_method, memcpy_method->signature, iargs, ip, NULL, FALSE, to_end);
2830 }
2831
2832 static MonoMethod*
2833 get_memset_method (void)
2834 {
2835         static MonoMethod *memset_method = NULL;
2836         if (!memset_method) {
2837                 memset_method = mono_class_get_method_from_name (mono_defaults.string_class, "memset", 3);
2838                 if (!memset_method)
2839                         g_error ("Old corlib found. Install a new one");
2840         }
2841         return memset_method;
2842 }
2843
2844 static void
2845 handle_initobj (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *dest, const guchar *ip, MonoClass *klass, MonoInst **stack_start, MonoInst **sp)
2846 {
2847         MonoInst *iargs [3];
2848         MonoInst *ins, *zero_int32;
2849         int n;
2850         MonoMethod *memset_method;
2851
2852         NEW_ICONST (cfg, zero_int32, 0);
2853
2854         mono_class_init (klass);
2855         n = mono_class_value_size (klass, NULL);
2856         MONO_INST_NEW (cfg, ins, 0);
2857         ins->cil_code = ip;
2858         ins->inst_left = dest;
2859         ins->inst_right = zero_int32;
2860         switch (n) {
2861         case 1:
2862                 ins->opcode = CEE_STIND_I1;
2863                 MONO_ADD_INS (bblock, ins);
2864                 break;
2865         case 2:
2866                 ins->opcode = CEE_STIND_I2;
2867                 MONO_ADD_INS (bblock, ins);
2868                 break;
2869         case 4:
2870                 ins->opcode = CEE_STIND_I4;
2871                 MONO_ADD_INS (bblock, ins);
2872                 break;
2873         default:
2874                 if (n <= sizeof (gpointer) * 5) {
2875                         ins->opcode = OP_MEMSET;
2876                         ins->inst_imm = 0;
2877                         ins->backend.size = n;
2878                         MONO_ADD_INS (bblock, ins);
2879                         break;
2880                 }
2881                 memset_method = get_memset_method ();
2882                 handle_loaded_temps (cfg, bblock, stack_start, sp);
2883                 iargs [0] = dest;
2884                 NEW_ICONST (cfg, iargs [1], 0);
2885                 NEW_ICONST (cfg, iargs [2], n);
2886                 mono_emit_method_call_spilled (cfg, bblock, memset_method, memset_method->signature, iargs, ip, NULL);
2887                 break;
2888         }
2889 }
2890
2891 static int
2892 handle_alloc (MonoCompile *cfg, MonoBasicBlock *bblock, MonoClass *klass, gboolean for_box, const guchar *ip)
2893 {
2894         MonoInst *iargs [2];
2895         void *alloc_ftn;
2896
2897         if (cfg->opt & MONO_OPT_SHARED) {
2898                 NEW_DOMAINCONST (cfg, iargs [0]);
2899                 NEW_CLASSCONST (cfg, iargs [1], klass);
2900
2901                 alloc_ftn = mono_object_new;
2902         } else if (cfg->compile_aot && bblock->out_of_line && klass->type_token && klass->image == mono_defaults.corlib) {
2903                 /* This happens often in argument checking code, eg. throw new FooException... */
2904                 /* Avoid relocations by calling a helper function specialized to mscorlib */
2905                 NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (klass->type_token));
2906                 return mono_emit_jit_icall (cfg, bblock, mono_helper_newobj_mscorlib, iargs, ip);
2907         } else {
2908                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
2909                 gboolean pass_lw;
2910
2911                 alloc_ftn = mono_class_get_allocation_ftn (vtable, for_box, &pass_lw);
2912                 if (pass_lw) {
2913                         guint32 lw = vtable->klass->instance_size;
2914                         lw = ((lw + (sizeof (gpointer) - 1)) & ~(sizeof (gpointer) - 1)) / sizeof (gpointer);
2915                         NEW_ICONST (cfg, iargs [0], lw);
2916                         NEW_VTABLECONST (cfg, iargs [1], vtable);
2917                 }
2918                 else
2919                         NEW_VTABLECONST (cfg, iargs [0], vtable);
2920         }
2921
2922         return mono_emit_jit_icall (cfg, bblock, alloc_ftn, iargs, ip);
2923 }
2924
2925 /**
2926  * Handles unbox of a Nullable<T>, returning a temp variable
2927  * where the result is stored
2928  */
2929 static int
2930 handle_unbox_nullable (MonoCompile* cfg, MonoBasicBlock* bblock, MonoInst* val, const guchar *ip, MonoClass* klass)
2931 {
2932        MonoMethod* method = mono_class_get_method_from_name (klass, "Unbox", 1);
2933        return mono_emit_method_call_spilled (cfg, bblock, method, mono_method_signature (method), &val, ip, NULL);
2934         
2935 }
2936
2937
2938
2939 static MonoInst *
2940 handle_box (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *val, const guchar *ip, MonoClass *klass)
2941 {
2942         MonoInst *dest, *vtoffset, *add, *vstore;
2943         int temp;
2944
2945        if (mono_class_is_nullable (klass)) {
2946                MonoMethod* method = mono_class_get_method_from_name (klass, "Box", 1);
2947                temp = mono_emit_method_call_spilled (cfg, bblock, method, mono_method_signature (method), &val, ip, NULL);
2948                NEW_TEMPLOAD (cfg, dest, temp);
2949                return dest;
2950        }
2951
2952
2953         temp = handle_alloc (cfg, bblock, klass, TRUE, ip);
2954         NEW_TEMPLOAD (cfg, dest, temp);
2955         NEW_ICONST (cfg, vtoffset, sizeof (MonoObject));
2956         MONO_INST_NEW (cfg, add, OP_PADD);
2957         add->inst_left = dest;
2958         add->inst_right = vtoffset;
2959         add->cil_code = ip;
2960         add->klass = klass;
2961         MONO_INST_NEW (cfg, vstore, CEE_STIND_I);
2962         vstore->opcode = mono_type_to_stind (&klass->byval_arg);
2963         vstore->cil_code = ip;
2964         vstore->inst_left = add;
2965         vstore->inst_right = val;
2966
2967 #ifdef MONO_ARCH_SOFT_FLOAT
2968         if (vstore->opcode == CEE_STIND_R4) {
2969                 handle_store_float (cfg, bblock, add, val, ip);
2970         } else
2971 #endif
2972         if (vstore->opcode == CEE_STOBJ) {
2973                 handle_stobj (cfg, bblock, add, val, ip, klass, FALSE, FALSE, TRUE);
2974         } else
2975                 MONO_ADD_INS (bblock, vstore);
2976
2977         NEW_TEMPLOAD (cfg, dest, temp);
2978         return dest;
2979 }
2980
2981 static int
2982 handle_array_new (MonoCompile *cfg, MonoBasicBlock *bblock, int rank, MonoInst **sp, unsigned char *ip)
2983 {
2984         MonoMethodSignature *esig;
2985         char icall_name [256];
2986         char *name;
2987         MonoJitICallInfo *info;
2988
2989         /* Need to register the icall so it gets an icall wrapper */
2990         sprintf (icall_name, "ves_array_new_va_%d", rank);
2991
2992         mono_jit_lock ();
2993         info = mono_find_jit_icall_by_name (icall_name);
2994         if (info == NULL) {
2995                 esig = mono_get_array_new_va_signature (rank);
2996                 name = g_strdup (icall_name);
2997                 info = mono_register_jit_icall (mono_array_new_va, name, esig, FALSE);
2998
2999                 g_hash_table_insert (jit_icall_name_hash, name, name);
3000         }
3001         mono_jit_unlock ();
3002
3003         cfg->flags |= MONO_CFG_HAS_VARARGS;
3004
3005         /* FIXME: This uses info->sig, but it should use the signature of the wrapper */
3006         return mono_emit_native_call (cfg, bblock, mono_icall_get_wrapper (info), info->sig, sp, ip, TRUE, FALSE);
3007 }
3008
3009 static void
3010 mono_emit_load_got_addr (MonoCompile *cfg)
3011 {
3012         MonoInst *load, *store, *dummy_use;
3013         MonoInst *get_got;
3014
3015         if (!cfg->got_var || cfg->got_var_allocated)
3016                 return;
3017
3018         MONO_INST_NEW (cfg, get_got, OP_LOAD_GOTADDR);
3019         NEW_TEMPSTORE (cfg, store, cfg->got_var->inst_c0, get_got);
3020
3021         /* Add it to the start of the first bblock */
3022         if (cfg->bb_entry->code) {
3023                 store->next = cfg->bb_entry->code;
3024                 cfg->bb_entry->code = store;
3025         }
3026         else
3027                 MONO_ADD_INS (cfg->bb_entry, store);
3028
3029         cfg->got_var_allocated = TRUE;
3030
3031         /* 
3032          * Add a dummy use to keep the got_var alive, since real uses might
3033          * only be generated in the decompose or instruction selection phases.
3034          * Add it to end_bblock, so the variable's lifetime covers the whole
3035          * method.
3036          */
3037         NEW_TEMPLOAD (cfg, load, cfg->got_var->inst_c0);
3038         NEW_DUMMY_USE (cfg, dummy_use, load);
3039         MONO_ADD_INS (cfg->bb_exit, dummy_use);
3040 }
3041
3042 #define CODE_IS_STLOC(ip) (((ip) [0] >= CEE_STLOC_0 && (ip) [0] <= CEE_STLOC_3) || ((ip) [0] == CEE_STLOC_S))
3043
3044 static gboolean
3045 mini_class_is_system_array (MonoClass *klass)
3046 {
3047         if (klass->parent == mono_defaults.array_class)
3048                 return TRUE;
3049         else
3050                 return FALSE;
3051 }
3052
3053 static gboolean
3054 mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method)
3055 {
3056         MonoMethodHeader *header = mono_method_get_header (method);
3057         MonoMethodSignature *signature = mono_method_signature (method);
3058         MonoVTable *vtable;
3059         int i;
3060
3061 #ifdef MONO_ARCH_HAVE_LMF_OPS
3062         if (((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
3063                  (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) &&
3064             !MONO_TYPE_ISSTRUCT (signature->ret) && !mini_class_is_system_array (method->klass))
3065                 return TRUE;
3066 #endif
3067
3068         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
3069             (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
3070             (method->iflags & METHOD_IMPL_ATTRIBUTE_NOINLINING) ||
3071             (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) ||
3072             (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
3073             (method->klass->marshalbyref) ||
3074             !header || header->num_clauses ||
3075             /* fixme: why cant we inline valuetype returns? */
3076             MONO_TYPE_ISSTRUCT (signature->ret))
3077                 return FALSE;
3078
3079 #ifdef MONO_ARCH_SOFT_FLOAT
3080         /* this complicates things, fix later */
3081         if (signature->ret->type == MONO_TYPE_R4)
3082                 return FALSE;
3083 #endif
3084         /* its not worth to inline methods with valuetype arguments?? */
3085         for (i = 0; i < signature->param_count; i++) {
3086                 if (MONO_TYPE_ISSTRUCT (signature->params [i])) {
3087                         return FALSE;
3088                 }
3089 #ifdef MONO_ARCH_SOFT_FLOAT
3090                 /* this complicates things, fix later */
3091                 if (signature->params [i]->type == MONO_TYPE_R4)
3092                         return FALSE;
3093 #endif
3094         }
3095
3096         /*
3097          * if we can initialize the class of the method right away, we do,
3098          * otherwise we don't allow inlining if the class needs initialization,
3099          * since it would mean inserting a call to mono_runtime_class_init()
3100          * inside the inlined code
3101          */
3102         if (!(cfg->opt & MONO_OPT_SHARED)) {
3103                 vtable = mono_class_vtable (cfg->domain, method->klass);
3104                 if (method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) {
3105                         if (cfg->run_cctors) {
3106                                 /* This makes so that inline cannot trigger */
3107                                 /* .cctors: too many apps depend on them */
3108                                 /* running with a specific order... */
3109                                 if (! vtable->initialized)
3110                                         return FALSE;
3111                                 mono_runtime_class_init (vtable);
3112                         }
3113                 }
3114                 else if (!vtable->initialized && mono_class_needs_cctor_run (method->klass, NULL))
3115                         return FALSE;
3116         } else {
3117                 /* 
3118                  * If we're compiling for shared code
3119                  * the cctor will need to be run at aot method load time, for example,
3120                  * or at the end of the compilation of the inlining method.
3121                  */
3122                 if (mono_class_needs_cctor_run (method->klass, NULL) && !((method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT)))
3123                         return FALSE;
3124         }
3125         //if (!MONO_TYPE_IS_VOID (signature->ret)) return FALSE;
3126
3127         /*
3128          * CAS - do not inline methods with declarative security
3129          * Note: this has to be before any possible return TRUE;
3130          */
3131         if (mono_method_has_declsec (method))
3132                 return FALSE;
3133
3134         /* also consider num_locals? */
3135         if (getenv ("MONO_INLINELIMIT")) {
3136                 if (header->code_size < atoi (getenv ("MONO_INLINELIMIT"))) {
3137                         return TRUE;
3138                 }
3139         } else if (header->code_size < INLINE_LENGTH_LIMIT)
3140                 return TRUE;
3141
3142         return FALSE;
3143 }
3144
3145 static gboolean
3146 mini_field_access_needs_cctor_run (MonoCompile *cfg, MonoMethod *method, MonoVTable *vtable)
3147 {
3148         if (vtable->initialized && !cfg->compile_aot)
3149                 return FALSE;
3150
3151         if (vtable->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT)
3152                 return FALSE;
3153
3154         if (!mono_class_needs_cctor_run (vtable->klass, method))
3155                 return FALSE;
3156
3157         if (! (method->flags & METHOD_ATTRIBUTE_STATIC) && (vtable->klass == method->klass))
3158                 /* The initialization is already done before the method is called */
3159                 return FALSE;
3160
3161         return TRUE;
3162 }
3163
3164 static MonoInst*
3165 mini_get_ldelema_ins (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *cmethod, MonoInst **sp, unsigned char *ip, gboolean is_set)
3166 {
3167         int temp, rank;
3168         MonoInst *addr;
3169         MonoMethod *addr_method;
3170         int element_size;
3171
3172         rank = mono_method_signature (cmethod)->param_count - (is_set? 1: 0);
3173
3174         if (rank == 1) {
3175                 MONO_INST_NEW (cfg, addr, CEE_LDELEMA);
3176                 addr->inst_left = sp [0];
3177                 addr->inst_right = sp [1];
3178                 addr->cil_code = ip;
3179                 addr->type = STACK_MP;
3180                 addr->klass = cmethod->klass->element_class;
3181                 return addr;
3182         }
3183
3184         if (rank == 2 && (cfg->opt & MONO_OPT_INTRINS)) {
3185 #if defined(MONO_ARCH_EMULATE_MUL_DIV) && !defined(MONO_ARCH_NO_EMULATE_MUL)
3186                 /* OP_LDELEMA2D depends on OP_LMUL */
3187 #else
3188                 MonoInst *indexes;
3189                 NEW_GROUP (cfg, indexes, sp [1], sp [2]);
3190                 MONO_INST_NEW (cfg, addr, OP_LDELEMA2D);
3191                 addr->inst_left = sp [0];
3192                 addr->inst_right = indexes;
3193                 addr->cil_code = ip;
3194                 addr->type = STACK_MP;
3195                 addr->klass = cmethod->klass->element_class;
3196                 return addr;
3197 #endif
3198         }
3199
3200         element_size = mono_class_array_element_size (cmethod->klass->element_class);
3201         addr_method = mono_marshal_get_array_address (rank, element_size);
3202         temp = mono_emit_method_call_spilled (cfg, bblock, addr_method, addr_method->signature, sp, ip, NULL);
3203         NEW_TEMPLOAD (cfg, addr, temp);
3204         return addr;
3205
3206 }
3207
3208 static MonoJitICallInfo **emul_opcode_map = NULL;
3209
3210 MonoJitICallInfo *
3211 mono_find_jit_opcode_emulation (int opcode)
3212 {
3213         g_assert (opcode >= 0 && opcode <= OP_LAST);
3214         if  (emul_opcode_map)
3215                 return emul_opcode_map [opcode];
3216         else
3217                 return NULL;
3218 }
3219
3220 static MonoInst*
3221 mini_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
3222 {
3223         MonoInst *ins = NULL;
3224         
3225         static MonoClass *runtime_helpers_class = NULL;
3226         if (! runtime_helpers_class)
3227                 runtime_helpers_class = mono_class_from_name (mono_defaults.corlib,
3228                         "System.Runtime.CompilerServices", "RuntimeHelpers");
3229
3230         if (cmethod->klass == mono_defaults.string_class) {
3231                 if (strcmp (cmethod->name, "get_Chars") == 0) {
3232                         MONO_INST_NEW (cfg, ins, OP_GETCHR);
3233                         ins->inst_i0 = args [0];
3234                         ins->inst_i1 = args [1];
3235                         return ins;
3236                 } else if (strcmp (cmethod->name, "get_Length") == 0) {
3237                         MONO_INST_NEW (cfg, ins, OP_STRLEN);
3238                         ins->inst_i0 = args [0];
3239                         return ins;
3240                 } else if (strcmp (cmethod->name, "InternalSetChar") == 0) {
3241                         MonoInst *get_addr;
3242                         MONO_INST_NEW (cfg, get_addr, OP_STR_CHAR_ADDR);
3243                         get_addr->inst_i0 = args [0];
3244                         get_addr->inst_i1 = args [1];
3245                         MONO_INST_NEW (cfg, ins, CEE_STIND_I2);
3246                         ins->inst_i0 = get_addr;
3247                         ins->inst_i1 = args [2];
3248                         return ins;
3249                 } else 
3250                         return NULL;
3251         } else if (cmethod->klass == mono_defaults.object_class) {
3252                 if (strcmp (cmethod->name, "GetType") == 0) {
3253                         MONO_INST_NEW (cfg, ins, OP_GETTYPE);
3254                         ins->inst_i0 = args [0];
3255                         return ins;
3256                 /* The OP_GETHASHCODE rule depends on OP_MUL */
3257 #if !defined(MONO_ARCH_EMULATE_MUL_DIV) && !defined(HAVE_MOVING_COLLECTOR)
3258                 } else if (strcmp (cmethod->name, "InternalGetHashCode") == 0) {
3259                         MONO_INST_NEW (cfg, ins, OP_GETHASHCODE);
3260                         ins->inst_i0 = args [0];
3261                         return ins;
3262 #endif
3263                 } else if (strcmp (cmethod->name, ".ctor") == 0) {
3264                         MONO_INST_NEW (cfg, ins, CEE_NOP);
3265                         return ins;
3266                 } else
3267                         return NULL;
3268         } else if (cmethod->klass == mono_defaults.array_class) {
3269                 if (cmethod->name [0] != 'g')
3270                         return NULL;
3271
3272                 if (strcmp (cmethod->name, "get_Rank") == 0) {
3273                         MONO_INST_NEW (cfg, ins, OP_ARRAY_RANK);
3274                         ins->inst_i0 = args [0];
3275                         return ins;
3276                 } else if (strcmp (cmethod->name, "get_Length") == 0) {
3277                         MONO_INST_NEW (cfg, ins, CEE_LDLEN);
3278                         ins->inst_i0 = args [0];
3279                         return ins;
3280                 } else
3281                         return NULL;
3282         } else if (cmethod->klass == runtime_helpers_class) {
3283                 if (strcmp (cmethod->name, "get_OffsetToStringData") == 0) {
3284                         NEW_ICONST (cfg, ins, G_STRUCT_OFFSET (MonoString, chars));
3285                         return ins;
3286                 } else
3287                         return NULL;
3288         } else if (cmethod->klass == mono_defaults.thread_class) {
3289                 if (strcmp (cmethod->name, "get_CurrentThread") == 0 && (ins = mono_arch_get_thread_intrinsic (cfg)))
3290                         return ins;
3291         } else if (mini_class_is_system_array (cmethod->klass) &&
3292                         strcmp (cmethod->name, "GetGenericValueImpl") == 0) {
3293                 MonoInst *sp [2];
3294                 MonoInst *ldelem, *store, *load;
3295                 MonoClass *eklass = mono_class_from_mono_type (fsig->params [1]);
3296                 int n;
3297                 n = mono_type_to_stind (&eklass->byval_arg);
3298                 if (n == CEE_STOBJ)
3299                         return NULL;
3300                 sp [0] = args [0];
3301                 sp [1] = args [1];
3302                 NEW_LDELEMA (cfg, ldelem, sp, eklass);
3303                 ldelem->flags |= MONO_INST_NORANGECHECK;
3304                 MONO_INST_NEW (cfg, store, n);
3305                 n = mono_type_to_ldind (&eklass->byval_arg);
3306                 MONO_INST_NEW (cfg, load, mono_type_to_ldind (&eklass->byval_arg));
3307                 type_to_eval_stack_type (&eklass->byval_arg, load);
3308                 load->inst_left = ldelem;
3309                 store->inst_left = args [2];
3310                 store->inst_right = load;
3311                 return store;
3312         } else if (cmethod->klass->image == mono_defaults.corlib) {
3313                 if (cmethod->name [0] == 'B' && strcmp (cmethod->name, "Break") == 0
3314                                 && strcmp (cmethod->klass->name, "Debugger") == 0) {
3315                         MONO_INST_NEW (cfg, ins, CEE_BREAK);
3316                         return ins;
3317                 }
3318                 if (cmethod->name [0] == 'g' && strcmp (cmethod->name, "get_IsRunningOnWindows") == 0
3319                                 && strcmp (cmethod->klass->name, "Environment") == 0) {
3320 #ifdef PLATFORM_WIN32
3321                         NEW_ICONST (cfg, ins, 1);
3322 #else
3323                         NEW_ICONST (cfg, ins, 0);
3324 #endif
3325                         return ins;
3326                 }
3327         }
3328
3329         return mono_arch_get_inst_for_method (cfg, cmethod, fsig, args);
3330 }
3331
3332 static void
3333 mono_save_args (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethodSignature *sig, MonoInst **sp, MonoInst **args)
3334 {
3335         MonoInst *store, *temp;
3336         int i;
3337
3338         g_assert (!MONO_TYPE_ISSTRUCT (sig->ret));
3339
3340         if (!sig->hasthis && sig->param_count == 0) 
3341                 return;
3342
3343         if (sig->hasthis) {
3344                 if (sp [0]->opcode == OP_ICONST) {
3345                         *args++ = sp [0];
3346                 } else {
3347                         temp = mono_compile_create_var (cfg, type_from_stack_type (*sp), OP_LOCAL);
3348                         *args++ = temp;
3349                         NEW_TEMPSTORE (cfg, store, temp->inst_c0, *sp);
3350                         store->cil_code = sp [0]->cil_code;
3351                         MONO_ADD_INS (bblock, store);
3352                 }
3353                 sp++;
3354         }
3355
3356         for (i = 0; i < sig->param_count; ++i) {
3357                 if (sp [0]->opcode == OP_ICONST) {
3358                         *args++ = sp [0];
3359                 } else {
3360                         temp = mono_compile_create_var (cfg, sig->params [i], OP_LOCAL);
3361                         *args++ = temp;
3362                         NEW_TEMPSTORE (cfg, store, temp->inst_c0, *sp);
3363                         store->cil_code = sp [0]->cil_code;
3364                         if (store->opcode == CEE_STOBJ) {
3365                                 NEW_TEMPLOADA (cfg, store, temp->inst_c0);
3366                                 handle_stobj (cfg, bblock, store, *sp, sp [0]->cil_code, temp->klass, FALSE, FALSE, FALSE);
3367                         } else {
3368                                 MONO_ADD_INS (bblock, store);
3369                         } 
3370                 }
3371                 sp++;
3372         }
3373 }
3374 #define MONO_INLINE_CALLED_LIMITED_METHODS 0
3375 #define MONO_INLINE_CALLER_LIMITED_METHODS 0
3376
3377 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
3378 static char*
3379 mono_inline_called_method_name_limit = NULL;
3380 static gboolean check_inline_called_method_name_limit (MonoMethod *called_method) {
3381         char *called_method_name = mono_method_full_name (called_method, TRUE);
3382         int strncmp_result;
3383         
3384         if (mono_inline_called_method_name_limit == NULL) {
3385                 char *limit_string = getenv ("MONO_INLINE_CALLED_METHOD_NAME_LIMIT");
3386                 if (limit_string != NULL) {
3387                         mono_inline_called_method_name_limit = limit_string;
3388                 } else {
3389                         mono_inline_called_method_name_limit = (char *) "";
3390                 }
3391         }
3392         
3393         strncmp_result = strncmp (called_method_name, mono_inline_called_method_name_limit, strlen (mono_inline_called_method_name_limit));
3394         g_free (called_method_name);
3395         
3396         //return (strncmp_result <= 0);
3397         return (strncmp_result == 0);
3398 }
3399 #endif
3400
3401 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
3402 static char*
3403 mono_inline_caller_method_name_limit = NULL;
3404 static gboolean check_inline_caller_method_name_limit (MonoMethod *caller_method) {
3405         char *caller_method_name = mono_method_full_name (caller_method, TRUE);
3406         int strncmp_result;
3407         
3408         if (mono_inline_caller_method_name_limit == NULL) {
3409                 char *limit_string = getenv ("MONO_INLINE_CALLER_METHOD_NAME_LIMIT");
3410                 if (limit_string != NULL) {
3411                         mono_inline_caller_method_name_limit = limit_string;
3412                 } else {
3413                         mono_inline_caller_method_name_limit = (char *) "";
3414                 }
3415         }
3416         
3417         strncmp_result = strncmp (caller_method_name, mono_inline_caller_method_name_limit, strlen (mono_inline_caller_method_name_limit));
3418         g_free (caller_method_name);
3419         
3420         //return (strncmp_result <= 0);
3421         return (strncmp_result == 0);
3422 }
3423 #endif
3424
3425 static int
3426 inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoBasicBlock *bblock, MonoInst **sp,
3427                 guchar *ip, guint real_offset, GList *dont_inline, MonoBasicBlock **last_b, gboolean inline_allways)
3428 {
3429         MonoInst *ins, *rvar = NULL;
3430         MonoMethodHeader *cheader;
3431         MonoBasicBlock *ebblock, *sbblock;
3432         int i, costs, new_locals_offset;
3433         MonoMethod *prev_inlined_method;
3434 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
3435         if ((! inline_allways) && ! check_inline_called_method_name_limit (cmethod))
3436                 return 0;
3437 #endif
3438 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
3439         if ((! inline_allways) && ! check_inline_caller_method_name_limit (cfg->method))
3440                 return 0;
3441 #endif
3442
3443         if (bblock->out_of_line && !inline_allways)
3444                 return 0;
3445
3446         if (cfg->verbose_level > 2)
3447                 g_print ("INLINE START %p %s -> %s\n", cmethod,  mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
3448
3449         if (!cmethod->inline_info) {
3450                 mono_jit_stats.inlineable_methods++;
3451                 cmethod->inline_info = 1;
3452         }
3453         /* allocate space to store the return value */
3454         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
3455                 rvar =  mono_compile_create_var (cfg, fsig->ret, OP_LOCAL);
3456         }
3457
3458         /* allocate local variables */
3459         cheader = mono_method_get_header (cmethod);
3460         new_locals_offset = cfg->num_varinfo;
3461         for (i = 0; i < cheader->num_locals; ++i)
3462                 mono_compile_create_var (cfg, cheader->locals [i], OP_LOCAL);
3463         
3464         /* allocate starte and end blocks */
3465         sbblock = NEW_BBLOCK (cfg);
3466         sbblock->block_num = cfg->num_bblocks++;
3467         sbblock->real_offset = real_offset;
3468
3469         ebblock = NEW_BBLOCK (cfg);
3470         ebblock->block_num = cfg->num_bblocks++;
3471         ebblock->real_offset = real_offset;
3472
3473         prev_inlined_method = cfg->inlined_method;
3474         cfg->inlined_method = cmethod;
3475
3476         costs = mono_method_to_ir (cfg, cmethod, sbblock, ebblock, new_locals_offset, rvar, dont_inline, sp, real_offset, *ip == CEE_CALLVIRT);
3477
3478         cfg->inlined_method = prev_inlined_method;
3479
3480         if ((costs >= 0 && costs < 60) || inline_allways) {
3481                 if (cfg->verbose_level > 2)
3482                         g_print ("INLINE END %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
3483                 
3484                 mono_jit_stats.inlined_methods++;
3485
3486                 /* always add some code to avoid block split failures */
3487                 MONO_INST_NEW (cfg, ins, CEE_NOP);
3488                 MONO_ADD_INS (bblock, ins);
3489                 ins->cil_code = ip;
3490
3491                 bblock->next_bb = sbblock;
3492                 link_bblock (cfg, bblock, sbblock);
3493
3494                 if (rvar) {
3495                         NEW_TEMPLOAD (cfg, ins, rvar->inst_c0);
3496                         *sp++ = ins;
3497                 }
3498                 *last_b = ebblock;
3499                 return costs + 1;
3500         } else {
3501                 if (cfg->verbose_level > 2)
3502                         g_print ("INLINE ABORTED %s\n", mono_method_full_name (cmethod, TRUE));
3503         }
3504         return 0;
3505 }
3506
3507 /*
3508  * Some of these comments may well be out-of-date.
3509  * Design decisions: we do a single pass over the IL code (and we do bblock 
3510  * splitting/merging in the few cases when it's required: a back jump to an IL
3511  * address that was not already seen as bblock starting point).
3512  * Code is validated as we go (full verification is still better left to metadata/verify.c).
3513  * Complex operations are decomposed in simpler ones right away. We need to let the 
3514  * arch-specific code peek and poke inside this process somehow (except when the 
3515  * optimizations can take advantage of the full semantic info of coarse opcodes).
3516  * All the opcodes of the form opcode.s are 'normalized' to opcode.
3517  * MonoInst->opcode initially is the IL opcode or some simplification of that 
3518  * (OP_LOAD, OP_STORE). The arch-specific code may rearrange it to an arch-specific 
3519  * opcode with value bigger than OP_LAST.
3520  * At this point the IR can be handed over to an interpreter, a dumb code generator
3521  * or to the optimizing code generator that will translate it to SSA form.
3522  *
3523  * Profiling directed optimizations.
3524  * We may compile by default with few or no optimizations and instrument the code
3525  * or the user may indicate what methods to optimize the most either in a config file
3526  * or through repeated runs where the compiler applies offline the optimizations to 
3527  * each method and then decides if it was worth it.
3528  *
3529  * TODO:
3530  * * consider using an array instead of an hash table (bb_hash)
3531  */
3532
3533 #define CHECK_TYPE(ins) if (!(ins)->type) UNVERIFIED
3534 #define CHECK_STACK(num) if ((sp - stack_start) < (num)) UNVERIFIED
3535 #define CHECK_STACK_OVF(num) if (((sp - stack_start) + (num)) > header->max_stack) UNVERIFIED
3536 #define CHECK_ARG(num) if ((unsigned)(num) >= (unsigned)num_args) UNVERIFIED
3537 #define CHECK_LOCAL(num) if ((unsigned)(num) >= (unsigned)header->num_locals) UNVERIFIED
3538 #define CHECK_OPSIZE(size) if (ip + size > end) UNVERIFIED
3539 #define CHECK_UNVERIFIABLE(cfg) if (cfg->unverifiable) UNVERIFIED
3540 #define CHECK_TYPELOAD(klass) if (!(klass) || (klass)->exception_type) {cfg->exception_ptr = klass; goto load_error;}
3541
3542 /* offset from br.s -> br like opcodes */
3543 #define BIG_BRANCH_OFFSET 13
3544
3545 static gboolean
3546 ip_in_bb (MonoCompile *cfg, MonoBasicBlock *bb, const guint8* ip)
3547 {
3548         MonoBasicBlock *b = g_hash_table_lookup (cfg->bb_hash, ip);
3549         
3550         return b == NULL || b == bb;
3551 }
3552
3553 static int
3554 get_basic_blocks (MonoCompile *cfg, GHashTable *bbhash, MonoMethodHeader* header, guint real_offset, unsigned char *start, unsigned char *end, unsigned char **pos)
3555 {
3556         unsigned char *ip = start;
3557         unsigned char *target;
3558         int i;
3559         guint cli_addr;
3560         MonoBasicBlock *bblock;
3561         const MonoOpcode *opcode;
3562
3563         while (ip < end) {
3564                 cli_addr = ip - start;
3565                 i = mono_opcode_value ((const guint8 **)&ip, end);
3566                 if (i < 0)
3567                         UNVERIFIED;
3568                 opcode = &mono_opcodes [i];
3569                 switch (opcode->argument) {
3570                 case MonoInlineNone:
3571                         ip++; 
3572                         break;
3573                 case MonoInlineString:
3574                 case MonoInlineType:
3575                 case MonoInlineField:
3576                 case MonoInlineMethod:
3577                 case MonoInlineTok:
3578                 case MonoInlineSig:
3579                 case MonoShortInlineR:
3580                 case MonoInlineI:
3581                         ip += 5;
3582                         break;
3583                 case MonoInlineVar:
3584                         ip += 3;
3585                         break;
3586                 case MonoShortInlineVar:
3587                 case MonoShortInlineI:
3588                         ip += 2;
3589                         break;
3590                 case MonoShortInlineBrTarget:
3591                         target = start + cli_addr + 2 + (signed char)ip [1];
3592                         GET_BBLOCK (cfg, bbhash, bblock, target);
3593                         ip += 2;
3594                         if (ip < end)
3595                                 GET_BBLOCK (cfg, bbhash, bblock, ip);
3596                         break;
3597                 case MonoInlineBrTarget:
3598                         target = start + cli_addr + 5 + (gint32)read32 (ip + 1);
3599                         GET_BBLOCK (cfg, bbhash, bblock, target);
3600                         ip += 5;
3601                         if (ip < end)
3602                                 GET_BBLOCK (cfg, bbhash, bblock, ip);
3603                         break;
3604                 case MonoInlineSwitch: {
3605                         guint32 n = read32 (ip + 1);
3606                         guint32 j;
3607                         ip += 5;
3608                         cli_addr += 5 + 4 * n;
3609                         target = start + cli_addr;
3610                         GET_BBLOCK (cfg, bbhash, bblock, target);
3611                         
3612                         for (j = 0; j < n; ++j) {
3613                                 target = start + cli_addr + (gint32)read32 (ip);
3614                                 GET_BBLOCK (cfg, bbhash, bblock, target);
3615                                 ip += 4;
3616                         }
3617                         break;
3618                 }
3619                 case MonoInlineR:
3620                 case MonoInlineI8:
3621                         ip += 9;
3622                         break;
3623                 default:
3624                         g_assert_not_reached ();
3625                 }
3626
3627                 if (i == CEE_THROW) {
3628                         unsigned char *bb_start = ip - 1;
3629                         
3630                         /* Find the start of the bblock containing the throw */
3631                         bblock = NULL;
3632                         while ((bb_start >= start) && !bblock) {
3633                                 bblock = g_hash_table_lookup (bbhash, (bb_start));
3634                                 bb_start --;
3635                         }
3636                         if (bblock)
3637                                 bblock->out_of_line = 1;
3638                 }
3639         }
3640         return 0;
3641 unverified:
3642         *pos = ip;
3643         return 1;
3644 }
3645
3646 static MonoInst*
3647 emit_tree (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *ins, const guint8* ip_next)
3648 {
3649         MonoInst *store, *temp, *load;
3650         
3651         if (ip_in_bb (cfg, bblock, ip_next) &&
3652                 (CODE_IS_STLOC (ip_next) || *ip_next == CEE_RET))
3653                         return ins;
3654         
3655         temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
3656         temp->flags |= MONO_INST_IS_TEMP;
3657         NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
3658         store->cil_code = ins->cil_code;
3659         MONO_ADD_INS (bblock, store);
3660         NEW_TEMPLOAD (cfg, load, temp->inst_c0);
3661         load->cil_code = ins->cil_code;
3662         return load;
3663 }
3664
3665 static inline MonoMethod *
3666 mini_get_method (MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
3667 {
3668         MonoMethod *method;
3669
3670         if (m->wrapper_type != MONO_WRAPPER_NONE)
3671                 return mono_method_get_wrapper_data (m, token);
3672
3673         method = mono_get_method_full (m->klass->image, token, klass, context);
3674
3675         if (method && method->is_inflated)
3676                 method = mono_get_inflated_method (method);
3677
3678         return method;
3679 }
3680
3681 static inline MonoClass*
3682 mini_get_class (MonoMethod *method, guint32 token, MonoGenericContext *context)
3683 {
3684         MonoClass *klass;
3685
3686         if (method->wrapper_type != MONO_WRAPPER_NONE)
3687                 klass = mono_method_get_wrapper_data (method, token);
3688         else
3689                 klass = mono_class_get_full (method->klass->image, token, context);
3690         if (klass)
3691                 mono_class_init (klass);
3692         return klass;
3693 }
3694
3695 /*
3696  * Returns TRUE if the JIT should abort inlining because "callee"
3697  * is influenced by security attributes.
3698  */
3699 static
3700 gboolean check_linkdemand (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee, MonoBasicBlock *bblock, unsigned char *ip)
3701 {
3702         guint32 result;
3703         
3704         if ((cfg->method != caller) && mono_method_has_declsec (callee)) {
3705                 return TRUE;
3706         }
3707         
3708         result = mono_declsec_linkdemand (cfg->domain, caller, callee);
3709         if (result == MONO_JIT_SECURITY_OK)
3710                 return FALSE;
3711
3712         if (result == MONO_JIT_LINKDEMAND_ECMA) {
3713                 /* Generate code to throw a SecurityException before the actual call/link */
3714                 MonoAssembly *assembly = mono_image_get_assembly (caller->klass->image);
3715                 MonoReflectionAssembly *refass = (MonoReflectionAssembly*) mono_assembly_get_object (cfg->domain, assembly);
3716                 MonoReflectionMethod *refmet = mono_method_get_object (cfg->domain, caller, NULL);
3717                 MonoSecurityManager *secman = mono_security_manager_get_methods ();
3718                 MonoInst *args [3];
3719
3720                 NEW_ICONST (cfg, args [0], 4);
3721                 NEW_PCONST (cfg, args [1], refass);
3722                 NEW_PCONST (cfg, args [2], refmet);
3723                 mono_emit_method_call_spilled (cfg, bblock, secman->linkdemandsecurityexception, mono_method_signature (secman->linkdemandsecurityexception), args, ip, NULL);
3724         } else if (cfg->exception_type == MONO_EXCEPTION_NONE) {
3725                  /* don't hide previous results */
3726                 cfg->exception_type = MONO_EXCEPTION_SECURITY_LINKDEMAND;
3727                 cfg->exception_data = result;
3728         }
3729         
3730         return FALSE;
3731 }
3732
3733 static gboolean
3734 can_access_internals (MonoAssembly *accessing, MonoAssembly* accessed)
3735 {
3736         GSList *tmp;
3737         if (accessing == accessed)
3738                 return TRUE;
3739         if (!accessed || !accessing)
3740                 return FALSE;
3741         for (tmp = accessed->friend_assembly_names; tmp; tmp = tmp->next) {
3742                 MonoAssemblyName *friend = tmp->data;
3743                 /* Be conservative with checks */
3744                 if (!friend->name)
3745                         continue;
3746                 if (strcmp (accessing->aname.name, friend->name))
3747                         continue;
3748                 if (friend->public_key_token [0]) {
3749                         if (!accessing->aname.public_key_token [0])
3750                                 continue;
3751                         if (strcmp ((char*)friend->public_key_token, (char*)accessing->aname.public_key_token))
3752                                 continue;
3753                 }
3754                 return TRUE;
3755         }
3756         return FALSE;
3757 }
3758
3759 /* FIXME: check visibility of type, too */
3760 static gboolean
3761 can_access_member (MonoClass *access_klass, MonoClass *member_klass, int access_level)
3762 {
3763         /* Partition I 8.5.3.2 */
3764         /* the access level values are the same for fields and methods */
3765         switch (access_level) {
3766         case FIELD_ATTRIBUTE_COMPILER_CONTROLLED:
3767                 /* same compilation unit */
3768                 return access_klass->image == member_klass->image;
3769         case FIELD_ATTRIBUTE_PRIVATE:
3770                 if (access_klass->generic_class && member_klass->generic_class && member_klass->generic_class->container_class)
3771                         return member_klass->generic_class->container_class == access_klass->generic_class->container_class;
3772                 return access_klass == member_klass;
3773         case FIELD_ATTRIBUTE_FAM_AND_ASSEM:
3774                 if (mono_class_has_parent (access_klass, member_klass) &&
3775                                 can_access_internals (access_klass->image->assembly, member_klass->image->assembly))
3776                         return TRUE;
3777                 return FALSE;
3778         case FIELD_ATTRIBUTE_ASSEMBLY:
3779                 return can_access_internals (access_klass->image->assembly, member_klass->image->assembly);
3780         case FIELD_ATTRIBUTE_FAMILY:
3781                 if (mono_class_has_parent (access_klass, member_klass))
3782                         return TRUE;
3783                 return FALSE;
3784         case FIELD_ATTRIBUTE_FAM_OR_ASSEM:
3785                 if (mono_class_has_parent (access_klass, member_klass))
3786                         return TRUE;
3787                 return can_access_internals (access_klass->image->assembly, member_klass->image->assembly);
3788         case FIELD_ATTRIBUTE_PUBLIC:
3789                 return TRUE;
3790         }
3791         return FALSE;
3792 }
3793
3794 static gboolean
3795 can_access_field (MonoMethod *method, MonoClassField *field)
3796 {
3797         /* FIXME: check all overlapping fields */
3798         int can = can_access_member (method->klass, field->parent, field->type->attrs & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK);
3799         if (!can) {
3800                 MonoClass *nested = method->klass->nested_in;
3801                 while (nested) {
3802                         can = can_access_member (nested, field->parent, field->type->attrs & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK);
3803                         if (can)
3804                                 return TRUE;
3805                         nested = nested->nested_in;
3806                 }
3807         }
3808         return can;
3809 }
3810
3811 static gboolean
3812 can_access_method (MonoMethod *method, MonoMethod *called)
3813 {
3814         int can = can_access_member (method->klass, called->klass, called->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK);
3815         if (!can) {
3816                 MonoClass *nested = method->klass->nested_in;
3817                 while (nested) {
3818                         can = can_access_member (nested, called->klass, called->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK);
3819                         if (can)
3820                                 return TRUE;
3821                         nested = nested->nested_in;
3822                 }
3823         }
3824         /* 
3825          * FIXME:
3826          * with generics calls to explicit interface implementations can be expressed
3827          * directly: the method is private, but we must allow it. This may be opening
3828          * a hole or the generics code should handle this differently.
3829          * Maybe just ensure the interface type is public.
3830          */
3831         if ((called->flags & METHOD_ATTRIBUTE_VIRTUAL) && (called->flags & METHOD_ATTRIBUTE_FINAL))
3832                 return TRUE;
3833         return can;
3834 }
3835
3836 /*
3837  * Check that the IL instructions at ip are the array initialization
3838  * sequence and return the pointer to the data and the size.
3839  */
3840 static const char*
3841 initialize_array_data (MonoMethod *method, gboolean aot, unsigned char *ip, MonoInst *newarr, int *out_size)
3842 {
3843         /*
3844          * newarr[System.Int32]
3845          * dup
3846          * ldtoken field valuetype ...
3847          * call void class [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype [mscorlib]System.RuntimeFieldHandle)
3848          */
3849         if (ip [0] == CEE_DUP && ip [1] == CEE_LDTOKEN && ip [5] == 0x4 && ip [6] == CEE_CALL) {
3850                 MonoClass *klass = newarr->inst_newa_class;
3851                 guint32 token = read32 (ip + 7);
3852                 guint32 rva, field_index;
3853                 const char *data_ptr;
3854                 int size = 0;
3855                 MonoMethod *cmethod;
3856
3857                 if (newarr->inst_newa_len->opcode != OP_ICONST)
3858                         return NULL;
3859                 cmethod = mini_get_method (method, token, NULL, NULL);
3860                 if (strcmp (cmethod->name, "InitializeArray") || strcmp (cmethod->klass->name, "RuntimeHelpers") || cmethod->klass->image != mono_defaults.corlib)
3861                         return NULL;
3862                 switch (mono_type_get_underlying_type (&klass->byval_arg)->type) {
3863                 case MONO_TYPE_BOOLEAN:
3864                 case MONO_TYPE_I1:
3865                 case MONO_TYPE_U1:
3866                         size = 1; break;
3867                 /* we need to swap on big endian, so punt. Should we handle R4 and R8 as well? */
3868 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
3869                 case MONO_TYPE_CHAR:
3870                 case MONO_TYPE_I2:
3871                 case MONO_TYPE_U2:
3872                         size = 2; break;
3873                 case MONO_TYPE_I4:
3874                 case MONO_TYPE_U4:
3875                 case MONO_TYPE_R4:
3876                         size = 4; break;
3877                 case MONO_TYPE_R8:
3878 #ifdef ARM_FPU_FPA
3879                         return NULL; /* stupid ARM FP swapped format */
3880 #endif
3881                 case MONO_TYPE_I8:
3882                 case MONO_TYPE_U8:
3883                         size = 8; break;
3884 #endif
3885                 default:
3886                         return NULL;
3887                 }
3888                 size *= newarr->inst_newa_len->inst_c0;
3889                 *out_size = size;
3890                 /*g_print ("optimized in %s: size: %d, numelems: %d\n", method->name, size, newarr->inst_newa_len->inst_c0);*/
3891                 field_index = read32 (ip + 2) & 0xffffff;
3892                 mono_metadata_field_info (method->klass->image, field_index - 1, NULL, &rva, NULL);
3893                 data_ptr = mono_image_rva_map (method->klass->image, rva);
3894                 /*g_print ("field: 0x%08x, rva: %d, rva_ptr: %p\n", read32 (ip + 2), rva, data_ptr);*/
3895                 /* for aot code we do the lookup on load */
3896                 if (aot && data_ptr)
3897                         return GUINT_TO_POINTER (rva);
3898                 return data_ptr;
3899         }
3900         return NULL;
3901 }
3902
3903 /*
3904  * mono_method_to_ir: translates IL into basic blocks containing trees
3905  */
3906 static int
3907 mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock, 
3908                    int locals_offset, MonoInst *return_var, GList *dont_inline, MonoInst **inline_args, 
3909                    guint inline_offset, gboolean is_virtual_call)
3910 {
3911         MonoInst *zero_int32, *zero_int64, *zero_ptr, *zero_obj, *zero_r8;
3912         MonoInst *ins, **sp, **stack_start;
3913         MonoBasicBlock *bblock, *tblock = NULL, *init_localsbb = NULL;
3914         GHashTable *bbhash;
3915         MonoMethod *cmethod;
3916         MonoInst **arg_array;
3917         MonoMethodHeader *header;
3918         MonoImage *image;
3919         guint32 token, ins_flag;
3920         MonoClass *klass;
3921         MonoClass *constrained_call = NULL;
3922         unsigned char *ip, *end, *target, *err_pos;
3923         static double r8_0 = 0.0;
3924         MonoMethodSignature *sig;
3925         MonoGenericContext *generic_context = NULL;
3926         MonoGenericContainer *generic_container = NULL;
3927         MonoType **param_types;
3928         GList *bb_recheck = NULL, *tmp;
3929         int i, n, start_new_bblock, ialign;
3930         int num_calls = 0, inline_costs = 0;
3931         int breakpoint_id = 0;
3932         guint32 align;
3933         guint real_offset, num_args;
3934         MonoBoolean security, pinvoke;
3935         MonoSecurityManager* secman = NULL;
3936         MonoDeclSecurityActions actions;
3937         GSList *class_inits = NULL;
3938         gboolean dont_verify, dont_verify_stloc;
3939
3940         /* serialization and xdomain stuff may need access to private fields and methods */
3941         dont_verify = method->klass->image->assembly->corlib_internal? TRUE: FALSE;
3942         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE;
3943         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH;
3944         dont_verify |= method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE; /* bug #77896 */
3945         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP;
3946         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP_INVOKE;
3947
3948         /* still some type unsafety issues in marshal wrappers... (unknown is PtrToStructure) */
3949         dont_verify_stloc = method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE;
3950         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_UNKNOWN;
3951         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED;
3952
3953         /* Not turned on yet */
3954         cfg->dont_verify_stack_merge = TRUE;
3955
3956         image = method->klass->image;
3957         header = mono_method_get_header (method);
3958         generic_container = method->generic_container;
3959         sig = mono_method_signature (method);
3960         num_args = sig->hasthis + sig->param_count;
3961         ip = (unsigned char*)header->code;
3962         end = ip + header->code_size;
3963         mono_jit_stats.cil_code_size += header->code_size;
3964
3965         if (sig->is_inflated)
3966                 generic_context = mono_method_get_context (method);
3967         else if (generic_container)
3968                 generic_context = &generic_container->context;
3969
3970         g_assert (!sig->has_type_parameters);
3971
3972         if (cfg->method == method) {
3973                 real_offset = 0;
3974                 bbhash = cfg->bb_hash;
3975         } else {
3976                 real_offset = inline_offset;
3977                 bbhash = g_hash_table_new (g_direct_hash, NULL);
3978         }
3979
3980         if (cfg->verbose_level > 2)
3981                 g_print ("method to IR %s\n", mono_method_full_name (method, TRUE));
3982
3983         dont_inline = g_list_prepend (dont_inline, method);
3984         if (cfg->method == method) {
3985
3986                 if (cfg->prof_options & MONO_PROFILE_INS_COVERAGE)
3987                         cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, header->code_size);
3988
3989                 /* ENTRY BLOCK */
3990                 cfg->bb_entry = start_bblock = NEW_BBLOCK (cfg);
3991                 start_bblock->cil_code = NULL;
3992                 start_bblock->cil_length = 0;
3993                 start_bblock->block_num = cfg->num_bblocks++;
3994
3995                 /* EXIT BLOCK */
3996                 cfg->bb_exit = end_bblock = NEW_BBLOCK (cfg);
3997                 end_bblock->cil_code = NULL;
3998                 end_bblock->cil_length = 0;
3999                 end_bblock->block_num = cfg->num_bblocks++;
4000                 g_assert (cfg->num_bblocks == 2);
4001
4002                 arg_array = alloca (sizeof (MonoInst *) * num_args);
4003                 for (i = num_args - 1; i >= 0; i--)
4004                         arg_array [i] = cfg->varinfo [i];
4005
4006                 if (header->num_clauses) {
4007                         cfg->spvars = g_hash_table_new (NULL, NULL);
4008                         cfg->exvars = g_hash_table_new (NULL, NULL);
4009                 }
4010                 /* handle exception clauses */
4011                 for (i = 0; i < header->num_clauses; ++i) {
4012                         MonoBasicBlock *try_bb;
4013                         MonoExceptionClause *clause = &header->clauses [i];
4014                         GET_BBLOCK (cfg, bbhash, try_bb, ip + clause->try_offset);
4015                         try_bb->real_offset = clause->try_offset;
4016                         GET_BBLOCK (cfg, bbhash, tblock, ip + clause->handler_offset);
4017                         tblock->real_offset = clause->handler_offset;
4018                         tblock->flags |= BB_EXCEPTION_HANDLER;
4019
4020                         link_bblock (cfg, try_bb, tblock);
4021
4022                         if (*(ip + clause->handler_offset) == CEE_POP)
4023                                 tblock->flags |= BB_EXCEPTION_DEAD_OBJ;
4024
4025                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY ||
4026                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER ||
4027                             clause->flags == MONO_EXCEPTION_CLAUSE_FAULT) {
4028                                 MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
4029                                 MONO_ADD_INS (tblock, ins);
4030
4031                                 /* todo: is a fault block unsafe to optimize? */
4032                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
4033                                         tblock->flags |= BB_EXCEPTION_UNSAFE;
4034                         }
4035
4036
4037                         /*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);
4038                           while (p < end) {
4039                           g_print ("%s", mono_disasm_code_one (NULL, method, p, &p));
4040                           }*/
4041                         /* catch and filter blocks get the exception object on the stack */
4042                         if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE ||
4043                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
4044                                 MonoInst *load, *dummy_use;
4045
4046                                 /* mostly like handle_stack_args (), but just sets the input args */
4047                                 /* g_print ("handling clause at IL_%04x\n", clause->handler_offset); */
4048                                 tblock->in_scount = 1;
4049                                 tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
4050                                 tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
4051                                 tblock->stack_state = mono_mempool_alloc (cfg->mempool, sizeof (MonoStackSlot));
4052                                 tblock->stack_state [0].type = STACK_OBJ;
4053                                 /* FIXME? */
4054                                 tblock->stack_state [0].klass = mono_defaults.object_class;
4055
4056                                 /* 
4057                                  * Add a dummy use for the exvar so its liveness info will be
4058                                  * correct.
4059                                  */
4060                                 NEW_TEMPLOAD (cfg, load, tblock->in_stack [0]->inst_c0);
4061                                 NEW_DUMMY_USE (cfg, dummy_use, load);
4062                                 MONO_ADD_INS (tblock, dummy_use);
4063                                 
4064                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
4065                                         GET_BBLOCK (cfg, bbhash, tblock, ip + clause->data.filter_offset);
4066                                         tblock->real_offset = clause->data.filter_offset;
4067                                         tblock->in_scount = 1;
4068                                         tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
4069                                         tblock->stack_state = mono_mempool_alloc (cfg->mempool, sizeof (MonoStackSlot));
4070                                         tblock->stack_state [0].type = STACK_OBJ;
4071                                         /* FIXME? */
4072                                         tblock->stack_state [0].klass = mono_defaults.object_class;
4073
4074                                         /* The filter block shares the exvar with the handler block */
4075                                         tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
4076                                         MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
4077                                         MONO_ADD_INS (tblock, ins);
4078                                 }
4079                         }
4080                 }
4081         } else {
4082                 arg_array = alloca (sizeof (MonoInst *) * num_args);
4083                 mono_save_args (cfg, start_bblock, sig, inline_args, arg_array);
4084         }
4085
4086         /* FIRST CODE BLOCK */
4087         bblock = NEW_BBLOCK (cfg);
4088         bblock->cil_code = ip;
4089
4090         ADD_BBLOCK (cfg, bbhash, bblock);
4091
4092         if (cfg->method == method) {
4093                 breakpoint_id = mono_debugger_method_has_breakpoint (method);
4094                 if (breakpoint_id && (mono_debug_format != MONO_DEBUG_FORMAT_DEBUGGER)) {
4095                         MONO_INST_NEW (cfg, ins, CEE_BREAK);
4096                         MONO_ADD_INS (bblock, ins);
4097                 }
4098         }
4099
4100         if (mono_use_security_manager)
4101                 secman = mono_security_manager_get_methods ();
4102
4103         security = (secman && mono_method_has_declsec (method));
4104         /* at this point having security doesn't mean we have any code to generate */
4105         if (security && (cfg->method == method)) {
4106                 /* Only Demand, NonCasDemand and DemandChoice requires code generation.
4107                  * And we do not want to enter the next section (with allocation) if we
4108                  * have nothing to generate */
4109                 security = mono_declsec_get_demands (method, &actions);
4110         }
4111
4112         /* we must Demand SecurityPermission.Unmanaged before P/Invoking */
4113         pinvoke = (secman && (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE));
4114         if (pinvoke) {
4115                 MonoMethod *wrapped = mono_marshal_method_from_wrapper (method);
4116                 if (wrapped && (wrapped->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
4117                         MonoCustomAttrInfo* custom = mono_custom_attrs_from_method (wrapped);
4118
4119                         /* unless the method or it's class has the [SuppressUnmanagedCodeSecurity] attribute */
4120                         if (custom && mono_custom_attrs_has_attr (custom, secman->suppressunmanagedcodesecurity)) {
4121                                 pinvoke = FALSE;
4122                         }
4123
4124                         if (pinvoke) {
4125                                 custom = mono_custom_attrs_from_class (wrapped->klass);
4126                                 if (custom && mono_custom_attrs_has_attr (custom, secman->suppressunmanagedcodesecurity)) {
4127                                         pinvoke = FALSE;
4128                                 }
4129                         }
4130                 } else {
4131                         /* not a P/Invoke after all */
4132                         pinvoke = FALSE;
4133                 }
4134         }
4135         
4136         if ((header->init_locals || (cfg->method == method && (cfg->opt & MONO_OPT_SHARED))) || cfg->compile_aot || security || pinvoke) {
4137                 /* we use a separate basic block for the initialization code */
4138                 cfg->bb_init = init_localsbb = NEW_BBLOCK (cfg);
4139                 init_localsbb->real_offset = real_offset;
4140                 start_bblock->next_bb = init_localsbb;
4141                 init_localsbb->next_bb = bblock;
4142                 link_bblock (cfg, start_bblock, init_localsbb);
4143                 link_bblock (cfg, init_localsbb, bblock);
4144                 init_localsbb->block_num = cfg->num_bblocks++;
4145         } else {
4146                 start_bblock->next_bb = bblock;
4147                 link_bblock (cfg, start_bblock, bblock);
4148         }
4149
4150         /* at this point we know, if security is TRUE, that some code needs to be generated */
4151         if (security && (cfg->method == method)) {
4152                 MonoInst *args [2];
4153
4154                 mono_jit_stats.cas_demand_generation++;
4155
4156                 if (actions.demand.blob) {
4157                         /* Add code for SecurityAction.Demand */
4158                         NEW_DECLSECCONST (cfg, args[0], image, actions.demand);
4159                         NEW_ICONST (cfg, args [1], actions.demand.size);
4160                         /* Calls static void SecurityManager.InternalDemand (byte* permissions, int size); */
4161                         mono_emit_method_call_spilled (cfg, init_localsbb, secman->demand, mono_method_signature (secman->demand), args, ip, NULL);
4162                 }
4163                 if (actions.noncasdemand.blob) {
4164                         /* CLR 1.x uses a .noncasdemand (but 2.x doesn't) */
4165                         /* For Mono we re-route non-CAS Demand to Demand (as the managed code must deal with it anyway) */
4166                         NEW_DECLSECCONST (cfg, args[0], image, actions.noncasdemand);
4167                         NEW_ICONST (cfg, args [1], actions.noncasdemand.size);
4168                         /* Calls static void SecurityManager.InternalDemand (byte* permissions, int size); */
4169                         mono_emit_method_call_spilled (cfg, init_localsbb, secman->demand, mono_method_signature (secman->demand), args, ip, NULL);
4170                 }
4171                 if (actions.demandchoice.blob) {
4172                         /* New in 2.0, Demand must succeed for one of the permissions (i.e. not all) */
4173                         NEW_DECLSECCONST (cfg, args[0], image, actions.demandchoice);
4174                         NEW_ICONST (cfg, args [1], actions.demandchoice.size);
4175                         /* Calls static void SecurityManager.InternalDemandChoice (byte* permissions, int size); */
4176                         mono_emit_method_call_spilled (cfg, init_localsbb, secman->demandchoice, mono_method_signature (secman->demandchoice), args, ip, NULL);
4177                 }
4178         }
4179
4180         /* we must Demand SecurityPermission.Unmanaged before p/invoking */
4181         if (pinvoke) {
4182                 mono_emit_method_call_spilled (cfg, init_localsbb, secman->demandunmanaged, mono_method_signature (secman->demandunmanaged), NULL, ip, NULL);
4183         }
4184
4185         if (get_basic_blocks (cfg, bbhash, header, real_offset, ip, end, &err_pos)) {
4186                 ip = err_pos;
4187                 UNVERIFIED;
4188         }
4189
4190         if (cfg->method == method)
4191                 mono_debug_init_method (cfg, bblock, breakpoint_id);
4192
4193         param_types = mono_mempool_alloc (cfg->mempool, sizeof (MonoType*) * num_args);
4194         if (sig->hasthis)
4195                 param_types [0] = method->klass->valuetype?&method->klass->this_arg:&method->klass->byval_arg;
4196         for (n = 0; n < sig->param_count; ++n)
4197                 param_types [n + sig->hasthis] = sig->params [n];
4198         for (n = 0; n < header->num_locals; ++n) {
4199                 if (header->locals [n]->type == MONO_TYPE_VOID && !header->locals [n]->byref)
4200                         UNVERIFIED;
4201         }
4202         class_inits = NULL;
4203
4204         /* do this somewhere outside - not here */
4205         NEW_ICONST (cfg, zero_int32, 0);
4206         NEW_ICONST (cfg, zero_int64, 0);
4207         zero_int64->type = STACK_I8;
4208         NEW_PCONST (cfg, zero_ptr, 0);
4209         NEW_PCONST (cfg, zero_obj, 0);
4210         zero_obj->type = STACK_OBJ;
4211
4212         MONO_INST_NEW (cfg, zero_r8, OP_R8CONST);
4213         zero_r8->type = STACK_R8;
4214         zero_r8->inst_p0 = &r8_0;
4215
4216         /* add a check for this != NULL to inlined methods */
4217         if (is_virtual_call) {
4218                 MONO_INST_NEW (cfg, ins, OP_CHECK_THIS);
4219                 NEW_ARGLOAD (cfg, ins->inst_left, 0);
4220                 ins->cil_code = ip;
4221                 MONO_ADD_INS (bblock, ins);
4222         }
4223
4224         /* we use a spare stack slot in SWITCH and NEWOBJ and others */
4225         stack_start = sp = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (header->max_stack + 1));
4226
4227         ins_flag = 0;
4228         start_new_bblock = 0;
4229         while (ip < end) {
4230
4231                 if (cfg->method == method)
4232                         real_offset = ip - header->code;
4233                 else
4234                         real_offset = inline_offset;
4235
4236                 if (start_new_bblock) {
4237                         bblock->cil_length = ip - bblock->cil_code;
4238                         if (start_new_bblock == 2) {
4239                                 g_assert (ip == tblock->cil_code);
4240                         } else {
4241                                 GET_BBLOCK (cfg, bbhash, tblock, ip);
4242                         }
4243                         bblock->next_bb = tblock;
4244                         bblock = tblock;
4245                         start_new_bblock = 0;
4246                         for (i = 0; i < bblock->in_scount; ++i) {
4247                                 if (cfg->verbose_level > 3)
4248                                         g_print ("loading %d from temp %d\n", i, (int)bblock->in_stack [i]->inst_c0);                                           
4249                                 NEW_TEMPLOAD (cfg, ins, bblock->in_stack [i]->inst_c0);
4250                                 *sp++ = ins;
4251                         }
4252                         g_slist_free (class_inits);
4253                         class_inits = NULL;
4254                 } else {
4255                         if ((tblock = g_hash_table_lookup (bbhash, ip)) && (tblock != bblock)) {
4256                                 link_bblock (cfg, bblock, tblock);
4257                                 if (sp != stack_start) {
4258                                         handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
4259                                         sp = stack_start;
4260                                         CHECK_UNVERIFIABLE (cfg);
4261                                 }
4262                                 bblock->next_bb = tblock;
4263                                 bblock = tblock;
4264                                 for (i = 0; i < bblock->in_scount; ++i) {
4265                                         if (cfg->verbose_level > 3)
4266                                                 g_print ("loading %d from temp %d\n", i, (int)bblock->in_stack [i]->inst_c0);                                           
4267                                         NEW_TEMPLOAD (cfg, ins, bblock->in_stack [i]->inst_c0);
4268                                         *sp++ = ins;
4269                                 }
4270                                 g_slist_free (class_inits);
4271                                 class_inits = NULL;
4272                         }
4273                 }
4274
4275                 bblock->real_offset = real_offset;
4276
4277                 if ((cfg->method == method) && cfg->coverage_info) {
4278                         MonoInst *store, *one;
4279                         guint32 cil_offset = ip - header->code;
4280                         cfg->coverage_info->data [cil_offset].cil_code = ip;
4281
4282                         /* TODO: Use an increment here */
4283                         NEW_ICONST (cfg, one, 1);
4284                         one->cil_code = ip;
4285
4286                         NEW_PCONST (cfg, ins, &(cfg->coverage_info->data [cil_offset].count));
4287                         ins->cil_code = ip;
4288
4289                         MONO_INST_NEW (cfg, store, CEE_STIND_I);
4290                         store->cil_code = ip;
4291                         store->inst_left = ins;
4292                         store->inst_right = one;
4293
4294                         MONO_ADD_INS (bblock, store);
4295                 }
4296
4297                 if (cfg->verbose_level > 3)
4298                         g_print ("converting (in B%d: stack: %d) %s", bblock->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
4299
4300                 switch (*ip) {
4301                 case CEE_NOP:
4302                 case CEE_BREAK:
4303                         MONO_INST_NEW (cfg, ins, *ip);
4304                         ins->cil_code = ip++;
4305                         MONO_ADD_INS (bblock, ins);
4306                         break;
4307                 case CEE_LDARG_0:
4308                 case CEE_LDARG_1:
4309                 case CEE_LDARG_2:
4310                 case CEE_LDARG_3:
4311                         CHECK_STACK_OVF (1);
4312                         n = (*ip)-CEE_LDARG_0;
4313                         CHECK_ARG (n);
4314                         NEW_ARGLOAD (cfg, ins, n);
4315                         LDARG_SOFT_FLOAT (cfg, ins, n, ip);
4316                         ins->cil_code = ip++;
4317                         *sp++ = ins;
4318                         break;
4319                 case CEE_LDLOC_0:
4320                 case CEE_LDLOC_1:
4321                 case CEE_LDLOC_2:
4322                 case CEE_LDLOC_3:
4323                         CHECK_STACK_OVF (1);
4324                         n = (*ip)-CEE_LDLOC_0;
4325                         CHECK_LOCAL (n);
4326                         NEW_LOCLOAD (cfg, ins, n);
4327                         LDLOC_SOFT_FLOAT (cfg, ins, n, ip);
4328                         ins->cil_code = ip++;
4329                         *sp++ = ins;
4330                         break;
4331                 case CEE_STLOC_0:
4332                 case CEE_STLOC_1:
4333                 case CEE_STLOC_2:
4334                 case CEE_STLOC_3:
4335                         CHECK_STACK (1);
4336                         n = (*ip)-CEE_STLOC_0;
4337                         CHECK_LOCAL (n);
4338                         --sp;
4339                         handle_loaded_temps (cfg, bblock, stack_start, sp);
4340                         NEW_LOCSTORE (cfg, ins, n, *sp);
4341                         ins->cil_code = ip;
4342                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
4343                                 UNVERIFIED;
4344                         STLOC_SOFT_FLOAT (cfg, ins, n, ip);
4345                         if (ins->opcode == CEE_STOBJ) {
4346                                 NEW_LOCLOADA (cfg, ins, n);
4347                                 handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE, FALSE);
4348                         } else
4349                                 MONO_ADD_INS (bblock, ins);
4350                         ++ip;
4351                         inline_costs += 1;
4352                         break;
4353                 case CEE_LDARG_S:
4354                         CHECK_OPSIZE (2);
4355                         CHECK_STACK_OVF (1);
4356                         CHECK_ARG (ip [1]);
4357                         NEW_ARGLOAD (cfg, ins, ip [1]);
4358                         LDARG_SOFT_FLOAT (cfg, ins, ip [1], ip);
4359                         ins->cil_code = ip;
4360                         *sp++ = ins;
4361                         ip += 2;
4362                         break;
4363                 case CEE_LDARGA_S:
4364                         CHECK_OPSIZE (2);
4365                         CHECK_STACK_OVF (1);
4366                         CHECK_ARG (ip [1]);
4367                         NEW_ARGLOADA (cfg, ins, ip [1]);
4368                         ins->cil_code = ip;
4369                         *sp++ = ins;
4370                         ip += 2;
4371                         break;
4372                 case CEE_STARG_S:
4373                         CHECK_OPSIZE (2);
4374                         CHECK_STACK (1);
4375                         --sp;
4376                         CHECK_ARG (ip [1]);
4377                         NEW_ARGSTORE (cfg, ins, ip [1], *sp);
4378                         handle_loaded_temps (cfg, bblock, stack_start, sp);
4379                         ins->cil_code = ip;
4380                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [ip [1]], *sp))
4381                                 UNVERIFIED;
4382                         STARG_SOFT_FLOAT (cfg, ins, ip [1], ip);
4383                         if (ins->opcode == CEE_STOBJ) {
4384                                 NEW_ARGLOADA (cfg, ins, ip [1]);
4385                                 handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE, FALSE);
4386                         } else
4387                                 MONO_ADD_INS (bblock, ins);
4388                         ip += 2;
4389                         break;
4390                 case CEE_LDLOC_S:
4391                         CHECK_OPSIZE (2);
4392                         CHECK_STACK_OVF (1);
4393                         CHECK_LOCAL (ip [1]);
4394                         NEW_LOCLOAD (cfg, ins, ip [1]);
4395                         LDLOC_SOFT_FLOAT (cfg, ins, ip [1], ip);
4396                         ins->cil_code = ip;
4397                         *sp++ = ins;
4398                         ip += 2;
4399                         break;
4400                 case CEE_LDLOCA_S:
4401                         CHECK_OPSIZE (2);
4402                         CHECK_STACK_OVF (1);
4403                         CHECK_LOCAL (ip [1]);
4404                         NEW_LOCLOADA (cfg, ins, ip [1]);
4405                         ins->cil_code = ip;
4406                         *sp++ = ins;
4407                         ip += 2;
4408                         break;
4409                 case CEE_STLOC_S:
4410                         CHECK_OPSIZE (2);
4411                         CHECK_STACK (1);
4412                         --sp;
4413                         handle_loaded_temps (cfg, bblock, stack_start, sp);
4414                         CHECK_LOCAL (ip [1]);
4415                         NEW_LOCSTORE (cfg, ins, ip [1], *sp);
4416                         ins->cil_code = ip;
4417                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [ip [1]], *sp))
4418                                 UNVERIFIED;
4419                         STLOC_SOFT_FLOAT (cfg, ins, ip [1], ip);
4420                         if (ins->opcode == CEE_STOBJ) {
4421                                 NEW_LOCLOADA (cfg, ins, ip [1]);
4422                                 handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE, FALSE);
4423                         } else
4424                                 MONO_ADD_INS (bblock, ins);
4425                         ip += 2;
4426                         inline_costs += 1;
4427                         break;
4428                 case CEE_LDNULL:
4429                         CHECK_STACK_OVF (1);
4430                         NEW_PCONST (cfg, ins, NULL);
4431                         ins->cil_code = ip;
4432                         ins->type = STACK_OBJ;
4433                         ++ip;
4434                         *sp++ = ins;
4435                         break;
4436                 case CEE_LDC_I4_M1:
4437                         CHECK_STACK_OVF (1);
4438                         NEW_ICONST (cfg, ins, -1);
4439                         ins->cil_code = ip;
4440                         ++ip;
4441                         *sp++ = ins;
4442                         break;
4443                 case CEE_LDC_I4_0:
4444                 case CEE_LDC_I4_1:
4445                 case CEE_LDC_I4_2:
4446                 case CEE_LDC_I4_3:
4447                 case CEE_LDC_I4_4:
4448                 case CEE_LDC_I4_5:
4449                 case CEE_LDC_I4_6:
4450                 case CEE_LDC_I4_7:
4451                 case CEE_LDC_I4_8:
4452                         CHECK_STACK_OVF (1);
4453                         NEW_ICONST (cfg, ins, (*ip) - CEE_LDC_I4_0);
4454                         ins->cil_code = ip;
4455                         ++ip;
4456                         *sp++ = ins;
4457                         break;
4458                 case CEE_LDC_I4_S:
4459                         CHECK_OPSIZE (2);
4460                         CHECK_STACK_OVF (1);
4461                         ++ip;
4462                         NEW_ICONST (cfg, ins, *((signed char*)ip));
4463                         ins->cil_code = ip;
4464                         ++ip;
4465                         *sp++ = ins;
4466                         break;
4467                 case CEE_LDC_I4:
4468                         CHECK_OPSIZE (5);
4469                         CHECK_STACK_OVF (1);
4470                         NEW_ICONST (cfg, ins, (gint32)read32 (ip + 1));
4471                         ins->cil_code = ip;
4472                         ip += 5;
4473                         *sp++ = ins;
4474                         break;
4475                 case CEE_LDC_I8:
4476                         CHECK_OPSIZE (9);
4477                         CHECK_STACK_OVF (1);
4478                         MONO_INST_NEW (cfg, ins, OP_I8CONST);
4479                         ins->cil_code = ip;
4480                         ins->type = STACK_I8;
4481                         ++ip;
4482                         ins->inst_l = (gint64)read64 (ip);
4483                         ip += 8;
4484                         *sp++ = ins;
4485                         break;
4486                 case CEE_LDC_R4: {
4487                         float *f;
4488                         /* we should really allocate this only late in the compilation process */
4489                         mono_domain_lock (cfg->domain);
4490                         f = mono_mempool_alloc (cfg->domain->mp, sizeof (float));
4491                         mono_domain_unlock (cfg->domain);
4492                         CHECK_OPSIZE (5);
4493                         CHECK_STACK_OVF (1);
4494                         MONO_INST_NEW (cfg, ins, OP_R4CONST);
4495                         ins->type = STACK_R8;
4496                         ++ip;
4497                         readr4 (ip, f);
4498                         ins->inst_p0 = f;
4499
4500                         ip += 4;
4501                         *sp++ = ins;                    
4502                         break;
4503                 }
4504                 case CEE_LDC_R8: {
4505                         double *d;
4506                         mono_domain_lock (cfg->domain);
4507                         d = mono_mempool_alloc (cfg->domain->mp, sizeof (double));
4508                         mono_domain_unlock (cfg->domain);
4509                         CHECK_OPSIZE (9);
4510                         CHECK_STACK_OVF (1);
4511                         MONO_INST_NEW (cfg, ins, OP_R8CONST);
4512                         ins->type = STACK_R8;
4513                         ++ip;
4514                         readr8 (ip, d);
4515                         ins->inst_p0 = d;
4516
4517                         ip += 8;
4518                         *sp++ = ins;                    
4519                         break;
4520                 }
4521                 case CEE_DUP: {
4522                         MonoInst *temp, *store;
4523                         CHECK_STACK (1);
4524                         CHECK_STACK_OVF (1);
4525                         sp--;
4526                         ins = *sp;
4527                 
4528                         /* 
4529                          * small optimization: if the loaded value was from a local already,
4530                          * just load it twice.
4531                          */
4532                         if (ins->ssa_op == MONO_SSA_LOAD && 
4533                             (ins->inst_i0->opcode == OP_LOCAL || ins->inst_i0->opcode == OP_ARG)) {
4534                                 sp++;
4535                                 MONO_INST_NEW (cfg, temp, 0);
4536                                 *temp = *ins;
4537                                 temp->cil_code = ip;
4538                                 *sp++ = temp;
4539                         } else {
4540                                 temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
4541                                 temp->flags |= MONO_INST_IS_TEMP;
4542                                 temp->cil_code = ip;
4543                                 NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
4544                                 store->cil_code = ip;
4545                                 if (store->opcode == CEE_STOBJ) {
4546                                         NEW_TEMPLOADA (cfg, store, temp->inst_c0);
4547                                         handle_stobj (cfg, bblock, store, sp [0], sp [0]->cil_code, store->klass, TRUE, FALSE, FALSE);
4548                                 } else {
4549                                         MONO_ADD_INS (bblock, store);
4550                                 }
4551                                 NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
4552                                 *sp++ = ins;
4553                                 ins->cil_code = ip;
4554                                 NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
4555                                 *sp++ = ins;
4556                                 ins->cil_code = ip;
4557                         }
4558                         ++ip;
4559                         inline_costs += 2;
4560                         break;
4561                 }
4562                 case CEE_POP:
4563                         CHECK_STACK (1);
4564                         MONO_INST_NEW (cfg, ins, CEE_POP);
4565                         MONO_ADD_INS (bblock, ins);
4566                         ins->cil_code = ip++;
4567                         --sp;
4568                         ins->inst_i0 = *sp;
4569                         break;
4570                 case CEE_JMP:
4571                         CHECK_OPSIZE (5);
4572                         if (stack_start != sp)
4573                                 UNVERIFIED;
4574                         MONO_INST_NEW (cfg, ins, CEE_JMP);
4575                         token = read32 (ip + 1);
4576                         /* FIXME: check the signature matches */
4577                         cmethod = mini_get_method (method, token, NULL, generic_context);
4578
4579                         if (!cmethod)
4580                                 goto load_error;
4581
4582                         if (mono_use_security_manager) {
4583                                 if (check_linkdemand (cfg, method, cmethod, bblock, ip))
4584                                         INLINE_FAILURE;
4585                         }
4586
4587                         ins->inst_p0 = cmethod;
4588                         MONO_ADD_INS (bblock, ins);
4589                         ip += 5;
4590                         start_new_bblock = 1;
4591                         break;
4592                 case CEE_CALLI:
4593                 case CEE_CALL:
4594                 case CEE_CALLVIRT: {
4595                         MonoInst *addr = NULL;
4596                         MonoMethodSignature *fsig = NULL;
4597                         int temp, array_rank = 0;
4598                         int virtual = *ip == CEE_CALLVIRT;
4599
4600                         CHECK_OPSIZE (5);
4601                         token = read32 (ip + 1);
4602
4603                         if (*ip == CEE_CALLI) {
4604                                 cmethod = NULL;
4605                                 CHECK_STACK (1);
4606                                 --sp;
4607                                 addr = *sp;
4608                                 if (method->wrapper_type != MONO_WRAPPER_NONE)
4609                                         fsig = (MonoMethodSignature *)mono_method_get_wrapper_data (method, token);
4610                                 else
4611                                         fsig = mono_metadata_parse_signature (image, token);
4612
4613                                 n = fsig->param_count + fsig->hasthis;
4614                         } else {
4615                                 MonoMethod *cil_method;
4616                                 
4617                                 if (method->wrapper_type != MONO_WRAPPER_NONE) {
4618                                         cmethod =  (MonoMethod *)mono_method_get_wrapper_data (method, token);
4619                                         cil_method = cmethod;
4620                                 } else if (constrained_call) {
4621                                         cmethod = mono_get_method_constrained (image, token, constrained_call, generic_context, &cil_method);
4622                                         cmethod = mono_get_inflated_method (cmethod);
4623                                         cil_method = cmethod;
4624                                 } else {
4625                                         cmethod = mini_get_method (method, token, NULL, generic_context);
4626                                         cil_method = cmethod;
4627                                 }
4628
4629                                 if (!cmethod)
4630                                         goto load_error;
4631                                 if (!dont_verify && !cfg->skip_visibility && !can_access_method (method, cil_method))
4632                                         UNVERIFIED;
4633
4634                                 if (!virtual && (cmethod->flags & METHOD_ATTRIBUTE_ABSTRACT))
4635                                         /* MS.NET seems to silently convert this to a callvirt */
4636                                         virtual = 1;
4637
4638                                 if (!cmethod->klass->inited){
4639                                         if (!mono_class_init (cmethod->klass))
4640                                                 goto load_error;
4641                                 }
4642
4643                                 if (mono_method_signature (cmethod)->pinvoke) {
4644                                         MonoMethod *wrapper = mono_marshal_get_native_wrapper (cmethod);
4645                                         fsig = mono_method_signature (wrapper);
4646                                 } else if (constrained_call) {
4647                                         fsig = mono_method_signature (cmethod);
4648                                 } else {
4649                                         fsig = mono_method_get_signature_full (cmethod, image, token, generic_context);
4650                                 }
4651
4652                                 n = fsig->param_count + fsig->hasthis;
4653
4654                                 if (mono_use_security_manager) {
4655                                         if (check_linkdemand (cfg, method, cmethod, bblock, ip))
4656                                                 INLINE_FAILURE;
4657                                 }
4658
4659                                 if (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL &&
4660                                     mini_class_is_system_array (cmethod->klass)) {
4661                                         array_rank = cmethod->klass->rank;
4662                                 }
4663
4664                                 if (cmethod->string_ctor)
4665                                         g_assert_not_reached ();
4666
4667                         }
4668
4669                         if (cmethod && cmethod->klass->generic_container)
4670                                 UNVERIFIED;
4671
4672                         CHECK_STACK (n);
4673
4674                         //g_assert (!virtual || fsig->hasthis);
4675
4676                         sp -= n;
4677
4678                         if (constrained_call) {
4679                                 /*
4680                                  * We have the `constrained.' prefix opcode.
4681                                  */
4682                                 if (constrained_call->valuetype && !cmethod->klass->valuetype) {
4683                                         MonoInst *load;
4684                                         /*
4685                                          * The type parameter is instantiated as a valuetype,
4686                                          * but that type doesn't override the method we're
4687                                          * calling, so we need to box `this'.
4688                                          * sp [0] is a pointer to the data: we need the value
4689                                          * in handle_box (), so load it here.
4690                                          */
4691                                         MONO_INST_NEW (cfg, load, mono_type_to_ldind (&constrained_call->byval_arg));
4692                                         type_to_eval_stack_type (&constrained_call->byval_arg, load);
4693                                         load->cil_code = ip;
4694                                         load->inst_left = sp [0];
4695                                         sp [0] = handle_box (cfg, bblock, load, ip, constrained_call);
4696                                 } else if (!constrained_call->valuetype) {
4697                                         MonoInst *ins;
4698
4699                                         /*
4700                                          * The type parameter is instantiated as a reference
4701                                          * type.  We have a managed pointer on the stack, so
4702                                          * we need to dereference it here.
4703                                          */
4704
4705                                         MONO_INST_NEW (cfg, ins, CEE_LDIND_REF);
4706                                         ins->cil_code = ip;
4707                                         ins->inst_i0 = sp [0];
4708                                         ins->type = STACK_OBJ;
4709                                         ins->klass = mono_class_from_mono_type (&constrained_call->byval_arg);
4710                                         sp [0] = ins;
4711                                 } else if (cmethod->klass->valuetype)
4712                                         virtual = 0;
4713                                 constrained_call = NULL;
4714                         }
4715
4716                         if (*ip != CEE_CALLI && check_call_signature (cfg, fsig, sp))
4717                                 UNVERIFIED;
4718
4719                         if (cmethod && virtual && 
4720                             (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) && 
4721                             !((cmethod->flags & METHOD_ATTRIBUTE_FINAL) && 
4722                               cmethod->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK) &&
4723                             mono_method_signature (cmethod)->generic_param_count) {
4724                                 MonoInst *this_temp, *this_arg_temp, *store;
4725                                 MonoInst *iargs [4];
4726
4727                                 g_assert (mono_method_signature (cmethod)->is_inflated);
4728                                 /* Prevent inlining of methods that contain indirect calls */
4729                                 INLINE_FAILURE;
4730
4731                                 this_temp = mono_compile_create_var (cfg, type_from_stack_type (sp [0]), OP_LOCAL);
4732                                 this_temp->cil_code = ip;
4733                                 NEW_TEMPSTORE (cfg, store, this_temp->inst_c0, sp [0]);
4734
4735                                 store->cil_code = ip;
4736                                 MONO_ADD_INS (bblock, store);
4737
4738                                 /* FIXME: This should be a managed pointer */
4739                                 this_arg_temp = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
4740                                 this_arg_temp->cil_code = ip;
4741
4742                                 NEW_TEMPLOAD (cfg, iargs [0], this_temp->inst_c0);
4743                                 NEW_PCONST (cfg, iargs [1], cmethod);
4744                                 NEW_PCONST (cfg, iargs [2], mono_method_get_context (cmethod));
4745                                 NEW_TEMPLOADA (cfg, iargs [3], this_arg_temp->inst_c0);
4746                                 temp = mono_emit_jit_icall (cfg, bblock, mono_helper_compile_generic_method, iargs, ip);
4747
4748                                 NEW_TEMPLOAD (cfg, addr, temp);
4749                                 NEW_TEMPLOAD (cfg, sp [0], this_arg_temp->inst_c0);
4750
4751                                 if ((temp = mono_emit_calli (cfg, bblock, fsig, sp, addr, ip)) != -1) {
4752                                         NEW_TEMPLOAD (cfg, *sp, temp);
4753                                         sp++;
4754                                 }
4755
4756                                 ip += 5;
4757                                 ins_flag = 0;
4758                                 break;
4759                         }
4760
4761                         if ((ins_flag & MONO_INST_TAILCALL) && cmethod && (*ip == CEE_CALL) &&
4762                                  (mono_metadata_signature_equal (mono_method_signature (method), mono_method_signature (cmethod)))) {
4763                                 int i;
4764
4765                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
4766                                 INLINE_FAILURE;
4767                                 /* FIXME: This assumes the two methods has the same number and type of arguments */
4768                                 /*
4769                                  * We implement tail calls by storing the actual arguments into the 
4770                                  * argument variables, then emitting a CEE_JMP. Since the actual arguments
4771                                  * can refer to the arg variables, we have to spill them.
4772                                  */
4773                                 handle_loaded_temps (cfg, bblock, sp, sp + n);
4774                                 for (i = 0; i < n; ++i) {
4775                                         /* Prevent argument from being register allocated */
4776                                         arg_array [i]->flags |= MONO_INST_VOLATILE;
4777
4778                                         /* Check if argument is the same */
4779                                         /* 
4780                                          * FIXME: This loses liveness info, so it can only be done if the
4781                                          * argument is not register allocated.
4782                                          */
4783                                         NEW_ARGLOAD (cfg, ins, i);
4784                                         if ((ins->opcode == sp [i]->opcode) && (ins->inst_i0 == sp [i]->inst_i0))
4785                                                 continue;
4786
4787                                         NEW_ARGSTORE (cfg, ins, i, sp [i]);
4788                                         ins->cil_code = ip;
4789                                         if (ins->opcode == CEE_STOBJ) {
4790                                                 NEW_ARGLOADA (cfg, ins, i);
4791                                                 handle_stobj (cfg, bblock, ins, sp [i], sp [i]->cil_code, ins->klass, FALSE, FALSE, FALSE);
4792                                         }
4793                                         else
4794                                                 MONO_ADD_INS (bblock, ins);
4795                                 }
4796                                 MONO_INST_NEW (cfg, ins, CEE_JMP);
4797                                 ins->cil_code = ip;
4798                                 ins->inst_p0 = cmethod;
4799                                 ins->inst_p1 = arg_array [0];
4800                                 MONO_ADD_INS (bblock, ins);
4801                                 link_bblock (cfg, bblock, end_bblock);                  
4802                                 start_new_bblock = 1;
4803                                 /* skip CEE_RET as well */
4804                                 ip += 6;
4805                                 ins_flag = 0;
4806                                 break;
4807                         }
4808                         if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_get_inst_for_method (cfg, cmethod, fsig, sp))) {
4809                                 ins->cil_code = ip;
4810
4811                                 if (MONO_TYPE_IS_VOID (fsig->ret)) {
4812                                         MONO_ADD_INS (bblock, ins);
4813                                 } else {
4814                                         type_to_eval_stack_type (fsig->ret, ins);
4815                                         *sp = ins;
4816                                         sp++;
4817                                 }
4818
4819                                 ip += 5;
4820                                 ins_flag = 0;
4821                                 break;
4822                         }
4823
4824                         handle_loaded_temps (cfg, bblock, stack_start, sp);
4825
4826                         if ((cfg->opt & MONO_OPT_INLINE) && cmethod &&
4827                             (!virtual || !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) || (cmethod->flags & METHOD_ATTRIBUTE_FINAL)) && 
4828                             mono_method_check_inlining (cfg, cmethod) &&
4829                                  !g_list_find (dont_inline, cmethod)) {
4830                                 int costs;
4831                                 MonoBasicBlock *ebblock;
4832                                 gboolean allways = FALSE;
4833
4834                                 if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
4835                                         (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
4836                                         /* Prevent inlining of methods that call wrappers */
4837                                         INLINE_FAILURE;
4838                                         cmethod = mono_marshal_get_native_wrapper (cmethod);
4839                                         allways = TRUE;
4840                                 }
4841
4842                                 if ((costs = inline_method (cfg, cmethod, fsig, bblock, sp, ip, real_offset, dont_inline, &ebblock, allways))) {
4843                                         ip += 5;
4844                                         real_offset += 5;
4845
4846                                         GET_BBLOCK (cfg, bbhash, bblock, ip);
4847                                         ebblock->next_bb = bblock;
4848                                         link_bblock (cfg, ebblock, bblock);
4849
4850                                         if (!MONO_TYPE_IS_VOID (fsig->ret))
4851                                                 sp++;
4852
4853                                         /* indicates start of a new block, and triggers a load of all 
4854                                            stack arguments at bb boundarie */
4855                                         bblock = ebblock;
4856
4857                                         inline_costs += costs;
4858                                         ins_flag = 0;
4859                                         break;
4860                                 }
4861                         }
4862                         
4863                         inline_costs += 10 * num_calls++;
4864
4865                         /* tail recursion elimination */
4866                         if ((cfg->opt & MONO_OPT_TAILC) && *ip == CEE_CALL && cmethod == method && ip [5] == CEE_RET) {
4867                                 gboolean has_vtargs = FALSE;
4868                                 int i;
4869                                 
4870                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
4871                                 INLINE_FAILURE;
4872                                 /* keep it simple */
4873                                 for (i =  fsig->param_count - 1; i >= 0; i--) {
4874                                         if (MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->params [i])) 
4875                                                 has_vtargs = TRUE;
4876                                 }
4877
4878                                 if (!has_vtargs) {
4879                                         for (i = 0; i < n; ++i) {
4880                                                 NEW_ARGSTORE (cfg, ins, i, sp [i]);
4881                                                 ins->cil_code = ip;
4882                                                 MONO_ADD_INS (bblock, ins);
4883                                         }
4884                                         MONO_INST_NEW (cfg, ins, CEE_BR);
4885                                         ins->cil_code = ip;
4886                                         MONO_ADD_INS (bblock, ins);
4887                                         tblock = start_bblock->out_bb [0];
4888                                         link_bblock (cfg, bblock, tblock);
4889                                         ins->inst_target_bb = tblock;
4890                                         start_new_bblock = 1;
4891
4892                                         /* skip the CEE_RET, too */
4893                                         if (ip_in_bb (cfg, bblock, ip + 5))
4894                                                 ip += 6;
4895                                         else
4896                                                 ip += 5;
4897                                         ins_flag = 0;
4898                                         break;
4899                                 }
4900                         }
4901
4902                         if (*ip == CEE_CALLI) {
4903                                 /* Prevent inlining of methods with indirect calls */
4904                                 INLINE_FAILURE;
4905                                 if ((temp = mono_emit_calli (cfg, bblock, fsig, sp, addr, ip)) != -1) {
4906                                         NEW_TEMPLOAD (cfg, *sp, temp);
4907                                         sp++;
4908                                 }                                       
4909                         } else if (array_rank) {
4910                                 MonoInst *addr;
4911
4912                                 if (strcmp (cmethod->name, "Set") == 0) { /* array Set */ 
4913                                         if (sp [fsig->param_count]->type == STACK_OBJ) {
4914                                                 MonoInst *iargs [2];
4915                                                 MonoInst *array, *to_store, *store;
4916
4917                                                 handle_loaded_temps (cfg, bblock, stack_start, sp);
4918                                                 
4919                                                 array = mono_compile_create_var (cfg, type_from_stack_type (sp [0]), OP_LOCAL);
4920                                                 NEW_TEMPSTORE (cfg, store, array->inst_c0, sp [0]);
4921                                                 store->cil_code = ip;
4922                                                 MONO_ADD_INS (bblock, store);
4923                                                 NEW_TEMPLOAD (cfg, iargs [0], array->inst_c0);
4924
4925                                                 to_store = mono_compile_create_var (cfg, type_from_stack_type (sp [fsig->param_count]), OP_LOCAL);
4926                                                 NEW_TEMPSTORE (cfg, store, to_store->inst_c0, sp [fsig->param_count]);
4927                                                 store->cil_code = ip;
4928                                                 MONO_ADD_INS (bblock, store);
4929                                                 NEW_TEMPLOAD (cfg, iargs [1], to_store->inst_c0);
4930
4931                                                 /*
4932                                                  * We first save the args for the call so that the args are copied to the stack
4933                                                  * and a new instruction tree for them is created. If we don't do this,
4934                                                  * the same MonoInst is added to two different trees and this is not 
4935                                                  * allowed by burg.
4936                                                  */
4937                                                 mono_emit_jit_icall (cfg, bblock, mono_helper_stelem_ref_check, iargs, ip);
4938
4939                                                 NEW_TEMPLOAD (cfg, sp [0], array->inst_c0);
4940                                                 NEW_TEMPLOAD (cfg, sp [fsig->param_count], to_store->inst_c0);
4941                                         }
4942
4943                                         addr = mini_get_ldelema_ins (cfg, bblock, cmethod, sp, ip, TRUE);
4944                                         NEW_INDSTORE (cfg, ins, addr, sp [fsig->param_count], fsig->params [fsig->param_count - 1]);
4945                                         ins->cil_code = ip;
4946                                         if (ins->opcode == CEE_STOBJ) {
4947                                                 handle_stobj (cfg, bblock, addr, sp [fsig->param_count], ip, mono_class_from_mono_type (fsig->params [fsig->param_count-1]), FALSE, FALSE, TRUE);
4948                                         } else {
4949                                                 MONO_ADD_INS (bblock, ins);
4950                                         }
4951
4952                                 } else if (strcmp (cmethod->name, "Get") == 0) { /* array Get */
4953                                         addr = mini_get_ldelema_ins (cfg, bblock, cmethod, sp, ip, FALSE);
4954                                         NEW_INDLOAD (cfg, ins, addr, fsig->ret);
4955                                         ins->cil_code = ip;
4956
4957                                         *sp++ = ins;
4958                                 } else if (strcmp (cmethod->name, "Address") == 0) { /* array Address */
4959                                         addr = mini_get_ldelema_ins (cfg, bblock, cmethod, sp, ip, FALSE);
4960                                         *sp++ = addr;
4961                                 } else {
4962                                         g_assert_not_reached ();
4963                                 }
4964
4965                         } else {
4966                                 /* Prevent inlining of methods which call other methods */
4967                                 INLINE_FAILURE;
4968                                 if (ip_in_bb (cfg, bblock, ip + 5) 
4969                                     && (!MONO_TYPE_ISSTRUCT (fsig->ret))
4970                                     && (!MONO_TYPE_IS_VOID (fsig->ret) || cmethod->string_ctor)
4971                                     && (CODE_IS_STLOC (ip + 5) || ip [5] == CEE_POP || ip [5] == CEE_RET)) {
4972                                         /* no need to spill */
4973                                         ins = (MonoInst*)mono_emit_method_call (cfg, bblock, cmethod, fsig, sp, ip, virtual ? sp [0] : NULL);
4974                                         *sp++ = ins;
4975                                 } else {
4976                                         if ((temp = mono_emit_method_call_spilled (cfg, bblock, cmethod, fsig, sp, ip, virtual ? sp [0] : NULL)) != -1) {
4977                                                 NEW_TEMPLOAD (cfg, *sp, temp);
4978                                                 sp++;
4979                                         }
4980                                 }
4981                         }
4982
4983                         ip += 5;
4984                         ins_flag = 0;
4985                         break;
4986                 }
4987                 case CEE_RET:
4988                         if (cfg->method != method) {
4989                                 /* return from inlined methode */
4990                                 if (return_var) {
4991                                         MonoInst *store;
4992                                         CHECK_STACK (1);
4993                                         --sp;
4994                                         //g_assert (returnvar != -1);
4995                                         NEW_TEMPSTORE (cfg, store, return_var->inst_c0, *sp);
4996                                         store->cil_code = sp [0]->cil_code;
4997                                         if (store->opcode == CEE_STOBJ) {
4998                                                 g_assert_not_reached ();
4999                                                 NEW_TEMPLOADA (cfg, store, return_var->inst_c0);
5000                                                 /* FIXME: it is possible some optimization will pass the a heap pointer for the struct address, so we'll need the write barrier */
5001                                                 handle_stobj (cfg, bblock, store, *sp, sp [0]->cil_code, return_var->klass, FALSE, FALSE, FALSE);
5002                                         } else
5003                                                 MONO_ADD_INS (bblock, store);
5004                                 } 
5005                         } else {
5006                                 if (cfg->ret) {
5007                                         g_assert (!return_var);
5008                                         CHECK_STACK (1);
5009                                         --sp;
5010                                         MONO_INST_NEW (cfg, ins, CEE_NOP);
5011                                         ins->opcode = mono_type_to_stind (mono_method_signature (method)->ret);
5012                                         if (ins->opcode == CEE_STOBJ) {
5013                                                 NEW_RETLOADA (cfg, ins);
5014                                                 /* FIXME: it is possible some optimization will pass the a heap pointer for the struct address, so we'll need the write barrier */
5015                                                 handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE, FALSE);
5016                                         } else {
5017                                                 ins->opcode = OP_SETRET;
5018                                                 ins->cil_code = ip;
5019                                                 ins->inst_i0 = *sp;;
5020                                                 ins->inst_i1 = NULL;
5021                                                 MONO_ADD_INS (bblock, ins);
5022                                         }
5023                                 }
5024                         }
5025                         if (sp != stack_start)
5026                                 UNVERIFIED;
5027                         MONO_INST_NEW (cfg, ins, CEE_BR);
5028                         ins->cil_code = ip++;
5029                         ins->inst_target_bb = end_bblock;
5030                         MONO_ADD_INS (bblock, ins);
5031                         link_bblock (cfg, bblock, end_bblock);
5032                         start_new_bblock = 1;
5033                         break;
5034                 case CEE_BR_S:
5035                         CHECK_OPSIZE (2);
5036                         MONO_INST_NEW (cfg, ins, CEE_BR);
5037                         ins->cil_code = ip++;
5038                         MONO_ADD_INS (bblock, ins);
5039                         target = ip + 1 + (signed char)(*ip);
5040                         ++ip;
5041                         GET_BBLOCK (cfg, bbhash, tblock, target);
5042                         link_bblock (cfg, bblock, tblock);
5043                         CHECK_BBLOCK (target, ip, tblock);
5044                         ins->inst_target_bb = tblock;
5045                         if (sp != stack_start) {
5046                                 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
5047                                 sp = stack_start;
5048                                 CHECK_UNVERIFIABLE (cfg);
5049                         }
5050                         start_new_bblock = 1;
5051                         inline_costs += BRANCH_COST;
5052                         break;
5053                 case CEE_BRFALSE_S:
5054                 case CEE_BRTRUE_S:
5055                         CHECK_OPSIZE (2);
5056                         CHECK_STACK (1);
5057                         if (sp [-1]->type == STACK_VTYPE || sp [-1]->type == STACK_R8)
5058                                 UNVERIFIED;
5059                         MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
5060                         ins->cil_code = ip++;
5061                         target = ip + 1 + *(signed char*)ip;
5062                         ip++;
5063                         ADD_UNCOND (ins->opcode == CEE_BRTRUE);
5064                         if (sp != stack_start) {
5065                                 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
5066                                 sp = stack_start;
5067                                 CHECK_UNVERIFIABLE (cfg);
5068                         }
5069                         inline_costs += BRANCH_COST;
5070                         break;
5071                 case CEE_BEQ_S:
5072                 case CEE_BGE_S:
5073                 case CEE_BGT_S:
5074                 case CEE_BLE_S:
5075                 case CEE_BLT_S:
5076                 case CEE_BNE_UN_S:
5077                 case CEE_BGE_UN_S:
5078                 case CEE_BGT_UN_S:
5079                 case CEE_BLE_UN_S:
5080                 case CEE_BLT_UN_S:
5081                         CHECK_OPSIZE (2);
5082                         CHECK_STACK (2);
5083                         MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
5084                         ins->cil_code = ip++;
5085                         target = ip + 1 + *(signed char*)ip;
5086                         ip++;
5087 #ifdef MONO_ARCH_SOFT_FLOAT
5088                         if (sp [-1]->type == STACK_R8 || sp [-2]->type == STACK_R8) {
5089                                 ins->opcode = condbr_to_fp_br (ins->opcode);
5090                                 sp -= 2;
5091                                 ins->inst_left = sp [0];
5092                                 ins->inst_right = sp [1];
5093                                 ins->type = STACK_I4;
5094                                 *sp++ = emit_tree (cfg, bblock, ins, ins->cil_code);
5095                                 MONO_INST_NEW (cfg, ins, CEE_BRTRUE);
5096                                 ADD_UNCOND (TRUE);
5097                         } else {
5098                                 ADD_BINCOND (NULL);
5099                         }
5100 #else
5101                         ADD_BINCOND (NULL);
5102 #endif
5103                         if (sp != stack_start) {
5104                                 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
5105                                 sp = stack_start;
5106                                 CHECK_UNVERIFIABLE (cfg);
5107                         }
5108                         inline_costs += BRANCH_COST;
5109                         break;
5110                 case CEE_BR:
5111                         CHECK_OPSIZE (5);
5112                         MONO_INST_NEW (cfg, ins, CEE_BR);
5113                         ins->cil_code = ip++;
5114                         MONO_ADD_INS (bblock, ins);
5115                         target = ip + 4 + (gint32)read32(ip);
5116                         ip += 4;
5117                         GET_BBLOCK (cfg, bbhash, tblock, target);
5118                         link_bblock (cfg, bblock, tblock);
5119                         CHECK_BBLOCK (target, ip, tblock);
5120                         ins->inst_target_bb = tblock;
5121                         if (sp != stack_start) {
5122                                 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
5123                                 sp = stack_start;
5124                                 CHECK_UNVERIFIABLE (cfg);
5125                         }
5126                         start_new_bblock = 1;
5127                         inline_costs += BRANCH_COST;
5128                         break;
5129                 case CEE_BRFALSE:
5130                 case CEE_BRTRUE:
5131                         CHECK_OPSIZE (5);
5132                         CHECK_STACK (1);
5133                         if (sp [-1]->type == STACK_VTYPE || sp [-1]->type == STACK_R8)
5134                                 UNVERIFIED;
5135                         MONO_INST_NEW (cfg, ins, *ip);
5136                         ins->cil_code = ip++;
5137                         target = ip + 4 + (gint32)read32(ip);
5138                         ip += 4;
5139                         ADD_UNCOND(ins->opcode == CEE_BRTRUE);
5140                         if (sp != stack_start) {
5141                                 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
5142                                 sp = stack_start;
5143                                 CHECK_UNVERIFIABLE (cfg);
5144                         }
5145                         inline_costs += BRANCH_COST;
5146                         break;
5147                 case CEE_BEQ:
5148                 case CEE_BGE:
5149                 case CEE_BGT:
5150                 case CEE_BLE:
5151                 case CEE_BLT:
5152                 case CEE_BNE_UN:
5153                 case CEE_BGE_UN:
5154                 case CEE_BGT_UN:
5155                 case CEE_BLE_UN:
5156                 case CEE_BLT_UN:
5157                         CHECK_OPSIZE (5);
5158                         CHECK_STACK (2);
5159                         MONO_INST_NEW (cfg, ins, *ip);
5160                         ins->cil_code = ip++;
5161                         target = ip + 4 + (gint32)read32(ip);
5162                         ip += 4;
5163 #ifdef MONO_ARCH_SOFT_FLOAT
5164                         if (sp [-1]->type == STACK_R8 || sp [-2]->type == STACK_R8) {
5165                                 ins->opcode = condbr_to_fp_br (ins->opcode);
5166                                 sp -= 2;
5167                                 ins->inst_left = sp [0];
5168                                 ins->inst_right = sp [1];
5169                                 ins->type = STACK_I4;
5170                                 *sp++ = emit_tree (cfg, bblock, ins, ins->cil_code);
5171                                 MONO_INST_NEW (cfg, ins, CEE_BRTRUE);
5172                                 ADD_UNCOND (TRUE);
5173                         } else {
5174                                 ADD_BINCOND (NULL);
5175                         }
5176 #else
5177                         ADD_BINCOND (NULL);
5178 #endif
5179                         if (sp != stack_start) {
5180                                 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
5181                                 sp = stack_start;
5182                                 CHECK_UNVERIFIABLE (cfg);
5183                         }
5184                         inline_costs += BRANCH_COST;
5185                         break;
5186                 case CEE_SWITCH:
5187                         CHECK_OPSIZE (5);
5188                         CHECK_STACK (1);
5189                         n = read32 (ip + 1);
5190                         MONO_INST_NEW (cfg, ins, *ip);
5191                         --sp;
5192                         ins->inst_left = *sp;
5193                         if ((ins->inst_left->type != STACK_I4) && (ins->inst_left->type != STACK_PTR)) 
5194                                 UNVERIFIED;
5195                         ins->cil_code = ip;
5196                         ip += 5;
5197                         CHECK_OPSIZE (n * sizeof (guint32));
5198                         target = ip + n * sizeof (guint32);
5199                         MONO_ADD_INS (bblock, ins);
5200                         GET_BBLOCK (cfg, bbhash, tblock, target);
5201                         link_bblock (cfg, bblock, tblock);
5202                         ins->klass = GUINT_TO_POINTER (n);
5203                         ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * (n + 1));
5204                         ins->inst_many_bb [n] = tblock;
5205
5206                         for (i = 0; i < n; ++i) {
5207                                 GET_BBLOCK (cfg, bbhash, tblock, target + (gint32)read32(ip));
5208                                 link_bblock (cfg, bblock, tblock);
5209                                 ins->inst_many_bb [i] = tblock;
5210                                 ip += 4;
5211                         }
5212                         if (sp != stack_start) {
5213                                 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
5214                                 sp = stack_start;
5215                                 CHECK_UNVERIFIABLE (cfg);
5216                         }
5217                         /* Needed by the code generated in inssel.brg */
5218                         mono_get_got_var (cfg);
5219                         inline_costs += (BRANCH_COST * 2);
5220                         break;
5221                 case CEE_LDIND_I1:
5222                 case CEE_LDIND_U1:
5223                 case CEE_LDIND_I2:
5224                 case CEE_LDIND_U2:
5225                 case CEE_LDIND_I4:
5226                 case CEE_LDIND_U4:
5227                 case CEE_LDIND_I8:
5228                 case CEE_LDIND_I:
5229                 case CEE_LDIND_R4:
5230                 case CEE_LDIND_R8:
5231                 case CEE_LDIND_REF:
5232                         CHECK_STACK (1);
5233                         MONO_INST_NEW (cfg, ins, *ip);
5234                         ins->cil_code = ip;
5235                         --sp;
5236                         ins->inst_i0 = *sp;
5237                         *sp++ = ins;
5238                         ins->type = ldind_type [*ip - CEE_LDIND_I1];
5239                         ins->flags |= ins_flag;
5240                         ins_flag = 0;
5241                         if (ins->type == STACK_OBJ)
5242                                 ins->klass = mono_defaults.object_class;
5243 #ifdef MONO_ARCH_SOFT_FLOAT
5244                         if (*ip == CEE_LDIND_R4) {
5245                                 int temp;
5246                                 --sp;
5247                                 temp = handle_load_float (cfg, bblock, ins->inst_i0, ip);
5248                                 NEW_TEMPLOAD (cfg, *sp, temp);
5249                                 sp++;
5250                         }
5251 #endif
5252                         ++ip;
5253                         break;
5254                 case CEE_STIND_REF:
5255                 case CEE_STIND_I1:
5256                 case CEE_STIND_I2:
5257                 case CEE_STIND_I4:
5258                 case CEE_STIND_I8:
5259                 case CEE_STIND_R4:
5260                 case CEE_STIND_R8:
5261                         CHECK_STACK (2);
5262 #ifdef MONO_ARCH_SOFT_FLOAT
5263                         if (*ip == CEE_STIND_R4) {
5264                                 sp -= 2;
5265                                 handle_store_float (cfg, bblock, sp [0], sp [1], ip);
5266                                 ip++;
5267                                 break;
5268                         }
5269 #endif
5270 #if HAVE_WRITE_BARRIERS
5271                         if (*ip == CEE_STIND_REF && method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER) {
5272                                 /* insert call to write barrier */
5273                                 MonoMethod *write_barrier = mono_marshal_get_write_barrier ();
5274                                 sp -= 2;
5275                                 mono_emit_method_call_spilled (cfg, bblock, write_barrier, mono_method_signature (write_barrier), sp, ip, NULL);
5276                                 ip++;
5277                                 break;
5278                         }
5279 #endif
5280                         MONO_INST_NEW (cfg, ins, *ip);
5281                         ins->cil_code = ip++;
5282                         sp -= 2;
5283                         handle_loaded_temps (cfg, bblock, stack_start, sp);
5284                         MONO_ADD_INS (bblock, ins);
5285                         ins->inst_i0 = sp [0];
5286                         ins->inst_i1 = sp [1];
5287                         ins->flags |= ins_flag;
5288                         ins_flag = 0;
5289                         inline_costs += 1;
5290                         break;
5291                 case CEE_MUL:
5292                         CHECK_STACK (2);
5293                         ADD_BINOP (*ip);
5294
5295 #ifdef MONO_ARCH_NO_EMULATE_MUL_IMM
5296                         /* FIXME: This breaks with ssapre (mono -O=ssapre loader.exe) */
5297                         if ((ins->inst_right->opcode == OP_ICONST) && !(cfg->opt & MONO_OPT_SSAPRE)) {
5298                                 switch (ins->opcode) {
5299                                 case CEE_MUL:
5300                                         ins->opcode = OP_IMUL_IMM;
5301                                         ins->inst_imm = ins->inst_right->inst_c0;
5302                                         break;
5303                                 case OP_LMUL:
5304                                         ins->opcode = OP_LMUL_IMM;
5305                                         ins->inst_imm = ins->inst_right->inst_c0;
5306                                         break;
5307                                 default:
5308                                         g_assert_not_reached ();
5309                                 }
5310                         }
5311 #endif
5312
5313                         if (mono_find_jit_opcode_emulation (ins->opcode)) {
5314                                 --sp;
5315                                 *sp++ = emit_tree (cfg, bblock, ins, ip + 1);
5316                         }
5317                         ip++;
5318                         break;
5319                 case CEE_ADD:
5320                 case CEE_SUB:
5321                 case CEE_DIV:
5322                 case CEE_DIV_UN:
5323                 case CEE_REM:
5324                 case CEE_REM_UN:
5325                 case CEE_AND:
5326                 case CEE_OR:
5327                 case CEE_XOR:
5328                 case CEE_SHL:
5329                 case CEE_SHR:
5330                 case CEE_SHR_UN:
5331                         CHECK_STACK (2);
5332                         ADD_BINOP (*ip);
5333                         /* special case that gives a nice speedup and happens to workaorund a ppc jit but (for the release)
5334                          * later apply the speedup to the left shift as well
5335                          * See BUG# 57957.
5336                          */
5337                         if ((ins->opcode == OP_LSHR_UN) && (ins->type == STACK_I8) 
5338                                         && (ins->inst_right->opcode == OP_ICONST) && (ins->inst_right->inst_c0 == 32)) {
5339                                 ins->opcode = OP_LONG_SHRUN_32;
5340                                 /*g_print ("applied long shr speedup to %s\n", cfg->method->name);*/
5341                                 ip++;
5342                                 break;
5343                         }
5344                         if (mono_find_jit_opcode_emulation (ins->opcode)) {
5345                                 --sp;
5346                                 *sp++ = emit_tree (cfg, bblock, ins, ip + 1);
5347                         }
5348                         ip++;
5349                         break;
5350                 case CEE_NEG:
5351                 case CEE_NOT:
5352                 case CEE_CONV_I1:
5353                 case CEE_CONV_I2:
5354                 case CEE_CONV_I4:
5355                 case CEE_CONV_R4:
5356                 case CEE_CONV_R8:
5357                 case CEE_CONV_U4:
5358                 case CEE_CONV_I8:
5359                 case CEE_CONV_U8:
5360                 case CEE_CONV_OVF_I8:
5361                 case CEE_CONV_OVF_U8:
5362                 case CEE_CONV_R_UN:
5363                         CHECK_STACK (1);
5364                         ADD_UNOP (*ip);
5365                         if (mono_find_jit_opcode_emulation (ins->opcode)) {
5366                                 --sp;
5367                                 *sp++ = emit_tree (cfg, bblock, ins, ip + 1);
5368                         }
5369                         ip++;                   
5370                         break;
5371                 case CEE_CONV_OVF_I4:
5372                 case CEE_CONV_OVF_I1:
5373                 case CEE_CONV_OVF_I2:
5374                 case CEE_CONV_OVF_I:
5375                 case CEE_CONV_OVF_U:
5376                         CHECK_STACK (1);
5377
5378                         if (sp [-1]->type == STACK_R8) {
5379                                 ADD_UNOP (CEE_CONV_OVF_I8);
5380                                 ADD_UNOP (*ip);
5381                         } else {
5382                                 ADD_UNOP (*ip);
5383                         }
5384
5385                         ip++;
5386                         break;
5387                 case CEE_CONV_OVF_U1:
5388                 case CEE_CONV_OVF_U2:
5389                 case CEE_CONV_OVF_U4:
5390                         CHECK_STACK (1);
5391
5392                         if (sp [-1]->type == STACK_R8) {
5393                                 ADD_UNOP (CEE_CONV_OVF_U8);
5394                                 ADD_UNOP (*ip);
5395                         } else {
5396                                 ADD_UNOP (*ip);
5397                         }
5398
5399                         ip++;
5400                         break;
5401                 case CEE_CONV_OVF_I1_UN:
5402                 case CEE_CONV_OVF_I2_UN:
5403                 case CEE_CONV_OVF_I4_UN:
5404                 case CEE_CONV_OVF_I8_UN:
5405                 case CEE_CONV_OVF_U1_UN:
5406                 case CEE_CONV_OVF_U2_UN:
5407                 case CEE_CONV_OVF_U4_UN:
5408                 case CEE_CONV_OVF_U8_UN:
5409                 case CEE_CONV_OVF_I_UN:
5410                 case CEE_CONV_OVF_U_UN:
5411                         CHECK_STACK (1);
5412                         ADD_UNOP (*ip);
5413                         ip++;
5414                         break;
5415                 case CEE_CPOBJ:
5416                         CHECK_OPSIZE (5);
5417                         CHECK_STACK (2);
5418                         token = read32 (ip + 1);
5419                         klass = mini_get_class (method, token, generic_context);
5420                         CHECK_TYPELOAD (klass);
5421                         sp -= 2;
5422                         if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
5423                                 MonoInst *store, *load;
5424                                 MONO_INST_NEW (cfg, load, CEE_LDIND_REF);
5425                                 load->cil_code = ip;
5426                                 load->inst_i0 = sp [1];
5427                                 load->type = STACK_OBJ;
5428                                 load->klass = klass;
5429                                 load->flags |= ins_flag;
5430                                 MONO_INST_NEW (cfg, store, CEE_STIND_REF);
5431                                 store->cil_code = ip;
5432                                 handle_loaded_temps (cfg, bblock, stack_start, sp);
5433                                 MONO_ADD_INS (bblock, store);
5434                                 store->inst_i0 = sp [0];
5435                                 store->inst_i1 = load;
5436                                 store->flags |= ins_flag;
5437                         } else {
5438                                 n = mono_class_value_size (klass, NULL);
5439                                 if ((cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 5) {
5440                                         MonoInst *copy;
5441                                         MONO_INST_NEW (cfg, copy, OP_MEMCPY);
5442                                         copy->inst_left = sp [0];
5443                                         copy->inst_right = sp [1];
5444                                         copy->cil_code = ip;
5445                                         copy->backend.size = n;
5446                                         MONO_ADD_INS (bblock, copy);
5447                                 } else {
5448                                         MonoMethod *memcpy_method = get_memcpy_method ();
5449                                         MonoInst *iargs [3];
5450                                         iargs [0] = sp [0];
5451                                         iargs [1] = sp [1];
5452                                         NEW_ICONST (cfg, iargs [2], n);
5453                                         iargs [2]->cil_code = ip;
5454
5455                                         mono_emit_method_call_spilled (cfg, bblock, memcpy_method, memcpy_method->signature, iargs, ip, NULL);
5456                                 }
5457                         }
5458                         ins_flag = 0;
5459                         ip += 5;
5460                         break;
5461                 case CEE_LDOBJ: {
5462                         MonoInst *iargs [3];
5463                         int loc_index = -1;
5464                         int stloc_len = 0;
5465                         CHECK_OPSIZE (5);
5466                         CHECK_STACK (1);
5467                         --sp;
5468                         token = read32 (ip + 1);
5469                         klass = mini_get_class (method, token, generic_context);
5470                         CHECK_TYPELOAD (klass);
5471                         if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
5472                                 MONO_INST_NEW (cfg, ins, CEE_LDIND_REF);
5473                                 ins->cil_code = ip;
5474                                 ins->inst_i0 = sp [0];
5475                                 ins->type = STACK_OBJ;
5476                                 ins->klass = klass;
5477                                 ins->flags |= ins_flag;
5478                                 ins_flag = 0;
5479                                 *sp++ = ins;
5480                                 ip += 5;
5481                                 break;
5482                         }
5483
5484                         /* Optimize the common ldobj+stloc combination */
5485                         switch (ip [5]) {
5486                         case CEE_STLOC_S:
5487                                 loc_index = ip [6];
5488                                 stloc_len = 2;
5489                                 break;
5490                         case CEE_STLOC_0:
5491                         case CEE_STLOC_1:
5492                         case CEE_STLOC_2:
5493                         case CEE_STLOC_3:
5494                                 loc_index = ip [5] - CEE_STLOC_0;
5495                                 stloc_len = 1;
5496                                 break;
5497                         default:
5498                                 break;
5499                         }
5500
5501                         if ((loc_index != -1) && ip_in_bb (cfg, bblock, ip + 5)) {
5502                                 CHECK_LOCAL (loc_index);
5503                                 NEW_LOCSTORE (cfg, ins, loc_index, *sp);
5504
5505                                 if (ins->opcode == CEE_STOBJ) {
5506                                         handle_loaded_temps (cfg, bblock, stack_start, sp);
5507                                         ins->cil_code = ip;
5508                                         g_assert (ins->opcode == CEE_STOBJ);
5509                                         NEW_LOCLOADA (cfg, ins, loc_index);
5510                                         handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE, FALSE);
5511                                         ip += 5;
5512                                         ip += stloc_len;
5513                                         break;
5514                                 }
5515                         }
5516
5517                         n = mono_class_value_size (klass, NULL);
5518                         ins = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
5519                         NEW_TEMPLOADA (cfg, iargs [0], ins->inst_c0);
5520                         if ((cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 5) {
5521                                 MonoInst *copy;
5522                                 MONO_INST_NEW (cfg, copy, OP_MEMCPY);
5523                                 copy->inst_left = iargs [0];
5524                                 copy->inst_right = *sp;
5525                                 copy->cil_code = ip;
5526                                 copy->backend.size = n;
5527                                 MONO_ADD_INS (bblock, copy);
5528                         } else {
5529                                 MonoMethod *memcpy_method = get_memcpy_method ();
5530                                 iargs [1] = *sp;
5531                                 NEW_ICONST (cfg, iargs [2], n);
5532                                 iargs [2]->cil_code = ip;
5533
5534                                 mono_emit_method_call_spilled (cfg, bblock, memcpy_method, memcpy_method->signature, iargs, ip, NULL);
5535                         }
5536                         NEW_TEMPLOAD (cfg, *sp, ins->inst_c0);
5537                         ++sp;
5538                         ip += 5;
5539                         ins_flag = 0;
5540                         inline_costs += 1;
5541                         break;
5542                 }
5543                 case CEE_LDSTR:
5544                         CHECK_STACK_OVF (1);
5545                         CHECK_OPSIZE (5);
5546                         n = read32 (ip + 1);
5547
5548                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
5549                                 /* FIXME: moving GC */
5550                                 NEW_PCONST (cfg, ins, mono_method_get_wrapper_data (method, n));
5551                                 ins->cil_code = ip;
5552                                 ins->type = STACK_OBJ;
5553                                 ins->klass = mono_defaults.string_class;
5554                                 *sp = ins;
5555                         }
5556                         else if (method->wrapper_type != MONO_WRAPPER_NONE) {
5557                                 int temp;
5558                                 MonoInst *iargs [1];
5559
5560                                 NEW_PCONST (cfg, iargs [0], mono_method_get_wrapper_data (method, n));                          
5561                                 temp = mono_emit_jit_icall (cfg, bblock, mono_string_new_wrapper, iargs, ip);
5562                                 NEW_TEMPLOAD (cfg, *sp, temp);
5563
5564                         } else {
5565
5566                                 if (cfg->opt & MONO_OPT_SHARED) {
5567                                         int temp;
5568                                         MonoInst *iargs [3];
5569                                         MonoInst* domain_var;
5570                                         
5571                                         if (cfg->compile_aot) {
5572                                                 cfg->ldstr_list = g_list_prepend (cfg->ldstr_list, GINT_TO_POINTER (n));
5573                                         }
5574                                         /* avoid depending on undefined C behavior in sequence points */
5575                                         domain_var = mono_get_domainvar (cfg);
5576                                         NEW_TEMPLOAD (cfg, iargs [0], domain_var->inst_c0);
5577                                         NEW_IMAGECONST (cfg, iargs [1], image);
5578                                         NEW_ICONST (cfg, iargs [2], mono_metadata_token_index (n));
5579                                         temp = mono_emit_jit_icall (cfg, bblock, mono_ldstr, iargs, ip);
5580                                         NEW_TEMPLOAD (cfg, *sp, temp);
5581                                         mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
5582                                 } else {
5583                                         if (bblock->out_of_line) {
5584                                                 MonoInst *iargs [2];
5585                                                 int temp;
5586
5587                                                 if (cfg->compile_aot && cfg->method->klass->image == mono_defaults.corlib) {
5588                                                         /* 
5589                                                          * Avoid relocations by using a version of helper_ldstr
5590                                                          * specialized to mscorlib.
5591                                                          */
5592                                                         NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (n));
5593                                                         temp = mono_emit_jit_icall (cfg, bblock, mono_helper_ldstr_mscorlib, iargs, ip);
5594                                                 } else {
5595                                                         /* Avoid creating the string object */
5596                                                         NEW_IMAGECONST (cfg, iargs [0], image);
5597                                                         NEW_ICONST (cfg, iargs [1], mono_metadata_token_index (n));
5598                                                         temp = mono_emit_jit_icall (cfg, bblock, mono_helper_ldstr, iargs, ip);
5599                                                 }
5600                                                 NEW_TEMPLOAD (cfg, *sp, temp);
5601                                         } 
5602                                         else
5603                                         if (cfg->compile_aot) {
5604                                                 NEW_LDSTRCONST (cfg, ins, image, n);
5605                                                 *sp = ins;
5606                                         } 
5607                                         else {
5608                                                 NEW_PCONST (cfg, ins, NULL);
5609                                                 ins->cil_code = ip;
5610                                                 ins->type = STACK_OBJ;
5611                                                 ins->inst_p0 = mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
5612                                                 ins->klass = mono_defaults.string_class;
5613                                                 *sp = ins;
5614                                         }
5615                                 }
5616                         }
5617
5618                         sp++;
5619                         ip += 5;
5620                         break;
5621                 case CEE_NEWOBJ: {
5622                         MonoInst *iargs [2];
5623                         MonoMethodSignature *fsig;
5624                         int temp;
5625                         
5626                         CHECK_OPSIZE (5);
5627                         token = read32 (ip + 1);
5628                         cmethod = mini_get_method (method, token, NULL, generic_context);
5629                         if (!cmethod)
5630                                 goto load_error;
5631                         fsig = mono_method_get_signature (cmethod, image, token);
5632
5633                         if (!mono_class_init (cmethod->klass))
5634                                 goto load_error;
5635
5636                         if (mono_use_security_manager) {
5637                                 if (check_linkdemand (cfg, method, cmethod, bblock, ip))
5638                                         INLINE_FAILURE;
5639                         }
5640
5641                         n = fsig->param_count;
5642                         CHECK_STACK (n);
5643
5644                         /* move the args to allow room for 'this' in the first position */
5645                         while (n--) {
5646                                 --sp;
5647                                 sp [1] = sp [0];
5648                         }
5649
5650                         handle_loaded_temps (cfg, bblock, stack_start, sp);
5651
5652                         if (mini_class_is_system_array (cmethod->klass)) {
5653                                 NEW_METHODCONST (cfg, *sp, cmethod);
5654                                 temp = handle_array_new (cfg, bblock, fsig->param_count, sp, ip);
5655                         } else if (cmethod->string_ctor) {
5656                                 /* we simply pass a null pointer */
5657                                 NEW_PCONST (cfg, *sp, NULL); 
5658                                 /* now call the string ctor */
5659                                 temp = mono_emit_method_call_spilled (cfg, bblock, cmethod, fsig, sp, ip, NULL);
5660                         } else {
5661                                 MonoInst* callvirt_this_arg = NULL;
5662                                 
5663                                 if (cmethod->klass->valuetype) {
5664                                         iargs [0] = mono_compile_create_var (cfg, &cmethod->klass->byval_arg, OP_LOCAL);
5665                                         temp = iargs [0]->inst_c0;
5666
5667                                         NEW_TEMPLOADA (cfg, *sp, temp);
5668
5669                                         handle_initobj (cfg, bblock, *sp, NULL, cmethod->klass, stack_start, sp);
5670
5671                                         NEW_TEMPLOADA (cfg, *sp, temp);
5672
5673                                         /* 
5674                                          * The code generated by mini_emit_virtual_call () expects
5675                                          * iargs [0] to be a boxed instance, but luckily the vcall
5676                                          * will be transformed into a normal call there.
5677                                          */
5678                                 } else {
5679                                         temp = handle_alloc (cfg, bblock, cmethod->klass, FALSE, ip);
5680                                         NEW_TEMPLOAD (cfg, *sp, temp);
5681                                 }
5682
5683                                 /* Avoid virtual calls to ctors if possible */
5684                                 if (cmethod->klass->marshalbyref)
5685                                         callvirt_this_arg = sp [0];
5686                                 
5687                                 if ((cfg->opt & MONO_OPT_INLINE) && cmethod &&
5688                                     mono_method_check_inlining (cfg, cmethod) &&
5689                                     !mono_class_is_subclass_of (cmethod->klass, mono_defaults.exception_class, FALSE) &&
5690                                     !g_list_find (dont_inline, cmethod)) {
5691                                         int costs;
5692                                         MonoBasicBlock *ebblock;
5693                                         if ((costs = inline_method (cfg, cmethod, fsig, bblock, sp, ip, real_offset, dont_inline, &ebblock, FALSE))) {
5694
5695                                                 ip += 5;
5696                                                 real_offset += 5;
5697                                                 
5698                                                 GET_BBLOCK (cfg, bbhash, bblock, ip);
5699                                                 ebblock->next_bb = bblock;
5700                                                 link_bblock (cfg, ebblock, bblock);
5701
5702                                                 NEW_TEMPLOAD (cfg, *sp, temp);
5703                                                 sp++;
5704
5705                                                 /* indicates start of a new block, and triggers a load 
5706                                                    of all stack arguments at bb boundarie */
5707                                                 bblock = ebblock;
5708
5709                                                 inline_costs += costs;
5710                                                 break;
5711                                                 
5712                                         } else {
5713                                                 /* Prevent inlining of methods which call other methods */
5714                                                 INLINE_FAILURE;
5715                                                 mono_emit_method_call_spilled (cfg, bblock, cmethod, fsig, sp, ip, callvirt_this_arg);
5716                                         }
5717                                 } else {
5718                                         /* Prevent inlining of methods which call other methods */
5719                                         INLINE_FAILURE;
5720                                         /* now call the actual ctor */
5721                                         mono_emit_method_call_spilled (cfg, bblock, cmethod, fsig, sp, ip, callvirt_this_arg);
5722                                 }
5723                         }
5724
5725                         NEW_TEMPLOAD (cfg, *sp, temp);
5726                         sp++;
5727                         
5728                         ip += 5;
5729                         inline_costs += 5;
5730                         break;
5731                 }
5732                 case CEE_ISINST:
5733                         CHECK_STACK (1);
5734                         --sp;
5735                         CHECK_OPSIZE (5);
5736                         token = read32 (ip + 1);
5737                         klass = mini_get_class (method, token, generic_context);
5738                         CHECK_TYPELOAD (klass);
5739                         if (sp [0]->type != STACK_OBJ)
5740                                 UNVERIFIED;
5741
5742                         /* Needed by the code generated in inssel.brg */
5743                         mono_get_got_var (cfg);
5744
5745                         if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
5746                         
5747                                 MonoMethod *mono_isinst;
5748                                 MonoInst *iargs [1];
5749                                 MonoBasicBlock *ebblock;
5750                                 int costs;
5751                                 int temp;
5752                                 
5753                                 mono_isinst = mono_marshal_get_isinst (klass); 
5754                                 iargs [0] = sp [0];
5755                                 
5756                                 costs = inline_method (cfg, mono_isinst, mono_method_signature (mono_isinst), bblock, 
5757                                                            iargs, ip, real_offset, dont_inline, &ebblock, TRUE);
5758                         
5759                                 g_assert (costs > 0);
5760                                 
5761                                 ip += 5;
5762                                 real_offset += 5;
5763                         
5764                                 GET_BBLOCK (cfg, bbhash, bblock, ip);
5765                                 ebblock->next_bb = bblock;
5766                                 link_bblock (cfg, ebblock, bblock);
5767
5768                                 temp = iargs [0]->inst_i0->inst_c0;
5769                                 NEW_TEMPLOAD (cfg, *sp, temp);
5770                                 
5771                                 sp++;
5772                                 bblock = ebblock;
5773                                 inline_costs += costs;
5774                         } else {
5775                                 MONO_INST_NEW (cfg, ins, *ip);
5776                                 ins->type = STACK_OBJ;
5777                                 ins->inst_left = *sp;
5778                                 ins->inst_newa_class = klass;
5779                                 ins->klass = klass;
5780                                 ins->cil_code = ip;
5781                                 *sp++ = emit_tree (cfg, bblock, ins, ip + 5);
5782                                 ip += 5;
5783                         }
5784                         break;
5785                 case CEE_UNBOX_ANY: {
5786                         MonoInst *add, *vtoffset;
5787                         MonoInst *iargs [3];
5788
5789                         CHECK_STACK (1);
5790                         --sp;
5791                         CHECK_OPSIZE (5);
5792                         token = read32 (ip + 1);
5793                         klass = mini_get_class (method, token, generic_context);
5794                         CHECK_TYPELOAD (klass);
5795
5796                         if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
5797                                 /* CASTCLASS */
5798                                 if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
5799                                         MonoMethod *mono_castclass;
5800                                         MonoInst *iargs [1];
5801                                         MonoBasicBlock *ebblock;
5802                                         int costs;
5803                                         int temp;
5804                                         
5805                                         mono_castclass = mono_marshal_get_castclass (klass); 
5806                                         iargs [0] = sp [0];
5807                                         
5808                                         costs = inline_method (cfg, mono_castclass, mono_method_signature (mono_castclass), bblock, 
5809                                                                    iargs, ip, real_offset, dont_inline, &ebblock, TRUE);
5810                                 
5811                                         g_assert (costs > 0);
5812                                         
5813                                         ip += 5;
5814                                         real_offset += 5;
5815                                 
5816                                         GET_BBLOCK (cfg, bbhash, bblock, ip);
5817                                         ebblock->next_bb = bblock;
5818                                         link_bblock (cfg, ebblock, bblock);
5819         
5820                                         temp = iargs [0]->inst_i0->inst_c0;
5821                                         NEW_TEMPLOAD (cfg, *sp, temp);
5822                                         
5823                                         sp++;
5824                                         bblock = ebblock;
5825                                         inline_costs += costs;                          
5826                                 } else {
5827                                         MONO_INST_NEW (cfg, ins, CEE_CASTCLASS);
5828                                         ins->type = STACK_OBJ;
5829                                         ins->inst_left = *sp;
5830                                         ins->klass = klass;
5831                                         ins->inst_newa_class = klass;
5832                                         ins->cil_code = ip;
5833                                         *sp++ = ins;
5834                                         ip += 5;
5835                                 }
5836                                 break;
5837                         }
5838
5839                         if (mono_class_is_nullable (klass)) {
5840                                 int v = handle_unbox_nullable (cfg, bblock, *sp, ip, klass);
5841                                 NEW_TEMPLOAD (cfg, *sp, v);
5842                                 sp ++;
5843                                 ip += 5;
5844                                 break;
5845                         }
5846
5847                         MONO_INST_NEW (cfg, ins, OP_UNBOXCAST);
5848                         ins->type = STACK_OBJ;
5849                         ins->inst_left = *sp;
5850                         ins->klass = klass;
5851                         ins->inst_newa_class = klass;
5852                         ins->cil_code = ip;
5853
5854                         MONO_INST_NEW (cfg, add, OP_PADD);
5855                         NEW_ICONST (cfg, vtoffset, sizeof (MonoObject));
5856                         add->inst_left = ins;
5857                         add->inst_right = vtoffset;
5858                         add->type = STACK_MP;
5859                         add->klass = mono_defaults.object_class;
5860                         *sp = add;
5861                         ip += 5;
5862                         /* LDOBJ impl */
5863                         n = mono_class_value_size (klass, NULL);
5864                         ins = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
5865                         NEW_TEMPLOADA (cfg, iargs [0], ins->inst_c0);
5866                         if ((cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 5) {
5867                                 MonoInst *copy;
5868                                 MONO_INST_NEW (cfg, copy, OP_MEMCPY);
5869                                 copy->inst_left = iargs [0];
5870                                 copy->inst_right = *sp;
5871                                 copy->cil_code = ip;
5872                                 copy->backend.size = n;
5873                                 MONO_ADD_INS (bblock, copy);
5874                         } else {
5875                                 MonoMethod *memcpy_method = get_memcpy_method ();
5876                                 iargs [1] = *sp;
5877                                 NEW_ICONST (cfg, iargs [2], n);
5878                                 iargs [2]->cil_code = ip;
5879
5880                                 mono_emit_method_call_spilled (cfg, bblock, memcpy_method, memcpy_method->signature, iargs, ip, NULL);
5881                         }
5882                         NEW_TEMPLOAD (cfg, *sp, ins->inst_c0);
5883                         ++sp;
5884                         inline_costs += 2;
5885                         break;
5886                 }
5887                 case CEE_UNBOX: {
5888                         MonoInst *add, *vtoffset;
5889
5890                         CHECK_STACK (1);
5891                         --sp;
5892                         CHECK_OPSIZE (5);
5893                         token = read32 (ip + 1);
5894                         klass = mini_get_class (method, token, generic_context);
5895                         CHECK_TYPELOAD (klass);
5896
5897                         if (mono_class_is_nullable (klass)) {
5898                                 int v = handle_unbox_nullable (cfg, bblock, *sp, ip, klass);
5899                                 NEW_TEMPLOAD (cfg, *sp, v);
5900                                 sp ++;
5901                                 ip += 5;
5902                                 break;
5903                         }
5904
5905                         /* Needed by the code generated in inssel.brg */
5906                         mono_get_got_var (cfg);
5907
5908                         MONO_INST_NEW (cfg, ins, OP_UNBOXCAST);
5909                         ins->type = STACK_OBJ;
5910                         ins->inst_left = *sp;
5911                         ins->klass = klass;
5912                         ins->inst_newa_class = klass;
5913                         ins->cil_code = ip;
5914
5915                         MONO_INST_NEW (cfg, add, OP_PADD);
5916                         NEW_ICONST (cfg, vtoffset, sizeof (MonoObject));
5917                         add->inst_left = ins;
5918                         add->inst_right = vtoffset;
5919                         add->type = STACK_MP;
5920                         add->klass = klass;
5921                         *sp++ = add;
5922                         ip += 5;
5923                         inline_costs += 2;
5924                         break;
5925                 }
5926                 case CEE_CASTCLASS:
5927                         CHECK_STACK (1);
5928                         --sp;
5929                         CHECK_OPSIZE (5);
5930                         token = read32 (ip + 1);
5931                         klass = mini_get_class (method, token, generic_context);
5932                         CHECK_TYPELOAD (klass);
5933                         if (sp [0]->type != STACK_OBJ)
5934                                 UNVERIFIED;
5935
5936                         /* Needed by the code generated in inssel.brg */
5937                         mono_get_got_var (cfg);
5938                 
5939                         if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
5940                                 
5941                                 MonoMethod *mono_castclass;
5942                                 MonoInst *iargs [1];
5943                                 MonoBasicBlock *ebblock;
5944                                 int costs;
5945                                 int temp;
5946                                 
5947                                 mono_castclass = mono_marshal_get_castclass (klass); 
5948                                 iargs [0] = sp [0];
5949                                 
5950                                 costs = inline_method (cfg, mono_castclass, mono_method_signature (mono_castclass), bblock, 
5951                                                            iargs, ip, real_offset, dont_inline, &ebblock, TRUE);
5952                         
5953                                 g_assert (costs > 0);
5954                                 
5955                                 ip += 5;
5956                                 real_offset += 5;
5957                         
5958                                 GET_BBLOCK (cfg, bbhash, bblock, ip);
5959                                 ebblock->next_bb = bblock;
5960                                 link_bblock (cfg, ebblock, bblock);
5961
5962                                 temp = iargs [0]->inst_i0->inst_c0;
5963                                 NEW_TEMPLOAD (cfg, *sp, temp);
5964                                 
5965                                 sp++;
5966                                 bblock = ebblock;
5967                                 inline_costs += costs;
5968                         } else {
5969                                 MONO_INST_NEW (cfg, ins, *ip);
5970                                 ins->type = STACK_OBJ;
5971                                 ins->inst_left = *sp;
5972                                 ins->klass = klass;
5973                                 ins->inst_newa_class = klass;
5974                                 ins->cil_code = ip;
5975                                 *sp++ = emit_tree (cfg, bblock, ins, ip + 5);
5976                                 ip += 5;
5977                         }
5978                         break;
5979                 case CEE_THROW:
5980                         CHECK_STACK (1);
5981                         MONO_INST_NEW (cfg, ins, *ip);
5982                         --sp;
5983                         ins->inst_left = *sp;
5984                         ins->cil_code = ip++;
5985                         bblock->out_of_line = TRUE;
5986                         MONO_ADD_INS (bblock, ins);
5987                         MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
5988                         ins->cil_code = ip - 1;
5989                         MONO_ADD_INS (bblock, ins);
5990                         sp = stack_start;
5991                         
5992                         link_bblock (cfg, bblock, end_bblock);
5993                         start_new_bblock = 1;
5994                         break;
5995                 case CEE_LDFLD:
5996                 case CEE_LDFLDA:
5997                 case CEE_STFLD: {
5998                         MonoInst *offset_ins;
5999                         MonoClassField *field;
6000                         MonoBasicBlock *ebblock;
6001                         int costs;
6002                         guint foffset;
6003
6004                         if (*ip == CEE_STFLD) {
6005                                 CHECK_STACK (2);
6006                                 sp -= 2;
6007                         } else {
6008                                 CHECK_STACK (1);
6009                                 --sp;
6010                         }
6011                         if (sp [0]->type == STACK_I4 || sp [0]->type == STACK_I8 || sp [0]->type == STACK_R8)
6012                                 UNVERIFIED;
6013                         if (*ip != CEE_LDFLD && sp [0]->type == STACK_VTYPE)
6014                                 UNVERIFIED;
6015                         CHECK_OPSIZE (5);
6016                         token = read32 (ip + 1);
6017                         if (method->wrapper_type != MONO_WRAPPER_NONE) {
6018                                 field = mono_method_get_wrapper_data (method, token);
6019                                 klass = field->parent;
6020                         } else {
6021                                 field = mono_field_from_token (image, token, &klass, generic_context);
6022                         }
6023                         if (!field)
6024                                 goto load_error;
6025                         mono_class_init (klass);
6026                         if (!dont_verify && !cfg->skip_visibility && !can_access_field (method, field))
6027                                 UNVERIFIED;
6028
6029                         foffset = klass->valuetype? field->offset - sizeof (MonoObject): field->offset;
6030                         /* FIXME: mark instructions for use in SSA */
6031                         if (*ip == CEE_STFLD) {
6032                                 if (target_type_is_incompatible (cfg, field->type, sp [1]))
6033                                         UNVERIFIED;
6034                                 if ((klass->marshalbyref && !MONO_CHECK_THIS (sp [0])) || klass->contextbound || klass == mono_defaults.marshalbyrefobject_class) {
6035                                         MonoMethod *stfld_wrapper = mono_marshal_get_stfld_wrapper (field->type); 
6036                                         MonoInst *iargs [5];
6037
6038                                         iargs [0] = sp [0];
6039                                         NEW_CLASSCONST (cfg, iargs [1], klass);
6040                                         NEW_FIELDCONST (cfg, iargs [2], field);
6041                                         NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : 
6042                                                     field->offset);
6043                                         iargs [4] = sp [1];
6044
6045                                         if (cfg->opt & MONO_OPT_INLINE) {
6046                                                 costs = inline_method (cfg, stfld_wrapper, mono_method_signature (stfld_wrapper), bblock, 
6047                                                                        iargs, ip, real_offset, dont_inline, &ebblock, TRUE);
6048                                                 g_assert (costs > 0);
6049                                                       
6050                                                 ip += 5;
6051                                                 real_offset += 5;
6052
6053                                                 GET_BBLOCK (cfg, bbhash, bblock, ip);
6054                                                 ebblock->next_bb = bblock;
6055                                                 link_bblock (cfg, ebblock, bblock);
6056
6057                                                 /* indicates start of a new block, and triggers a load 
6058                                                    of all stack arguments at bb boundarie */
6059                                                 bblock = ebblock;
6060
6061                                                 inline_costs += costs;
6062                                                 break;
6063                                         } else {
6064                                                 mono_emit_method_call_spilled (cfg, bblock, stfld_wrapper, mono_method_signature (stfld_wrapper), iargs, ip, NULL);
6065                                         }
6066 #if HAVE_WRITE_BARRIERS
6067                                 } else if (mono_type_to_stind (field->type) == CEE_STIND_REF) {
6068                                         /* insert call to write barrier */
6069                                         MonoMethod *write_barrier = mono_marshal_get_write_barrier ();
6070                                         MonoInst *iargs [2];
6071                                         NEW_ICONST (cfg, offset_ins, foffset);
6072                                         MONO_INST_NEW (cfg, ins, OP_PADD);
6073                                         ins->cil_code = ip;
6074                                         ins->inst_left = *sp;
6075                                         ins->inst_right = offset_ins;
6076                                         ins->type = STACK_MP;
6077                                         ins->klass = mono_defaults.object_class;
6078                                         iargs [0] = ins;
6079                                         iargs [1] = sp [1];
6080                                         mono_emit_method_call_spilled (cfg, bblock, write_barrier, mono_method_signature (write_barrier), iargs, ip, NULL);
6081 #endif
6082 #ifdef MONO_ARCH_SOFT_FLOAT
6083                                 } else if (mono_type_to_stind (field->type) == CEE_STIND_R4) {
6084                                         NEW_ICONST (cfg, offset_ins, foffset);
6085                                         MONO_INST_NEW (cfg, ins, OP_PADD);
6086                                         ins->cil_code = ip;
6087                                         ins->inst_left = *sp;
6088                                         ins->inst_right = offset_ins;
6089                                         ins->type = STACK_MP;
6090                                         ins->klass = mono_defaults.object_class;
6091                                         handle_store_float (cfg, bblock, ins, sp [1], ip);
6092 #endif
6093                                 } else {
6094                                         MonoInst *store;
6095                                         NEW_ICONST (cfg, offset_ins, foffset);
6096                                         MONO_INST_NEW (cfg, ins, OP_PADD);
6097                                         ins->cil_code = ip;
6098                                         ins->inst_left = *sp;
6099                                         ins->inst_right = offset_ins;
6100                                         ins->type = STACK_MP;
6101
6102                                         MONO_INST_NEW (cfg, store, mono_type_to_stind (field->type));
6103                                         store->cil_code = ip;
6104                                         store->inst_left = ins;
6105                                         store->inst_right = sp [1];
6106                                         handle_loaded_temps (cfg, bblock, stack_start, sp);
6107                                         store->flags |= ins_flag;
6108                                         ins_flag = 0;
6109                                         if (store->opcode == CEE_STOBJ) {
6110                                                 handle_stobj (cfg, bblock, ins, sp [1], ip, 
6111                                                               mono_class_from_mono_type (field->type), FALSE, FALSE, TRUE);
6112                                         } else
6113                                                 MONO_ADD_INS (bblock, store);
6114                                 }
6115                         } else {
6116                                 if ((klass->marshalbyref && !MONO_CHECK_THIS (sp [0])) || klass->contextbound || klass == mono_defaults.marshalbyrefobject_class) {
6117                                         MonoMethod *wrapper = (*ip == CEE_LDFLDA) ? mono_marshal_get_ldflda_wrapper (field->type) : mono_marshal_get_ldfld_wrapper (field->type); 
6118                                         MonoInst *iargs [4];
6119                                         int temp;
6120                                         
6121                                         iargs [0] = sp [0];
6122                                         NEW_CLASSCONST (cfg, iargs [1], klass);
6123                                         NEW_FIELDCONST (cfg, iargs [2], field);
6124                                         NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset);
6125                                         if ((cfg->opt & MONO_OPT_INLINE) && !MONO_TYPE_ISSTRUCT (mono_method_signature (wrapper)->ret)) {
6126                                                 costs = inline_method (cfg, wrapper, mono_method_signature (wrapper), bblock, 
6127                                                                        iargs, ip, real_offset, dont_inline, &ebblock, TRUE);
6128                                                 g_assert (costs > 0);
6129                                                       
6130                                                 ip += 5;
6131                                                 real_offset += 5;
6132
6133                                                 GET_BBLOCK (cfg, bbhash, bblock, ip);
6134                                                 ebblock->next_bb = bblock;
6135                                                 link_bblock (cfg, ebblock, bblock);
6136
6137                                                 temp = iargs [0]->inst_i0->inst_c0;
6138
6139                                                 NEW_TEMPLOAD (cfg, *sp, temp);
6140                                                 sp++;
6141
6142                                                 /* indicates start of a new block, and triggers a load of
6143                                                    all stack arguments at bb boundarie */
6144                                                 bblock = ebblock;
6145                                                 
6146                                                 inline_costs += costs;
6147                                                 break;
6148                                         } else {
6149                                                 temp = mono_emit_method_call_spilled (cfg, bblock, wrapper, mono_method_signature (wrapper), iargs, ip, NULL);
6150                                                 NEW_TEMPLOAD (cfg, *sp, temp);
6151                                                 sp++;
6152                                         }
6153                                 } else {
6154                                         NEW_ICONST (cfg, offset_ins, foffset);
6155                                         MONO_INST_NEW (cfg, ins, OP_PADD);
6156                                         ins->cil_code = ip;
6157                                         ins->inst_left = *sp;
6158                                         ins->inst_right = offset_ins;
6159                                         ins->type = STACK_MP;
6160
6161                                         if (*ip == CEE_LDFLDA) {
6162                                                 ins->klass = mono_class_from_mono_type (field->type);
6163                                                 *sp++ = ins;
6164                                         } else {
6165                                                 MonoInst *load;
6166                                                 MONO_INST_NEW (cfg, load, mono_type_to_ldind (field->type));
6167                                                 type_to_eval_stack_type (field->type, load);
6168                                                 load->cil_code = ip;
6169                                                 load->inst_left = ins;
6170                                                 load->flags |= ins_flag;
6171                                                 ins_flag = 0;
6172 #ifdef MONO_ARCH_SOFT_FLOAT
6173                                                 if (mono_type_to_ldind (field->type) == CEE_LDIND_R4) {
6174                                                         int temp;
6175                                                         temp = handle_load_float (cfg, bblock, ins, ip);
6176                                                         NEW_TEMPLOAD (cfg, *sp, temp);
6177                                                         sp++;
6178                                                 } else
6179 #endif
6180                                                 *sp++ = load;
6181                                         }
6182                                 }
6183                         }
6184                         ip += 5;
6185                         break;
6186                 }
6187                 case CEE_LDSFLD:
6188                 case CEE_LDSFLDA:
6189                 case CEE_STSFLD: {
6190                         MonoClassField *field;
6191                         gpointer addr = NULL;
6192
6193                         CHECK_OPSIZE (5);
6194                         token = read32 (ip + 1);
6195                         if (method->wrapper_type != MONO_WRAPPER_NONE) {
6196                                 field = mono_method_get_wrapper_data (method, token);
6197                                 klass = field->parent;
6198                         }
6199                         else
6200                                 field = mono_field_from_token (image, token, &klass, generic_context);
6201                         if (!field)
6202                                 goto load_error;
6203                         mono_class_init (klass);
6204
6205                         g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
6206
6207                         if ((*ip) == CEE_STSFLD)
6208                                 handle_loaded_temps (cfg, bblock, stack_start, sp);
6209
6210                         /* The special_static_fields field is init'd in mono_class_vtable, so it needs
6211                          * to be called here.
6212                          */
6213                         if (!(cfg->opt & MONO_OPT_SHARED))
6214                                 mono_class_vtable (cfg->domain, klass);
6215                         mono_domain_lock (cfg->domain);
6216                         if (cfg->domain->special_static_fields)
6217                                 addr = g_hash_table_lookup (cfg->domain->special_static_fields, field);
6218                         mono_domain_unlock (cfg->domain);
6219
6220                         if ((cfg->opt & MONO_OPT_SHARED) || (cfg->compile_aot && addr)) {
6221                                 int temp;
6222                                 MonoInst *iargs [2];
6223                                 MonoInst *domain_var;
6224                                 
6225                                 g_assert (field->parent);
6226                                 /* avoid depending on undefined C behavior in sequence points */
6227                                 domain_var = mono_get_domainvar (cfg);
6228                                 NEW_TEMPLOAD (cfg, iargs [0], domain_var->inst_c0);
6229                                 NEW_FIELDCONST (cfg, iargs [1], field);
6230                                 temp = mono_emit_jit_icall (cfg, bblock, mono_class_static_field_address, iargs, ip);
6231                                 NEW_TEMPLOAD (cfg, ins, temp);
6232                         } else {
6233                                 MonoVTable *vtable;
6234                                 vtable = mono_class_vtable (cfg->domain, klass);
6235                                 if (!addr) {
6236                                         if (mini_field_access_needs_cctor_run (cfg, method, vtable) && !(g_slist_find (class_inits, vtable))) {
6237                                                 guint8 *tramp = mono_create_class_init_trampoline (vtable);
6238                                                 mono_emit_native_call (cfg, bblock, tramp, 
6239                                                                                            helper_sig_class_init_trampoline,
6240                                                                                            NULL, ip, FALSE, FALSE);
6241                                                 if (cfg->verbose_level > 2)
6242                                                         g_print ("class %s.%s needs init call for %s\n", klass->name_space, klass->name, field->name);
6243                                                 class_inits = g_slist_prepend (class_inits, vtable);
6244                                         } else {
6245                                                 if (cfg->run_cctors) {
6246                                                         /* This makes so that inline cannot trigger */
6247                                                         /* .cctors: too many apps depend on them */
6248                                                         /* running with a specific order... */
6249                                                         if (! vtable->initialized)
6250                                                                 INLINE_FAILURE;
6251                                                         mono_runtime_class_init (vtable);
6252                                                 }
6253                                         }
6254                                         addr = (char*)vtable->data + field->offset;
6255
6256                                         if (cfg->compile_aot)
6257                                                 NEW_SFLDACONST (cfg, ins, field);
6258                                         else
6259                                                 NEW_PCONST (cfg, ins, addr);
6260                                         ins->cil_code = ip;
6261                                 } else {
6262                                         /* 
6263                                          * insert call to mono_threads_get_static_data (GPOINTER_TO_UINT (addr)) 
6264                                          * This could be later optimized to do just a couple of
6265                                          * memory dereferences with constant offsets.
6266                                          */
6267                                         int temp;
6268                                         MonoInst *iargs [1];
6269                                         NEW_ICONST (cfg, iargs [0], GPOINTER_TO_UINT (addr));
6270                                         temp = mono_emit_jit_icall (cfg, bblock, mono_get_special_static_data, iargs, ip);
6271                                         NEW_TEMPLOAD (cfg, ins, temp);
6272                                 }
6273                         }
6274
6275                         /* FIXME: mark instructions for use in SSA */
6276                         if (*ip == CEE_LDSFLDA) {
6277                                 ins->klass = mono_class_from_mono_type (field->type);
6278                                 *sp++ = ins;
6279                         } else if (*ip == CEE_STSFLD) {
6280                                 MonoInst *store;
6281                                 CHECK_STACK (1);
6282                                 sp--;
6283                                 MONO_INST_NEW (cfg, store, mono_type_to_stind (field->type));
6284                                 store->cil_code = ip;
6285                                 store->inst_left = ins;
6286                                 store->inst_right = sp [0];
6287                                 store->flags |= ins_flag;
6288                                 ins_flag = 0;
6289
6290                                 if (store->opcode == CEE_STOBJ) {
6291                                         handle_stobj (cfg, bblock, ins, sp [0], ip, mono_class_from_mono_type (field->type), FALSE, FALSE, FALSE);
6292                                 } else
6293                                         MONO_ADD_INS (bblock, store);
6294                         } else {
6295                                 gboolean is_const = FALSE;
6296                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
6297                                 if (!((cfg->opt & MONO_OPT_SHARED) || cfg->compile_aot) && 
6298                                     vtable->initialized && (field->type->attrs & FIELD_ATTRIBUTE_INIT_ONLY)) {
6299                                         gpointer addr = (char*)vtable->data + field->offset;
6300                                         int ro_type = field->type->type;
6301                                         if (ro_type == MONO_TYPE_VALUETYPE && field->type->data.klass->enumtype) {
6302                                                 ro_type = field->type->data.klass->enum_basetype->type;
6303                                         }
6304                                         /* g_print ("RO-FIELD %s.%s:%s\n", klass->name_space, klass->name, field->name);*/
6305                                         is_const = TRUE;
6306                                         switch (ro_type) {
6307                                         case MONO_TYPE_BOOLEAN:
6308                                         case MONO_TYPE_U1:
6309                                                 NEW_ICONST (cfg, *sp, *((guint8 *)addr));
6310                                                 sp++;
6311                                                 break;
6312                                         case MONO_TYPE_I1:
6313                                                 NEW_ICONST (cfg, *sp, *((gint8 *)addr));
6314                                                 sp++;
6315                                                 break;                                          
6316                                         case MONO_TYPE_CHAR:
6317                                         case MONO_TYPE_U2:
6318                                                 NEW_ICONST (cfg, *sp, *((guint16 *)addr));
6319                                                 sp++;
6320                                                 break;
6321                                         case MONO_TYPE_I2:
6322                                                 NEW_ICONST (cfg, *sp, *((gint16 *)addr));
6323                                                 sp++;
6324                                                 break;
6325                                                 break;
6326                                         case MONO_TYPE_I4:
6327                                                 NEW_ICONST (cfg, *sp, *((gint32 *)addr));
6328                                                 sp++;
6329                                                 break;                                          
6330                                         case MONO_TYPE_U4:
6331                                                 NEW_ICONST (cfg, *sp, *((guint32 *)addr));
6332                                                 sp++;
6333                                                 break;
6334 #ifndef HAVE_MOVING_COLLECTOR
6335                                         case MONO_TYPE_I:
6336                                         case MONO_TYPE_U:
6337                                         case MONO_TYPE_STRING:
6338                                         case MONO_TYPE_OBJECT:
6339                                         case MONO_TYPE_CLASS:
6340                                         case MONO_TYPE_SZARRAY:
6341                                         case MONO_TYPE_PTR:
6342                                         case MONO_TYPE_FNPTR:
6343                                         case MONO_TYPE_ARRAY:
6344                                                 NEW_PCONST (cfg, *sp, *((gpointer *)addr));
6345                                                 type_to_eval_stack_type (field->type, *sp);
6346                                                 sp++;
6347                                                 break;
6348 #endif
6349                                         case MONO_TYPE_I8:
6350                                         case MONO_TYPE_U8:
6351                                                 MONO_INST_NEW (cfg, *sp, OP_I8CONST);
6352                                                 sp [0]->type = STACK_I8;
6353                                                 sp [0]->inst_l = *((gint64 *)addr);
6354                                                 sp++;
6355                                                 break;
6356                                         case MONO_TYPE_R4:
6357                                         case MONO_TYPE_R8:
6358                                         case MONO_TYPE_VALUETYPE:
6359                                         default:
6360                                                 is_const = FALSE;
6361                                                 break;
6362                                         }
6363                                 }
6364
6365                                 if (!is_const) {
6366                                         MonoInst *load;
6367                                         CHECK_STACK_OVF (1);
6368                                         MONO_INST_NEW (cfg, load, mono_type_to_ldind (field->type));
6369                                         type_to_eval_stack_type (field->type, load);
6370                                         load->cil_code = ip;
6371                                         load->inst_left = ins;
6372                                         *sp++ = load;
6373                                         load->flags |= ins_flag;
6374                                         ins_flag = 0;
6375                                         /* fixme: dont see the problem why this does not work */
6376                                         //cfg->disable_aot = TRUE;
6377                                 }
6378                         }
6379                         ip += 5;
6380                         break;
6381                 }
6382                 case CEE_STOBJ:
6383                         CHECK_STACK (2);
6384                         sp -= 2;
6385                         CHECK_OPSIZE (5);
6386                         token = read32 (ip + 1);
6387                         klass = mini_get_class (method, token, generic_context);
6388                         CHECK_TYPELOAD (klass);
6389                         n = mono_type_to_stind (&klass->byval_arg);
6390                         if (n == CEE_STOBJ) {
6391                                 handle_stobj (cfg, bblock, sp [0], sp [1], ip, klass, FALSE, FALSE, TRUE);
6392                         } else {
6393                                 /* FIXME: should check item at sp [1] is compatible with the type of the store. */
6394                                 MonoInst *store;
6395                                 MONO_INST_NEW (cfg, store, n);
6396                                 store->cil_code = ip;
6397                                 store->inst_left = sp [0];
6398                                 store->inst_right = sp [1];
6399                                 store->flags |= ins_flag;
6400                                 MONO_ADD_INS (bblock, store);
6401                         }
6402                         ins_flag = 0;
6403                         ip += 5;
6404                         inline_costs += 1;
6405                         break;
6406                 case CEE_BOX: {
6407                         MonoInst *val;
6408                         CHECK_STACK (1);
6409                         --sp;
6410                         val = *sp;
6411                         CHECK_OPSIZE (5);
6412                         token = read32 (ip + 1);
6413                         klass = mini_get_class (method, token, generic_context);
6414                         CHECK_TYPELOAD (klass);
6415
6416                         if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
6417                                 *sp++ = val;
6418                                 ip += 5;
6419                                 break;
6420                         }
6421                         if (klass == mono_defaults.void_class)
6422                                 UNVERIFIED;
6423                         if (target_type_is_incompatible (cfg, &klass->byval_arg, *sp))
6424                                 UNVERIFIED;
6425                         /* frequent check in generic code: box (struct), brtrue */
6426                         if (!mono_class_is_nullable (klass) &&
6427                             ip + 5 < end && ip_in_bb (cfg, bblock, ip + 5) && (ip [5] == CEE_BRTRUE || ip [5] == CEE_BRTRUE_S)) {
6428                                 /*g_print ("box-brtrue opt at 0x%04x in %s\n", real_offset, method->name);*/
6429                                 MONO_INST_NEW (cfg, ins, CEE_POP);
6430                                 MONO_ADD_INS (bblock, ins);
6431                                 ins->cil_code = ip;
6432                                 ins->inst_i0 = *sp;
6433                                 ip += 5;
6434                                 MONO_INST_NEW (cfg, ins, CEE_BR);
6435                                 ins->cil_code = ip;
6436                                 MONO_ADD_INS (bblock, ins);
6437                                 if (*ip == CEE_BRTRUE_S) {
6438                                         CHECK_OPSIZE (2);
6439                                         ip++;
6440                                         target = ip + 1 + (signed char)(*ip);
6441                                         ip++;
6442                                 } else {
6443                                         CHECK_OPSIZE (5);
6444                                         ip++;
6445                                         target = ip + 4 + (gint)(read32 (ip));
6446                                         ip += 4;
6447                                 }
6448                                 GET_BBLOCK (cfg, bbhash, tblock, target);
6449                                 link_bblock (cfg, bblock, tblock);
6450                                 CHECK_BBLOCK (target, ip, tblock);
6451                                 ins->inst_target_bb = tblock;
6452                                 GET_BBLOCK (cfg, bbhash, tblock, ip);
6453                                 link_bblock (cfg, bblock, tblock);
6454                                 if (sp != stack_start) {
6455                                         handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
6456                                         sp = stack_start;
6457                                         CHECK_UNVERIFIABLE (cfg);
6458                                 }
6459                                 start_new_bblock = 1;
6460                                 break;
6461                         }
6462                         *sp++ = handle_box (cfg, bblock, val, ip, klass);
6463                         ip += 5;
6464                         inline_costs += 1;
6465                         break;
6466                 }
6467                 case CEE_NEWARR:
6468                         CHECK_STACK (1);
6469                         MONO_INST_NEW (cfg, ins, *ip);
6470                         ins->cil_code = ip;
6471                         --sp;
6472
6473                         CHECK_OPSIZE (5);
6474                         token = read32 (ip + 1);
6475
6476                         /* allocate the domainvar - becaus this is used in decompose_foreach */
6477                         if (cfg->opt & MONO_OPT_SHARED) {
6478                                 mono_get_domainvar (cfg);
6479                                 /* LAME-IR: Mark it as used since otherwise it will be optimized away */
6480                                 cfg->domainvar->flags |= MONO_INST_VOLATILE;
6481                         }
6482
6483                         /* Ditto */
6484                         mono_get_got_var (cfg);
6485
6486                         klass = mini_get_class (method, token, generic_context);
6487                         CHECK_TYPELOAD (klass);
6488                         ins->inst_newa_class = klass;
6489                         ins->inst_newa_len = *sp;
6490                         ins->type = STACK_OBJ;
6491                         ins->klass = mono_array_class_get (klass, 1);
6492                         ip += 5;
6493                         *sp++ = ins;
6494                         /* 
6495                          * we store the object so calls to create the array are not interleaved
6496                          * with the arguments of other calls.
6497                          */
6498                         if (1) {
6499                                 MonoInst *store, *temp, *load;
6500                                 const char *data_ptr;
6501                                 int data_size = 0;
6502                                 --sp;
6503                                 temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
6504                                 NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
6505                                 store->cil_code = ins->cil_code;
6506                                 MONO_ADD_INS (bblock, store);
6507                                 /* 
6508                                  * we inline/optimize the initialization sequence if possible.
6509                                  * we should also allocate the array as not cleared, since we spend as much time clearing to 0 as initializing
6510                                  * for small sizes open code the memcpy
6511                                  * ensure the rva field is big enough
6512                                  */
6513                                 if ((cfg->opt & MONO_OPT_INTRINS) && ip_in_bb (cfg, bblock, ip + 6) && (data_ptr = initialize_array_data (method, cfg->compile_aot, ip, ins, &data_size))) {
6514                                         MonoMethod *memcpy_method = get_memcpy_method ();
6515                                         MonoInst *data_offset, *add;
6516                                         MonoInst *iargs [3];
6517                                         NEW_ICONST (cfg, iargs [2], data_size);
6518                                         NEW_TEMPLOAD (cfg, load, temp->inst_c0);
6519                                         load->cil_code = ins->cil_code;
6520                                         NEW_ICONST (cfg, data_offset, G_STRUCT_OFFSET (MonoArray, vector));
6521                                         MONO_INST_NEW (cfg, add, OP_PADD);
6522                                         add->inst_left = load;
6523                                         add->inst_right = data_offset;
6524                                         add->cil_code = ip;
6525                                         iargs [0] = add;
6526                                         if (cfg->compile_aot) {
6527                                                 NEW_AOTCONST_TOKEN (cfg, iargs [1], MONO_PATCH_INFO_RVA, method->klass->image, GPOINTER_TO_UINT(data_ptr), STACK_PTR, NULL);
6528                                         } else {
6529                                                 NEW_PCONST (cfg, iargs [1], (char*)data_ptr);
6530                                         }
6531                                         mono_emit_method_call_spilled (cfg, bblock, memcpy_method, memcpy_method->signature, iargs, ip, NULL);
6532                                         ip += 11;
6533                                 }
6534                                 NEW_TEMPLOAD (cfg, load, temp->inst_c0);
6535                                 load->cil_code = ins->cil_code;
6536                                 *sp++ = load;
6537                         }
6538                         inline_costs += 1;
6539                         break;
6540                 case CEE_LDLEN:
6541                         CHECK_STACK (1);
6542                         --sp;
6543                         if (sp [0]->type != STACK_OBJ)
6544                                 UNVERIFIED;
6545                         MONO_INST_NEW (cfg, ins, *ip);
6546                         ins->cil_code = ip++;
6547                         ins->inst_left = *sp;
6548                         ins->type = STACK_PTR;
6549                         *sp++ = ins;
6550                         break;
6551                 case CEE_LDELEMA:
6552                         CHECK_STACK (2);
6553                         sp -= 2;
6554                         CHECK_OPSIZE (5);
6555                         if (sp [0]->type != STACK_OBJ)
6556                                 UNVERIFIED;
6557
6558                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
6559                         CHECK_TYPELOAD (klass);
6560                         /* we need to make sure that this array is exactly the type it needs
6561                          * to be for correctness. the wrappers are lax with their usage
6562                          * so we need to ignore them here
6563                          */
6564                         if (!klass->valuetype && method->wrapper_type == MONO_WRAPPER_NONE) {
6565                                 MonoInst* check;
6566
6567                                 /* Needed by the code generated in inssel.brg */
6568                                 mono_get_got_var (cfg);
6569
6570                                 MONO_INST_NEW (cfg, check, OP_CHECK_ARRAY_TYPE);
6571                                 check->cil_code = ip;
6572                                 check->klass = klass;
6573                                 check->inst_left = sp [0];
6574                                 check->type = STACK_OBJ;
6575                                 check->klass = klass;
6576                                 sp [0] = check;
6577                         }
6578                         
6579                         mono_class_init (klass);
6580                         NEW_LDELEMA (cfg, ins, sp, klass);
6581                         ins->cil_code = ip;
6582                         *sp++ = ins;
6583                         ip += 5;
6584                         break;
6585                 case CEE_LDELEM_ANY: {
6586                         MonoInst *load;
6587                         CHECK_STACK (2);
6588                         sp -= 2;
6589                         if (sp [0]->type != STACK_OBJ)
6590                                 UNVERIFIED;
6591                         CHECK_OPSIZE (5);
6592                         token = read32 (ip + 1);
6593                         klass = mono_class_get_full (image, token, generic_context);
6594                         CHECK_TYPELOAD (klass);
6595                         mono_class_init (klass);
6596                         NEW_LDELEMA (cfg, load, sp, klass);
6597                         load->cil_code = ip;
6598                         MONO_INST_NEW (cfg, ins, mono_type_to_ldind (&klass->byval_arg));
6599                         ins->cil_code = ip;
6600                         ins->inst_left = load;
6601                         *sp++ = ins;
6602                         type_to_eval_stack_type (&klass->byval_arg, ins);
6603                         ip += 5;
6604                         break;
6605                 }
6606                 case CEE_LDELEM_I1:
6607                 case CEE_LDELEM_U1:
6608                 case CEE_LDELEM_I2:
6609                 case CEE_LDELEM_U2:
6610                 case CEE_LDELEM_I4:
6611                 case CEE_LDELEM_U4:
6612                 case CEE_LDELEM_I8:
6613                 case CEE_LDELEM_I:
6614                 case CEE_LDELEM_R4:
6615                 case CEE_LDELEM_R8:
6616                 case CEE_LDELEM_REF: {
6617                         MonoInst *load;
6618                         /*
6619                          * translate to:
6620                          * ldind.x (ldelema (array, index))
6621                          * ldelema does the bounds check
6622                          */
6623                         CHECK_STACK (2);
6624                         sp -= 2;
6625                         if (sp [0]->type != STACK_OBJ)
6626                                 UNVERIFIED;
6627                         klass = array_access_to_klass (*ip, sp [0]);
6628                         NEW_LDELEMA (cfg, load, sp, klass);
6629                         load->cil_code = ip;
6630 #ifdef MONO_ARCH_SOFT_FLOAT
6631                         if (*ip == CEE_LDELEM_R4) {
6632                                 int temp;
6633                                 temp = handle_load_float (cfg, bblock, load, ip);
6634                                 NEW_TEMPLOAD (cfg, *sp, temp);
6635                                 sp++;
6636                                 ++ip;
6637                                 break;
6638                         }
6639 #endif
6640                         MONO_INST_NEW (cfg, ins, ldelem_to_ldind [*ip - CEE_LDELEM_I1]);
6641                         ins->cil_code = ip;
6642                         ins->inst_left = load;
6643                         *sp++ = ins;
6644                         ins->type = ldind_type [ins->opcode - CEE_LDIND_I1];
6645                         ins->klass = klass;
6646                         ++ip;
6647                         break;
6648                 }
6649                 case CEE_STELEM_I:
6650                 case CEE_STELEM_I1:
6651                 case CEE_STELEM_I2:
6652                 case CEE_STELEM_I4:
6653                 case CEE_STELEM_I8:
6654                 case CEE_STELEM_R4:
6655                 case CEE_STELEM_R8: {
6656                         MonoInst *load;
6657                         /*
6658                          * translate to:
6659                          * stind.x (ldelema (array, index), val)
6660                          * ldelema does the bounds check
6661                          */
6662                         CHECK_STACK (3);
6663                         sp -= 3;
6664                         if (sp [0]->type != STACK_OBJ)
6665                                 UNVERIFIED;
6666                         klass = array_access_to_klass (*ip, sp [0]);
6667                         NEW_LDELEMA (cfg, load, sp, klass);
6668                         load->cil_code = ip;
6669 #ifdef MONO_ARCH_SOFT_FLOAT
6670                         if (*ip == CEE_STELEM_R4) {
6671                                 handle_store_float (cfg, bblock, load, sp [2], ip);
6672                                 ip++;
6673                                 break;
6674                         }
6675 #endif
6676                         MONO_INST_NEW (cfg, ins, stelem_to_stind [*ip - CEE_STELEM_I]);
6677                         ins->cil_code = ip;
6678                         ins->inst_left = load;
6679                         ins->inst_right = sp [2];
6680                         ++ip;
6681                         handle_loaded_temps (cfg, bblock, stack_start, sp);
6682                         MONO_ADD_INS (bblock, ins);
6683                         inline_costs += 1;
6684                         break;
6685                 }
6686                 case CEE_STELEM_ANY: {
6687                         MonoInst *load;
6688                         /*
6689                          * translate to:
6690                          * stind.x (ldelema (array, index), val)
6691                          * ldelema does the bounds check
6692                          */
6693                         CHECK_STACK (3);
6694                         sp -= 3;
6695                         if (sp [0]->type != STACK_OBJ)
6696                                 UNVERIFIED;
6697                         CHECK_OPSIZE (5);
6698                         token = read32 (ip + 1);
6699                         klass = mono_class_get_full (image, token, generic_context);
6700                         CHECK_TYPELOAD (klass);
6701                         mono_class_init (klass);
6702                         if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
6703                                 MonoMethod* helper = mono_marshal_get_stelemref ();
6704                                 MonoInst *iargs [3];
6705                                 handle_loaded_temps (cfg, bblock, stack_start, sp);
6706
6707                                 iargs [2] = sp [2];
6708                                 iargs [1] = sp [1];
6709                                 iargs [0] = sp [0];
6710                                 
6711                                 mono_emit_method_call_spilled (cfg, bblock, helper, mono_method_signature (helper), iargs, ip, NULL);
6712                         } else {
6713                                 NEW_LDELEMA (cfg, load, sp, klass);
6714                                 load->cil_code = ip;
6715
6716                                 n = mono_type_to_stind (&klass->byval_arg);
6717                                 if (n == CEE_STOBJ)
6718                                         handle_stobj (cfg, bblock, load, sp [2], ip, klass, FALSE, FALSE, TRUE);
6719                                 else {
6720                                         MONO_INST_NEW (cfg, ins, n);
6721                                         ins->cil_code = ip;
6722                                         ins->inst_left = load;
6723                                         ins->inst_right = sp [2];
6724                                         handle_loaded_temps (cfg, bblock, stack_start, sp);
6725                                         MONO_ADD_INS (bblock, ins);
6726                                 }
6727                         }
6728                         ip += 5;
6729                         inline_costs += 1;
6730                         break;
6731                 }
6732                 case CEE_STELEM_REF: {
6733                         MonoInst *iargs [3];
6734                         MonoMethod* helper = mono_marshal_get_stelemref ();
6735
6736                         CHECK_STACK (3);
6737                         sp -= 3;
6738                         if (sp [0]->type != STACK_OBJ)
6739                                 UNVERIFIED;
6740                         if (sp [2]->type != STACK_OBJ)
6741                                 UNVERIFIED;
6742
6743                         handle_loaded_temps (cfg, bblock, stack_start, sp);
6744
6745                         iargs [2] = sp [2];
6746                         iargs [1] = sp [1];
6747                         iargs [0] = sp [0];
6748                         
6749                         mono_emit_method_call_spilled (cfg, bblock, helper, mono_method_signature (helper), iargs, ip, NULL);
6750
6751                         /*
6752                         MonoInst *group;
6753                         NEW_GROUP (cfg, group, sp [0], sp [1]);
6754                         MONO_INST_NEW (cfg, ins, CEE_STELEM_REF);
6755                         ins->cil_code = ip;
6756                         ins->inst_left = group;
6757                         ins->inst_right = sp [2];
6758                         MONO_ADD_INS (bblock, ins);
6759                         */
6760
6761                         ++ip;
6762                         inline_costs += 1;
6763                         break;
6764                 }
6765                 case CEE_CKFINITE: {
6766                         MonoInst *store, *temp;
6767                         CHECK_STACK (1);
6768
6769                         /* this instr. can throw exceptions as side effect,
6770                          * so we cant eliminate dead code which contains CKFINITE opdodes.
6771                          * Spilling to memory makes sure that we always perform
6772                          * this check */
6773
6774                         
6775                         MONO_INST_NEW (cfg, ins, CEE_CKFINITE);
6776                         ins->cil_code = ip;
6777                         ins->inst_left = sp [-1];
6778                         temp = mono_compile_create_var (cfg, &mono_defaults.double_class->byval_arg, OP_LOCAL);
6779
6780                         NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
6781                         store->cil_code = ip;
6782                         MONO_ADD_INS (bblock, store);
6783
6784                         NEW_TEMPLOAD (cfg, sp [-1], temp->inst_c0);
6785                        
6786                         ++ip;
6787                         break;
6788                 }
6789                 case CEE_REFANYVAL:
6790                         CHECK_STACK (1);
6791                         MONO_INST_NEW (cfg, ins, *ip);
6792                         --sp;
6793                         CHECK_OPSIZE (5);
6794                         klass = mono_class_get_full (image, read32 (ip + 1), generic_context);
6795                         CHECK_TYPELOAD (klass);
6796                         mono_class_init (klass);
6797                         ins->type = STACK_MP;
6798                         ins->inst_left = *sp;
6799                         ins->klass = klass;
6800                         ins->inst_newa_class = klass;
6801                         ins->cil_code = ip;
6802                         ip += 5;
6803                         *sp++ = ins;
6804                         break;
6805                 case CEE_MKREFANY: {
6806                         MonoInst *loc, *klassconst;
6807
6808                         CHECK_STACK (1);
6809                         MONO_INST_NEW (cfg, ins, *ip);
6810                         --sp;
6811                         CHECK_OPSIZE (5);
6812                         klass = mono_class_get_full (image, read32 (ip + 1), generic_context);
6813                         CHECK_TYPELOAD (klass);
6814                         mono_class_init (klass);
6815                         ins->cil_code = ip;
6816
6817                         loc = mono_compile_create_var (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL);
6818                         NEW_TEMPLOADA (cfg, ins->inst_right, loc->inst_c0);
6819
6820                         NEW_PCONST (cfg, klassconst, klass);
6821                         NEW_GROUP (cfg, ins->inst_left, *sp, klassconst);
6822                         
6823                         MONO_ADD_INS (bblock, ins);
6824
6825                         NEW_TEMPLOAD (cfg, *sp, loc->inst_c0);
6826                         ++sp;
6827                         ip += 5;
6828                         break;
6829                 }
6830                 case CEE_LDTOKEN: {
6831                         gpointer handle;
6832                         MonoClass *handle_class;
6833
6834                         CHECK_STACK_OVF (1);
6835
6836                         CHECK_OPSIZE (5);
6837                         n = read32 (ip + 1);
6838
6839                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
6840                                 handle = mono_method_get_wrapper_data (method, n);
6841                                 handle_class = mono_method_get_wrapper_data (method, n + 1);
6842                                 if (handle_class == mono_defaults.typehandle_class)
6843                                         handle = &((MonoClass*)handle)->byval_arg;
6844                         }
6845                         else {
6846                                 handle = mono_ldtoken (image, n, &handle_class, generic_context);
6847                         }
6848                         if (!handle)
6849                                 goto load_error;
6850                         mono_class_init (handle_class);
6851
6852                         if (cfg->opt & MONO_OPT_SHARED) {
6853                                 int temp;
6854                                 MonoInst *res, *store, *addr, *vtvar, *iargs [3];
6855
6856                                 vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL); 
6857
6858                                 NEW_IMAGECONST (cfg, iargs [0], image);
6859                                 NEW_ICONST (cfg, iargs [1], n);
6860                                 NEW_PCONST (cfg, iargs [2], generic_context);
6861                                 temp = mono_emit_jit_icall (cfg, bblock, mono_ldtoken_wrapper, iargs, ip);
6862                                 NEW_TEMPLOAD (cfg, res, temp);
6863                                 NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
6864                                 NEW_INDSTORE (cfg, store, addr, res, &mono_defaults.int_class->byval_arg);
6865                                 MONO_ADD_INS (bblock, store);
6866                                 NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
6867                         } else {
6868                                 if ((ip [5] == CEE_CALL) && (cmethod = mini_get_method (method, read32 (ip + 6), NULL, generic_context)) &&
6869                                                 (cmethod->klass == mono_defaults.monotype_class->parent) &&
6870                                                 (strcmp (cmethod->name, "GetTypeFromHandle") == 0) && ip_in_bb (cfg, bblock, ip + 5)) {
6871                                         MonoClass *tclass = mono_class_from_mono_type (handle);
6872                                         mono_class_init (tclass);
6873                                         if (cfg->compile_aot)
6874                                                 NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, image, n);
6875                                         else
6876                                                 NEW_PCONST (cfg, ins, mono_type_get_object (cfg->domain, handle));
6877                                         ins->type = STACK_OBJ;
6878                                         ins->klass = cmethod->klass;
6879                                         ip += 5;
6880                                 } else {
6881                                         MonoInst *store, *addr, *vtvar;
6882
6883                                         if (cfg->compile_aot)
6884                                                 NEW_LDTOKENCONST (cfg, ins, image, n);
6885                                         else
6886                                                 NEW_PCONST (cfg, ins, handle);
6887                                         vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL);
6888                                         NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
6889                                         NEW_INDSTORE (cfg, store, addr, ins, &mono_defaults.int_class->byval_arg);
6890                                         MONO_ADD_INS (bblock, store);
6891                                         NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
6892                                 }
6893                         }
6894
6895                         *sp++ = ins;
6896                         ip += 5;
6897                         break;
6898                 }
6899                 case CEE_CONV_U2:
6900                 case CEE_CONV_U1:
6901                 case CEE_CONV_I:
6902                         CHECK_STACK (1);
6903                         ADD_UNOP (*ip);
6904                         ip++;
6905                         break;
6906                 case CEE_ADD_OVF:
6907                 case CEE_ADD_OVF_UN:
6908                 case CEE_MUL_OVF:
6909                 case CEE_MUL_OVF_UN:
6910                 case CEE_SUB_OVF:
6911                 case CEE_SUB_OVF_UN:
6912                         CHECK_STACK (2);
6913                         ADD_BINOP (*ip);
6914                         if (mono_find_jit_opcode_emulation (ins->opcode)) {
6915                                 --sp;
6916                                 *sp++ = emit_tree (cfg, bblock, ins, ip + 1);
6917                         }
6918                         ip++;
6919                         break;
6920                 case CEE_ENDFINALLY:
6921                         MONO_INST_NEW (cfg, ins, *ip);
6922                         MONO_ADD_INS (bblock, ins);
6923                         ins->cil_code = ip++;
6924                         start_new_bblock = 1;
6925
6926                         /*
6927                          * Control will leave the method so empty the stack, otherwise
6928                          * the next basic block will start with a nonempty stack.
6929                          */
6930                         while (sp != stack_start) {
6931                                 MONO_INST_NEW (cfg, ins, CEE_POP);
6932                                 ins->cil_code = ip;
6933                                 sp--;
6934                                 ins->inst_i0 = *sp;
6935                                 MONO_ADD_INS (bblock, ins);
6936                         }
6937                         break;
6938                 case CEE_LEAVE:
6939                 case CEE_LEAVE_S: {
6940                         GList *handlers;
6941
6942                         if (*ip == CEE_LEAVE) {
6943                                 CHECK_OPSIZE (5);
6944                                 target = ip + 5 + (gint32)read32(ip + 1);
6945                         } else {
6946                                 CHECK_OPSIZE (2);
6947                                 target = ip + 2 + (signed char)(ip [1]);
6948                         }
6949
6950                         /* empty the stack */
6951                         while (sp != stack_start) {
6952                                 MONO_INST_NEW (cfg, ins, CEE_POP);
6953                                 ins->cil_code = ip;
6954                                 sp--;
6955                                 ins->inst_i0 = *sp;
6956                                 MONO_ADD_INS (bblock, ins);
6957                         }
6958
6959                         /* 
6960                          * If this leave statement is in a catch block, check for a
6961                          * pending exception, and rethrow it if necessary.
6962                          */
6963                         for (i = 0; i < header->num_clauses; ++i) {
6964                                 MonoExceptionClause *clause = &header->clauses [i];
6965
6966                                 /* 
6967                                  * Use <= in the final comparison to handle clauses with multiple
6968                                  * leave statements, like in bug #78024.
6969                                  * The ordering of the exception clauses guarantees that we find the
6970                                  * innermost clause.
6971                                  */
6972                                 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)) {
6973                                         int temp;
6974                                         MonoInst *load;
6975
6976                                         NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, clause->handler_offset)->inst_c0);
6977                                         load->cil_code = ip;
6978
6979                                         temp = mono_emit_jit_icall (cfg, bblock, mono_thread_get_pending_exception, NULL, ip);
6980                                         NEW_TEMPLOAD (cfg, *sp, temp);
6981                                 
6982                                         MONO_INST_NEW (cfg, ins, OP_THROW_OR_NULL);
6983                                         ins->inst_left = *sp;
6984                                         ins->inst_right = load;
6985                                         ins->cil_code = ip;
6986                                         MONO_ADD_INS (bblock, ins);
6987                                 }
6988                         }
6989
6990                         if ((handlers = mono_find_final_block (cfg, ip, target, MONO_EXCEPTION_CLAUSE_FINALLY))) {
6991                                 GList *tmp;
6992                                 for (tmp = handlers; tmp; tmp = tmp->next) {
6993                                         tblock = tmp->data;
6994                                         link_bblock (cfg, bblock, tblock);
6995                                         MONO_INST_NEW (cfg, ins, OP_CALL_HANDLER);
6996                                         ins->cil_code = ip;
6997                                         ins->inst_target_bb = tblock;
6998                                         MONO_ADD_INS (bblock, ins);
6999                                 }
7000                                 g_list_free (handlers);
7001                         } 
7002
7003                         MONO_INST_NEW (cfg, ins, CEE_BR);
7004                         ins->cil_code = ip;
7005                         MONO_ADD_INS (bblock, ins);
7006                         GET_BBLOCK (cfg, bbhash, tblock, target);
7007                         link_bblock (cfg, bblock, tblock);
7008                         CHECK_BBLOCK (target, ip, tblock);
7009                         ins->inst_target_bb = tblock;
7010                         start_new_bblock = 1;
7011
7012                         if (*ip == CEE_LEAVE)
7013                                 ip += 5;
7014                         else
7015                                 ip += 2;
7016
7017                         break;
7018                 }
7019                 case CEE_STIND_I:
7020                         CHECK_STACK (2);
7021                         MONO_INST_NEW (cfg, ins, *ip);
7022                         sp -= 2;
7023                         handle_loaded_temps (cfg, bblock, stack_start, sp);
7024                         MONO_ADD_INS (bblock, ins);
7025                         ins->cil_code = ip++;
7026                         ins->inst_i0 = sp [0];
7027                         ins->inst_i1 = sp [1];
7028                         inline_costs += 1;
7029                         break;
7030                 case CEE_CONV_U:
7031                         CHECK_STACK (1);
7032                         ADD_UNOP (*ip);
7033                         ip++;
7034                         break;
7035                 /* trampoline mono specific opcodes */
7036                 case MONO_CUSTOM_PREFIX: {
7037
7038                         g_assert (method->wrapper_type != MONO_WRAPPER_NONE);
7039
7040                         CHECK_OPSIZE (2);
7041                         switch (ip [1]) {
7042
7043                         case CEE_MONO_ICALL: {
7044                                 int temp;
7045                                 gpointer func;
7046                                 MonoJitICallInfo *info;
7047
7048                                 token = read32 (ip + 2);
7049                                 func = mono_method_get_wrapper_data (method, token);
7050                                 info = mono_find_jit_icall_by_addr (func);
7051                                 if (info == NULL){
7052                                         g_error ("An attempt has been made to perform an icall to address %p, "
7053                                                  "but the address has not been registered as an icall\n", info);
7054                                         g_assert_not_reached ();
7055                                 }
7056
7057                                 CHECK_STACK (info->sig->param_count);
7058                                 sp -= info->sig->param_count;
7059
7060                                 temp = mono_emit_jit_icall (cfg, bblock, info->func, sp, ip);
7061                                 if (!MONO_TYPE_IS_VOID (info->sig->ret)) {
7062                                         NEW_TEMPLOAD (cfg, *sp, temp);
7063                                         sp++;
7064                                 }
7065
7066                                 ip += 6;
7067                                 inline_costs += 10 * num_calls++;
7068
7069                                 break;
7070                         }
7071                         case CEE_MONO_LDPTR:
7072                                 CHECK_STACK_OVF (1);
7073                                 CHECK_OPSIZE (6);
7074                                 token = read32 (ip + 2);
7075                                 NEW_PCONST (cfg, ins, mono_method_get_wrapper_data (method, token));
7076                                 ins->cil_code = ip;
7077                                 *sp++ = ins;
7078                                 ip += 6;
7079                                 inline_costs += 10 * num_calls++;
7080                                 /* Can't embed random pointers into AOT code */
7081                                 cfg->disable_aot = 1;
7082                                 break;
7083                         case CEE_MONO_VTADDR:
7084                                 CHECK_STACK (1);
7085                                 --sp;
7086                                 MONO_INST_NEW (cfg, ins, OP_VTADDR);
7087                                 ins->cil_code = ip;
7088                                 ins->type = STACK_MP;
7089                                 ins->inst_left = *sp;
7090                                 *sp++ = ins;
7091                                 ip += 2;
7092                                 break;
7093                         case CEE_MONO_NEWOBJ: {
7094                                 MonoInst *iargs [2];
7095                                 int temp;
7096                                 CHECK_STACK_OVF (1);
7097                                 CHECK_OPSIZE (6);
7098                                 token = read32 (ip + 2);
7099                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
7100                                 mono_class_init (klass);
7101                                 NEW_DOMAINCONST (cfg, iargs [0]);
7102                                 NEW_CLASSCONST (cfg, iargs [1], klass);
7103                                 temp = mono_emit_jit_icall (cfg, bblock, mono_object_new, iargs, ip);
7104                                 NEW_TEMPLOAD (cfg, *sp, temp);
7105                                 sp++;
7106                                 ip += 6;
7107                                 inline_costs += 10 * num_calls++;
7108                                 break;
7109                         }
7110                         case CEE_MONO_OBJADDR:
7111                                 CHECK_STACK (1);
7112                                 --sp;
7113                                 MONO_INST_NEW (cfg, ins, OP_OBJADDR);
7114                                 ins->cil_code = ip;
7115                                 ins->type = STACK_MP;
7116                                 ins->inst_left = *sp;
7117                                 *sp++ = ins;
7118                                 ip += 2;
7119                                 break;
7120                         case CEE_MONO_LDNATIVEOBJ:
7121                                 CHECK_STACK (1);
7122                                 CHECK_OPSIZE (6);
7123                                 token = read32 (ip + 2);
7124                                 klass = mono_method_get_wrapper_data (method, token);
7125                                 g_assert (klass->valuetype);
7126                                 mono_class_init (klass);
7127                                 NEW_INDLOAD (cfg, ins, sp [-1], &klass->byval_arg);
7128                                 sp [-1] = ins;
7129                                 ip += 6;
7130                                 break;
7131                         case CEE_MONO_RETOBJ:
7132                                 g_assert (cfg->ret);
7133                                 g_assert (mono_method_signature (method)->pinvoke); 
7134                                 CHECK_STACK (1);
7135                                 --sp;
7136                                 
7137                                 CHECK_OPSIZE (6);
7138                                 token = read32 (ip + 2);    
7139                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
7140
7141                                 NEW_RETLOADA (cfg, ins);
7142                                 handle_stobj (cfg, bblock, ins, *sp, ip, klass, FALSE, TRUE, FALSE);
7143                                 
7144                                 if (sp != stack_start)
7145                                         UNVERIFIED;
7146                                 
7147                                 MONO_INST_NEW (cfg, ins, CEE_BR);
7148                                 ins->cil_code = ip;
7149                                 ins->inst_target_bb = end_bblock;
7150                                 MONO_ADD_INS (bblock, ins);
7151                                 link_bblock (cfg, bblock, end_bblock);
7152                                 start_new_bblock = 1;
7153                                 ip += 6;
7154                                 break;
7155                         case CEE_MONO_CISINST:
7156                         case CEE_MONO_CCASTCLASS: {
7157                                 int token;
7158                                 CHECK_STACK (1);
7159                                 --sp;
7160                                 CHECK_OPSIZE (6);
7161                                 token = read32 (ip + 2);
7162                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
7163                                 MONO_INST_NEW (cfg, ins, (ip [1] == CEE_MONO_CISINST) ? OP_CISINST : OP_CCASTCLASS);
7164                                 ins->type = STACK_I4;
7165                                 ins->inst_left = *sp;
7166                                 ins->inst_newa_class = klass;
7167                                 ins->cil_code = ip;
7168                                 *sp++ = emit_tree (cfg, bblock, ins, ip + 6);
7169                                 ip += 6;
7170                                 break;
7171                         }
7172                         case CEE_MONO_SAVE_LMF:
7173                         case CEE_MONO_RESTORE_LMF:
7174 #ifdef MONO_ARCH_HAVE_LMF_OPS
7175                                 MONO_INST_NEW (cfg, ins, (ip [1] == CEE_MONO_SAVE_LMF) ? OP_SAVE_LMF : OP_RESTORE_LMF);
7176                                 MONO_ADD_INS (bblock, ins);
7177                                 cfg->need_lmf_area = TRUE;
7178 #endif
7179                                 ip += 2;
7180                                 break;
7181                         case CEE_MONO_CLASSCONST:
7182                                 CHECK_STACK_OVF (1);
7183                                 CHECK_OPSIZE (6);
7184                                 token = read32 (ip + 2);
7185                                 NEW_CLASSCONST (cfg, ins, mono_method_get_wrapper_data (method, token));
7186                                 ins->cil_code = ip;
7187                                 *sp++ = ins;
7188                                 ip += 6;
7189                                 inline_costs += 10 * num_calls++;
7190                                 break;
7191                         case CEE_MONO_NOT_TAKEN:
7192                                 bblock->out_of_line = TRUE;
7193                                 ip += 2;
7194                                 break;
7195                         default:
7196                                 g_error ("opcode 0x%02x 0x%02x not handled", MONO_CUSTOM_PREFIX, ip [1]);
7197                                 break;
7198                         }
7199                         break;
7200                 }
7201                 case CEE_PREFIX1: {
7202                         CHECK_OPSIZE (2);
7203                         switch (ip [1]) {
7204                         case CEE_ARGLIST: {
7205                                 /* somewhat similar to LDTOKEN */
7206                                 MonoInst *addr, *vtvar;
7207                                 CHECK_STACK_OVF (1);
7208                                 vtvar = mono_compile_create_var (cfg, &mono_defaults.argumenthandle_class->byval_arg, OP_LOCAL); 
7209
7210                                 NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
7211                                 addr->cil_code = ip;
7212                                 MONO_INST_NEW (cfg, ins, OP_ARGLIST);
7213                                 ins->cil_code = ip;
7214                                 ins->inst_left = addr;
7215                                 MONO_ADD_INS (bblock, ins);
7216                                 NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
7217                                 ins->cil_code = ip;
7218                                 *sp++ = ins;
7219                                 ip += 2;
7220                                 break;
7221                         }
7222                         case CEE_CEQ:
7223                         case CEE_CGT:
7224                         case CEE_CGT_UN:
7225                         case CEE_CLT:
7226                         case CEE_CLT_UN: {
7227                                 MonoInst *cmp;
7228                                 CHECK_STACK (2);
7229                                 /*
7230                                  * The following transforms:
7231                                  *    CEE_CEQ    into OP_CEQ
7232                                  *    CEE_CGT    into OP_CGT
7233                                  *    CEE_CGT_UN into OP_CGT_UN
7234                                  *    CEE_CLT    into OP_CLT
7235                                  *    CEE_CLT_UN into OP_CLT_UN
7236                                  */
7237                                 MONO_INST_NEW (cfg, cmp, 256 + ip [1]);
7238                                 
7239                                 MONO_INST_NEW (cfg, ins, cmp->opcode);
7240                                 sp -= 2;
7241                                 cmp->inst_i0 = sp [0];
7242                                 cmp->inst_i1 = sp [1];
7243                                 cmp->cil_code = ip;
7244                                 type_from_op (cmp);
7245                                 CHECK_TYPE (cmp);
7246                                 ins->cil_code = ip;
7247                                 ins->type = STACK_I4;
7248                                 ins->inst_i0 = cmp;
7249 #if MONO_ARCH_SOFT_FLOAT
7250                                 if (sp [0]->type == STACK_R8) {
7251                                         cmp->type = STACK_I4;
7252                                         *sp++ = emit_tree (cfg, bblock, cmp, ip + 2);
7253                                         ip += 2;
7254                                         break;
7255                                 }
7256 #endif
7257                                 if ((sp [0]->type == STACK_I8) || ((sizeof (gpointer) == 8) && ((sp [0]->type == STACK_PTR) || (sp [0]->type == STACK_OBJ) || (sp [0]->type == STACK_MP))))
7258                                         cmp->opcode = OP_LCOMPARE;
7259                                 else
7260                                         cmp->opcode = OP_COMPARE;
7261                                 *sp++ = ins;
7262                                 /* spill it to reduce the expression complexity
7263                                  * and workaround bug 54209 
7264                                  */
7265                                 if (cmp->inst_left->type == STACK_I8) {
7266                                         --sp;
7267                                         *sp++ = emit_tree (cfg, bblock, ins, ip + 2);
7268                                 }
7269                                 ip += 2;
7270                                 break;
7271                         }
7272                         case CEE_LDFTN: {
7273                                 MonoInst *argconst;
7274                                 int temp;
7275
7276                                 CHECK_STACK_OVF (1);
7277                                 CHECK_OPSIZE (6);
7278                                 n = read32 (ip + 2);
7279                                 cmethod = mini_get_method (method, n, NULL, generic_context);
7280                                 if (!cmethod)
7281                                         goto load_error;
7282                                 mono_class_init (cmethod->klass);
7283
7284                                 if (mono_use_security_manager) {
7285                                         if (check_linkdemand (cfg, method, cmethod, bblock, ip))
7286                                                 INLINE_FAILURE;
7287                                 }
7288
7289                                 handle_loaded_temps (cfg, bblock, stack_start, sp);
7290
7291                                 NEW_METHODCONST (cfg, argconst, cmethod);
7292                                 if (method->wrapper_type != MONO_WRAPPER_SYNCHRONIZED)
7293                                         temp = mono_emit_jit_icall (cfg, bblock, mono_ldftn, &argconst, ip);
7294                                 else
7295                                         temp = mono_emit_jit_icall (cfg, bblock, mono_ldftn_nosync, &argconst, ip);
7296                                 NEW_TEMPLOAD (cfg, *sp, temp);
7297                                 sp ++;
7298                                 
7299                                 ip += 6;
7300                                 inline_costs += 10 * num_calls++;
7301                                 break;
7302                         }
7303                         case CEE_LDVIRTFTN: {
7304                                 MonoInst *args [2];
7305                                 int temp;
7306
7307                                 CHECK_STACK (1);
7308                                 CHECK_OPSIZE (6);
7309                                 n = read32 (ip + 2);
7310                                 cmethod = mini_get_method (method, n, NULL, generic_context);
7311                                 if (!cmethod)
7312                                         goto load_error;
7313                                 mono_class_init (cmethod->klass);
7314
7315                                 if (mono_use_security_manager) {
7316                                         if (check_linkdemand (cfg, method, cmethod, bblock, ip))
7317                                                 INLINE_FAILURE;
7318                                 }
7319
7320                                 handle_loaded_temps (cfg, bblock, stack_start, sp);
7321
7322                                 --sp;
7323                                 args [0] = *sp;
7324                                 NEW_METHODCONST (cfg, args [1], cmethod);
7325                                 temp = mono_emit_jit_icall (cfg, bblock, mono_ldvirtfn, args, ip);
7326                                 NEW_TEMPLOAD (cfg, *sp, temp);
7327                                 sp ++;
7328
7329                                 ip += 6;
7330                                 inline_costs += 10 * num_calls++;
7331                                 break;
7332                         }
7333                         case CEE_LDARG:
7334                                 CHECK_STACK_OVF (1);
7335                                 CHECK_OPSIZE (4);
7336                                 n = read16 (ip + 2);
7337                                 CHECK_ARG (n);
7338                                 NEW_ARGLOAD (cfg, ins, n);
7339                                 LDARG_SOFT_FLOAT (cfg, ins, n, ip);
7340                                 ins->cil_code = ip;
7341                                 *sp++ = ins;
7342                                 ip += 4;
7343                                 break;
7344                         case CEE_LDARGA:
7345                                 CHECK_STACK_OVF (1);
7346                                 CHECK_OPSIZE (4);
7347                                 n = read16 (ip + 2);
7348                                 CHECK_ARG (n);
7349                                 NEW_ARGLOADA (cfg, ins, n);
7350                                 ins->cil_code = ip;
7351                                 *sp++ = ins;
7352                                 ip += 4;
7353                                 break;
7354                         case CEE_STARG:
7355                                 CHECK_STACK (1);
7356                                 --sp;
7357                                 handle_loaded_temps (cfg, bblock, stack_start, sp);
7358                                 CHECK_OPSIZE (4);
7359                                 n = read16 (ip + 2);
7360                                 CHECK_ARG (n);
7361                                 NEW_ARGSTORE (cfg, ins, n, *sp);
7362                                 ins->cil_code = ip;
7363                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [n], *sp))
7364                                         UNVERIFIED;
7365                                 STARG_SOFT_FLOAT (cfg, ins, n, ip);
7366                                 if (ins->opcode == CEE_STOBJ) {
7367                                         NEW_ARGLOADA (cfg, ins, n);
7368                                         handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE, FALSE);
7369                                 } else
7370                                         MONO_ADD_INS (bblock, ins);
7371                                 ip += 4;
7372                                 break;
7373                         case CEE_LDLOC:
7374                                 CHECK_STACK_OVF (1);
7375                                 CHECK_OPSIZE (4);
7376                                 n = read16 (ip + 2);
7377                                 CHECK_LOCAL (n);
7378                                 NEW_LOCLOAD (cfg, ins, n);
7379                                 LDLOC_SOFT_FLOAT (cfg, ins, n, ip);
7380                                 ins->cil_code = ip;
7381                                 *sp++ = ins;
7382                                 ip += 4;
7383                                 break;
7384                         case CEE_LDLOCA:
7385                                 CHECK_STACK_OVF (1);
7386                                 CHECK_OPSIZE (4);
7387                                 n = read16 (ip + 2);
7388                                 CHECK_LOCAL (n);
7389                                 NEW_LOCLOADA (cfg, ins, n);
7390                                 ins->cil_code = ip;
7391                                 *sp++ = ins;
7392                                 ip += 4;
7393                                 break;
7394                         case CEE_STLOC:
7395                                 CHECK_STACK (1);
7396                                 --sp;
7397                                 CHECK_OPSIZE (4);
7398                                 n = read16 (ip + 2);
7399                                 CHECK_LOCAL (n);
7400                                 handle_loaded_temps (cfg, bblock, stack_start, sp);
7401                                 NEW_LOCSTORE (cfg, ins, n, *sp);
7402                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
7403                                         UNVERIFIED;
7404                                 ins->cil_code = ip;
7405                                 STLOC_SOFT_FLOAT (cfg, ins, n, ip);
7406                                 if (ins->opcode == CEE_STOBJ) {
7407                                         NEW_LOCLOADA (cfg, ins, n);
7408                                         handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE, FALSE);
7409                                 } else
7410                                         MONO_ADD_INS (bblock, ins);
7411                                 ip += 4;
7412                                 inline_costs += 1;
7413                                 break;
7414                         case CEE_LOCALLOC:
7415                                 CHECK_STACK (1);
7416                                 --sp;
7417                                 if (sp != stack_start) 
7418                                         UNVERIFIED;
7419                                 if (cfg->method != method) 
7420                                         /* 
7421                                          * Inlining this into a loop in a parent could lead to 
7422                                          * stack overflows which is different behavior than the
7423                                          * non-inlined case, thus disable inlining in this case.
7424                                          */
7425                                         goto inline_failure;
7426                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
7427                                 ins->inst_left = *sp;
7428                                 ins->cil_code = ip;
7429                                 ins->type = STACK_PTR;
7430
7431                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
7432                                 if (header->init_locals)
7433                                         ins->flags |= MONO_INST_INIT;
7434
7435                                 *sp++ = ins;
7436                                 ip += 2;
7437                                 /* FIXME: set init flag if locals init is set in this method */
7438                                 break;
7439                         case CEE_ENDFILTER: {
7440                                 MonoExceptionClause *clause, *nearest;
7441                                 int cc, nearest_num;
7442
7443                                 CHECK_STACK (1);
7444                                 --sp;
7445                                 if ((sp != stack_start) || (sp [0]->type != STACK_I4)) 
7446                                         UNVERIFIED;
7447                                 MONO_INST_NEW (cfg, ins, OP_ENDFILTER);
7448                                 ins->inst_left = *sp;
7449                                 ins->cil_code = ip;
7450                                 MONO_ADD_INS (bblock, ins);
7451                                 start_new_bblock = 1;
7452                                 ip += 2;
7453
7454                                 nearest = NULL;
7455                                 nearest_num = 0;
7456                                 for (cc = 0; cc < header->num_clauses; ++cc) {
7457                                         clause = &header->clauses [cc];
7458                                         if ((clause->flags & MONO_EXCEPTION_CLAUSE_FILTER) &&
7459                                                 ((ip - header->code) > clause->data.filter_offset && (ip - header->code) <= clause->handler_offset) &&
7460                                             (!nearest || (clause->data.filter_offset < nearest->data.filter_offset))) {
7461                                                 nearest = clause;
7462                                                 nearest_num = cc;
7463                                         }
7464                                 }
7465                                 g_assert (nearest);
7466                                 if ((ip - header->code) != nearest->handler_offset)
7467                                         UNVERIFIED;
7468
7469                                 break;
7470                         }
7471                         case CEE_UNALIGNED_:
7472                                 ins_flag |= MONO_INST_UNALIGNED;
7473                                 /* FIXME: record alignment? we can assume 1 for now */
7474                                 CHECK_OPSIZE (3);
7475                                 ip += 3;
7476                                 break;
7477                         case CEE_VOLATILE_:
7478                                 ins_flag |= MONO_INST_VOLATILE;
7479                                 ip += 2;
7480                                 break;
7481                         case CEE_TAIL_:
7482                                 ins_flag   |= MONO_INST_TAILCALL;
7483                                 cfg->flags |= MONO_CFG_HAS_TAIL;
7484                                 /* Can't inline tail calls at this time */
7485                                 inline_costs += 100000;
7486                                 ip += 2;
7487                                 break;
7488                         case CEE_INITOBJ:
7489                                 CHECK_STACK (1);
7490                                 --sp;
7491                                 CHECK_OPSIZE (6);
7492                                 token = read32 (ip + 2);
7493                                 klass = mini_get_class (method, token, generic_context);
7494                                 CHECK_TYPELOAD (klass);
7495                                 if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
7496                                         MonoInst *store, *load;
7497                                         NEW_PCONST (cfg, load, NULL);
7498                                         load->cil_code = ip;
7499                                         load->type = STACK_OBJ;
7500                                         load->klass = klass;
7501                                         MONO_INST_NEW (cfg, store, CEE_STIND_REF);
7502                                         store->cil_code = ip;
7503                                         handle_loaded_temps (cfg, bblock, stack_start, sp);
7504                                         MONO_ADD_INS (bblock, store);
7505                                         store->inst_i0 = sp [0];
7506                                         store->inst_i1 = load;
7507                                 } else {
7508                                         handle_initobj (cfg, bblock, *sp, NULL, klass, stack_start, sp);
7509                                 }
7510                                 ip += 6;
7511                                 inline_costs += 1;
7512                                 break;
7513                         case CEE_CONSTRAINED_:
7514                                 /* FIXME: implement */
7515                                 CHECK_OPSIZE (6);
7516                                 token = read32 (ip + 2);
7517                                 constrained_call = mono_class_get_full (image, token, generic_context);
7518                                 CHECK_TYPELOAD (constrained_call);
7519                                 ip += 6;
7520                                 break;
7521                         case CEE_CPBLK:
7522                         case CEE_INITBLK: {
7523                                 MonoInst *iargs [3];
7524                                 CHECK_STACK (3);
7525                                 sp -= 3;
7526                                 if ((cfg->opt & MONO_OPT_INTRINS) && (ip [1] == CEE_CPBLK) && (sp [2]->opcode == OP_ICONST) && ((n = sp [2]->inst_c0) <= sizeof (gpointer) * 5)) {
7527                                         MonoInst *copy;
7528                                         MONO_INST_NEW (cfg, copy, OP_MEMCPY);
7529                                         copy->inst_left = sp [0];
7530                                         copy->inst_right = sp [1];
7531                                         copy->cil_code = ip;
7532                                         copy->backend.size = n;
7533                                         MONO_ADD_INS (bblock, copy);
7534                                         ip += 2;
7535                                         break;
7536                                 }
7537                                 iargs [0] = sp [0];
7538                                 iargs [1] = sp [1];
7539                                 iargs [2] = sp [2];
7540                                 handle_loaded_temps (cfg, bblock, stack_start, sp);
7541                                 if (ip [1] == CEE_CPBLK) {
7542                                         MonoMethod *memcpy_method = get_memcpy_method ();
7543                                         mono_emit_method_call_spilled (cfg, bblock, memcpy_method, memcpy_method->signature, iargs, ip, NULL);
7544                                 } else {
7545                                         MonoMethod *memset_method = get_memset_method ();
7546                                         mono_emit_method_call_spilled (cfg, bblock, memset_method, memset_method->signature, iargs, ip, NULL);
7547                                 }
7548                                 ip += 2;
7549                                 inline_costs += 1;
7550                                 break;
7551                         }
7552                         case CEE_NO_:
7553                                 CHECK_OPSIZE (3);
7554                                 if (ip [2] & 0x1)
7555                                         ins_flag |= MONO_INST_NOTYPECHECK;
7556                                 if (ip [2] & 0x2)
7557                                         ins_flag |= MONO_INST_NORANGECHECK;
7558                                 /* we ignore the no-nullcheck for now since we
7559                                  * really do it explicitly only when doing callvirt->call
7560                                  */
7561                                 ip += 3;
7562                                 break;
7563                         case CEE_RETHROW: {
7564                                 MonoInst *load;
7565                                 int handler_offset = -1;
7566
7567                                 for (i = 0; i < header->num_clauses; ++i) {
7568                                         MonoExceptionClause *clause = &header->clauses [i];
7569                                         if (MONO_OFFSET_IN_HANDLER (clause, ip - header->code) && !(clause->flags & MONO_EXCEPTION_CLAUSE_FINALLY))
7570                                                 handler_offset = clause->handler_offset;
7571                                 }
7572
7573                                 bblock->flags |= BB_EXCEPTION_UNSAFE;
7574
7575                                 g_assert (handler_offset != -1);
7576
7577                                 NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, handler_offset)->inst_c0);
7578                                 load->cil_code = ip;
7579                                 MONO_INST_NEW (cfg, ins, OP_RETHROW);
7580                                 ins->inst_left = load;
7581                                 ins->cil_code = ip;
7582                                 MONO_ADD_INS (bblock, ins);
7583                                 sp = stack_start;
7584                                 link_bblock (cfg, bblock, end_bblock);
7585                                 start_new_bblock = 1;
7586                                 ip += 2;
7587                                 break;
7588                         }
7589                         case CEE_SIZEOF:
7590                                 CHECK_STACK_OVF (1);
7591                                 CHECK_OPSIZE (6);
7592                                 token = read32 (ip + 2);
7593                                 /* FIXXME: handle generics. */
7594                                 if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC) {
7595                                         MonoType *type = mono_type_create_from_typespec (image, token);
7596                                         token = mono_type_size (type, &ialign);
7597                                 } else {
7598                                         MonoClass *klass = mono_class_get_full (image, token, generic_context);
7599                                         CHECK_TYPELOAD (klass);
7600                                         mono_class_init (klass);
7601                                         token = mono_class_value_size (klass, &align);
7602                                 }
7603                                 NEW_ICONST (cfg, ins, token);
7604                                 ins->cil_code = ip;
7605                                 *sp++= ins;
7606                                 ip += 6;
7607                                 break;
7608                         case CEE_REFANYTYPE:
7609                                 CHECK_STACK (1);
7610                                 MONO_INST_NEW (cfg, ins, OP_REFANYTYPE);
7611                                 --sp;
7612                                 ins->type = STACK_MP;
7613                                 ins->inst_left = *sp;
7614                                 ins->type = STACK_VTYPE;
7615                                 ins->klass = mono_defaults.typehandle_class;
7616                                 ins->cil_code = ip;
7617                                 ip += 2;
7618                                 *sp++ = ins;
7619                                 break;
7620                         case CEE_READONLY_:
7621                                 ip += 2;
7622                                 break;
7623                         default:
7624                                 g_error ("opcode 0xfe 0x%02x not handled", ip [1]);
7625                         }
7626                         break;
7627                 }
7628                 default:
7629                         g_error ("opcode 0x%02x not handled", *ip);
7630                 }
7631         }
7632         if (start_new_bblock != 1)
7633                 UNVERIFIED;
7634
7635         bblock->cil_length = ip - bblock->cil_code;
7636         bblock->next_bb = end_bblock;
7637
7638         if (cfg->method == method && cfg->domainvar) {
7639                 MonoInst *store;
7640                 MonoInst *get_domain;
7641                 
7642                 if (! (get_domain = mono_arch_get_domain_intrinsic (cfg))) {
7643                         MonoCallInst *call;
7644                         
7645                         MONO_INST_NEW_CALL (cfg, call, CEE_CALL);
7646                         call->signature = helper_sig_domain_get;
7647                         call->inst.type = STACK_PTR;
7648                         call->fptr = mono_domain_get;
7649                         get_domain = (MonoInst*)call;
7650                 }
7651                 
7652                 NEW_TEMPSTORE (cfg, store, cfg->domainvar->inst_c0, get_domain);
7653                 MONO_ADD_INS (init_localsbb, store);
7654         }
7655
7656         if (cfg->method == method && cfg->got_var)
7657                 mono_emit_load_got_addr (cfg);
7658
7659         if (header->init_locals) {
7660                 MonoInst *store;
7661                 for (i = 0; i < header->num_locals; ++i) {
7662                         MonoType *ptype = header->locals [i];
7663                         int t = ptype->type;
7664                         if (t == MONO_TYPE_VALUETYPE && ptype->data.klass->enumtype)
7665                                 t = ptype->data.klass->enum_basetype->type;
7666                         if (ptype->byref) {
7667                                 NEW_PCONST (cfg, ins, NULL);
7668                                 NEW_LOCSTORE (cfg, store, i, ins);
7669                                 MONO_ADD_INS (init_localsbb, store);
7670                         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
7671                                 NEW_ICONST (cfg, ins, 0);
7672                                 NEW_LOCSTORE (cfg, store, i, ins);
7673                                 MONO_ADD_INS (init_localsbb, store);
7674                         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
7675                                 MONO_INST_NEW (cfg, ins, OP_I8CONST);
7676                                 ins->type = STACK_I8;
7677                                 ins->inst_l = 0;
7678                                 NEW_LOCSTORE (cfg, store, i, ins);
7679                                 MONO_ADD_INS (init_localsbb, store);
7680                         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
7681 #ifdef MONO_ARCH_SOFT_FLOAT
7682                                 /* FIXME: handle init of R4 */
7683 #else
7684                                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
7685                                 ins->type = STACK_R8;
7686                                 ins->inst_p0 = (void*)&r8_0;
7687                                 NEW_LOCSTORE (cfg, store, i, ins);
7688                                 MONO_ADD_INS (init_localsbb, store);
7689 #endif
7690                         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
7691                                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (ptype))) {
7692                                 NEW_LOCLOADA (cfg, ins, i);
7693                                 handle_initobj (cfg, init_localsbb, ins, NULL, mono_class_from_mono_type (ptype), NULL, NULL);
7694                         } else {
7695                                 NEW_PCONST (cfg, ins, NULL);
7696                                 NEW_LOCSTORE (cfg, store, i, ins);
7697                                 MONO_ADD_INS (init_localsbb, store);
7698                         }
7699                 }
7700         }
7701
7702         /* resolve backward branches in the middle of an existing basic block */
7703         for (tmp = bb_recheck; tmp; tmp = tmp->next) {
7704                 bblock = tmp->data;
7705                 /*g_print ("need recheck in %s at IL_%04x\n", method->name, bblock->cil_code - header->code);*/
7706                 tblock = find_previous (bbhash, start_bblock, bblock->cil_code);
7707                 if (tblock != start_bblock) {
7708                         int l;
7709                         split_bblock (cfg, tblock, bblock);
7710                         l = bblock->cil_code - header->code;
7711                         bblock->cil_length = tblock->cil_length - l;
7712                         tblock->cil_length = l;
7713                 } else {
7714                         g_print ("recheck failed.\n");
7715                 }
7716         }
7717
7718         if (cfg->method == method) {
7719                 MonoBasicBlock *bb;
7720                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
7721                         bb->region = mono_find_block_region (cfg, bb->real_offset);
7722                         if (cfg->spvars)
7723                                 mono_create_spvar_for_region (cfg, bb->region);
7724                         if (cfg->verbose_level > 2)
7725                                 g_print ("REGION BB%d IL_%04x ID_%08X\n", bb->block_num, bb->real_offset, bb->region);
7726                 }
7727         } else {
7728                 g_hash_table_destroy (bbhash);
7729         }
7730
7731         g_slist_free (class_inits);
7732         dont_inline = g_list_remove (dont_inline, method);
7733
7734         if (inline_costs < 0) {
7735                 char *mname;
7736
7737                 /* Method is too large */
7738                 mname = mono_method_full_name (method, TRUE);
7739                 cfg->exception_type = MONO_EXCEPTION_INVALID_PROGRAM;
7740                 cfg->exception_message = g_strdup_printf ("Method %s is too complex.", mname);
7741                 g_free (mname);
7742                 return -1;
7743         }
7744
7745         return inline_costs;
7746
7747  inline_failure:
7748         if (cfg->method != method) 
7749                 g_hash_table_destroy (bbhash);
7750         g_slist_free (class_inits);
7751         dont_inline = g_list_remove (dont_inline, method);
7752         return -1;
7753
7754  load_error:
7755         if (cfg->method != method)
7756                 g_hash_table_destroy (bbhash);
7757         g_slist_free (class_inits);
7758         dont_inline = g_list_remove (dont_inline, method);
7759         cfg->exception_type = MONO_EXCEPTION_TYPE_LOAD;
7760         return -1;
7761
7762  unverified:
7763         if (cfg->method != method) 
7764                 g_hash_table_destroy (bbhash);
7765         g_slist_free (class_inits);
7766         dont_inline = g_list_remove (dont_inline, method);
7767         cfg->exception_type = MONO_EXCEPTION_INVALID_PROGRAM;
7768         cfg->exception_message = g_strdup_printf ("Invalid IL code in %s: %s\n",
7769                  mono_method_full_name (method, TRUE), mono_disasm_code_one (NULL, method, ip, NULL));
7770         return -1;
7771 }
7772
7773 void
7774 mono_print_tree (MonoInst *tree) {
7775         int arity;
7776
7777         if (!tree)
7778                 return;
7779
7780         arity = mono_burg_arity [tree->opcode];
7781
7782         printf (" %s%s", arity?"(":"",  mono_inst_name (tree->opcode));
7783
7784         switch (tree->opcode) {
7785         case OP_ICONST:
7786                 printf ("[%d]", (int)tree->inst_c0);
7787                 break;
7788         case OP_I8CONST:
7789                 printf ("[%lld]", (long long)tree->inst_l);
7790                 break;
7791         case OP_R8CONST:
7792                 printf ("[%f]", *(double*)tree->inst_p0);
7793                 break;
7794         case OP_R4CONST:
7795                 printf ("[%f]", *(float*)tree->inst_p0);
7796                 break;
7797         case OP_ARG:
7798         case OP_LOCAL:
7799                 printf ("[%d]", (int)tree->inst_c0);
7800                 break;
7801         case OP_REGOFFSET:
7802                 if (tree->inst_offset < 0)
7803                         printf ("[-0x%x(%s)]", (int)(-tree->inst_offset), mono_arch_regname (tree->inst_basereg));
7804                 else
7805                         printf ("[0x%x(%s)]", (int)(tree->inst_offset), mono_arch_regname (tree->inst_basereg));
7806                 break;
7807         case OP_REGVAR:
7808                 printf ("[%s]", mono_arch_regname (tree->dreg));
7809                 break;
7810         case CEE_NEWARR:
7811                 printf ("[%s]",  tree->inst_newa_class->name);
7812                 mono_print_tree (tree->inst_newa_len);
7813                 break;
7814         case CEE_CALL:
7815         case CEE_CALLVIRT:
7816         case OP_FCALL:
7817         case OP_FCALLVIRT:
7818         case OP_LCALL:
7819         case OP_LCALLVIRT:
7820         case OP_VCALL:
7821         case OP_VCALLVIRT:
7822         case OP_VOIDCALL:
7823         case OP_VOIDCALLVIRT: {
7824                 MonoCallInst *call = (MonoCallInst*)tree;
7825                 if (call->method)
7826                         printf ("[%s]", call->method->name);
7827                 else if (call->fptr) {
7828                         MonoJitICallInfo *info = mono_find_jit_icall_by_addr (call->fptr);
7829                         if (info)
7830                                 printf ("[%s]", info->name);
7831                 }
7832                 break;
7833         }
7834         case OP_PHI: {
7835                 int i;
7836                 printf ("[%d (", (int)tree->inst_c0);
7837                 for (i = 0; i < tree->inst_phi_args [0]; i++) {
7838                         if (i)
7839                                 printf (", ");
7840                         printf ("%d", tree->inst_phi_args [i + 1]);
7841                 }
7842                 printf (")]");
7843                 break;
7844         }
7845         case OP_RENAME:
7846         case OP_RETARG:
7847         case CEE_NOP:
7848         case CEE_JMP:
7849         case CEE_BREAK:
7850                 break;
7851         case OP_LOAD_MEMBASE:
7852         case OP_LOADI4_MEMBASE:
7853         case OP_LOADU4_MEMBASE:
7854         case OP_LOADU1_MEMBASE:
7855         case OP_LOADI1_MEMBASE:
7856         case OP_LOADU2_MEMBASE:
7857         case OP_LOADI2_MEMBASE:
7858                 printf ("[%s] <- [%s + 0x%x]", mono_arch_regname (tree->dreg), mono_arch_regname (tree->inst_basereg), (int)tree->inst_offset);
7859                 break;
7860         case CEE_BR:
7861         case OP_CALL_HANDLER:
7862                 printf ("[B%d]", tree->inst_target_bb->block_num);
7863                 break;
7864         case CEE_SWITCH:
7865         case CEE_ISINST:
7866         case CEE_CASTCLASS:
7867         case OP_OUTARG:
7868         case OP_CALL_REG:
7869         case OP_FCALL_REG:
7870         case OP_LCALL_REG:
7871         case OP_VCALL_REG:
7872         case OP_VOIDCALL_REG:
7873                 mono_print_tree (tree->inst_left);
7874                 break;
7875         case CEE_BNE_UN:
7876         case CEE_BEQ:
7877         case CEE_BLT:
7878         case CEE_BLT_UN:
7879         case CEE_BGT:
7880         case CEE_BGT_UN:
7881         case CEE_BGE:
7882         case CEE_BGE_UN:
7883         case CEE_BLE:
7884         case CEE_BLE_UN:
7885                 printf ("[B%dB%d]", tree->inst_true_bb->block_num, tree->inst_false_bb->block_num);
7886                 mono_print_tree (tree->inst_left);
7887                 break;
7888         default:
7889                 if (!mono_arch_print_tree(tree, arity)) {
7890                         if (arity) {
7891                                 mono_print_tree (tree->inst_left);
7892                                 if (arity > 1)
7893                                         mono_print_tree (tree->inst_right);
7894                         }
7895                 }
7896                 break;
7897         }
7898
7899         if (arity)
7900                 printf (")");
7901 }
7902
7903 void
7904 mono_print_tree_nl (MonoInst *tree)
7905 {
7906         mono_print_tree (tree);
7907         printf ("\n");
7908 }
7909
7910 static void
7911 create_helper_signature (void)
7912 {
7913         helper_sig_domain_get = mono_create_icall_signature ("ptr");
7914         helper_sig_class_init_trampoline = mono_create_icall_signature ("void");
7915 }
7916
7917 gconstpointer
7918 mono_icall_get_wrapper (MonoJitICallInfo* callinfo)
7919 {
7920         char *name;
7921         MonoMethod *wrapper;
7922         gconstpointer trampoline;
7923         MonoDomain *domain = mono_get_root_domain ();
7924         
7925         if (callinfo->wrapper) {
7926                 return callinfo->wrapper;
7927         }
7928
7929         if (callinfo->trampoline)
7930                 return callinfo->trampoline;
7931
7932         /* 
7933          * We use the lock on the root domain instead of the JIT lock to protect 
7934          * callinfo->trampoline, since we do a lot of stuff inside the critical section.
7935          */
7936         mono_domain_lock (domain);
7937
7938         if (callinfo->trampoline) {
7939                 mono_domain_unlock (domain);
7940                 return callinfo->trampoline;
7941         }
7942
7943         name = g_strdup_printf ("__icall_wrapper_%s", callinfo->name);
7944         wrapper = mono_marshal_get_icall_wrapper (callinfo->sig, name, callinfo->func);
7945         g_free (name);
7946
7947         trampoline = mono_create_ftnptr (domain, mono_create_jit_trampoline_in_domain (domain, wrapper));
7948         mono_register_jit_icall_wrapper (callinfo, trampoline);
7949
7950         callinfo->trampoline = trampoline;
7951
7952         mono_domain_unlock (domain);
7953         
7954         return callinfo->trampoline;
7955 }
7956
7957 static void
7958 mono_init_trampolines (void)
7959 {
7960         mono_trampoline_code [MONO_TRAMPOLINE_GENERIC] = mono_arch_create_trampoline_code (MONO_TRAMPOLINE_GENERIC);
7961         mono_trampoline_code [MONO_TRAMPOLINE_JUMP] = mono_arch_create_trampoline_code (MONO_TRAMPOLINE_JUMP);
7962         mono_trampoline_code [MONO_TRAMPOLINE_CLASS_INIT] = mono_arch_create_trampoline_code (MONO_TRAMPOLINE_CLASS_INIT);
7963 #ifdef MONO_ARCH_HAVE_PIC_AOT
7964         mono_trampoline_code [MONO_TRAMPOLINE_AOT] = mono_arch_create_trampoline_code (MONO_TRAMPOLINE_AOT);
7965         mono_trampoline_code [MONO_TRAMPOLINE_AOT_PLT] = mono_arch_create_trampoline_code (MONO_TRAMPOLINE_AOT_PLT);
7966 #endif
7967 #ifdef MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE
7968         mono_trampoline_code [MONO_TRAMPOLINE_DELEGATE] = mono_arch_create_trampoline_code (MONO_TRAMPOLINE_DELEGATE);
7969 #endif
7970 }
7971
7972 static void
7973 mono_init_exceptions (void)
7974 {
7975 #ifndef CUSTOM_EXCEPTION_HANDLING
7976         mono_arch_get_restore_context ();
7977         mono_arch_get_call_filter ();
7978         mono_arch_get_throw_exception ();
7979         mono_arch_get_rethrow_exception ();
7980 #endif
7981 }
7982
7983 guint8 *
7984 mono_get_trampoline_code (MonoTrampolineType tramp_type)
7985 {
7986         return mono_trampoline_code [tramp_type];
7987 }
7988
7989 gpointer
7990 mono_create_class_init_trampoline (MonoVTable *vtable)
7991 {
7992         gpointer code, ptr;
7993
7994         /* previously created trampoline code */
7995         mono_domain_lock (vtable->domain);
7996         ptr = 
7997                 g_hash_table_lookup (vtable->domain->class_init_trampoline_hash,
7998                                                                   vtable);
7999         mono_domain_unlock (vtable->domain);
8000         if (ptr)
8001                 return ptr;
8002
8003 #ifdef MONO_ARCH_HAVE_CREATE_SPECIFIC_TRAMPOLINE
8004         code = mono_arch_create_specific_trampoline (vtable, MONO_TRAMPOLINE_CLASS_INIT, vtable->domain, NULL);
8005 #else
8006         code = mono_arch_create_class_init_trampoline (vtable);
8007 #endif
8008
8009         ptr = mono_create_ftnptr (vtable->domain, code);
8010
8011         /* store trampoline address */
8012         mono_domain_lock (vtable->domain);
8013         g_hash_table_insert (vtable->domain->class_init_trampoline_hash,
8014                                                           vtable, ptr);
8015         mono_domain_unlock (vtable->domain);
8016
8017         mono_jit_lock ();
8018         if (!class_init_hash_addr)
8019                 class_init_hash_addr = g_hash_table_new (NULL, NULL);
8020         g_hash_table_insert (class_init_hash_addr, ptr, vtable);
8021         mono_jit_unlock ();
8022
8023         return ptr;
8024 }
8025
8026 gpointer
8027 mono_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, 
8028                                                          gboolean add_sync_wrapper)
8029 {
8030         MonoJitInfo *ji;
8031         gpointer code;
8032 #ifdef MONO_ARCH_HAVE_CREATE_SPECIFIC_TRAMPOLINE
8033         guint32 code_size;
8034 #endif
8035
8036         if (add_sync_wrapper && method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
8037                 return mono_create_jump_trampoline (domain, mono_marshal_get_synchronized_wrapper (method), FALSE);
8038
8039         code = mono_jit_find_compiled_method (domain, method);
8040         if (code)
8041                 return code;
8042
8043         mono_domain_lock (domain);
8044         code = g_hash_table_lookup (domain->jump_trampoline_hash, method);
8045         mono_domain_unlock (domain);
8046         if (code)
8047                 return code;
8048
8049 #ifdef MONO_ARCH_HAVE_CREATE_SPECIFIC_TRAMPOLINE
8050         code = mono_arch_create_specific_trampoline (method, MONO_TRAMPOLINE_JUMP, mono_domain_get (), &code_size);
8051
8052         mono_domain_lock (domain);
8053         ji = mono_mempool_alloc0 (domain->mp, sizeof (MonoJitInfo));
8054         mono_domain_unlock (domain);
8055         ji->code_start = code;
8056         ji->code_size = code_size;
8057         ji->method = method;
8058 #else
8059         ji = mono_arch_create_jump_trampoline (method);
8060 #endif
8061
8062         /*
8063          * mono_delegate_ctor needs to find the method metadata from the 
8064          * trampoline address, so we save it here.
8065          */
8066
8067         mono_jit_info_table_add (domain, ji);
8068
8069         mono_domain_lock (domain);
8070         g_hash_table_insert (domain->jump_trampoline_hash, method, ji->code_start);
8071         mono_domain_unlock (domain);
8072
8073         return ji->code_start;
8074 }
8075
8076 static gpointer
8077 mono_create_jit_trampoline_in_domain (MonoDomain *domain, MonoMethod *method)
8078 {
8079         gpointer tramp;
8080
8081         mono_domain_lock (domain);
8082         tramp = g_hash_table_lookup (domain->jit_trampoline_hash, method);
8083         mono_domain_unlock (domain);
8084         if (tramp)
8085                 return tramp;
8086
8087         if (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
8088                 return mono_create_jit_trampoline (mono_marshal_get_synchronized_wrapper (method));
8089
8090 #ifdef MONO_ARCH_HAVE_CREATE_SPECIFIC_TRAMPOLINE
8091         tramp =  mono_arch_create_specific_trampoline (method, MONO_TRAMPOLINE_GENERIC, domain, NULL);
8092 #else
8093         tramp = mono_arch_create_jit_trampoline (method);
8094 #endif
8095         
8096         mono_domain_lock (domain);
8097         g_hash_table_insert (domain->jit_trampoline_hash, method, tramp);
8098         mono_domain_unlock (domain);
8099
8100         mono_jit_stats.method_trampolines++;
8101
8102         return tramp;
8103 }       
8104
8105 gpointer
8106 mono_create_jit_trampoline (MonoMethod *method)
8107 {
8108         return mono_create_jit_trampoline_in_domain (mono_domain_get (), method);
8109 }
8110
8111 #ifdef MONO_ARCH_HAVE_CREATE_TRAMPOLINE_FROM_TOKEN
8112 gpointer
8113 mono_create_jit_trampoline_from_token (MonoImage *image, guint32 token)
8114 {
8115         gpointer tramp;
8116
8117         MonoDomain *domain = mono_domain_get ();
8118         guint8 *buf, *start;
8119
8120         mono_domain_lock (domain);
8121         buf = start = mono_code_manager_reserve (domain->code_mp, 2 * sizeof (gpointer));
8122         mono_domain_unlock (domain);
8123
8124         *(gpointer*)(gpointer)buf = image;
8125         buf += sizeof (gpointer);
8126         *(guint32*)(gpointer)buf = token;
8127
8128         tramp = mono_arch_create_specific_trampoline (start, MONO_TRAMPOLINE_AOT, domain, NULL);
8129
8130         mono_jit_stats.method_trampolines++;
8131
8132         return tramp;
8133 }       
8134 #endif
8135
8136 static gpointer
8137 mono_create_delegate_trampoline (MonoMethod *method, gpointer addr)
8138 {
8139 #ifdef MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE
8140         gpointer code, ptr;
8141         guint32 code_size;
8142         MonoDomain *domain = mono_domain_get ();
8143
8144 #ifndef __ia64__
8145         code = mono_jit_find_compiled_method (domain, method);
8146         if (code)
8147                 return code;
8148 #else
8149         /* 
8150          * FIXME: We should return a function descriptor here but it is not stored
8151          * anywhere so it would be leaked.
8152          */
8153 #endif
8154
8155         mono_domain_lock (domain);
8156         ptr = g_hash_table_lookup (domain->delegate_trampoline_hash, method);
8157         mono_domain_unlock (domain);
8158         if (ptr)
8159                 return ptr;
8160
8161         code = mono_arch_create_specific_trampoline (method, MONO_TRAMPOLINE_DELEGATE, domain, &code_size);
8162
8163         ptr = mono_create_ftnptr (domain, code);
8164
8165         /* store trampoline address */
8166         mono_domain_lock (domain);
8167         g_hash_table_insert (domain->delegate_trampoline_hash,
8168                                                           method, ptr);
8169         mono_domain_unlock (domain);
8170
8171         return ptr;
8172 #else
8173         return addr;
8174 #endif
8175 }
8176
8177 MonoVTable*
8178 mono_find_class_init_trampoline_by_addr (gconstpointer addr)
8179 {
8180         MonoVTable *res;
8181
8182         mono_jit_lock ();
8183         if (class_init_hash_addr)
8184                 res = g_hash_table_lookup (class_init_hash_addr, addr);
8185         else
8186                 res = NULL;
8187         mono_jit_unlock ();
8188         return res;
8189 }
8190
8191 static void
8192 mono_dynamic_code_hash_insert (MonoDomain *domain, MonoMethod *method, MonoJitDynamicMethodInfo *ji)
8193 {
8194         if (!domain->dynamic_code_hash)
8195                 domain->dynamic_code_hash = g_hash_table_new (NULL, NULL);
8196         g_hash_table_insert (domain->dynamic_code_hash, method, ji);
8197 }
8198
8199 static MonoJitDynamicMethodInfo*
8200 mono_dynamic_code_hash_lookup (MonoDomain *domain, MonoMethod *method)
8201 {
8202         MonoJitDynamicMethodInfo *res;
8203
8204         if (domain->dynamic_code_hash)
8205                 res = g_hash_table_lookup (domain->dynamic_code_hash, method);
8206         else
8207                 res = NULL;
8208         return res;
8209 }
8210
8211 typedef struct {
8212         MonoClass *vtype;
8213         GList *active;
8214         GSList *slots;
8215 } StackSlotInfo;
8216
8217 static inline GSList*
8218 g_slist_prepend_mempool (MonoMemPool *mp, GSList   *list,
8219                                                  gpointer  data)
8220 {
8221   GSList *new_list;
8222
8223   new_list = mono_mempool_alloc (mp, sizeof (GSList));
8224   new_list->data = data;
8225   new_list->next = list;
8226
8227   return new_list;
8228 }
8229
8230 /*
8231  *  mono_allocate_stack_slots_full:
8232  *
8233  *  Allocate stack slots for all non register allocated variables using a
8234  * linear scan algorithm.
8235  * Returns: an array of stack offsets.
8236  * STACK_SIZE is set to the amount of stack space needed.
8237  * STACK_ALIGN is set to the alignment needed by the locals area.
8238  */
8239 gint32*
8240 mono_allocate_stack_slots_full (MonoCompile *m, gboolean backward, guint32 *stack_size, guint32 *stack_align)
8241 {
8242         int i, slot, offset, size;
8243         guint32 align;
8244         MonoMethodVar *vmv;
8245         MonoInst *inst;
8246         gint32 *offsets;
8247         GList *vars = NULL, *l;
8248         StackSlotInfo *scalar_stack_slots, *vtype_stack_slots, *slot_info;
8249         MonoType *t;
8250         int nvtypes;
8251
8252         scalar_stack_slots = mono_mempool_alloc0 (m->mempool, sizeof (StackSlotInfo) * MONO_TYPE_PINNED);
8253         vtype_stack_slots = NULL;
8254         nvtypes = 0;
8255
8256         offsets = mono_mempool_alloc (m->mempool, sizeof (gint32) * m->num_varinfo);
8257         for (i = 0; i < m->num_varinfo; ++i)
8258                 offsets [i] = -1;
8259
8260         for (i = m->locals_start; i < m->num_varinfo; i++) {
8261                 inst = m->varinfo [i];
8262                 vmv = MONO_VARINFO (m, i);
8263
8264                 if ((inst->flags & MONO_INST_IS_DEAD) || inst->opcode == OP_REGVAR || inst->opcode == OP_REGOFFSET)
8265                         continue;
8266
8267                 vars = g_list_prepend (vars, vmv);
8268         }
8269
8270         vars = mono_varlist_sort (m, vars, 0);
8271         offset = 0;
8272         *stack_align = 0;
8273         for (l = vars; l; l = l->next) {
8274                 vmv = l->data;
8275                 inst = m->varinfo [vmv->idx];
8276
8277                 /* inst->backend.is_pinvoke indicates native sized value types, this is used by the
8278                 * pinvoke wrappers when they call functions returning structures */
8279                 if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->inst_vtype->type != MONO_TYPE_TYPEDBYREF)
8280                         size = mono_class_native_size (inst->inst_vtype->data.klass, &align);
8281                 else {
8282                         int ialign;
8283
8284                         size = mono_type_size (inst->inst_vtype, &ialign);
8285                         align = ialign;
8286                 }
8287
8288                 t = mono_type_get_underlying_type (inst->inst_vtype);
8289                 if (t->byref) {
8290                         slot_info = &scalar_stack_slots [MONO_TYPE_I];
8291                 } else {
8292                         switch (t->type) {
8293                         case MONO_TYPE_GENERICINST:
8294                                 if (!mono_type_generic_inst_is_valuetype (t)) {
8295                                         slot_info = &scalar_stack_slots [t->type];
8296                                         break;
8297                                 }
8298                                 /* Fall through */
8299                         case MONO_TYPE_VALUETYPE:
8300                                 if (!vtype_stack_slots)
8301                                         vtype_stack_slots = mono_mempool_alloc0 (m->mempool, sizeof (StackSlotInfo) * 256);
8302                                 for (i = 0; i < nvtypes; ++i)
8303                                         if (t->data.klass == vtype_stack_slots [i].vtype)
8304                                                 break;
8305                                 if (i < nvtypes)
8306                                         slot_info = &vtype_stack_slots [i];
8307                                 else {
8308                                         g_assert (nvtypes < 256);
8309                                         vtype_stack_slots [nvtypes].vtype = t->data.klass;
8310                                         slot_info = &vtype_stack_slots [nvtypes];
8311                                         nvtypes ++;
8312                                 }
8313                                 break;
8314                         case MONO_TYPE_CLASS:
8315                         case MONO_TYPE_OBJECT:
8316                         case MONO_TYPE_ARRAY:
8317                         case MONO_TYPE_SZARRAY:
8318                         case MONO_TYPE_STRING:
8319                         case MONO_TYPE_PTR:
8320                         case MONO_TYPE_I:
8321                         case MONO_TYPE_U:
8322 #if SIZEOF_VOID_P == 4
8323                         case MONO_TYPE_I4:
8324 #else
8325                         case MONO_TYPE_I8:
8326 #endif
8327                                 /* Share non-float stack slots of the same size */
8328                                 slot_info = &scalar_stack_slots [MONO_TYPE_CLASS];
8329                                 break;
8330                         default:
8331                                 slot_info = &scalar_stack_slots [t->type];
8332                         }
8333                 }
8334
8335                 slot = 0xffffff;
8336                 if (m->comp_done & MONO_COMP_LIVENESS) {
8337                         //printf ("START  %2d %08x %08x\n",  vmv->idx, vmv->range.first_use.abs_pos, vmv->range.last_use.abs_pos);
8338                         
8339                         /* expire old intervals in active */
8340                         while (slot_info->active) {
8341                                 MonoMethodVar *amv = (MonoMethodVar *)slot_info->active->data;
8342
8343                                 if (amv->range.last_use.abs_pos > vmv->range.first_use.abs_pos)
8344                                         break;
8345
8346                                 //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);
8347
8348                                 slot_info->active = g_list_delete_link (slot_info->active, slot_info->active);
8349                                 slot_info->slots = g_slist_prepend_mempool (m->mempool, slot_info->slots, GINT_TO_POINTER (offsets [amv->idx]));
8350                         }
8351
8352                         /* 
8353                          * This also handles the case when the variable is used in an
8354                          * exception region, as liveness info is not computed there.
8355                          */
8356                         /* 
8357                          * FIXME: All valuetypes are marked as INDIRECT because of LDADDR
8358                          * opcodes.
8359                          */
8360                         if (! (inst->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT))) {
8361                                 if (slot_info->slots) {
8362                                         slot = GPOINTER_TO_INT (slot_info->slots->data);
8363
8364                                         slot_info->slots = slot_info->slots->next;
8365                                 }
8366
8367                                 slot_info->active = mono_varlist_insert_sorted (m, slot_info->active, vmv, TRUE);
8368                         }
8369                 }
8370
8371                 {
8372                         static int count = 0;
8373                         count ++;
8374
8375                         /*
8376                         if (count == atoi (getenv ("COUNT")))
8377                                 printf ("LAST: %s\n", mono_method_full_name (m->method, TRUE));
8378                         if (count > atoi (getenv ("COUNT")))
8379                                 slot = 0xffffff;
8380                         else {
8381                                 mono_print_tree_nl (inst);
8382                                 }
8383                         */
8384                 }
8385                 if (slot == 0xffffff) {
8386                         /*
8387                          * Allways allocate valuetypes to sizeof (gpointer) to allow more
8388                          * efficient copying (and to work around the fact that OP_MEMCPY
8389                          * and OP_MEMSET ignores alignment).
8390                          */
8391                         if (MONO_TYPE_ISSTRUCT (t))
8392                                 align = sizeof (gpointer);
8393
8394                         if (backward) {
8395                                 offset += size;
8396                                 offset += align - 1;
8397                                 offset &= ~(align - 1);
8398                                 slot = offset;
8399                         }
8400                         else {
8401                                 offset += align - 1;
8402                                 offset &= ~(align - 1);
8403                                 slot = offset;
8404                                 offset += size;
8405                         }
8406
8407                         if (*stack_align == 0)
8408                                 *stack_align = align;
8409                 }
8410
8411                 offsets [vmv->idx] = slot;
8412         }
8413         g_list_free (vars);
8414         for (i = 0; i < MONO_TYPE_PINNED; ++i) {
8415                 if (scalar_stack_slots [i].active)
8416                         g_list_free (scalar_stack_slots [i].active);
8417         }
8418         for (i = 0; i < nvtypes; ++i) {
8419                 if (vtype_stack_slots [i].active)
8420                         g_list_free (vtype_stack_slots [i].active);
8421         }
8422
8423         mono_jit_stats.locals_stack_size += offset;
8424
8425         *stack_size = offset;
8426         return offsets;
8427 }
8428
8429 gint32*
8430 mono_allocate_stack_slots (MonoCompile *m, guint32 *stack_size, guint32 *stack_align)
8431 {
8432         return mono_allocate_stack_slots_full (m, TRUE, stack_size, stack_align);
8433 }
8434
8435 void
8436 mono_register_opcode_emulation (int opcode, const char *name, const char *sigstr, gpointer func, gboolean no_throw)
8437 {
8438         MonoJitICallInfo *info;
8439         MonoMethodSignature *sig = mono_create_icall_signature (sigstr);
8440
8441         if (!emul_opcode_map)
8442                 emul_opcode_map = g_new0 (MonoJitICallInfo*, OP_LAST + 1);
8443
8444         g_assert (!sig->hasthis);
8445         g_assert (sig->param_count < 3);
8446
8447         info = mono_register_jit_icall (func, name, sig, no_throw);
8448
8449         emul_opcode_map [opcode] = info;
8450 }
8451
8452 static void
8453 register_icall (gpointer func, const char *name, const char *sigstr, gboolean save)
8454 {
8455         MonoMethodSignature *sig;
8456
8457         if (sigstr)
8458                 sig = mono_create_icall_signature (sigstr);
8459         else
8460                 sig = NULL;
8461
8462         mono_register_jit_icall (func, name, sig, save);
8463 }
8464
8465 static void
8466 decompose_foreach (MonoInst *tree, gpointer data) 
8467 {
8468         static MonoJitICallInfo *newarr_info = NULL;
8469         static MonoJitICallInfo *newarr_specific_info = NULL;
8470         MonoJitICallInfo *info;
8471         int i;
8472
8473         switch (tree->opcode) {
8474         case CEE_NEWARR: {
8475                 MonoCompile *cfg = data;
8476                 MonoInst *iargs [3];
8477
8478                 if (!newarr_info) {
8479                         newarr_info = mono_find_jit_icall_by_addr (mono_array_new);
8480                         g_assert (newarr_info);
8481                         newarr_specific_info = mono_find_jit_icall_by_addr (mono_array_new_specific);
8482                         g_assert (newarr_specific_info);
8483                 }
8484
8485                 if (cfg->opt & MONO_OPT_SHARED) {
8486                         NEW_DOMAINCONST (cfg, iargs [0]);
8487                         NEW_CLASSCONST (cfg, iargs [1], tree->inst_newa_class);
8488                         iargs [2] = tree->inst_newa_len;
8489
8490                         info = newarr_info;
8491                 }
8492                 else {
8493                         MonoVTable *vtable = mono_class_vtable (cfg->domain, mono_array_class_get (tree->inst_newa_class, 1));
8494
8495                         NEW_VTABLECONST (cfg, iargs [0], vtable);
8496                         iargs [1] = tree->inst_newa_len;
8497
8498                         info = newarr_specific_info;
8499                 }
8500
8501                 mono_emulate_opcode (cfg, tree, iargs, info);
8502
8503                 /* Need to decompose arguments after the the opcode is decomposed */
8504                 for (i = 0; i < info->sig->param_count; ++i)
8505                         dec_foreach (iargs [i], cfg);
8506                 break;
8507         }
8508 #ifdef MONO_ARCH_SOFT_FLOAT
8509         case OP_FBEQ:
8510         case OP_FBGE:
8511         case OP_FBGT:
8512         case OP_FBLE:
8513         case OP_FBLT:
8514         case OP_FBNE_UN:
8515         case OP_FBGE_UN:
8516         case OP_FBGT_UN:
8517         case OP_FBLE_UN:
8518         case OP_FBLT_UN: {
8519                 if ((info = mono_find_jit_opcode_emulation (tree->opcode))) {
8520                         MonoCompile *cfg = data;
8521                         MonoInst *iargs [2];
8522                 
8523                         iargs [0] = tree->inst_i0;
8524                         iargs [1] = tree->inst_i1;
8525                 
8526                         mono_emulate_opcode (cfg, tree, iargs, info);
8527
8528                         dec_foreach (iargs [0], cfg);
8529                         dec_foreach (iargs [1], cfg);
8530                         break;
8531                 } else {
8532                         g_assert_not_reached ();
8533                 }
8534                 break;
8535         }
8536         case OP_FCEQ:
8537         case OP_FCGT:
8538         case OP_FCGT_UN:
8539         case OP_FCLT:
8540         case OP_FCLT_UN: {
8541                 if ((info = mono_find_jit_opcode_emulation (tree->opcode))) {
8542                         MonoCompile *cfg = data;
8543                         MonoInst *iargs [2];
8544
8545                         /* the args are in the compare opcode ... */
8546                         iargs [0] = tree->inst_i0;
8547                         iargs [1] = tree->inst_i1;
8548                 
8549                         mono_emulate_opcode (cfg, tree, iargs, info);
8550
8551                         dec_foreach (iargs [0], cfg);
8552                         dec_foreach (iargs [1], cfg);
8553                         break;
8554                 } else {
8555                         g_assert_not_reached ();
8556                 }
8557                 break;
8558         }
8559 #endif
8560
8561         default:
8562                 break;
8563         }
8564 }
8565
8566 void
8567 mono_inst_foreach (MonoInst *tree, MonoInstFunc func, gpointer data) {
8568
8569         switch (mono_burg_arity [tree->opcode]) {
8570         case 0: break;
8571         case 1: 
8572                 mono_inst_foreach (tree->inst_left, func, data);
8573                 break;
8574         case 2: 
8575                 mono_inst_foreach (tree->inst_left, func, data);
8576                 mono_inst_foreach (tree->inst_right, func, data);
8577                 break;
8578         default:
8579                 g_assert_not_reached ();
8580         }
8581         func (tree, data);
8582 }
8583
8584 G_GNUC_UNUSED
8585 static void
8586 mono_print_bb_code (MonoBasicBlock *bb) {
8587         if (bb->code) {
8588                 MonoInst *c = bb->code;
8589                 while (c) {
8590                         mono_print_tree (c);
8591                         g_print ("\n");
8592                         c = c->next;
8593                 }
8594         }
8595 }
8596
8597 static void
8598 print_dfn (MonoCompile *cfg) {
8599         int i, j;
8600         char *code;
8601         MonoBasicBlock *bb;
8602
8603         g_print ("IR code for method %s\n", mono_method_full_name (cfg->method, TRUE));
8604
8605         for (i = 0; i < cfg->num_bblocks; ++i) {
8606                 bb = cfg->bblocks [i];
8607                 /*if (bb->cil_code) {
8608                         char* code1, *code2;
8609                         code1 = mono_disasm_code_one (NULL, cfg->method, bb->cil_code, NULL);
8610                         if (bb->last_ins->cil_code)
8611                                 code2 = mono_disasm_code_one (NULL, cfg->method, bb->last_ins->cil_code, NULL);
8612                         else
8613                                 code2 = g_strdup ("");
8614
8615                         code1 [strlen (code1) - 1] = 0;
8616                         code = g_strdup_printf ("%s -> %s", code1, code2);
8617                         g_free (code1);
8618                         g_free (code2);
8619                 } else*/
8620                         code = g_strdup ("\n");
8621                 g_print ("\nBB%d DFN%d (len: %d): %s", bb->block_num, i, bb->cil_length, code);
8622                 if (bb->code) {
8623                         MonoInst *c = bb->code;
8624                         while (c) {
8625                                 mono_print_tree (c);
8626                                 g_print ("\n");
8627                                 c = c->next;
8628                         }
8629                 } else {
8630
8631                 }
8632
8633                 g_print ("\tprev:");
8634                 for (j = 0; j < bb->in_count; ++j) {
8635                         g_print (" BB%d", bb->in_bb [j]->block_num);
8636                 }
8637                 g_print ("\t\tsucc:");
8638                 for (j = 0; j < bb->out_count; ++j) {
8639                         g_print (" BB%d", bb->out_bb [j]->block_num);
8640                 }
8641                 g_print ("\n\tidom: BB%d\n", bb->idom? bb->idom->block_num: -1);
8642
8643                 if (bb->idom)
8644                         g_assert (mono_bitset_test_fast (bb->dominators, bb->idom->dfn));
8645
8646                 if (bb->dominators)
8647                         mono_blockset_print (cfg, bb->dominators, "\tdominators", bb->idom? bb->idom->dfn: -1);
8648                 if (bb->dfrontier)
8649                         mono_blockset_print (cfg, bb->dfrontier, "\tdfrontier", -1);
8650                 g_free (code);
8651         }
8652
8653         g_print ("\n");
8654 }
8655
8656 void
8657 mono_bblock_add_inst (MonoBasicBlock *bb, MonoInst *inst)
8658 {
8659         inst->next = NULL;
8660         if (bb->last_ins) {
8661                 g_assert (bb->code);
8662                 bb->last_ins->next = inst;
8663                 bb->last_ins = inst;
8664         } else {
8665                 bb->last_ins = bb->code = inst;
8666         }
8667 }
8668
8669 void
8670 mono_destroy_compile (MonoCompile *cfg)
8671 {
8672         //mono_mempool_stats (cfg->mempool);
8673         g_hash_table_destroy (cfg->bb_hash);
8674         mono_free_loop_info (cfg);
8675         if (cfg->rs)
8676                 mono_regstate_free (cfg->rs);
8677         if (cfg->spvars)
8678                 g_hash_table_destroy (cfg->spvars);
8679         if (cfg->exvars)
8680                 g_hash_table_destroy (cfg->exvars);
8681         mono_mempool_destroy (cfg->mempool);
8682         g_list_free (cfg->ldstr_list);
8683
8684         g_free (cfg->varinfo);
8685         g_free (cfg->vars);
8686         g_free (cfg->exception_message);
8687         g_free (cfg);
8688 }
8689
8690 #ifdef HAVE_KW_THREAD
8691 static __thread gpointer mono_lmf_addr MONO_TLS_FAST;
8692 #ifdef MONO_ARCH_ENABLE_MONO_LMF_VAR
8693 /* 
8694  * When this is defined, the current lmf is stored in this tls variable instead of in 
8695  * jit_tls->lmf.
8696  */
8697 static __thread gpointer mono_lmf MONO_TLS_FAST;
8698 #endif
8699 #endif
8700
8701 guint32
8702 mono_get_jit_tls_key (void)
8703 {
8704         return mono_jit_tls_id;
8705 }
8706
8707 gint32
8708 mono_get_lmf_tls_offset (void)
8709 {
8710 #if defined(HAVE_KW_THREAD) && defined(MONO_ARCH_ENABLE_MONO_LMF_VAR)
8711         int offset;
8712         MONO_THREAD_VAR_OFFSET(mono_lmf,offset);
8713         return offset;
8714 #else
8715         return -1;
8716 #endif
8717 }
8718
8719 gint32
8720 mono_get_lmf_addr_tls_offset (void)
8721 {
8722         int offset;
8723         MONO_THREAD_VAR_OFFSET(mono_lmf_addr,offset);
8724         return offset;
8725 }
8726
8727 MonoLMF *
8728 mono_get_lmf (void)
8729 {
8730 #if defined(HAVE_KW_THREAD) && defined(MONO_ARCH_ENABLE_MONO_LMF_VAR)
8731         return mono_lmf;
8732 #else
8733         MonoJitTlsData *jit_tls;
8734
8735         if ((jit_tls = TlsGetValue (mono_jit_tls_id)))
8736                 return jit_tls->lmf;
8737
8738         g_assert_not_reached ();
8739         return NULL;
8740 #endif
8741 }
8742
8743 MonoLMF **
8744 mono_get_lmf_addr (void)
8745 {
8746 #ifdef HAVE_KW_THREAD
8747         return mono_lmf_addr;
8748 #else
8749         MonoJitTlsData *jit_tls;
8750
8751         if ((jit_tls = TlsGetValue (mono_jit_tls_id)))
8752                 return &jit_tls->lmf;
8753
8754         g_assert_not_reached ();
8755         return NULL;
8756 #endif
8757 }
8758
8759 /* Called by native->managed wrappers */
8760 void
8761 mono_jit_thread_attach (MonoDomain *domain)
8762 {
8763 #ifdef HAVE_KW_THREAD
8764         if (!mono_lmf_addr) {
8765                 mono_thread_attach (domain);
8766         }
8767 #else
8768         if (!TlsGetValue (mono_jit_tls_id))
8769                 mono_thread_attach (domain);
8770 #endif
8771 }       
8772
8773 /**
8774  * mono_thread_abort:
8775  * @obj: exception object
8776  *
8777  * abort the thread, print exception information and stack trace
8778  */
8779 static void
8780 mono_thread_abort (MonoObject *obj)
8781 {
8782         /* MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id); */
8783         
8784         /* handle_remove should be eventually called for this thread, too
8785         g_free (jit_tls);*/
8786
8787         mono_thread_exit ();
8788 }
8789
8790 static void*
8791 setup_jit_tls_data (gpointer stack_start, gpointer abort_func)
8792 {
8793         MonoJitTlsData *jit_tls;
8794         MonoLMF *lmf;
8795
8796         jit_tls = TlsGetValue (mono_jit_tls_id);
8797         if (jit_tls)
8798                 return jit_tls;
8799
8800         jit_tls = g_new0 (MonoJitTlsData, 1);
8801
8802         TlsSetValue (mono_jit_tls_id, jit_tls);
8803
8804         jit_tls->abort_func = abort_func;
8805         jit_tls->end_of_stack = stack_start;
8806
8807         lmf = g_new0 (MonoLMF, 1);
8808         lmf->ebp = -1;
8809
8810         jit_tls->first_lmf = lmf;
8811
8812 #if defined(HAVE_KW_THREAD) && defined(MONO_ARCH_ENABLE_MONO_LMF_VAR)
8813         /* jit_tls->lmf is unused */
8814         mono_lmf = lmf;
8815         mono_lmf_addr = &mono_lmf;
8816 #else
8817 #if defined(HAVE_KW_THREAD)
8818         mono_lmf_addr = &jit_tls->lmf;  
8819 #endif
8820
8821         jit_tls->lmf = lmf;
8822 #endif
8823
8824         mono_arch_setup_jit_tls_data (jit_tls);
8825
8826 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
8827         mono_setup_altstack (jit_tls);
8828 #endif
8829
8830         return jit_tls;
8831 }
8832
8833 static void
8834 mono_thread_start_cb (gsize tid, gpointer stack_start, gpointer func)
8835 {
8836         MonoThread *thread;
8837         void *jit_tls = setup_jit_tls_data (stack_start, mono_thread_abort);
8838         thread = mono_thread_current ();
8839         if (thread)
8840                 thread->jit_data = jit_tls;
8841 }
8842
8843 void (*mono_thread_attach_aborted_cb ) (MonoObject *obj) = NULL;
8844
8845 static void
8846 mono_thread_abort_dummy (MonoObject *obj)
8847 {
8848   if (mono_thread_attach_aborted_cb)
8849     mono_thread_attach_aborted_cb (obj);
8850   else
8851     mono_thread_abort (obj);
8852 }
8853
8854 static void
8855 mono_thread_attach_cb (gsize tid, gpointer stack_start)
8856 {
8857         MonoThread *thread;
8858         void *jit_tls = setup_jit_tls_data (stack_start, mono_thread_abort_dummy);
8859         thread = mono_thread_current ();
8860         if (thread)
8861                 thread->jit_data = jit_tls;
8862         if (mono_profiler_get_events () & MONO_PROFILE_STATISTICAL)
8863                 setup_stat_profiler ();
8864 }
8865
8866 static void
8867 mini_thread_cleanup (MonoThread *thread)
8868 {
8869         MonoJitTlsData *jit_tls = thread->jit_data;
8870
8871         if (jit_tls) {
8872                 mono_arch_free_jit_tls_data (jit_tls);
8873
8874 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
8875                 mono_free_altstack (jit_tls);
8876 #endif
8877                 g_free (jit_tls->first_lmf);
8878                 g_free (jit_tls);
8879                 thread->jit_data = NULL;
8880                 TlsSetValue (mono_jit_tls_id, NULL);
8881         }
8882 }
8883
8884 void
8885 mono_add_patch_info (MonoCompile *cfg, int ip, MonoJumpInfoType type, gconstpointer target)
8886 {
8887         MonoJumpInfo *ji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo));
8888
8889         ji->ip.i = ip;
8890         ji->type = type;
8891         ji->data.target = target;
8892         ji->next = cfg->patch_info;
8893
8894         cfg->patch_info = ji;
8895 }
8896
8897 void
8898 mono_remove_patch_info (MonoCompile *cfg, int ip)
8899 {
8900         MonoJumpInfo **ji = &cfg->patch_info;
8901
8902         while (*ji) {
8903                 if ((*ji)->ip.i == ip)
8904                         *ji = (*ji)->next;
8905                 else
8906                         ji = &((*ji)->next);
8907         }
8908 }
8909
8910 /**
8911  * mono_patch_info_dup_mp:
8912  *
8913  * Make a copy of PATCH_INFO, allocating memory from the mempool MP.
8914  */
8915 MonoJumpInfo*
8916 mono_patch_info_dup_mp (MonoMemPool *mp, MonoJumpInfo *patch_info)
8917 {
8918         MonoJumpInfo *res = mono_mempool_alloc (mp, sizeof (MonoJumpInfo));
8919         memcpy (res, patch_info, sizeof (MonoJumpInfo));
8920
8921         switch (patch_info->type) {
8922         case MONO_PATCH_INFO_RVA:
8923         case MONO_PATCH_INFO_LDSTR:
8924         case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
8925         case MONO_PATCH_INFO_LDTOKEN:
8926         case MONO_PATCH_INFO_DECLSEC:
8927                 res->data.token = mono_mempool_alloc (mp, sizeof (MonoJumpInfoToken));
8928                 memcpy (res->data.token, patch_info->data.token, sizeof (MonoJumpInfoToken));
8929                 break;
8930         case MONO_PATCH_INFO_SWITCH:
8931                 res->data.table = mono_mempool_alloc (mp, sizeof (MonoJumpInfoBBTable));
8932                 memcpy (res->data.table, patch_info->data.table, sizeof (MonoJumpInfoBBTable));
8933                 break;
8934         default:
8935                 break;
8936         }
8937
8938         return res;
8939 }
8940
8941 guint
8942 mono_patch_info_hash (gconstpointer data)
8943 {
8944         const MonoJumpInfo *ji = (MonoJumpInfo*)data;
8945
8946         switch (ji->type) {
8947         case MONO_PATCH_INFO_RVA:
8948         case MONO_PATCH_INFO_LDSTR:
8949         case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
8950         case MONO_PATCH_INFO_LDTOKEN:
8951         case MONO_PATCH_INFO_DECLSEC:
8952                 return (ji->type << 8) | ji->data.token->token;
8953         default:
8954                 return (ji->type << 8);
8955         }
8956 }
8957
8958 /* 
8959  * mono_patch_info_equal:
8960  * 
8961  * This might fail to recognize equivalent patches, i.e. floats, so its only
8962  * usable in those cases where this is not a problem, i.e. sharing GOT slots
8963  * in AOT.
8964  */
8965 gint
8966 mono_patch_info_equal (gconstpointer ka, gconstpointer kb)
8967 {
8968         const MonoJumpInfo *ji1 = (MonoJumpInfo*)ka;
8969         const MonoJumpInfo *ji2 = (MonoJumpInfo*)kb;
8970
8971         if (ji1->type != ji2->type)
8972                 return 0;
8973
8974         switch (ji1->type) {
8975         case MONO_PATCH_INFO_RVA:
8976         case MONO_PATCH_INFO_LDSTR:
8977         case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
8978         case MONO_PATCH_INFO_LDTOKEN:
8979         case MONO_PATCH_INFO_DECLSEC:
8980                 if ((ji1->data.token->image != ji2->data.token->image) ||
8981                         (ji1->data.token->token != ji2->data.token->token))
8982                         return 0;
8983                 break;
8984         default:
8985                 if (ji1->data.name != ji2->data.name)
8986                         return 0;
8987                 break;
8988         }
8989
8990         return 1;
8991 }
8992
8993 gpointer
8994 mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *patch_info, gboolean run_cctors)
8995 {
8996         unsigned char *ip = patch_info->ip.i + code;
8997         gconstpointer target = NULL;
8998
8999         switch (patch_info->type) {
9000         case MONO_PATCH_INFO_BB:
9001                 target = patch_info->data.bb->native_offset + code;
9002                 break;
9003         case MONO_PATCH_INFO_ABS:
9004                 target = patch_info->data.target;
9005                 break;
9006         case MONO_PATCH_INFO_LABEL:
9007                 target = patch_info->data.inst->inst_c0 + code;
9008                 break;
9009         case MONO_PATCH_INFO_IP:
9010                 target = ip;
9011                 break;
9012         case MONO_PATCH_INFO_METHOD_REL:
9013                 target = code + patch_info->data.offset;
9014                 break;
9015         case MONO_PATCH_INFO_INTERNAL_METHOD: {
9016                 MonoJitICallInfo *mi = mono_find_jit_icall_by_name (patch_info->data.name);
9017                 if (!mi) {
9018                         g_warning ("unknown MONO_PATCH_INFO_INTERNAL_METHOD %s", patch_info->data.name);
9019                         g_assert_not_reached ();
9020                 }
9021                 target = mono_icall_get_wrapper (mi);
9022                 break;
9023         }
9024         case MONO_PATCH_INFO_METHOD_JUMP: {
9025                 GSList *list;
9026
9027                 /* get the trampoline to the method from the domain */
9028                 target = mono_create_jump_trampoline (domain, patch_info->data.method, TRUE);
9029                 if (!domain->jump_target_hash)
9030                         domain->jump_target_hash = g_hash_table_new (NULL, NULL);
9031                 list = g_hash_table_lookup (domain->jump_target_hash, patch_info->data.method);
9032                 list = g_slist_prepend (list, ip);
9033                 g_hash_table_insert (domain->jump_target_hash, patch_info->data.method, list);
9034                 break;
9035         }
9036         case MONO_PATCH_INFO_METHOD:
9037                 if (patch_info->data.method == method) {
9038                         target = code;
9039                 } else
9040                         /* get the trampoline to the method from the domain */
9041                         target = mono_create_jit_trampoline (patch_info->data.method);
9042                 break;
9043         case MONO_PATCH_INFO_SWITCH: {
9044                 gpointer *jump_table;
9045                 int i;
9046
9047                 if (method && method->dynamic) {
9048                         jump_table = mono_code_manager_reserve (mono_dynamic_code_hash_lookup (domain, method)->code_mp, sizeof (gpointer) * patch_info->data.table->table_size);
9049                 } else {
9050                         mono_domain_lock (domain);
9051                         jump_table = mono_code_manager_reserve (domain->code_mp, sizeof (gpointer) * patch_info->data.table->table_size);
9052                         mono_domain_unlock (domain);
9053                 }
9054
9055                 for (i = 0; i < patch_info->data.table->table_size; i++) {
9056                         jump_table [i] = code + GPOINTER_TO_INT (patch_info->data.table->table [i]);
9057                 }
9058                 target = jump_table;
9059                 break;
9060         }
9061         case MONO_PATCH_INFO_METHODCONST:
9062         case MONO_PATCH_INFO_CLASS:
9063         case MONO_PATCH_INFO_IMAGE:
9064         case MONO_PATCH_INFO_FIELD:
9065                 target = patch_info->data.target;
9066                 break;
9067         case MONO_PATCH_INFO_IID:
9068                 mono_class_init (patch_info->data.klass);
9069                 target = GINT_TO_POINTER ((int)patch_info->data.klass->interface_id);
9070                 break;
9071         case MONO_PATCH_INFO_ADJUSTED_IID:
9072                 mono_class_init (patch_info->data.klass);
9073                 target = GINT_TO_POINTER ((int)(-((patch_info->data.klass->interface_id + 1) * SIZEOF_VOID_P)));
9074                 break;
9075         case MONO_PATCH_INFO_VTABLE:
9076                 target = mono_class_vtable (domain, patch_info->data.klass);
9077                 break;
9078         case MONO_PATCH_INFO_CLASS_INIT:
9079                 target = mono_create_class_init_trampoline (mono_class_vtable (domain, patch_info->data.klass));
9080                 break;
9081         case MONO_PATCH_INFO_SFLDA: {
9082                 MonoVTable *vtable = mono_class_vtable (domain, patch_info->data.field->parent);
9083                 if (!vtable->initialized && !(vtable->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) && (method && mono_class_needs_cctor_run (vtable->klass, method)))
9084                         /* Done by the generated code */
9085                         ;
9086                 else {
9087                         if (run_cctors)
9088                                 mono_runtime_class_init (vtable);
9089                 }
9090                 target = (char*)vtable->data + patch_info->data.field->offset;
9091                 break;
9092         }
9093         case MONO_PATCH_INFO_RVA:
9094                 target = mono_image_rva_map (patch_info->data.token->image, patch_info->data.token->token);
9095                 break;
9096         case MONO_PATCH_INFO_R4:
9097         case MONO_PATCH_INFO_R8:
9098                 target = patch_info->data.target;
9099                 break;
9100         case MONO_PATCH_INFO_EXC_NAME:
9101                 target = patch_info->data.name;
9102                 break;
9103         case MONO_PATCH_INFO_LDSTR:
9104                 target =
9105                         mono_ldstr (domain, patch_info->data.token->image, 
9106                                                 mono_metadata_token_index (patch_info->data.token->token));
9107                 break;
9108         case MONO_PATCH_INFO_TYPE_FROM_HANDLE: {
9109                 gpointer handle;
9110                 MonoClass *handle_class;
9111
9112                 handle = mono_ldtoken (patch_info->data.token->image, 
9113                                        patch_info->data.token->token, &handle_class, NULL);
9114                 mono_class_init (handle_class);
9115                 mono_class_init (mono_class_from_mono_type (handle));
9116
9117                 target =
9118                         mono_type_get_object (domain, handle);
9119                 break;
9120         }
9121         case MONO_PATCH_INFO_LDTOKEN: {
9122                 gpointer handle;
9123                 MonoClass *handle_class;
9124                 
9125                 handle = mono_ldtoken (patch_info->data.token->image,
9126                                        patch_info->data.token->token, &handle_class, NULL);
9127                 mono_class_init (handle_class);
9128                 
9129                 target = handle;
9130                 break;
9131         }
9132         case MONO_PATCH_INFO_DECLSEC:
9133                 target = (mono_metadata_blob_heap (patch_info->data.token->image, patch_info->data.token->token) + 2);
9134                 break;
9135         case MONO_PATCH_INFO_BB_OVF:
9136         case MONO_PATCH_INFO_EXC_OVF:
9137         case MONO_PATCH_INFO_GOT_OFFSET:
9138         case MONO_PATCH_INFO_NONE:
9139                 break;
9140         default:
9141                 g_assert_not_reached ();
9142         }
9143
9144         return (gpointer)target;
9145 }
9146
9147 static void
9148 dec_foreach (MonoInst *tree, MonoCompile *cfg) {
9149         MonoJitICallInfo *info;
9150
9151         decompose_foreach (tree, cfg);
9152
9153         switch (mono_burg_arity [tree->opcode]) {
9154         case 0: break;
9155         case 1: 
9156                 dec_foreach (tree->inst_left, cfg);
9157
9158                 if ((info = mono_find_jit_opcode_emulation (tree->opcode))) {
9159                         MonoInst *iargs [2];
9160                 
9161                         iargs [0] = tree->inst_left;
9162
9163                         mono_emulate_opcode (cfg, tree, iargs, info);
9164                         return;
9165                 }
9166
9167                 break;
9168         case 2:
9169 #ifdef MONO_ARCH_BIGMUL_INTRINS
9170                 if (tree->opcode == OP_LMUL
9171                                 && (cfg->opt & MONO_OPT_INTRINS)
9172                                 && (tree->inst_left->opcode == CEE_CONV_I8 
9173                                         || tree->inst_left->opcode == CEE_CONV_U8)
9174                                 && tree->inst_left->inst_left->type == STACK_I4
9175                                 && (tree->inst_right->opcode == CEE_CONV_I8 
9176                                         || tree->inst_right->opcode == CEE_CONV_U8)
9177                                 && tree->inst_right->inst_left->type == STACK_I4
9178                                 && tree->inst_left->opcode == tree->inst_right->opcode) {
9179                         tree->opcode = (tree->inst_left->opcode == CEE_CONV_I8 ? OP_BIGMUL: OP_BIGMUL_UN);
9180                         tree->inst_left = tree->inst_left->inst_left;
9181                         tree->inst_right = tree->inst_right->inst_left;
9182                         dec_foreach (tree, cfg);
9183                 } else 
9184 #endif
9185                         if ((info = mono_find_jit_opcode_emulation (tree->opcode))) {
9186                         MonoInst *iargs [2];
9187                 
9188                         iargs [0] = tree->inst_i0;
9189                         iargs [1] = tree->inst_i1;
9190                 
9191                         mono_emulate_opcode (cfg, tree, iargs, info);
9192
9193                         dec_foreach (iargs [0], cfg);
9194                         dec_foreach (iargs [1], cfg);
9195                         return;
9196                 } else {
9197                         dec_foreach (tree->inst_left, cfg);
9198                         dec_foreach (tree->inst_right, cfg);
9199                 }
9200                 break;
9201         default:
9202                 g_assert_not_reached ();
9203         }
9204 }
9205
9206 static void
9207 decompose_pass (MonoCompile *cfg) {
9208         MonoBasicBlock *bb;
9209
9210         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
9211                 MonoInst *tree;
9212                 cfg->cbb = bb;
9213                 cfg->prev_ins = NULL;
9214                 for (tree = cfg->cbb->code; tree; tree = tree->next) {
9215                         dec_foreach (tree, cfg);
9216                         cfg->prev_ins = tree;
9217                 }
9218         }
9219 }
9220
9221 static void
9222 nullify_basic_block (MonoBasicBlock *bb) 
9223 {
9224         bb->in_count = 0;
9225         bb->out_count = 0;
9226         bb->in_bb = NULL;
9227         bb->out_bb = NULL;
9228         bb->next_bb = NULL;
9229         bb->code = bb->last_ins = NULL;
9230         bb->cil_code = NULL;
9231 }
9232
9233 static void 
9234 replace_out_block (MonoBasicBlock *bb, MonoBasicBlock *orig,  MonoBasicBlock *repl)
9235 {
9236         int i;
9237
9238         for (i = 0; i < bb->out_count; i++) {
9239                 MonoBasicBlock *ob = bb->out_bb [i];
9240                 if (ob == orig) {
9241                         if (!repl) {
9242                                 if (bb->out_count > 1) {
9243                                         bb->out_bb [i] = bb->out_bb [bb->out_count - 1];
9244                                 }
9245                                 bb->out_count--;
9246                         } else {
9247                                 bb->out_bb [i] = repl;
9248                         }
9249                 }
9250         }
9251 }
9252
9253 static void 
9254 replace_in_block (MonoBasicBlock *bb, MonoBasicBlock *orig, MonoBasicBlock *repl)
9255 {
9256         int i;
9257
9258         for (i = 0; i < bb->in_count; i++) {
9259                 MonoBasicBlock *ib = bb->in_bb [i];
9260                 if (ib == orig) {
9261                         if (!repl) {
9262                                 if (bb->in_count > 1) {
9263                                         bb->in_bb [i] = bb->in_bb [bb->in_count - 1];
9264                                 }
9265                                 bb->in_count--;
9266                         } else {
9267                                 bb->in_bb [i] = repl;
9268                         }
9269                 }
9270         }
9271 }
9272
9273 static void
9274 replace_out_block_in_code (MonoBasicBlock *bb, MonoBasicBlock *orig, MonoBasicBlock *repl) {
9275         MonoInst *inst;
9276         
9277         for (inst = bb->code; inst != NULL; inst = inst->next) {
9278                 if (inst->opcode == OP_CALL_HANDLER) {
9279                         if (inst->inst_target_bb == orig) {
9280                                 inst->inst_target_bb = repl;
9281                         }
9282                 }
9283         }
9284         if (bb->last_ins != NULL) {
9285                 switch (bb->last_ins->opcode) {
9286                 case CEE_BR:
9287                         if (bb->last_ins->inst_target_bb == orig) {
9288                                 bb->last_ins->inst_target_bb = repl;
9289                         }
9290                         break;
9291                 case CEE_SWITCH: {
9292                         int i;
9293                         int n = GPOINTER_TO_INT (bb->last_ins->klass);
9294                         for (i = 0; i < n; i++ ) {
9295                                 if (bb->last_ins->inst_many_bb [i] == orig) {
9296                                         bb->last_ins->inst_many_bb [i] = repl;
9297                                 }
9298                         }
9299                         break;
9300                 }
9301                 case CEE_BNE_UN:
9302                 case CEE_BEQ:
9303                 case CEE_BLT:
9304                 case CEE_BLT_UN:
9305                 case CEE_BGT:
9306                 case CEE_BGT_UN:
9307                 case CEE_BGE:
9308                 case CEE_BGE_UN:
9309                 case CEE_BLE:
9310                 case CEE_BLE_UN:
9311                         if (bb->last_ins->inst_true_bb == orig) {
9312                                 bb->last_ins->inst_true_bb = repl;
9313                         }
9314                         if (bb->last_ins->inst_false_bb == orig) {
9315                                 bb->last_ins->inst_false_bb = repl;
9316                         }
9317                         break;
9318                 default:
9319                         break;
9320                 }
9321         }
9322 }
9323
9324 static void 
9325 replace_basic_block (MonoBasicBlock *bb, MonoBasicBlock *orig,  MonoBasicBlock *repl)
9326 {
9327         int i, j;
9328
9329         for (i = 0; i < bb->out_count; i++) {
9330                 MonoBasicBlock *ob = bb->out_bb [i];
9331                 for (j = 0; j < ob->in_count; j++) {
9332                         if (ob->in_bb [j] == orig) {
9333                                 ob->in_bb [j] = repl;
9334                         }
9335                 }
9336         }
9337
9338 }
9339
9340 /**
9341   * Check if a bb is useless (is just made of NOPs and ends with an
9342   * unconditional branch, or nothing).
9343   * If it is so, unlink it from the CFG and nullify it, and return TRUE.
9344   * Otherwise, return FALSE;
9345   */
9346 static gboolean
9347 remove_block_if_useless (MonoCompile *cfg, MonoBasicBlock *bb, MonoBasicBlock *previous_bb) {
9348         MonoBasicBlock *target_bb = NULL;
9349         MonoInst *inst;
9350         
9351         /* Do not touch handlers */
9352         if (bb->region != -1) {
9353                 bb->not_useless = TRUE;
9354                 return FALSE;
9355         }
9356         
9357         for (inst = bb->code; inst != NULL; inst = inst->next) {
9358                 switch (inst->opcode) {
9359                 case CEE_NOP:
9360                         break;
9361                 case CEE_BR:
9362                         target_bb = inst->inst_target_bb;
9363                         break;
9364                 default:
9365                         bb->not_useless = TRUE;
9366                         return FALSE;
9367                 }
9368         }
9369         
9370         if (target_bb == NULL) {
9371                 if ((bb->out_count == 1) && (bb->out_bb [0] == bb->next_bb)) {
9372                         target_bb = bb->next_bb;
9373                 } else {
9374                         /* Do not touch empty BBs that do not "fall through" to their next BB (like the exit BB) */
9375                         return FALSE;
9376                 }
9377         }
9378         
9379         /* Do not touch BBs following a switch (they are the "default" branch) */
9380         if ((previous_bb->last_ins != NULL) && (previous_bb->last_ins->opcode == CEE_SWITCH)) {
9381                 return FALSE;
9382         }
9383         
9384         /* Do not touch BBs following the entry BB and jumping to something that is not */
9385         /* thiry "next" bb (the entry BB cannot contain the branch) */
9386         if ((previous_bb == cfg->bb_entry) && (bb->next_bb != target_bb)) {
9387                 return FALSE;
9388         }
9389
9390         /* 
9391          * Do not touch BBs following a try block as the code in 
9392          * mini_method_compile needs them to compute the length of the try block.
9393          */
9394         if (MONO_BBLOCK_IS_IN_REGION (previous_bb, MONO_REGION_TRY))
9395                 return FALSE;
9396         
9397         /* Check that there is a target BB, and that bb is not an empty loop (Bug 75061) */
9398         if ((target_bb != NULL) && (target_bb != bb)) {
9399                 int i;
9400
9401                 if (cfg->verbose_level > 1) {
9402                         printf ("remove_block_if_useless %s, removed BB%d\n", mono_method_full_name (cfg->method, TRUE), bb->block_num);
9403                 }
9404                 
9405                 /* unlink_bblock () modifies the bb->in_bb array so can't use a for loop here */
9406                 while (bb->in_count) {
9407                         MonoBasicBlock *in_bb = bb->in_bb [0];
9408                         mono_unlink_bblock (cfg, in_bb, bb);
9409                         link_bblock (cfg, in_bb, target_bb);
9410                         replace_out_block_in_code (in_bb, bb, target_bb);
9411                 }
9412                 
9413                 mono_unlink_bblock (cfg, bb, target_bb);
9414                 
9415                 if ((previous_bb != cfg->bb_entry) &&
9416                                 (previous_bb->region == bb->region) &&
9417                                 ((previous_bb->last_ins == NULL) ||
9418                                 ((previous_bb->last_ins->opcode != CEE_BR) &&
9419                                 (! (MONO_IS_COND_BRANCH_OP (previous_bb->last_ins))) &&
9420                                 (previous_bb->last_ins->opcode != CEE_SWITCH)))) {
9421                         for (i = 0; i < previous_bb->out_count; i++) {
9422                                 if (previous_bb->out_bb [i] == target_bb) {
9423                                         MonoInst *jump;
9424                                         MONO_INST_NEW (cfg, jump, CEE_BR);
9425                                         MONO_ADD_INS (previous_bb, jump);
9426                                         jump->cil_code = previous_bb->cil_code;
9427                                         jump->inst_target_bb = target_bb;
9428                                         break;
9429                                 }
9430                         }
9431                 }
9432                 
9433                 previous_bb->next_bb = bb->next_bb;
9434                 nullify_basic_block (bb);
9435                 
9436                 return TRUE;
9437         } else {
9438                 return FALSE;
9439         }
9440 }
9441
9442 static void
9443 merge_basic_blocks (MonoBasicBlock *bb, MonoBasicBlock *bbn) 
9444 {
9445         bb->out_count = bbn->out_count;
9446         bb->out_bb = bbn->out_bb;
9447
9448         replace_basic_block (bb, bbn, bb);
9449
9450         /* Nullify branch at the end of bb */
9451         if (bb->last_ins && MONO_IS_BRANCH_OP (bb->last_ins)) {
9452                 bb->last_ins->opcode = CEE_NOP;
9453         }               
9454
9455         if (bb->last_ins) {
9456                 if (bbn->code) {
9457                         bb->last_ins->next = bbn->code;
9458                         bb->last_ins = bbn->last_ins;
9459                 }
9460         } else {
9461                 bb->code = bbn->code;
9462                 bb->last_ins = bbn->last_ins;
9463         }
9464         bb->next_bb = bbn->next_bb;
9465         nullify_basic_block (bbn);
9466 }
9467
9468 static void
9469 move_basic_block_to_end (MonoCompile *cfg, MonoBasicBlock *bb)
9470 {
9471         MonoBasicBlock *bbn, *next;
9472
9473         next = bb->next_bb;
9474
9475         /* Find the previous */
9476         for (bbn = cfg->bb_entry; bbn->next_bb && bbn->next_bb != bb; bbn = bbn->next_bb)
9477                 ;
9478         if (bbn->next_bb) {
9479                 bbn->next_bb = bb->next_bb;
9480         }
9481
9482         /* Find the last */
9483         for (bbn = cfg->bb_entry; bbn->next_bb; bbn = bbn->next_bb)
9484                 ;
9485         bbn->next_bb = bb;
9486         bb->next_bb = NULL;
9487
9488         /* Add a branch */
9489         if (next && (!bb->last_ins || (bb->last_ins->opcode != OP_NOT_REACHED))) {
9490                 MonoInst *ins;
9491
9492                 MONO_INST_NEW (cfg, ins, CEE_BR);
9493                 MONO_ADD_INS (bb, ins);
9494                 link_bblock (cfg, bb, next);
9495                 ins->inst_target_bb = next;
9496         }               
9497 }
9498
9499 /* checks that a and b represent the same instructions, conservatively,
9500  * it can return FALSE also for two trees that are equal.
9501  * FIXME: also make sure there are no side effects.
9502  */
9503 static int
9504 same_trees (MonoInst *a, MonoInst *b)
9505 {
9506         int arity;
9507         if (a->opcode != b->opcode)
9508                 return FALSE;
9509         arity = mono_burg_arity [a->opcode];
9510         if (arity == 1) {
9511                 if (a->ssa_op == b->ssa_op && a->ssa_op == MONO_SSA_LOAD && a->inst_i0 == b->inst_i0)
9512                         return TRUE;
9513                 return same_trees (a->inst_left, b->inst_left);
9514         } else if (arity == 2) {
9515                 return same_trees (a->inst_left, b->inst_left) && same_trees (a->inst_right, b->inst_right);
9516         } else if (arity == 0) {
9517                 switch (a->opcode) {
9518                 case OP_ICONST:
9519                         return a->inst_c0 == b->inst_c0;
9520                 default:
9521                         return FALSE;
9522                 }
9523         }
9524         return FALSE;
9525 }
9526
9527 static int
9528 get_unsigned_condbranch (int opcode)
9529 {
9530         switch (opcode) {
9531         case CEE_BLE: return CEE_BLE_UN;
9532         case CEE_BLT: return CEE_BLT_UN;
9533         case CEE_BGE: return CEE_BGE_UN;
9534         case CEE_BGT: return CEE_BGT_UN;
9535         }
9536         g_assert_not_reached ();
9537         return 0;
9538 }
9539
9540 static int
9541 tree_is_unsigned (MonoInst* ins) {
9542         switch (ins->opcode) {
9543         case OP_ICONST:
9544                 return (int)ins->inst_c0 >= 0;
9545         /* array lengths are positive as are string sizes */
9546         case CEE_LDLEN:
9547         case OP_STRLEN:
9548                 return TRUE;
9549         case CEE_CONV_U1:
9550         case CEE_CONV_U2:
9551         case CEE_CONV_U4:
9552         case CEE_CONV_OVF_U1:
9553         case CEE_CONV_OVF_U2:
9554         case CEE_CONV_OVF_U4:
9555                 return TRUE;
9556         case CEE_LDIND_U1:
9557         case CEE_LDIND_U2:
9558         case CEE_LDIND_U4:
9559                 return TRUE;
9560         default:
9561                 return FALSE;
9562         }
9563 }
9564
9565 /* check if an unsigned compare can be used instead of two signed compares
9566  * for (val < 0 || val > limit) conditionals.
9567  * Returns TRUE if the optimization has been applied.
9568  * Note that this can't be applied if the second arg is not positive...
9569  */
9570 static int
9571 try_unsigned_compare (MonoCompile *cfg, MonoBasicBlock *bb)
9572 {
9573         MonoBasicBlock *truet, *falset;
9574         MonoInst *cmp_inst = bb->last_ins->inst_left;
9575         MonoInst *condb;
9576         if (!cmp_inst->inst_right->inst_c0 == 0)
9577                 return FALSE;
9578         truet = bb->last_ins->inst_true_bb;
9579         falset = bb->last_ins->inst_false_bb;
9580         if (falset->in_count != 1)
9581                 return FALSE;
9582         condb = falset->last_ins;
9583         /* target bb must have one instruction */
9584         if (!condb || (condb != falset->code))
9585                 return FALSE;
9586         if ((((condb->opcode == CEE_BLE || condb->opcode == CEE_BLT) && (condb->inst_false_bb == truet))
9587                         || ((condb->opcode == CEE_BGE || condb->opcode == CEE_BGT) && (condb->inst_true_bb == truet)))
9588                         && same_trees (cmp_inst->inst_left, condb->inst_left->inst_left)) {
9589                 if (!tree_is_unsigned (condb->inst_left->inst_right))
9590                         return FALSE;
9591                 condb->opcode = get_unsigned_condbranch (condb->opcode);
9592                 /* change the original condbranch to just point to the new unsigned check */
9593                 bb->last_ins->opcode = CEE_BR;
9594                 bb->last_ins->inst_target_bb = falset;
9595                 replace_out_block (bb, truet, NULL);
9596                 replace_in_block (truet, bb, NULL);
9597                 return TRUE;
9598         }
9599         return FALSE;
9600 }
9601
9602 /*
9603  * Optimizes the branches on the Control Flow Graph
9604  *
9605  */
9606 static void
9607 optimize_branches (MonoCompile *cfg)
9608 {
9609         int i, changed = FALSE;
9610         MonoBasicBlock *bb, *bbn;
9611         guint32 niterations;
9612
9613         /*
9614          * Some crazy loops could cause the code below to go into an infinite
9615          * loop, see bug #53003 for an example. To prevent this, we put an upper
9616          * bound on the number of iterations.
9617          */
9618         if (cfg->num_bblocks > 1000)
9619                 niterations = cfg->num_bblocks * 2;
9620         else
9621                 niterations = 1000;
9622
9623         do {
9624                 MonoBasicBlock *previous_bb;
9625                 changed = FALSE;
9626                 niterations --;
9627
9628                 /* we skip the entry block (exit is handled specially instead ) */
9629                 for (previous_bb = cfg->bb_entry, bb = cfg->bb_entry->next_bb; bb; previous_bb = bb, bb = bb->next_bb) {
9630
9631                         /* dont touch code inside exception clauses */
9632                         if (bb->region != -1)
9633                                 continue;
9634
9635                         if (!bb->not_useless && remove_block_if_useless (cfg, bb, previous_bb)) {
9636                                 changed = TRUE;
9637                                 continue;
9638                         }
9639
9640                         if ((bbn = bb->next_bb) && bbn->in_count == 0 && bb->region == bbn->region) {
9641                                 if (cfg->verbose_level > 2)
9642                                         g_print ("nullify block triggered %d\n", bbn->block_num);
9643
9644                                 bb->next_bb = bbn->next_bb;
9645
9646                                 for (i = 0; i < bbn->out_count; i++)
9647                                         replace_in_block (bbn->out_bb [i], bbn, NULL);
9648
9649                                 nullify_basic_block (bbn);                      
9650                                 changed = TRUE;
9651                         }
9652
9653                         if (bb->out_count == 1) {
9654                                 bbn = bb->out_bb [0];
9655
9656                                 /* conditional branches where true and false targets are the same can be also replaced with CEE_BR */
9657                                 if (bb->last_ins && MONO_IS_COND_BRANCH_OP (bb->last_ins)) {
9658                                         MonoInst *pop;
9659                                         MONO_INST_NEW (cfg, pop, CEE_POP);
9660                                         pop->inst_left = bb->last_ins->inst_left->inst_left;
9661                                         mono_add_ins_to_end (bb, pop);
9662                                         MONO_INST_NEW (cfg, pop, CEE_POP);
9663                                         pop->inst_left = bb->last_ins->inst_left->inst_right;
9664                                         mono_add_ins_to_end (bb, pop);
9665                                         bb->last_ins->opcode = CEE_BR;
9666                                         bb->last_ins->inst_target_bb = bb->last_ins->inst_true_bb;
9667                                         changed = TRUE;
9668                                         if (cfg->verbose_level > 2)
9669                                                 g_print ("cond branch removal triggered in %d %d\n", bb->block_num, bb->out_count);
9670                                 }
9671
9672                                 if (bb->region == bbn->region && bb->next_bb == bbn) {
9673                                         /* the block are in sequence anyway ... */
9674
9675                                         /* branches to the following block can be removed */
9676                                         if (bb->last_ins && bb->last_ins->opcode == CEE_BR) {
9677                                                 bb->last_ins->opcode = CEE_NOP;
9678                                                 changed = TRUE;
9679                                                 if (cfg->verbose_level > 2)
9680                                                         g_print ("br removal triggered %d -> %d\n", bb->block_num, bbn->block_num);
9681                                         }
9682
9683                                         if (bbn->in_count == 1) {
9684
9685                                                 if (bbn != cfg->bb_exit) {
9686                                                         if (cfg->verbose_level > 2)
9687                                                                 g_print ("block merge triggered %d -> %d\n", bb->block_num, bbn->block_num);
9688                                                         merge_basic_blocks (bb, bbn);
9689                                                         changed = TRUE;
9690                                                         continue;
9691                                                 }
9692
9693                                                 //mono_print_bb_code (bb);
9694                                         }
9695                                 }
9696                         }
9697                         if ((bbn = bb->next_bb) && bbn->in_count == 0 && bb->region == bbn->region) {
9698                                 if (cfg->verbose_level > 2) {
9699                                         g_print ("nullify block triggered %d\n", bbn->block_num);
9700                                 }
9701                                 bb->next_bb = bbn->next_bb;
9702
9703                                 for (i = 0; i < bbn->out_count; i++)
9704                                         replace_in_block (bbn->out_bb [i], bbn, NULL);
9705
9706                                 nullify_basic_block (bbn);                      
9707                                 changed = TRUE;
9708                                 continue;
9709                         }
9710
9711                         if (bb->out_count == 1) {
9712                                 bbn = bb->out_bb [0];
9713
9714                                 if (bb->last_ins && bb->last_ins->opcode == CEE_BR) {
9715                                         bbn = bb->last_ins->inst_target_bb;
9716                                         if (bb->region == bbn->region && bbn->code && bbn->code->opcode == CEE_BR &&
9717                                             bbn->code->inst_target_bb->region == bb->region) {
9718                                                 
9719                                                 if (cfg->verbose_level > 2)
9720                                                         g_print ("in %s branch to branch triggered %d -> %d -> %d\n", cfg->method->name, 
9721                                                                  bb->block_num, bbn->block_num, bbn->code->inst_target_bb->block_num);
9722
9723                                                 replace_in_block (bbn, bb, NULL);
9724                                                 replace_out_block (bb, bbn, bbn->code->inst_target_bb);
9725                                                 link_bblock (cfg, bb, bbn->code->inst_target_bb);
9726                                                 bb->last_ins->inst_target_bb = bbn->code->inst_target_bb;
9727                                                 changed = TRUE;
9728                                                 continue;
9729                                         }
9730                                 }
9731                         } else if (bb->out_count == 2) {
9732                                 if (bb->last_ins && MONO_IS_COND_BRANCH_NOFP (bb->last_ins)) {
9733                                         int branch_result = mono_eval_cond_branch (bb->last_ins);
9734                                         MonoBasicBlock *taken_branch_target = NULL, *untaken_branch_target = NULL;
9735                                         if (branch_result == BRANCH_TAKEN) {
9736                                                 taken_branch_target = bb->last_ins->inst_true_bb;
9737                                                 untaken_branch_target = bb->last_ins->inst_false_bb;
9738                                         } else if (branch_result == BRANCH_NOT_TAKEN) {
9739                                                 taken_branch_target = bb->last_ins->inst_false_bb;
9740                                                 untaken_branch_target = bb->last_ins->inst_true_bb;
9741                                         }
9742                                         if (taken_branch_target) {
9743                                                 /* if mono_eval_cond_branch () is ever taken to handle 
9744                                                  * non-constant values to compare, issue a pop here.
9745                                                  */
9746                                                 bb->last_ins->opcode = CEE_BR;
9747                                                 bb->last_ins->inst_target_bb = taken_branch_target;
9748                                                 mono_unlink_bblock (cfg, bb, untaken_branch_target);
9749                                                 changed = TRUE;
9750                                                 continue;
9751                                         }
9752                                         bbn = bb->last_ins->inst_true_bb;
9753                                         if (bb->region == bbn->region && bbn->code && bbn->code->opcode == CEE_BR &&
9754                                             bbn->code->inst_target_bb->region == bb->region) {
9755                                                 if (cfg->verbose_level > 2)             
9756                                                         g_print ("cbranch1 to branch triggered %d -> (%d) %d (0x%02x)\n", 
9757                                                                  bb->block_num, bbn->block_num, bbn->code->inst_target_bb->block_num, 
9758                                                                  bbn->code->opcode);
9759
9760                                                 /* 
9761                                                  * Unlink, then relink bblocks to avoid various
9762                                                  * tricky situations when the two targets of the branch
9763                                                  * are equal, or will become equal after the change.
9764                                                  */
9765                                                 mono_unlink_bblock (cfg, bb, bb->last_ins->inst_true_bb);
9766                                                 mono_unlink_bblock (cfg, bb, bb->last_ins->inst_false_bb);
9767
9768                                                 bb->last_ins->inst_true_bb = bbn->code->inst_target_bb;
9769
9770                                                 link_bblock (cfg, bb, bb->last_ins->inst_true_bb);
9771                                                 link_bblock (cfg, bb, bb->last_ins->inst_false_bb);
9772
9773                                                 changed = TRUE;
9774                                                 continue;
9775                                         }
9776
9777                                         bbn = bb->last_ins->inst_false_bb;
9778                                         if (bb->region == bbn->region && bbn->code && bbn->code->opcode == CEE_BR &&
9779                                             bbn->code->inst_target_bb->region == bb->region) {
9780                                                 if (cfg->verbose_level > 2)
9781                                                         g_print ("cbranch2 to branch triggered %d -> (%d) %d (0x%02x)\n", 
9782                                                                  bb->block_num, bbn->block_num, bbn->code->inst_target_bb->block_num, 
9783                                                                  bbn->code->opcode);
9784
9785                                                 mono_unlink_bblock (cfg, bb, bb->last_ins->inst_true_bb);
9786                                                 mono_unlink_bblock (cfg, bb, bb->last_ins->inst_false_bb);
9787
9788                                                 bb->last_ins->inst_false_bb = bbn->code->inst_target_bb;
9789
9790                                                 link_bblock (cfg, bb, bb->last_ins->inst_true_bb);
9791                                                 link_bblock (cfg, bb, bb->last_ins->inst_false_bb);
9792
9793                                                 changed = TRUE;
9794                                                 continue;
9795                                         }
9796                                 }
9797
9798                                 /* detect and optimize to unsigned compares checks like: if (v < 0 || v > limit */
9799                                 if (bb->last_ins && bb->last_ins->opcode == CEE_BLT && bb->last_ins->inst_left->inst_right->opcode == OP_ICONST) {
9800                                         if (try_unsigned_compare (cfg, bb)) {
9801                                                 /*g_print ("applied in bb %d (->%d) %s\n", bb->block_num, bb->last_ins->inst_target_bb->block_num, mono_method_full_name (cfg->method, TRUE));*/
9802                                                 changed = TRUE;
9803                                                 continue;
9804                                         }
9805                                 }
9806
9807                                 if (bb->last_ins && MONO_IS_COND_BRANCH_NOFP (bb->last_ins)) {
9808                                         if (bb->last_ins->inst_false_bb->out_of_line && (bb->region == bb->last_ins->inst_false_bb->region)) {
9809                                                 /* Reverse the branch */
9810                                                 bb->last_ins->opcode = reverse_branch_op (bb->last_ins->opcode);
9811                                                 bbn = bb->last_ins->inst_false_bb;
9812                                                 bb->last_ins->inst_false_bb = bb->last_ins->inst_true_bb;
9813                                                 bb->last_ins->inst_true_bb = bbn;
9814
9815                                                 move_basic_block_to_end (cfg, bb->last_ins->inst_true_bb);
9816                                                 if (cfg->verbose_level > 2)
9817                                                         g_print ("cbranch to throw block triggered %d.\n", 
9818                                                                          bb->block_num);
9819                                         }
9820                                 }
9821                         }
9822                 }
9823         } while (changed && (niterations > 0));
9824
9825 }
9826
9827 static void
9828 mono_compile_create_vars (MonoCompile *cfg)
9829 {
9830         MonoMethodSignature *sig;
9831         MonoMethodHeader *header;
9832         int i;
9833
9834         header = mono_method_get_header (cfg->method);
9835
9836         sig = mono_method_signature (cfg->method);
9837         
9838         if (!MONO_TYPE_IS_VOID (sig->ret)) {
9839                 cfg->ret = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst));
9840                 cfg->ret->opcode = OP_RETARG;
9841                 cfg->ret->inst_vtype = sig->ret;
9842                 cfg->ret->klass = mono_class_from_mono_type (sig->ret);
9843         }
9844         if (cfg->verbose_level > 2)
9845                 g_print ("creating vars\n");
9846
9847         if (sig->hasthis)
9848                 mono_compile_create_var (cfg, &cfg->method->klass->this_arg, OP_ARG);
9849
9850         for (i = 0; i < sig->param_count; ++i) {
9851                 mono_compile_create_var (cfg, sig->params [i], OP_ARG);
9852                 if (sig->params [i]->byref) {
9853                         cfg->disable_ssa = TRUE;
9854                 }
9855         }
9856
9857         cfg->locals_start = cfg->num_varinfo;
9858
9859         if (cfg->verbose_level > 2)
9860                 g_print ("creating locals\n");
9861         for (i = 0; i < header->num_locals; ++i)
9862                 mono_compile_create_var (cfg, header->locals [i], OP_LOCAL);
9863         if (cfg->verbose_level > 2)
9864                 g_print ("locals done\n");
9865
9866 #ifdef MONO_ARCH_HAVE_CREATE_VARS
9867         mono_arch_create_vars (cfg);
9868 #endif
9869 }
9870
9871 void
9872 mono_print_code (MonoCompile *cfg)
9873 {
9874         MonoBasicBlock *bb;
9875         
9876         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
9877                 MonoInst *tree = bb->code;      
9878
9879                 if (!tree)
9880                         continue;
9881                 
9882                 g_print ("CODE BLOCK %d (nesting %d):\n", bb->block_num, bb->nesting);
9883
9884                 for (; tree; tree = tree->next) {
9885                         mono_print_tree (tree);
9886                         g_print ("\n");
9887                 }
9888
9889                 if (bb->last_ins)
9890                         bb->last_ins->next = NULL;
9891         }
9892 }
9893
9894 extern const char * const mono_burg_rule_string [];
9895
9896 static void
9897 emit_state (MonoCompile *cfg, MBState *state, int goal)
9898 {
9899         MBState *kids [10];
9900         int ern = mono_burg_rule (state, goal);
9901         const guint16 *nts = mono_burg_nts_data + mono_burg_nts [ern];
9902
9903         //g_print ("rule: %s\n", mono_burg_rule_string [ern]);
9904         switch (goal) {
9905         case MB_NTERM_reg:
9906                 //if (state->reg2)
9907                 //      state->reg1 = state->reg2; /* chain rule */
9908                 //else
9909 #ifdef MONO_ARCH_ENABLE_EMIT_STATE_OPT
9910                 if (!state->reg1)
9911 #endif
9912                         state->reg1 = mono_regstate_next_int (cfg->rs);
9913                 //g_print ("alloc symbolic R%d (reg2: R%d) in block %d\n", state->reg1, state->reg2, cfg->cbb->block_num);
9914                 break;
9915         case MB_NTERM_lreg:
9916                 state->reg1 = mono_regstate_next_int (cfg->rs);
9917                 state->reg2 = mono_regstate_next_int (cfg->rs);
9918                 break;
9919         case MB_NTERM_freg:
9920 #ifdef MONO_ARCH_SOFT_FLOAT
9921                 state->reg1 = mono_regstate_next_int (cfg->rs);
9922                 state->reg2 = mono_regstate_next_int (cfg->rs);
9923 #else
9924                 state->reg1 = mono_regstate_next_float (cfg->rs);
9925 #endif
9926                 break;
9927         default:
9928 #ifdef MONO_ARCH_ENABLE_EMIT_STATE_OPT
9929                 /*
9930                  * Enabling this might cause bugs to surface in the local register
9931                  * allocators on some architectures like x86.
9932                  */
9933                 if ((state->tree->ssa_op == MONO_SSA_STORE) && (state->left->tree->opcode == OP_REGVAR)) {
9934                         /* Do not optimize away reg-reg moves */
9935                         if (! ((state->right->tree->ssa_op == MONO_SSA_LOAD) && (state->right->left->tree->opcode == OP_REGVAR))) {
9936                                 state->right->reg1 = state->left->tree->dreg;
9937                         }
9938                 }
9939 #endif
9940
9941                 /* do nothing */
9942                 break;
9943         }
9944         if (nts [0]) {
9945                 mono_burg_kids (state, ern, kids);
9946
9947                 emit_state (cfg, kids [0], nts [0]);
9948                 if (nts [1]) {
9949                         emit_state (cfg, kids [1], nts [1]);
9950                         if (nts [2]) {
9951                                 g_assert (!nts [3]);
9952                                 emit_state (cfg, kids [2], nts [2]);
9953                         }
9954                 }
9955         }
9956
9957 //      g_print ("emit: %s (%p)\n", mono_burg_rule_string [ern], state);
9958         mono_burg_emit (ern, state, state->tree, cfg);
9959 }
9960
9961 #define DEBUG_SELECTION
9962
9963 static void 
9964 mini_select_instructions (MonoCompile *cfg)
9965 {
9966         MonoBasicBlock *bb;
9967         
9968         cfg->state_pool = mono_mempool_new ();
9969         cfg->rs = mono_regstate_new ();
9970
9971         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
9972                 if (bb->last_ins && MONO_IS_COND_BRANCH_OP (bb->last_ins) &&
9973                     bb->next_bb != bb->last_ins->inst_false_bb) {
9974
9975                         /* we are careful when inverting, since bugs like #59580
9976                          * could show up when dealing with NaNs.
9977                          */
9978                         if (MONO_IS_COND_BRANCH_NOFP(bb->last_ins) && bb->next_bb == bb->last_ins->inst_true_bb) {
9979                                 MonoBasicBlock *tmp =  bb->last_ins->inst_true_bb;
9980                                 bb->last_ins->inst_true_bb = bb->last_ins->inst_false_bb;
9981                                 bb->last_ins->inst_false_bb = tmp;
9982
9983                                 bb->last_ins->opcode = reverse_branch_op (bb->last_ins->opcode);
9984                         } else {                        
9985                                 MonoInst *inst = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst));
9986                                 inst->opcode = CEE_BR;
9987                                 inst->inst_target_bb = bb->last_ins->inst_false_bb;
9988                                 mono_bblock_add_inst (bb, inst);
9989                         }
9990                 }
9991         }
9992
9993 #ifdef DEBUG_SELECTION
9994         if (cfg->verbose_level >= 4) {
9995         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
9996                 MonoInst *tree = bb->code;      
9997                 g_print ("DUMP BLOCK %d:\n", bb->block_num);
9998                 if (!tree)
9999                         continue;
10000                 for (; tree; tree = tree->next) {
10001                         mono_print_tree (tree);
10002                         g_print ("\n");
10003                 }
10004         }
10005         }
10006 #endif
10007
10008         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
10009                 MonoInst *tree = bb->code, *next;       
10010                 MBState *mbstate;
10011
10012                 if (!tree)
10013                         continue;
10014                 bb->code = NULL;
10015                 bb->last_ins = NULL;
10016                 
10017                 cfg->cbb = bb;
10018                 mono_regstate_reset (cfg->rs);
10019
10020 #ifdef DEBUG_SELECTION
10021                 if (cfg->verbose_level >= 3)
10022                         g_print ("LABEL BLOCK %d:\n", bb->block_num);
10023 #endif
10024                 for (; tree; tree = next) {
10025                         next = tree->next;
10026 #ifdef DEBUG_SELECTION
10027                         if (cfg->verbose_level >= 3) {
10028                                 mono_print_tree (tree);
10029                                 g_print ("\n");
10030                         }
10031 #endif
10032
10033                         if (!(mbstate = mono_burg_label (tree, cfg))) {
10034                                 g_warning ("unable to label tree %p", tree);
10035                                 mono_print_tree (tree);
10036                                 g_print ("\n");                         
10037                                 g_assert_not_reached ();
10038                         }
10039                         emit_state (cfg, mbstate, MB_NTERM_stmt);
10040                 }
10041                 bb->max_vreg = cfg->rs->next_vreg;
10042
10043                 if (bb->last_ins)
10044                         bb->last_ins->next = NULL;
10045
10046                 mono_mempool_empty (cfg->state_pool); 
10047         }
10048         mono_mempool_destroy (cfg->state_pool); 
10049 }
10050
10051 void
10052 mono_codegen (MonoCompile *cfg)
10053 {
10054         MonoJumpInfo *patch_info;
10055         MonoBasicBlock *bb;
10056         int i, max_epilog_size;
10057         guint8 *code;
10058
10059         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
10060                 cfg->spill_count = 0;
10061                 /* we reuse dfn here */
10062                 /* bb->dfn = bb_count++; */
10063                 mono_arch_local_regalloc (cfg, bb);
10064         }
10065
10066         if (cfg->prof_options & MONO_PROFILE_COVERAGE)
10067                 cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, cfg->num_bblocks);
10068
10069         code = mono_arch_emit_prolog (cfg);
10070
10071         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
10072                 code = mono_arch_instrument_prolog (cfg, mono_profiler_method_enter, code, FALSE);
10073
10074         cfg->code_len = code - cfg->native_code;
10075         cfg->prolog_end = cfg->code_len;
10076
10077         mono_debug_open_method (cfg);
10078
10079         /* emit code all basic blocks */
10080         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
10081                 bb->native_offset = cfg->code_len;
10082                 mono_arch_output_basic_block (cfg, bb);
10083
10084                 if (bb == cfg->bb_exit) {
10085                         cfg->epilog_begin = cfg->code_len;
10086
10087                         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE) {
10088                                 code = cfg->native_code + cfg->code_len;
10089                                 code = mono_arch_instrument_epilog (cfg, mono_profiler_method_leave, code, FALSE);
10090                                 cfg->code_len = code - cfg->native_code;
10091                         }
10092
10093                         mono_arch_emit_epilog (cfg);
10094                 }
10095         }
10096
10097         mono_arch_emit_exceptions (cfg);
10098
10099         max_epilog_size = 0;
10100
10101         code = cfg->native_code + cfg->code_len;
10102
10103         /* we always allocate code in cfg->domain->code_mp to increase locality */
10104         cfg->code_size = cfg->code_len + max_epilog_size;
10105         /* fixme: align to MONO_ARCH_CODE_ALIGNMENT */
10106
10107         if (cfg->method->dynamic) {
10108                 /* Allocate the code into a separate memory pool so it can be freed */
10109                 cfg->dynamic_info = g_new0 (MonoJitDynamicMethodInfo, 1);
10110                 cfg->dynamic_info->code_mp = mono_code_manager_new_dynamic ();
10111                 mono_domain_lock (cfg->domain);
10112                 mono_dynamic_code_hash_insert (cfg->domain, cfg->method, cfg->dynamic_info);
10113                 mono_domain_unlock (cfg->domain);
10114
10115                 code = mono_code_manager_reserve (cfg->dynamic_info->code_mp, cfg->code_size);
10116         } else {
10117                 mono_domain_lock (cfg->domain);
10118                 code = mono_code_manager_reserve (cfg->domain->code_mp, cfg->code_size);
10119                 mono_domain_unlock (cfg->domain);
10120         }
10121
10122         memcpy (code, cfg->native_code, cfg->code_len);
10123         g_free (cfg->native_code);
10124         cfg->native_code = code;
10125         code = cfg->native_code + cfg->code_len;
10126   
10127         /* g_assert (((int)cfg->native_code & (MONO_ARCH_CODE_ALIGNMENT - 1)) == 0); */
10128         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
10129                 switch (patch_info->type) {
10130                 case MONO_PATCH_INFO_ABS: {
10131                         MonoJitICallInfo *info = mono_find_jit_icall_by_addr (patch_info->data.target);
10132                         if (info) {
10133                                 //printf ("TEST %s %p\n", info->name, patch_info->data.target);
10134                                 if ((cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) && 
10135                                         strstr (cfg->method->name, info->name))
10136                                         /*
10137                                          * This is an icall wrapper, and this is a call to the
10138                                          * wrapped function.
10139                                          */
10140                                         ;
10141                                 else {
10142                                         /* for these array methods we currently register the same function pointer
10143                                          * since it's a vararg function. But this means that mono_find_jit_icall_by_addr ()
10144                                          * will return the incorrect one depending on the order they are registered.
10145                                          * See tests/test-arr.cs
10146                                          */
10147                                         if (strstr (info->name, "ves_array_new_va_") == NULL && strstr (info->name, "ves_array_element_address_") == NULL) {
10148                                                 patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
10149                                                 patch_info->data.name = info->name;
10150                                         }
10151                                 }
10152                         }
10153                         else {
10154                                 MonoVTable *vtable = mono_find_class_init_trampoline_by_addr (patch_info->data.target);
10155                                 if (vtable) {
10156                                         patch_info->type = MONO_PATCH_INFO_CLASS_INIT;
10157                                         patch_info->data.klass = vtable->klass;
10158                                 }
10159                         }
10160                         break;
10161                 }
10162                 case MONO_PATCH_INFO_SWITCH: {
10163                         gpointer *table;
10164                         if (cfg->method->dynamic) {
10165                                 table = mono_code_manager_reserve (cfg->dynamic_info->code_mp, sizeof (gpointer) * patch_info->data.table->table_size);
10166                         } else {
10167                                 mono_domain_lock (cfg->domain);
10168                                 table = mono_code_manager_reserve (cfg->domain->code_mp, sizeof (gpointer) * patch_info->data.table->table_size);
10169                                 mono_domain_unlock (cfg->domain);
10170                         }
10171
10172                         if (!cfg->compile_aot)
10173                                 /* In the aot case, the patch already points to the correct location */
10174                                 patch_info->ip.i = patch_info->ip.label->inst_c0;
10175                         for (i = 0; i < patch_info->data.table->table_size; i++) {
10176                                 table [i] = GINT_TO_POINTER (patch_info->data.table->table [i]->native_offset);
10177                         }
10178                         patch_info->data.table->table = (MonoBasicBlock**)table;
10179                         break;
10180                 }
10181                 default:
10182                         /* do nothing */
10183                         break;
10184                 }
10185         }
10186        
10187         if (cfg->verbose_level > 0) {
10188                 char* nm = mono_method_full_name (cfg->method, TRUE);
10189                 g_print ("Method %s emitted at %p to %p (code length %d) [%s]\n", 
10190                                  nm, 
10191                                  cfg->native_code, cfg->native_code + cfg->code_len, cfg->code_len, cfg->domain->friendly_name);
10192                 g_free (nm);
10193         }
10194
10195 #ifdef MONO_ARCH_HAVE_SAVE_UNWIND_INFO
10196         mono_arch_save_unwind_info (cfg);
10197 #endif
10198         
10199         mono_arch_patch_code (cfg->method, cfg->domain, cfg->native_code, cfg->patch_info, cfg->run_cctors);
10200
10201         if (cfg->method->dynamic) {
10202                 mono_code_manager_commit (cfg->dynamic_info->code_mp, cfg->native_code, cfg->code_size, cfg->code_len);
10203         } else {
10204                 mono_domain_lock (cfg->domain);
10205                 mono_code_manager_commit (cfg->domain->code_mp, cfg->native_code, cfg->code_size, cfg->code_len);
10206                 mono_domain_unlock (cfg->domain);
10207         }
10208         
10209         mono_arch_flush_icache (cfg->native_code, cfg->code_len);
10210
10211         mono_debug_close_method (cfg);
10212 }
10213
10214
10215
10216 static void
10217 remove_critical_edges (MonoCompile *cfg) {
10218         MonoBasicBlock *bb;
10219         MonoBasicBlock *previous_bb;
10220         
10221         if (cfg->verbose_level > 3) {
10222                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
10223                         int i;
10224                         printf ("remove_critical_edges %s, BEFORE BB%d (in:", mono_method_full_name (cfg->method, TRUE), bb->block_num);
10225                         for (i = 0; i < bb->in_count; i++) {
10226                                 printf (" %d", bb->in_bb [i]->block_num);
10227                         }
10228                         printf (") (out:");
10229                         for (i = 0; i < bb->out_count; i++) {
10230                                 printf (" %d", bb->out_bb [i]->block_num);
10231                         }
10232                         printf (")");
10233                         if (bb->last_ins != NULL) {
10234                                 printf (" ");
10235                                 mono_print_tree (bb->last_ins);
10236                         }
10237                         printf ("\n");
10238                 }
10239         }
10240         
10241         for (previous_bb = cfg->bb_entry, bb = previous_bb->next_bb; bb != NULL; previous_bb = previous_bb->next_bb, bb = bb->next_bb) {
10242                 if (bb->in_count > 1) {
10243                         int in_bb_index;
10244                         for (in_bb_index = 0; in_bb_index < bb->in_count; in_bb_index++) {
10245                                 MonoBasicBlock *in_bb = bb->in_bb [in_bb_index];
10246                                 if (in_bb->out_count > 1) {
10247                                         MonoBasicBlock *new_bb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
10248                                         new_bb->block_num = cfg->num_bblocks++;
10249 //                                      new_bb->real_offset = bb->real_offset;
10250                                         new_bb->region = bb->region;
10251                                         
10252                                         /* Do not alter the CFG while altering the BB list */
10253                                         if (previous_bb->region == bb->region) {
10254                                                 if (previous_bb != cfg->bb_entry) {
10255                                                         /* If previous_bb "followed through" to bb, */
10256                                                         /* keep it linked with a CEE_BR */
10257                                                         if ((previous_bb->last_ins == NULL) ||
10258                                                                         ((previous_bb->last_ins->opcode != CEE_BR) &&
10259                                                                         (! (MONO_IS_COND_BRANCH_OP (previous_bb->last_ins))) &&
10260                                                                         (previous_bb->last_ins->opcode != CEE_SWITCH))) {
10261                                                                 int i;
10262                                                                 /* Make sure previous_bb really falls through bb */
10263                                                                 for (i = 0; i < previous_bb->out_count; i++) {
10264                                                                         if (previous_bb->out_bb [i] == bb) {
10265                                                                                 MonoInst *jump;
10266                                                                                 MONO_INST_NEW (cfg, jump, CEE_BR);
10267                                                                                 MONO_ADD_INS (previous_bb, jump);
10268                                                                                 jump->cil_code = previous_bb->cil_code;
10269                                                                                 jump->inst_target_bb = bb;
10270                                                                                 break;
10271                                                                         }
10272                                                                 }
10273                                                         }
10274                                                 } else {
10275                                                         /* We cannot add any inst to the entry BB, so we must */
10276                                                         /* put a new BB in the middle to hold the CEE_BR */
10277                                                         MonoInst *jump;
10278                                                         MonoBasicBlock *new_bb_after_entry = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
10279                                                         new_bb_after_entry->block_num = cfg->num_bblocks++;
10280 //                                                      new_bb_after_entry->real_offset = bb->real_offset;
10281                                                         new_bb_after_entry->region = bb->region;
10282                                                         
10283                                                         MONO_INST_NEW (cfg, jump, CEE_BR);
10284                                                         MONO_ADD_INS (new_bb_after_entry, jump);
10285                                                         jump->cil_code = bb->cil_code;
10286                                                         jump->inst_target_bb = bb;
10287                                                         
10288                                                         previous_bb->next_bb = new_bb_after_entry;
10289                                                         previous_bb = new_bb_after_entry;
10290                                                         
10291                                                         if (cfg->verbose_level > 2) {
10292                                                                 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);
10293                                                         }
10294                                                 }
10295                                         }
10296                                         
10297                                         /* Insert new_bb in the BB list */
10298                                         previous_bb->next_bb = new_bb;
10299                                         new_bb->next_bb = bb;
10300                                         previous_bb = new_bb;
10301                                         
10302                                         /* Setup in_bb and out_bb */
10303                                         new_bb->in_bb = mono_mempool_alloc ((cfg)->mempool, sizeof (MonoBasicBlock*));
10304                                         new_bb->in_bb [0] = in_bb;
10305                                         new_bb->in_count = 1;
10306                                         new_bb->out_bb = mono_mempool_alloc ((cfg)->mempool, sizeof (MonoBasicBlock*));
10307                                         new_bb->out_bb [0] = bb;
10308                                         new_bb->out_count = 1;
10309                                         
10310                                         /* Relink in_bb and bb to (from) new_bb */
10311                                         replace_out_block (in_bb, bb, new_bb);
10312                                         replace_out_block_in_code (in_bb, bb, new_bb);
10313                                         replace_in_block (bb, in_bb, new_bb);
10314                                         
10315                                         if (cfg->verbose_level > 2) {
10316                                                 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);
10317                                         }
10318                                 }
10319                         }
10320                 }
10321         }
10322         
10323         if (cfg->verbose_level > 3) {
10324                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
10325                         int i;
10326                         printf ("remove_critical_edges %s, AFTER BB%d (in:", mono_method_full_name (cfg->method, TRUE), bb->block_num);
10327                         for (i = 0; i < bb->in_count; i++) {
10328                                 printf (" %d", bb->in_bb [i]->block_num);
10329                         }
10330                         printf (") (out:");
10331                         for (i = 0; i < bb->out_count; i++) {
10332                                 printf (" %d", bb->out_bb [i]->block_num);
10333                         }
10334                         printf (")");
10335                         if (bb->last_ins != NULL) {
10336                                 printf (" ");
10337                                 mono_print_tree (bb->last_ins);
10338                         }
10339                         printf ("\n");
10340                 }
10341         }
10342 }
10343
10344 /*
10345  * mini_method_compile:
10346  * @method: the method to compile
10347  * @opts: the optimization flags to use
10348  * @domain: the domain where the method will be compiled in
10349  * @run_cctors: whether we should run type ctors if possible
10350  * @compile_aot: whether this is an AOT compilation
10351  * @parts: debug flag
10352  *
10353  * Returns: a MonoCompile* pointer. Caller must check the exception_type
10354  * field in the returned struct to see if compilation succeded.
10355  */
10356 MonoCompile*
10357 mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gboolean run_cctors, gboolean compile_aot, int parts)
10358 {
10359         MonoMethodHeader *header = mono_method_get_header (method);
10360         guint8 *ip;
10361         MonoCompile *cfg;
10362         MonoJitInfo *jinfo;
10363         int dfn = 0, i, code_size_ratio;
10364         gboolean deadce_has_run = FALSE;
10365
10366         mono_jit_stats.methods_compiled++;
10367         if (mono_profiler_get_events () & MONO_PROFILE_JIT_COMPILATION)
10368                 mono_profiler_method_jit (method);
10369
10370         cfg = g_new0 (MonoCompile, 1);
10371         cfg->method = method;
10372         cfg->mempool = mono_mempool_new ();
10373         cfg->opt = opts;
10374         cfg->prof_options = mono_profiler_get_events ();
10375         cfg->run_cctors = run_cctors;
10376         cfg->bb_hash = g_hash_table_new (NULL, NULL);
10377         cfg->domain = domain;
10378         cfg->verbose_level = mini_verbose;
10379         cfg->compile_aot = compile_aot;
10380         cfg->skip_visibility = method->skip_visibility;
10381         if (!header) {
10382                 cfg->exception_type = MONO_EXCEPTION_INVALID_PROGRAM;
10383                 cfg->exception_message = g_strdup_printf ("Missing or incorrect header for method %s", cfg->method->name);
10384                 if (cfg->prof_options & MONO_PROFILE_JIT_COMPILATION)
10385                         mono_profiler_method_end_jit (method, NULL, MONO_PROFILE_FAILED);
10386                 return cfg;
10387         }
10388
10389         ip = (guint8 *)header->code;
10390
10391         cfg->intvars = mono_mempool_alloc0 (cfg->mempool, sizeof (guint16) * STACK_MAX * header->max_stack);
10392         cfg->aliasing_info = NULL;
10393         
10394         if (cfg->verbose_level > 2)
10395                 g_print ("converting method %s\n", mono_method_full_name (method, TRUE));
10396
10397         /*
10398          * create MonoInst* which represents arguments and local variables
10399          */
10400         mono_compile_create_vars (cfg);
10401
10402         if ((i = mono_method_to_ir (cfg, method, NULL, NULL, cfg->locals_start, NULL, NULL, NULL, 0, FALSE)) < 0) {
10403                 if (cfg->prof_options & MONO_PROFILE_JIT_COMPILATION)
10404                         mono_profiler_method_end_jit (method, NULL, MONO_PROFILE_FAILED);
10405                 /* cfg contains the details of the failure, so let the caller cleanup */
10406                 return cfg;
10407         }
10408
10409         mono_jit_stats.basic_blocks += cfg->num_bblocks;
10410         mono_jit_stats.max_basic_blocks = MAX (cfg->num_bblocks, mono_jit_stats.max_basic_blocks);
10411
10412         if ((cfg->num_varinfo > 2000) && !cfg->compile_aot) {
10413                 /* 
10414                  * we disable some optimizations if there are too many variables
10415                  * because JIT time may become too expensive. The actual number needs 
10416                  * to be tweaked and eventually the non-linear algorithms should be fixed.
10417                  */
10418                 cfg->opt &= ~ (MONO_OPT_LINEARS | MONO_OPT_COPYPROP | MONO_OPT_CONSPROP);
10419                 cfg->disable_ssa = TRUE;
10420         }
10421
10422         /*g_print ("numblocks = %d\n", cfg->num_bblocks);*/
10423
10424         if (cfg->opt & MONO_OPT_BRANCH)
10425                 optimize_branches (cfg);
10426
10427         if (cfg->opt & MONO_OPT_SSAPRE) {
10428                 remove_critical_edges (cfg);
10429         }
10430
10431         /* Depth-first ordering on basic blocks */
10432         cfg->bblocks = mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * (cfg->num_bblocks + 1));
10433
10434         df_visit (cfg->bb_entry, &dfn, cfg->bblocks);
10435         if (cfg->num_bblocks != dfn + 1) {
10436                 MonoBasicBlock *bb;
10437
10438                 cfg->num_bblocks = dfn + 1;
10439
10440                 if (!header->clauses) {
10441                         /* remove unreachable code, because the code in them may be 
10442                          * inconsistent  (access to dead variables for example) */
10443                         for (bb = cfg->bb_entry; bb;) {
10444                                 MonoBasicBlock *bbn = bb->next_bb;
10445
10446                                 if (bbn && bbn->region == -1 && !bbn->dfn) {
10447                                         if (cfg->verbose_level > 1)
10448                                                 g_print ("found unreachable code in BB%d\n", bbn->block_num);
10449                                         bb->next_bb = bbn->next_bb;
10450                                         nullify_basic_block (bbn);                      
10451                                 } else {
10452                                         bb = bb->next_bb;
10453                                 }
10454                         }
10455                 }
10456         }
10457
10458         if (cfg->opt & MONO_OPT_LOOP) {
10459                 mono_compile_dominator_info (cfg, MONO_COMP_DOM | MONO_COMP_IDOM);
10460                 mono_compute_natural_loops (cfg);
10461         }
10462
10463         /* after method_to_ir */
10464         if (parts == 1)
10465                 return cfg;
10466
10467 //#define DEBUGSSA "logic_run"
10468 #define DEBUGSSA_CLASS "Tests"
10469 #ifdef DEBUGSSA
10470
10471         if (!header->num_clauses && !cfg->disable_ssa) {
10472                 mono_local_cprop (cfg);
10473                 mono_ssa_compute (cfg);
10474         }
10475 #else 
10476
10477         /* fixme: add all optimizations which requires SSA */
10478         if (cfg->opt & (MONO_OPT_SSA | MONO_OPT_ABCREM | MONO_OPT_SSAPRE)) {
10479                 if (!(cfg->comp_done & MONO_COMP_SSA) && !header->num_clauses && !cfg->disable_ssa) {
10480                         mono_local_cprop (cfg);
10481                         mono_ssa_compute (cfg);
10482
10483                         if (cfg->verbose_level >= 2) {
10484                                 print_dfn (cfg);
10485                         }
10486                 }
10487         }
10488 #endif
10489
10490         /* after SSA translation */
10491         if (parts == 2)
10492                 return cfg;
10493
10494         if ((cfg->opt & MONO_OPT_CONSPROP) || (cfg->opt & MONO_OPT_COPYPROP)) {
10495                 if (cfg->comp_done & MONO_COMP_SSA) {
10496                         mono_ssa_cprop (cfg);
10497                 } else {
10498                         mono_local_cprop (cfg);
10499                 }
10500         }
10501
10502         if (cfg->comp_done & MONO_COMP_SSA) {                   
10503                 //mono_ssa_deadce (cfg);
10504
10505                 //mono_ssa_strength_reduction (cfg);
10506
10507                 if (cfg->opt & MONO_OPT_SSAPRE) {
10508                         mono_perform_ssapre (cfg);
10509                         //mono_local_cprop (cfg);
10510                 }
10511                 
10512                 if (cfg->opt & MONO_OPT_DEADCE) {
10513                         mono_ssa_deadce (cfg);
10514                         deadce_has_run = TRUE;
10515                 }
10516                 
10517                 if ((cfg->flags & MONO_CFG_HAS_LDELEMA) && (cfg->opt & MONO_OPT_ABCREM))
10518                         mono_perform_abc_removal (cfg);
10519                 
10520                 mono_ssa_remove (cfg);
10521
10522                 if (cfg->opt & MONO_OPT_BRANCH)
10523                         optimize_branches (cfg);
10524         }
10525
10526         /* after SSA removal */
10527         if (parts == 3)
10528                 return cfg;
10529
10530         if (cfg->verbose_level > 4) {
10531                 printf ("BEFORE DECOMPSE START\n");
10532                 mono_print_code (cfg);
10533                 printf ("BEFORE DECOMPSE END\n");
10534         }
10535         
10536         decompose_pass (cfg);
10537
10538         if (cfg->got_var) {
10539                 GList *regs;
10540
10541                 g_assert (cfg->got_var_allocated);
10542
10543                 /* 
10544                  * Allways allocate the GOT var to a register, because keeping it
10545                  * in memory will increase the number of live temporaries in some
10546                  * code created by inssel.brg, leading to the well known spills+
10547                  * branches problem. Testcase: mcs crash in 
10548                  * System.MonoCustomAttrs:GetCustomAttributes.
10549                  */
10550                 regs = mono_arch_get_global_int_regs (cfg);
10551                 g_assert (regs);
10552                 cfg->got_var->opcode = OP_REGVAR;
10553                 cfg->got_var->dreg = GPOINTER_TO_INT (regs->data);
10554                 cfg->used_int_regs |= 1LL << cfg->got_var->dreg;
10555                 
10556                 g_list_free (regs);
10557         }
10558
10559         /* todo: remove code when we have verified that the liveness for try/catch blocks
10560          * works perfectly 
10561          */
10562         /* 
10563          * Currently, this can't be commented out since exception blocks are not
10564          * processed during liveness analysis.
10565          */
10566         mono_liveness_handle_exception_clauses (cfg);
10567
10568         if (cfg->opt & MONO_OPT_LINEARS) {
10569                 GList *vars, *regs;
10570                 
10571                 /* For now, compute aliasing info only if needed for deadce... */
10572                 if ((cfg->opt & MONO_OPT_DEADCE) && (! deadce_has_run) && (header->num_clauses == 0)) {
10573                         cfg->aliasing_info = mono_build_aliasing_information (cfg);
10574                 }
10575
10576                 /* fixme: maybe we can avoid to compute livenesss here if already computed ? */
10577                 cfg->comp_done &= ~MONO_COMP_LIVENESS;
10578                 if (!(cfg->comp_done & MONO_COMP_LIVENESS))
10579                         mono_analyze_liveness (cfg);
10580
10581                 if (cfg->aliasing_info != NULL) {
10582                         mono_aliasing_deadce (cfg->aliasing_info);
10583                         deadce_has_run = TRUE;
10584                 }
10585                 
10586                 if ((vars = mono_arch_get_allocatable_int_vars (cfg))) {
10587                         regs = mono_arch_get_global_int_regs (cfg);
10588                         if (cfg->got_var)
10589                                 regs = g_list_delete_link (regs, regs);
10590                         mono_linear_scan (cfg, vars, regs, &cfg->used_int_regs);
10591                 }
10592                 
10593                 if (cfg->aliasing_info != NULL) {
10594                         mono_destroy_aliasing_information (cfg->aliasing_info);
10595                         cfg->aliasing_info = NULL;
10596                 }
10597         }
10598
10599         //mono_print_code (cfg);
10600
10601     //print_dfn (cfg);
10602         
10603         /* variables are allocated after decompose, since decompose could create temps */
10604         mono_arch_allocate_vars (cfg);
10605
10606         if (cfg->opt & MONO_OPT_CFOLD)
10607                 mono_constant_fold (cfg);
10608
10609         mini_select_instructions (cfg);
10610
10611         mono_codegen (cfg);
10612         if (cfg->verbose_level >= 2) {
10613                 char *id =  mono_method_full_name (cfg->method, FALSE);
10614                 mono_disassemble_code (cfg, cfg->native_code, cfg->code_len, id + 3);
10615                 g_free (id);
10616         }
10617         
10618         if (cfg->method->dynamic) {
10619                 jinfo = g_malloc0 (sizeof (MonoJitInfo) + (header->num_clauses * sizeof (MonoJitExceptionInfo)));
10620         } else {
10621                 /* we access cfg->domain->mp */
10622                 mono_domain_lock (cfg->domain);
10623                 jinfo = mono_mempool_alloc0 (cfg->domain->mp, sizeof (MonoJitInfo) + (header->num_clauses * sizeof (MonoJitExceptionInfo)));
10624                 mono_domain_unlock (cfg->domain);
10625         }
10626
10627         jinfo->method = method;
10628         jinfo->code_start = cfg->native_code;
10629         jinfo->code_size = cfg->code_len;
10630         jinfo->used_regs = cfg->used_int_regs;
10631         jinfo->domain_neutral = (cfg->opt & MONO_OPT_SHARED) != 0;
10632         jinfo->cas_inited = FALSE; /* initialization delayed at the first stalk walk using this method */
10633
10634         if (header->num_clauses) {
10635                 int i;
10636
10637                 jinfo->num_clauses = header->num_clauses;
10638
10639                 for (i = 0; i < header->num_clauses; i++) {
10640                         MonoExceptionClause *ec = &header->clauses [i];
10641                         MonoJitExceptionInfo *ei = &jinfo->clauses [i];
10642                         MonoBasicBlock *tblock;
10643                         MonoInst *exvar;
10644
10645                         ei->flags = ec->flags;
10646
10647                         exvar = mono_find_exvar_for_offset (cfg, ec->handler_offset);
10648                         ei->exvar_offset = exvar ? exvar->inst_offset : 0;
10649
10650                         if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
10651                                 tblock = g_hash_table_lookup (cfg->bb_hash, ip + ec->data.filter_offset);
10652                                 g_assert (tblock);
10653                                 ei->data.filter = cfg->native_code + tblock->native_offset;
10654                         } else {
10655                                 ei->data.catch_class = ec->data.catch_class;
10656                         }
10657
10658                         tblock = g_hash_table_lookup (cfg->bb_hash, ip + ec->try_offset);
10659                         g_assert (tblock);
10660                         ei->try_start = cfg->native_code + tblock->native_offset;
10661                         g_assert (tblock->native_offset);
10662                         tblock = g_hash_table_lookup (cfg->bb_hash, ip + ec->try_offset + ec->try_len);
10663                         g_assert (tblock);
10664                         ei->try_end = cfg->native_code + tblock->native_offset;
10665                         g_assert (tblock->native_offset);
10666                         tblock = g_hash_table_lookup (cfg->bb_hash, ip + ec->handler_offset);
10667                         g_assert (tblock);
10668                         ei->handler_start = cfg->native_code + tblock->native_offset;
10669                 }
10670         }
10671
10672         cfg->jit_info = jinfo;
10673 #if defined(__arm__)
10674         mono_arch_fixup_jinfo (cfg);
10675 #endif
10676
10677         mono_domain_lock (cfg->domain);
10678         mono_jit_info_table_add (cfg->domain, jinfo);
10679
10680         if (cfg->method->dynamic)
10681                 mono_dynamic_code_hash_lookup (cfg->domain, cfg->method)->ji = jinfo;
10682         mono_domain_unlock (cfg->domain);
10683
10684         /* collect statistics */
10685         mono_jit_stats.allocated_code_size += cfg->code_len;
10686         code_size_ratio = cfg->code_len;
10687         if (code_size_ratio > mono_jit_stats.biggest_method_size) {
10688                         mono_jit_stats.biggest_method_size = code_size_ratio;
10689                         mono_jit_stats.biggest_method = method;
10690         }
10691         code_size_ratio = (code_size_ratio * 100) / mono_method_get_header (method)->code_size;
10692         if (code_size_ratio > mono_jit_stats.max_code_size_ratio) {
10693                 mono_jit_stats.max_code_size_ratio = code_size_ratio;
10694                 mono_jit_stats.max_ratio_method = method;
10695         }
10696         mono_jit_stats.native_code_size += cfg->code_len;
10697
10698         if (cfg->prof_options & MONO_PROFILE_JIT_COMPILATION)
10699                 mono_profiler_method_end_jit (method, jinfo, MONO_PROFILE_OK);
10700
10701         return cfg;
10702 }
10703
10704 static gpointer
10705 mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, int opt)
10706 {
10707         MonoCompile *cfg;
10708         GHashTable *jit_code_hash;
10709         gpointer code = NULL;
10710         MonoJitInfo *info;
10711
10712         jit_code_hash = target_domain->jit_code_hash;
10713
10714         method = mono_get_inflated_method (method);
10715
10716 #ifdef MONO_USE_AOT_COMPILER
10717         if ((opt & MONO_OPT_AOT) && !(mono_profiler_get_events () & MONO_PROFILE_JIT_COMPILATION)) {
10718                 MonoDomain *domain = mono_domain_get ();
10719
10720                 mono_class_init (method->klass);
10721
10722                 mono_domain_lock (domain);
10723                 if ((code = mono_aot_get_method (domain, method))) {
10724                         mono_domain_unlock (domain);
10725                         mono_runtime_class_init (mono_class_vtable (domain, method->klass));
10726                         return code;
10727                 }
10728
10729                 mono_domain_unlock (domain);
10730         }
10731 #endif
10732
10733         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
10734             (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
10735                 MonoMethod *nm;
10736                 MonoMethodPInvoke* piinfo = (MonoMethodPInvoke *) method;
10737
10738                 if (method->iflags & METHOD_IMPL_ATTRIBUTE_NATIVE && !MONO_CLASS_IS_IMPORT(method->klass))
10739                         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);
10740
10741                 if (!piinfo->addr) {
10742                         if (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL)
10743                                 piinfo->addr = mono_lookup_internal_call (method);
10744                         else
10745                                 if (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
10746                                         mono_lookup_pinvoke_call (method, NULL, NULL);
10747                 }
10748                         nm = mono_marshal_get_native_wrapper (method);
10749                         return mono_get_addr_from_ftnptr (mono_compile_method (nm));
10750
10751                         //if (mono_debug_format != MONO_DEBUG_FORMAT_NONE) 
10752                         //mono_debug_add_wrapper (method, nm);
10753         } else if ((method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME)) {
10754                 const char *name = method->name;
10755                 MonoMethod *nm;
10756
10757                 if (method->klass->parent == mono_defaults.multicastdelegate_class) {
10758                         if (*name == '.' && (strcmp (name, ".ctor") == 0)) {
10759                                 MonoJitICallInfo *mi = mono_find_jit_icall_by_name ("mono_delegate_ctor");
10760                                 g_assert (mi);
10761                                 return mono_get_addr_from_ftnptr ((gpointer)mono_icall_get_wrapper (mi));
10762                         } else if (*name == 'I' && (strcmp (name, "Invoke") == 0)) {
10763                                 nm = mono_marshal_get_delegate_invoke (method);
10764                                         return mono_get_addr_from_ftnptr (mono_compile_method (nm));
10765                         } else if (*name == 'B' && (strcmp (name, "BeginInvoke") == 0)) {
10766                                 nm = mono_marshal_get_delegate_begin_invoke (method);
10767                                 return mono_get_addr_from_ftnptr (mono_compile_method (nm));
10768                         } else if (*name == 'E' && (strcmp (name, "EndInvoke") == 0)) {
10769                                 nm = mono_marshal_get_delegate_end_invoke (method);
10770                                 return mono_get_addr_from_ftnptr (mono_compile_method (nm));
10771                         }
10772                 }
10773                 return NULL;
10774         }
10775
10776         cfg = mini_method_compile (method, opt, target_domain, TRUE, FALSE, 0);
10777
10778         switch (cfg->exception_type) {
10779         case MONO_EXCEPTION_NONE: break;
10780         case MONO_EXCEPTION_TYPE_LOAD:
10781         case MONO_EXCEPTION_MISSING_FIELD:
10782         case MONO_EXCEPTION_MISSING_METHOD: {
10783                 /* Throw a type load exception if needed */
10784                 MonoLoaderError *error = mono_loader_get_last_error ();
10785
10786                 if (error) {
10787                         MonoException *ex = mono_loader_error_prepare_exception (error);
10788                         mono_destroy_compile (cfg);
10789                         mono_raise_exception (ex);
10790                 } else {
10791                         if (cfg->exception_ptr) {
10792                                 MonoException *ex = mono_class_get_exception_for_failure (cfg->exception_ptr);
10793                                 mono_destroy_compile (cfg);
10794                                 mono_raise_exception (ex);
10795                         }
10796                         g_assert_not_reached ();
10797                 }
10798         }
10799         case MONO_EXCEPTION_INVALID_PROGRAM: {
10800                 MonoException *ex = mono_exception_from_name_msg (mono_defaults.corlib, "System", "InvalidProgramException", cfg->exception_message);
10801                 mono_destroy_compile (cfg);
10802                 mono_raise_exception (ex);
10803                 break;
10804         }
10805         case MONO_EXCEPTION_UNVERIFIABLE_IL: {
10806                 MonoException *ex = mono_exception_from_name_msg (mono_defaults.corlib, "System.Security", "VerificationException", cfg->exception_message);
10807                 mono_destroy_compile (cfg);
10808                 mono_raise_exception (ex);
10809                 break;
10810         }
10811         /* this can only be set if the security manager is active */
10812         case MONO_EXCEPTION_SECURITY_LINKDEMAND: {
10813                 MonoAssembly *assembly = mono_image_get_assembly (method->klass->image);
10814                 MonoReflectionAssembly *refass = (MonoReflectionAssembly*) mono_assembly_get_object (target_domain, assembly);
10815                 MonoReflectionMethod *refmet = mono_method_get_object (target_domain, method, NULL);
10816                 MonoSecurityManager* secman = mono_security_manager_get_methods ();
10817                 MonoObject *exc = NULL;
10818                 gpointer args [3];
10819
10820                 args [0] = &cfg->exception_data;
10821                 args [1] = refass;
10822                 args [2] = refmet;
10823                 mono_runtime_invoke (secman->linkdemandsecurityexception, NULL, args, &exc);
10824
10825                 mono_destroy_compile (cfg);
10826                 cfg = NULL;
10827
10828                 mono_raise_exception ((MonoException*)exc);
10829         }
10830         default:
10831                 g_assert_not_reached ();
10832         }
10833
10834         mono_domain_lock (target_domain);
10835
10836         /* Check if some other thread already did the job. In this case, we can
10837        discard the code this thread generated. */
10838
10839         if ((info = g_hash_table_lookup (target_domain->jit_code_hash, method))) {
10840                 /* We can't use a domain specific method in another domain */
10841                 if ((target_domain == mono_domain_get ()) || info->domain_neutral) {
10842                         code = info->code_start;
10843 //                      printf("Discarding code for method %s\n", method->name);
10844                 }
10845         }
10846         
10847         if (code == NULL) {
10848                 g_hash_table_insert (jit_code_hash, method, cfg->jit_info);
10849                 code = cfg->native_code;
10850         }
10851
10852         mono_destroy_compile (cfg);
10853
10854         if (target_domain->jump_target_hash) {
10855                 MonoJumpInfo patch_info;
10856                 GSList *list, *tmp;
10857                 list = g_hash_table_lookup (target_domain->jump_target_hash, method);
10858                 if (list) {
10859                         patch_info.next = NULL;
10860                         patch_info.ip.i = 0;
10861                         patch_info.type = MONO_PATCH_INFO_METHOD_JUMP;
10862                         patch_info.data.method = method;
10863                         g_hash_table_remove (target_domain->jump_target_hash, method);
10864                 }
10865                 for (tmp = list; tmp; tmp = tmp->next)
10866                         mono_arch_patch_code (NULL, target_domain, tmp->data, &patch_info, TRUE);
10867                 g_slist_free (list);
10868         }
10869
10870         mono_domain_unlock (target_domain);
10871
10872         mono_runtime_class_init (mono_class_vtable (target_domain, method->klass));
10873         return code;
10874 }
10875
10876 static gpointer
10877 mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt)
10878 {
10879         MonoDomain *target_domain, *domain = mono_domain_get ();
10880         MonoJitInfo *info;
10881         gpointer p;
10882         MonoJitICallInfo *callinfo = NULL;
10883
10884         /*
10885          * ICALL wrappers are handled specially, since there is only one copy of them
10886          * shared by all appdomains.
10887          */
10888         if ((method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) && (strstr (method->name, "__icall_wrapper_") == method->name)) {
10889                 const char *icall_name;
10890
10891                 icall_name = method->name + strlen ("__icall_wrapper_");
10892                 g_assert (icall_name);
10893                 callinfo = mono_find_jit_icall_by_name (icall_name);
10894                 g_assert (callinfo);
10895
10896                 /* Must be domain neutral since there is only one copy */
10897                 opt |= MONO_OPT_SHARED;
10898         }
10899
10900         if (opt & MONO_OPT_SHARED)
10901                 target_domain = mono_get_root_domain ();
10902         else 
10903                 target_domain = domain;
10904
10905         mono_domain_lock (target_domain);
10906
10907         if ((info = g_hash_table_lookup (target_domain->jit_code_hash, method))) {
10908                 /* We can't use a domain specific method in another domain */
10909                 if (! ((domain != target_domain) && !info->domain_neutral)) {
10910                         mono_domain_unlock (target_domain);
10911                         mono_jit_stats.methods_lookups++;
10912                         mono_runtime_class_init (mono_class_vtable (domain, method->klass));
10913                         return mono_create_ftnptr (target_domain, info->code_start);
10914                 }
10915         }
10916
10917         mono_domain_unlock (target_domain);
10918         p = mono_create_ftnptr (target_domain, mono_jit_compile_method_inner (method, target_domain, opt));
10919
10920         if (callinfo) {
10921                 mono_jit_lock ();
10922                 if (!callinfo->wrapper) {
10923                         callinfo->wrapper = p;
10924                         mono_register_jit_icall_wrapper (callinfo, p);
10925                         mono_debug_add_icall_wrapper (method, callinfo);
10926                 }
10927                 mono_jit_unlock ();
10928         }
10929
10930         return p;
10931 }
10932
10933 static gpointer
10934 mono_jit_compile_method (MonoMethod *method)
10935 {
10936         return mono_jit_compile_method_with_opt (method, default_opt);
10937 }
10938
10939 static void
10940 invalidated_delegate_trampoline (char *desc)
10941 {
10942         g_error ("Unmanaged code called delegate of type %s which was already garbage collected.\n"
10943                  "See http://www.go-mono.com/delegate.html for an explanation and ways to fix this.",
10944                  desc);
10945 }
10946
10947 /*
10948  * mono_jit_free_method:
10949  *
10950  *  Free all memory allocated by the JIT for METHOD.
10951  */
10952 static void
10953 mono_jit_free_method (MonoDomain *domain, MonoMethod *method)
10954 {
10955         MonoJitDynamicMethodInfo *ji;
10956         gboolean destroy = TRUE;
10957
10958         g_assert (method->dynamic);
10959
10960         mono_domain_lock (domain);
10961         ji = mono_dynamic_code_hash_lookup (domain, method);
10962         mono_domain_unlock (domain);
10963
10964         if (!ji)
10965                 return;
10966         mono_domain_lock (domain);
10967         g_hash_table_remove (domain->dynamic_code_hash, method);
10968         g_hash_table_remove (domain->jit_code_hash, method);
10969         g_hash_table_remove (domain->jump_trampoline_hash, method);
10970         mono_domain_unlock (domain);
10971
10972 #ifdef MONO_ARCH_HAVE_INVALIDATE_METHOD
10973         if (debug_options.keep_delegates && method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
10974                 /*
10975                  * Instead of freeing the code, change it to call an error routine
10976                  * so people can fix their code.
10977                  */
10978                 char *type = mono_type_full_name (&method->klass->byval_arg);
10979                 char *type_and_method = g_strdup_printf ("%s.%s", type, method->name);
10980
10981                 g_free (type);
10982                 mono_arch_invalidate_method (ji->ji, invalidated_delegate_trampoline, type_and_method);
10983                 destroy = FALSE;
10984         }
10985 #endif
10986
10987         /* 
10988          * This needs to be done before freeing code_mp, since the code address is the
10989          * key in the table, so if we the code_mp first, another thread can grab the
10990          * same code address and replace our entry in the table.
10991          */
10992         mono_jit_info_table_remove (domain, ji->ji);
10993
10994         if (destroy)
10995                 mono_code_manager_destroy (ji->code_mp);
10996         g_free (ji->ji);
10997         g_free (ji);
10998 }
10999
11000 static gpointer
11001 mono_jit_find_compiled_method (MonoDomain *domain, MonoMethod *method)
11002 {
11003         MonoDomain *target_domain;
11004         MonoJitInfo *info;
11005
11006         if (default_opt & MONO_OPT_SHARED)
11007                 target_domain = mono_get_root_domain ();
11008         else 
11009                 target_domain = domain;
11010
11011         mono_domain_lock (target_domain);
11012
11013         if ((info = g_hash_table_lookup (target_domain->jit_code_hash, method))) {
11014                 /* We can't use a domain specific method in another domain */
11015                 if (! ((domain != target_domain) && !info->domain_neutral)) {
11016                         mono_domain_unlock (target_domain);
11017                         mono_jit_stats.methods_lookups++;
11018                         return info->code_start;
11019                 }
11020         }
11021
11022         mono_domain_unlock (target_domain);
11023
11024         return NULL;
11025 }
11026
11027 /**
11028  * mono_jit_runtime_invoke:
11029  * @method: the method to invoke
11030  * @obj: this pointer
11031  * @params: array of parameter values.
11032  * @exc: used to catch exceptions objects
11033  */
11034 static MonoObject*
11035 mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
11036 {
11037         MonoMethod *invoke;
11038         MonoObject *(*runtime_invoke) (MonoObject *this, void **params, MonoObject **exc, void* compiled_method);
11039         void* compiled_method;
11040
11041         if (obj == NULL && !(method->flags & METHOD_ATTRIBUTE_STATIC) && !method->string_ctor && (method->wrapper_type == 0)) {
11042                 g_warning ("Ignoring invocation of an instance method on a NULL instance.\n");
11043                 return NULL;
11044         }
11045
11046         method = mono_get_inflated_method (method);
11047         invoke = mono_marshal_get_runtime_invoke (method);
11048         runtime_invoke = mono_jit_compile_method (invoke);
11049         
11050         /* We need this here becuase mono_marshal_get_runtime_invoke can be place 
11051          * the helper method in System.Object and not the target class
11052          */
11053         mono_runtime_class_init (mono_class_vtable (mono_domain_get (), method->klass));
11054
11055         compiled_method = mono_jit_compile_method (method);
11056         return runtime_invoke (obj, params, exc, compiled_method);
11057 }
11058
11059 #ifdef MONO_GET_CONTEXT
11060 #define GET_CONTEXT MONO_GET_CONTEXT
11061 #endif
11062
11063 #ifndef GET_CONTEXT
11064 #ifdef PLATFORM_WIN32
11065 #define GET_CONTEXT \
11066         struct sigcontext *ctx = (struct sigcontext*)_dummy;
11067 #else
11068 #ifdef MONO_ARCH_USE_SIGACTION
11069 #define GET_CONTEXT \
11070     void *ctx = context;
11071 #elif defined(__sparc__)
11072 #define GET_CONTEXT \
11073     void *ctx = sigctx;
11074 #else
11075 #define GET_CONTEXT \
11076         void **_p = (void **)&_dummy; \
11077         struct sigcontext *ctx = (struct sigcontext *)++_p;
11078 #endif
11079 #endif
11080 #endif
11081
11082 #ifdef MONO_ARCH_USE_SIGACTION
11083 #define SIG_HANDLER_SIGNATURE(ftn) ftn (int _dummy, siginfo_t *info, void *context)
11084 #elif defined(__sparc__)
11085 #define SIG_HANDLER_SIGNATURE(ftn) ftn (int _dummy, void *sigctx)
11086 #else
11087 #define SIG_HANDLER_SIGNATURE(ftn) ftn (int _dummy)
11088 #endif
11089
11090 static void
11091 SIG_HANDLER_SIGNATURE (sigfpe_signal_handler)
11092 {
11093         MonoException *exc = NULL;
11094 #ifndef MONO_ARCH_USE_SIGACTION
11095         void *info = NULL;
11096 #endif
11097         GET_CONTEXT;
11098
11099 #if defined(MONO_ARCH_HAVE_IS_INT_OVERFLOW)
11100         if (mono_arch_is_int_overflow (ctx, info))
11101                 exc = mono_get_exception_arithmetic ();
11102         else
11103                 exc = mono_get_exception_divide_by_zero ();
11104 #else
11105         exc = mono_get_exception_divide_by_zero ();
11106 #endif
11107         
11108         mono_arch_handle_exception (ctx, exc, FALSE);
11109 }
11110
11111 static void
11112 SIG_HANDLER_SIGNATURE (sigill_signal_handler)
11113 {
11114         MonoException *exc;
11115         GET_CONTEXT;
11116
11117         exc = mono_get_exception_execution_engine ("SIGILL");
11118         
11119         mono_arch_handle_exception (ctx, exc, FALSE);
11120 }
11121
11122 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
11123
11124 #ifndef MONO_ARCH_USE_SIGACTION
11125 #error "Can't use sigaltstack without sigaction"
11126 #endif
11127
11128 #endif
11129
11130 static void
11131 SIG_HANDLER_SIGNATURE (sigsegv_signal_handler)
11132 {
11133         MonoException *exc = NULL;
11134         MonoJitInfo *ji;
11135
11136 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
11137         MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
11138 #endif
11139         GET_CONTEXT;
11140
11141 #ifdef MONO_ARCH_USE_SIGACTION
11142         if (debug_options.collect_pagefault_stats) {
11143                 if (mono_raw_buffer_is_pagefault (info->si_addr)) {
11144                         mono_raw_buffer_handle_pagefault (info->si_addr);
11145                         return;
11146                 }
11147                 if (mono_aot_is_pagefault (info->si_addr)) {
11148                         mono_aot_handle_pagefault (info->si_addr);
11149                         return;
11150                 }
11151         }
11152 #endif
11153
11154 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
11155         /* Can't allocate memory using Boehm GC on altstack */
11156         if (jit_tls->stack_size && 
11157                 ((guint8*)info->si_addr >= (guint8*)jit_tls->end_of_stack - jit_tls->stack_size) &&
11158                 ((guint8*)info->si_addr < (guint8*)jit_tls->end_of_stack))
11159                 exc = mono_domain_get ()->stack_overflow_ex;
11160         else
11161                 exc = mono_domain_get ()->null_reference_ex;
11162 #endif
11163
11164         ji = mono_jit_info_table_find (mono_domain_get (), mono_arch_ip_from_context(ctx));
11165         if (!ji) {
11166                 mono_handle_native_sigsegv (SIGSEGV, ctx);
11167         }
11168                         
11169         mono_arch_handle_exception (ctx, exc, FALSE);
11170 }
11171
11172 #ifndef PLATFORM_WIN32
11173
11174 static void
11175 SIG_HANDLER_SIGNATURE (sigabrt_signal_handler)
11176 {
11177         MonoJitInfo *ji;
11178         GET_CONTEXT;
11179
11180         ji = mono_jit_info_table_find (mono_domain_get (), mono_arch_ip_from_context(ctx));
11181         if (!ji) {
11182                 mono_handle_native_sigsegv (SIGABRT, ctx);
11183         }
11184 }
11185
11186 static void
11187 SIG_HANDLER_SIGNATURE (sigusr1_signal_handler)
11188 {
11189         gboolean running_managed;
11190         MonoException *exc;
11191         MonoThread *thread = mono_thread_current ();
11192         void *ji;
11193         
11194         GET_CONTEXT;
11195
11196         if (thread->thread_dump_requested) {
11197                 thread->thread_dump_requested = FALSE;
11198
11199                 mono_print_thread_dump (ctx);
11200         }
11201
11202         /*
11203          * FIXME:
11204          * This is an async signal, so the code below must not call anything which
11205          * is not async safe. That includes the pthread locking functions. If we
11206          * know that we interrupted managed code, then locking is safe.
11207          */
11208         ji = mono_jit_info_table_find (mono_domain_get (), mono_arch_ip_from_context(ctx));
11209         running_managed = ji != NULL;
11210         
11211         exc = mono_thread_request_interruption (running_managed); 
11212         if (!exc) return;
11213
11214         mono_arch_handle_exception (ctx, exc, FALSE);
11215 }
11216
11217 static void
11218 SIG_HANDLER_SIGNATURE (sigprof_signal_handler)
11219 {
11220         GET_CONTEXT;
11221
11222         mono_profiler_stat_hit (mono_arch_ip_from_context (ctx), ctx);
11223 }
11224
11225 static void
11226 SIG_HANDLER_SIGNATURE (sigquit_signal_handler)
11227 {
11228         GET_CONTEXT;
11229
11230         printf ("Full thread dump:\n");
11231
11232         mono_threads_request_thread_dump ();
11233
11234         /*
11235          * print_thread_dump () skips the current thread, since sending a signal
11236          * to it would invoke the signal handler below the sigquit signal handler,
11237          * and signal handlers don't create an lmf, so the stack walk could not
11238          * be performed.
11239          */
11240         mono_print_thread_dump (ctx);
11241 }
11242
11243 static void
11244 SIG_HANDLER_SIGNATURE (sigusr2_signal_handler)
11245 {
11246         gboolean enabled = mono_trace_is_enabled ();
11247
11248         mono_trace_enable (!enabled);
11249 }
11250
11251 #endif
11252
11253 static void
11254 SIG_HANDLER_SIGNATURE (sigint_signal_handler)
11255 {
11256         MonoException *exc;
11257         GET_CONTEXT;
11258
11259         exc = mono_get_exception_execution_engine ("Interrupted (SIGINT).");
11260         
11261         mono_arch_handle_exception (ctx, exc, FALSE);
11262 }
11263
11264 #ifdef PLATFORM_MACOSX
11265
11266 /*
11267  * This code disables the CrashReporter of MacOS X by installing
11268  * a dummy Mach exception handler.
11269  */
11270
11271 /*
11272  * http://darwinsource.opendarwin.org/10.4.3/xnu-792.6.22/osfmk/man/exc_server.html
11273  */
11274 extern
11275 boolean_t
11276 exc_server (mach_msg_header_t *request_msg,
11277             mach_msg_header_t *reply_msg);
11278
11279 /*
11280  * The exception message
11281  */
11282 typedef struct {
11283         mach_msg_base_t msg;  /* common mach message header */
11284         char payload [1024];  /* opaque */
11285 } mach_exception_msg_t;
11286
11287 /* The exception port */
11288 static mach_port_t mach_exception_port = VM_MAP_NULL;
11289
11290 /*
11291  * Implicitly called by exc_server. Must be public.
11292  *
11293  * http://darwinsource.opendarwin.org/10.4.3/xnu-792.6.22/osfmk/man/catch_exception_raise.html
11294  */
11295 kern_return_t
11296 catch_exception_raise (
11297         mach_port_t exception_port,
11298         mach_port_t thread,
11299         mach_port_t task,
11300         exception_type_t exception,
11301         exception_data_t code,
11302         mach_msg_type_number_t code_count)
11303 {
11304         /* consume the exception */
11305         return KERN_FAILURE;
11306 }
11307
11308 /*
11309  * Exception thread handler.
11310  */
11311 static
11312 void *
11313 mach_exception_thread (void *arg)
11314 {
11315         for (;;) {
11316                 mach_exception_msg_t request;
11317                 mach_exception_msg_t reply;
11318                 mach_msg_return_t result;
11319
11320                 /* receive from "mach_exception_port" */
11321                 result = mach_msg (&request.msg.header,
11322                                    MACH_RCV_MSG | MACH_RCV_LARGE,
11323                                    0,
11324                                    sizeof (request),
11325                                    mach_exception_port,
11326                                    MACH_MSG_TIMEOUT_NONE,
11327                                    MACH_PORT_NULL);
11328
11329                 g_assert (result == MACH_MSG_SUCCESS);
11330
11331                 /* dispatch to catch_exception_raise () */
11332                 exc_server (&request.msg.header, &reply.msg.header);
11333
11334                 /* send back to sender */
11335                 result = mach_msg (&reply.msg.header,
11336                                    MACH_SEND_MSG,
11337                                    reply.msg.header.msgh_size,
11338                                    0,
11339                                    MACH_PORT_NULL,
11340                                    MACH_MSG_TIMEOUT_NONE,
11341                                    MACH_PORT_NULL);
11342
11343                 g_assert (result == MACH_MSG_SUCCESS);
11344         }
11345         return NULL;
11346 }
11347
11348 static void
11349 macosx_register_exception_handler ()
11350 {
11351         mach_port_t task;
11352         pthread_attr_t attr;
11353         pthread_t thread;
11354
11355         if (mach_exception_port != VM_MAP_NULL)
11356                 return;
11357
11358         task = mach_task_self ();
11359
11360         /* create the "mach_exception_port" with send & receive rights */
11361         g_assert (mach_port_allocate (task, MACH_PORT_RIGHT_RECEIVE,
11362                                       &mach_exception_port) == KERN_SUCCESS);
11363         g_assert (mach_port_insert_right (task, mach_exception_port, mach_exception_port,
11364                                           MACH_MSG_TYPE_MAKE_SEND) == KERN_SUCCESS);
11365
11366         /* create the exception handler thread */
11367         g_assert (!pthread_attr_init (&attr));
11368         g_assert (!pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED));
11369         g_assert (!pthread_create (&thread, &attr, mach_exception_thread, NULL));
11370         pthread_attr_destroy (&attr);
11371
11372         /*
11373          * register "mach_exception_port" as a receiver for the
11374          * EXC_BAD_ACCESS exception
11375          *
11376          * http://darwinsource.opendarwin.org/10.4.3/xnu-792.6.22/osfmk/man/task_set_exception_ports.html
11377          */
11378         g_assert (task_set_exception_ports (task, EXC_MASK_BAD_ACCESS,
11379                                             mach_exception_port,
11380                                             EXCEPTION_DEFAULT,
11381                                             MACHINE_THREAD_STATE) == KERN_SUCCESS);
11382 }
11383 #endif
11384
11385 #ifndef PLATFORM_WIN32
11386 static void
11387 add_signal_handler (int signo, gpointer handler)
11388 {
11389         struct sigaction sa;
11390
11391 #ifdef MONO_ARCH_USE_SIGACTION
11392         sa.sa_sigaction = handler;
11393         sigemptyset (&sa.sa_mask);
11394         sa.sa_flags = SA_SIGINFO;
11395 #else
11396         sa.sa_handler = handler;
11397         sigemptyset (&sa.sa_mask);
11398         sa.sa_flags = 0;
11399 #endif
11400         g_assert (sigaction (signo, &sa, NULL) != -1);
11401 }
11402
11403 static void
11404 remove_signal_handler (int signo)
11405 {
11406         struct sigaction sa;
11407
11408         sa.sa_handler = SIG_DFL;
11409         sigemptyset (&sa.sa_mask);
11410         sa.sa_flags = 0;
11411
11412         g_assert (sigaction (signo, &sa, NULL) != -1);
11413 }
11414 #endif
11415
11416 static void
11417 mono_runtime_install_handlers (void)
11418 {
11419 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
11420         struct sigaction sa;
11421 #endif
11422
11423 #ifdef PLATFORM_WIN32
11424         win32_seh_init();
11425         win32_seh_set_handler(SIGFPE, sigfpe_signal_handler);
11426         win32_seh_set_handler(SIGILL, sigill_signal_handler);
11427         win32_seh_set_handler(SIGSEGV, sigsegv_signal_handler);
11428         if (debug_options.handle_sigint)
11429                 win32_seh_set_handler(SIGINT, sigint_signal_handler);
11430
11431 #else /* !PLATFORM_WIN32 */
11432
11433
11434 #ifdef PLATFORM_MACOSX
11435         macosx_register_exception_handler ();
11436 #endif
11437
11438         if (debug_options.handle_sigint)
11439                 add_signal_handler (SIGINT, sigint_signal_handler);
11440
11441         add_signal_handler (SIGFPE, sigfpe_signal_handler);
11442         add_signal_handler (SIGQUIT, sigquit_signal_handler);
11443         add_signal_handler (SIGILL, sigill_signal_handler);
11444         add_signal_handler (SIGBUS, sigsegv_signal_handler);
11445         if (mono_jit_trace_calls != NULL)
11446                 add_signal_handler (SIGUSR2, sigusr2_signal_handler);
11447
11448         add_signal_handler (mono_thread_get_abort_signal (), sigusr1_signal_handler);
11449         signal (SIGPIPE, SIG_IGN);
11450
11451         add_signal_handler (SIGABRT, sigabrt_signal_handler);
11452
11453         /* catch SIGSEGV */
11454 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
11455         sa.sa_sigaction = sigsegv_signal_handler;
11456         sigemptyset (&sa.sa_mask);
11457         sa.sa_flags = SA_SIGINFO | SA_ONSTACK;
11458         g_assert (sigaction (SIGSEGV, &sa, NULL) != -1);
11459 #else
11460         add_signal_handler (SIGSEGV, sigsegv_signal_handler);
11461 #endif
11462 #endif /* PLATFORM_WIN32 */
11463 }
11464
11465 static void
11466 mono_runtime_cleanup_handlers (void)
11467 {
11468 #ifdef PLATFORM_WIN32
11469         win32_seh_cleanup();
11470 #else
11471         if (debug_options.handle_sigint)
11472                 remove_signal_handler (SIGINT);
11473
11474         remove_signal_handler (SIGFPE);
11475         remove_signal_handler (SIGQUIT);
11476         remove_signal_handler (SIGILL);
11477         remove_signal_handler (SIGBUS);
11478         if (mono_jit_trace_calls != NULL)
11479                 remove_signal_handler (SIGUSR2);
11480
11481         remove_signal_handler (mono_thread_get_abort_signal ());
11482
11483         remove_signal_handler (SIGABRT);
11484
11485         remove_signal_handler (SIGSEGV);
11486 #endif /* PLATFORM_WIN32 */
11487 }
11488
11489
11490 #ifdef HAVE_LINUX_RTC_H
11491 #include <linux/rtc.h>
11492 #include <sys/ioctl.h>
11493 #include <fcntl.h>
11494 static int rtc_fd = -1;
11495
11496 static int
11497 enable_rtc_timer (gboolean enable)
11498 {
11499         int flags;
11500         flags = fcntl (rtc_fd, F_GETFL);
11501         if (flags < 0) {
11502                 perror ("getflags");
11503                 return 0;
11504         }
11505         if (enable)
11506                 flags |= FASYNC;
11507         else
11508                 flags &= ~FASYNC;
11509         if (fcntl (rtc_fd, F_SETFL, flags) == -1) {
11510                 perror ("setflags");
11511                 return 0;
11512         }
11513         return 1;
11514 }
11515 #endif
11516
11517 #ifdef PLATFORM_WIN32
11518 static HANDLE win32_main_thread;
11519 static MMRESULT win32_timer;
11520
11521 static void CALLBACK
11522 win32_time_proc (UINT uID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2)
11523 {
11524         CONTEXT context;
11525
11526         context.ContextFlags = CONTEXT_CONTROL;
11527         if (GetThreadContext (win32_main_thread, &context))
11528                 mono_profiler_stat_hit ((guchar *) context.Eip, &context);
11529 }
11530 #endif
11531
11532 static void
11533 setup_stat_profiler (void)
11534 {
11535 #ifdef ITIMER_PROF
11536         struct itimerval itval;
11537         static int inited = 0;
11538 #ifdef HAVE_LINUX_RTC_H
11539         const char *rtc_freq;
11540         if (!inited && (rtc_freq = g_getenv ("MONO_RTC"))) {
11541                 int freq = 0;
11542                 inited = 1;
11543                 if (*rtc_freq)
11544                         freq = atoi (rtc_freq);
11545                 if (!freq)
11546                         freq = 1024;
11547                 rtc_fd = open ("/dev/rtc", O_RDONLY);
11548                 if (rtc_fd == -1) {
11549                         perror ("open /dev/rtc");
11550                         return;
11551                 }
11552                 add_signal_handler (SIGPROF, sigprof_signal_handler);
11553                 if (ioctl (rtc_fd, RTC_IRQP_SET, freq) == -1) {
11554                         perror ("set rtc freq");
11555                         return;
11556                 }
11557                 if (ioctl (rtc_fd, RTC_PIE_ON, 0) == -1) {
11558                         perror ("start rtc");
11559                         return;
11560                 }
11561                 if (fcntl (rtc_fd, F_SETSIG, SIGPROF) == -1) {
11562                         perror ("setsig");
11563                         return;
11564                 }
11565                 if (fcntl (rtc_fd, F_SETOWN, getpid ()) == -1) {
11566                         perror ("setown");
11567                         return;
11568                 }
11569                 enable_rtc_timer (TRUE);
11570                 return;
11571         }
11572         if (rtc_fd >= 0)
11573                 return;
11574 #endif
11575
11576         itval.it_interval.tv_usec = 999;
11577         itval.it_interval.tv_sec = 0;
11578         itval.it_value = itval.it_interval;
11579         setitimer (ITIMER_PROF, &itval, NULL);
11580         if (inited)
11581                 return;
11582         inited = 1;
11583         add_signal_handler (SIGPROF, sigprof_signal_handler);
11584 #elif defined (PLATFORM_WIN32)
11585         static int inited = 0;
11586         TIMECAPS timecaps;
11587
11588         if (inited)
11589                 return;
11590
11591         inited = 1;
11592         if (timeGetDevCaps (&timecaps, sizeof (timecaps)) != TIMERR_NOERROR)
11593                 return;
11594
11595         if ((win32_main_thread = OpenThread (READ_CONTROL | THREAD_GET_CONTEXT, FALSE, GetCurrentThreadId ())) == NULL)
11596                 return;
11597
11598         if (timeBeginPeriod (1) != TIMERR_NOERROR)
11599                 return;
11600
11601         if ((win32_timer = timeSetEvent (1, 0, win32_time_proc, 0, TIME_PERIODIC)) == 0) {
11602                 timeEndPeriod (1);
11603                 return;
11604         }
11605 #endif
11606 }
11607
11608 /* mono_jit_create_remoting_trampoline:
11609  * @method: pointer to the method info
11610  *
11611  * Creates a trampoline which calls the remoting functions. This
11612  * is used in the vtable of transparent proxies.
11613  * 
11614  * Returns: a pointer to the newly created code 
11615  */
11616 static gpointer
11617 mono_jit_create_remoting_trampoline (MonoMethod *method, MonoRemotingTarget target)
11618 {
11619         MonoMethod *nm;
11620         guint8 *addr = NULL;
11621
11622         if ((method->flags & METHOD_ATTRIBUTE_ABSTRACT) || 
11623             (mono_method_signature (method)->hasthis && (method->klass->marshalbyref || method->klass == mono_defaults.object_class))) {
11624                 nm = mono_marshal_get_remoting_invoke_for_target (method, target);
11625                 addr = mono_compile_method (nm);
11626         } else {
11627                 addr = mono_compile_method (method);
11628         }
11629         return mono_get_addr_from_ftnptr (addr);
11630 }
11631
11632 static void
11633 mini_parse_debug_options (void)
11634 {
11635         char *options = getenv ("MONO_DEBUG");
11636         gchar **args, **ptr;
11637         
11638         if (!options)
11639                 return;
11640
11641         args = g_strsplit (options, ",", -1);
11642
11643         for (ptr = args; ptr && *ptr; ptr++) {
11644                 const char *arg = *ptr;
11645
11646                 if (!strcmp (arg, "handle-sigint"))
11647                         debug_options.handle_sigint = TRUE;
11648                 else if (!strcmp (arg, "keep-delegates"))
11649                         debug_options.keep_delegates = TRUE;
11650                 else if (!strcmp (arg, "collect-pagefault-stats"))
11651                         debug_options.collect_pagefault_stats = TRUE;
11652                 else if (!strcmp (arg, "break-on-unverified"))
11653                         debug_options.break_on_unverified = TRUE;
11654                 else {
11655                         fprintf (stderr, "Invalid option for the MONO_DEBUG env variable: %s\n", arg);
11656                         fprintf (stderr, "Available options: 'handle-sigint', 'keep-delegates', 'collect-pagefault-stats', 'break-on-unverified'\n");
11657                         exit (1);
11658                 }
11659         }
11660 }
11661
11662 MonoDomain *
11663 mini_init (const char *filename, const char *runtime_version)
11664 {
11665         MonoDomain *domain;
11666
11667 #ifdef __linux__
11668         if (access ("/proc/self/maps", F_OK) != 0) {
11669                 g_print ("Mono requires /proc to be mounted.\n");
11670                 exit (1);
11671         }
11672 #endif
11673
11674         /* Happens when using the embedding interface */
11675         if (!default_opt_set)
11676                 default_opt = mono_parse_default_optimizations (NULL);
11677
11678         InitializeCriticalSection (&jit_mutex);
11679
11680         global_codeman = mono_code_manager_new ();
11681         jit_icall_name_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
11682
11683         mono_arch_cpu_init ();
11684
11685         mono_init_trampolines ();
11686
11687         mono_init_exceptions ();
11688
11689         if (!g_thread_supported ())
11690                 g_thread_init (NULL);
11691
11692         if (getenv ("MONO_DEBUG") != NULL)
11693                 mini_parse_debug_options ();
11694
11695         /*
11696          * Handle the case when we are called from a thread different from the main thread,
11697          * confusing libgc.
11698          * FIXME: Move this to libgc where it belongs.
11699          *
11700          * we used to do this only when running on valgrind,
11701          * but it happens also in other setups.
11702          */
11703 #if defined(HAVE_BOEHM_GC)
11704 #if defined(HAVE_PTHREAD_GETATTR_NP) && defined(HAVE_PTHREAD_ATTR_GETSTACK)
11705         {
11706                 size_t size;
11707                 void *sstart;
11708                 pthread_attr_t attr;
11709                 pthread_getattr_np (pthread_self (), &attr);
11710                 pthread_attr_getstack (&attr, &sstart, &size);
11711                 pthread_attr_destroy (&attr); 
11712                 /*g_print ("stackbottom pth is: %p\n", (char*)sstart + size);*/
11713 #ifdef __ia64__
11714                 /*
11715                  * The calculation above doesn't seem to work on ia64, also we need to set
11716                  * GC_register_stackbottom as well, but don't know how.
11717                  */
11718 #else
11719                 /* apparently with some linuxthreads implementations sstart can be NULL,
11720                  * fallback to the more imprecise method (bug# 78096).
11721                  */
11722                 if (sstart) {
11723                         GC_stackbottom = (char*)sstart + size;
11724                 } else {
11725                         gsize stack_bottom = (gsize)&domain;
11726                         stack_bottom += 4095;
11727                         stack_bottom &= ~4095;
11728                         GC_stackbottom = (char*)stack_bottom;
11729                 }
11730 #endif
11731         }
11732 #elif defined(HAVE_PTHREAD_GET_STACKSIZE_NP) && defined(HAVE_PTHREAD_GET_STACKADDR_NP)
11733                 GC_stackbottom = (char*)pthread_get_stackaddr_np (pthread_self ());
11734 #else
11735         {
11736                 gsize stack_bottom = (gsize)&domain;
11737                 stack_bottom += 4095;
11738                 stack_bottom &= ~4095;
11739                 /*g_print ("stackbottom is: %p\n", (char*)stack_bottom);*/
11740                 GC_stackbottom = (char*)stack_bottom;
11741         }
11742 #endif
11743 #endif
11744         MONO_GC_PRE_INIT ();
11745
11746         mono_jit_tls_id = TlsAlloc ();
11747         setup_jit_tls_data ((gpointer)-1, mono_thread_abort);
11748
11749         mono_burg_init ();
11750
11751         if (default_opt & MONO_OPT_AOT)
11752                 mono_aot_init ();
11753
11754         mono_runtime_install_handlers ();
11755         mono_threads_install_cleanup (mini_thread_cleanup);
11756
11757 #define JIT_TRAMPOLINES_WORK
11758 #ifdef JIT_TRAMPOLINES_WORK
11759         mono_install_compile_method (mono_jit_compile_method);
11760         mono_install_free_method (mono_jit_free_method);
11761         mono_install_trampoline (mono_create_jit_trampoline);
11762         mono_install_remoting_trampoline (mono_jit_create_remoting_trampoline);
11763         mono_install_delegate_trampoline (mono_create_delegate_trampoline);
11764 #endif
11765 #define JIT_INVOKE_WORKS
11766 #ifdef JIT_INVOKE_WORKS
11767         mono_install_runtime_invoke (mono_jit_runtime_invoke);
11768         mono_install_handler (mono_arch_get_throw_exception ());
11769 #endif
11770         mono_install_stack_walk (mono_jit_walk_stack);
11771         mono_install_init_vtable (mono_aot_init_vtable);
11772         mono_install_get_cached_class_info (mono_aot_get_cached_class_info);
11773         mono_install_get_class_from_name (mono_aot_get_class_from_name);
11774         mono_install_jit_info_find_in_aot (mono_aot_find_jit_info);
11775
11776         if (debug_options.collect_pagefault_stats) {
11777                 mono_raw_buffer_set_make_unreadable (TRUE);
11778                 mono_aot_set_make_unreadable (TRUE);
11779         }
11780
11781         if (runtime_version)
11782                 domain = mono_init_version (filename, runtime_version);
11783         else
11784                 domain = mono_init_from_assembly (filename, filename);
11785         mono_icall_init ();
11786
11787         mono_add_internal_call ("System.Diagnostics.StackFrame::get_frame_info", 
11788                                 ves_icall_get_frame_info);
11789         mono_add_internal_call ("System.Diagnostics.StackTrace::get_trace", 
11790                                 ves_icall_get_trace);
11791         mono_add_internal_call ("System.Exception::get_trace", 
11792                                 ves_icall_System_Exception_get_trace);
11793         mono_add_internal_call ("System.Security.SecurityFrame::_GetSecurityFrame",
11794                                 ves_icall_System_Security_SecurityFrame_GetSecurityFrame);
11795         mono_add_internal_call ("System.Security.SecurityFrame::_GetSecurityStack",
11796                                 ves_icall_System_Security_SecurityFrame_GetSecurityStack);
11797         mono_add_internal_call ("Mono.Runtime::mono_runtime_install_handlers", 
11798                                 mono_runtime_install_handlers);
11799
11800
11801         create_helper_signature ();
11802
11803 #define JIT_CALLS_WORK
11804 #ifdef JIT_CALLS_WORK
11805         /* Needs to be called here since register_jit_icall depends on it */
11806         mono_marshal_init ();
11807
11808         mono_arch_register_lowlevel_calls ();
11809         register_icall (mono_profiler_method_enter, "mono_profiler_method_enter", NULL, TRUE);
11810         register_icall (mono_profiler_method_leave, "mono_profiler_method_leave", NULL, TRUE);
11811         register_icall (mono_trace_enter_method, "mono_trace_enter_method", NULL, TRUE);
11812         register_icall (mono_trace_leave_method, "mono_trace_leave_method", NULL, TRUE);
11813         register_icall (mono_get_lmf_addr, "mono_get_lmf_addr", "ptr", TRUE);
11814         register_icall (mono_jit_thread_attach, "mono_jit_thread_attach", "void", TRUE);
11815         register_icall (mono_domain_get, "mono_domain_get", "ptr", TRUE);
11816
11817         register_icall (mono_arch_get_throw_exception (), "mono_arch_throw_exception", "void object", TRUE);
11818         register_icall (mono_arch_get_rethrow_exception (), "mono_arch_rethrow_exception", "void object", TRUE);
11819         register_icall (mono_arch_get_throw_exception_by_name (), "mono_arch_throw_exception_by_name", "void ptr", TRUE); 
11820 #if MONO_ARCH_HAVE_THROW_CORLIB_EXCEPTION
11821         register_icall (mono_arch_get_throw_corlib_exception (), "mono_arch_throw_corlib_exception", 
11822                                  "void ptr", TRUE);
11823 #endif
11824         register_icall (mono_thread_get_pending_exception, "mono_thread_get_pending_exception", "object", FALSE);
11825         register_icall (mono_thread_interruption_checkpoint, "mono_thread_interruption_checkpoint", "void", FALSE);
11826         register_icall (mono_thread_force_interruption_checkpoint, "mono_thread_force_interruption_checkpoint", "void", FALSE);
11827         register_icall (mono_load_remote_field_new, "mono_load_remote_field_new", "object object ptr ptr", FALSE);
11828         register_icall (mono_store_remote_field_new, "mono_store_remote_field_new", "void object ptr ptr object", FALSE);
11829
11830         /* 
11831          * NOTE, NOTE, NOTE, NOTE:
11832          * when adding emulation for some opcodes, remember to also add a dummy
11833          * rule to the burg files, because we need the arity information to be correct.
11834          */
11835 #ifndef MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS
11836         mono_register_opcode_emulation (OP_LMUL, "__emul_lmul", "long long long", mono_llmult, TRUE);
11837         mono_register_opcode_emulation (OP_LDIV, "__emul_ldiv", "long long long", mono_lldiv, FALSE);
11838         mono_register_opcode_emulation (OP_LDIV_UN, "__emul_ldiv_un", "long long long", mono_lldiv_un, FALSE);
11839         mono_register_opcode_emulation (OP_LREM, "__emul_lrem", "long long long", mono_llrem, FALSE);
11840         mono_register_opcode_emulation (OP_LREM_UN, "__emul_lrem_un", "long long long", mono_llrem_un, FALSE);
11841         mono_register_opcode_emulation (OP_LMUL_OVF_UN, "__emul_lmul_ovf_un", "long long long", mono_llmult_ovf_un, FALSE);
11842         mono_register_opcode_emulation (OP_LMUL_OVF, "__emul_lmul_ovf", "long long long", mono_llmult_ovf, FALSE);
11843 #endif
11844
11845 #ifndef MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
11846         mono_register_opcode_emulation (OP_LSHL, "__emul_lshl", "long long int32", mono_lshl, TRUE);
11847         mono_register_opcode_emulation (OP_LSHR, "__emul_lshr", "long long int32", mono_lshr, TRUE);
11848         mono_register_opcode_emulation (OP_LSHR_UN, "__emul_lshr_un", "long long int32", mono_lshr_un, TRUE);
11849 #endif
11850
11851 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
11852         mono_register_opcode_emulation (CEE_DIV, "__emul_idiv", "int32 int32 int32", mono_idiv, FALSE);
11853         mono_register_opcode_emulation (CEE_DIV_UN, "__emul_idiv_un", "int32 int32 int32", mono_idiv_un, FALSE);
11854         mono_register_opcode_emulation (CEE_REM, "__emul_irem", "int32 int32 int32", mono_irem, FALSE);
11855         mono_register_opcode_emulation (CEE_REM_UN, "__emul_irem_un", "int32 int32 int32", mono_irem_un, FALSE);
11856 #endif
11857
11858 #ifdef MONO_ARCH_EMULATE_MUL_DIV
11859         mono_register_opcode_emulation (CEE_MUL_OVF, "__emul_imul_ovf", "int32 int32 int32", mono_imul_ovf, FALSE);
11860         mono_register_opcode_emulation (CEE_MUL_OVF_UN, "__emul_imul_ovf_un", "int32 int32 int32", mono_imul_ovf_un, FALSE);
11861         mono_register_opcode_emulation (CEE_MUL, "__emul_imul", "int32 int32 int32", mono_imul, TRUE);
11862 #endif
11863 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_SOFT_FLOAT)
11864         mono_register_opcode_emulation (OP_FDIV, "__emul_fdiv", "double double double", mono_fdiv, FALSE);
11865 #endif
11866
11867         mono_register_opcode_emulation (OP_FCONV_TO_U8, "__emul_fconv_to_u8", "ulong double", mono_fconv_u8, FALSE);
11868         mono_register_opcode_emulation (OP_FCONV_TO_U4, "__emul_fconv_to_u4", "uint32 double", mono_fconv_u4, FALSE);
11869         mono_register_opcode_emulation (OP_FCONV_TO_OVF_I8, "__emul_fconv_to_ovf_i8", "long double", mono_fconv_ovf_i8, FALSE);
11870         mono_register_opcode_emulation (OP_FCONV_TO_OVF_U8, "__emul_fconv_to_ovf_u8", "ulong double", mono_fconv_ovf_u8, FALSE);
11871
11872 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
11873         mono_register_opcode_emulation (OP_FCONV_TO_I8, "__emul_fconv_to_i8", "long double", mono_fconv_i8, FALSE);
11874 #endif
11875 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
11876         mono_register_opcode_emulation (CEE_CONV_R_UN, "__emul_conv_r_un", "double int32", mono_conv_to_r8_un, FALSE);
11877 #endif
11878 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
11879         mono_register_opcode_emulation (OP_LCONV_TO_R8, "__emul_lconv_to_r8", "double long", mono_lconv_to_r8, FALSE);
11880 #endif
11881 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
11882         mono_register_opcode_emulation (OP_LCONV_TO_R4, "__emul_lconv_to_r4", "float long", mono_lconv_to_r4, FALSE);
11883 #endif
11884 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
11885         mono_register_opcode_emulation (OP_LCONV_TO_R_UN, "__emul_lconv_to_r8_un", "double long", mono_lconv_to_r8_un, FALSE);
11886 #endif
11887 #ifdef MONO_ARCH_EMULATE_FREM
11888         mono_register_opcode_emulation (OP_FREM, "__emul_frem", "double double double", fmod, FALSE);
11889 #endif
11890
11891 #ifdef MONO_ARCH_SOFT_FLOAT
11892         mono_register_opcode_emulation (OP_FSUB, "__emul_fsub", "double double double", mono_fsub, FALSE);
11893         mono_register_opcode_emulation (OP_FADD, "__emul_fadd", "double double double", mono_fadd, FALSE);
11894         mono_register_opcode_emulation (OP_FMUL, "__emul_fmul", "double double double", mono_fmul, FALSE);
11895         mono_register_opcode_emulation (OP_FNEG, "__emul_fneg", "double double", mono_fneg, FALSE);
11896         mono_register_opcode_emulation (CEE_CONV_R8, "__emul_conv_r8", "double int32", mono_conv_to_r8, FALSE);
11897         mono_register_opcode_emulation (CEE_CONV_R4, "__emul_conv_r4", "double int32", mono_conv_to_r4, FALSE);
11898         mono_register_opcode_emulation (OP_FCONV_TO_R4, "__emul_fconv_to_r4", "double double", mono_fconv_r4, FALSE);
11899         mono_register_opcode_emulation (OP_FCONV_TO_I1, "__emul_fconv_to_i1", "int8 double", mono_fconv_i1, FALSE);
11900         mono_register_opcode_emulation (OP_FCONV_TO_I2, "__emul_fconv_to_i2", "int16 double", mono_fconv_i2, FALSE);
11901         mono_register_opcode_emulation (OP_FCONV_TO_I4, "__emul_fconv_to_i4", "int32 double", mono_fconv_i4, FALSE);
11902         mono_register_opcode_emulation (OP_FCONV_TO_U1, "__emul_fconv_to_u1", "uint8 double", mono_fconv_u1, FALSE);
11903         mono_register_opcode_emulation (OP_FCONV_TO_U2, "__emul_fconv_to_u2", "uint16 double", mono_fconv_u2, FALSE);
11904
11905         mono_register_opcode_emulation (OP_FBEQ, "__emul_fcmp_eq", "uint32 double double", mono_fcmp_eq, FALSE);
11906         mono_register_opcode_emulation (OP_FBLT, "__emul_fcmp_lt", "uint32 double double", mono_fcmp_lt, FALSE);
11907         mono_register_opcode_emulation (OP_FBGT, "__emul_fcmp_gt", "uint32 double double", mono_fcmp_gt, FALSE);
11908         mono_register_opcode_emulation (OP_FBLE, "__emul_fcmp_le", "uint32 double double", mono_fcmp_le, FALSE);
11909         mono_register_opcode_emulation (OP_FBGE, "__emul_fcmp_ge", "uint32 double double", mono_fcmp_ge, FALSE);
11910         mono_register_opcode_emulation (OP_FBNE_UN, "__emul_fcmp_ne_un", "uint32 double double", mono_fcmp_ne_un, FALSE);
11911         mono_register_opcode_emulation (OP_FBLT_UN, "__emul_fcmp_lt_un", "uint32 double double", mono_fcmp_lt_un, FALSE);
11912         mono_register_opcode_emulation (OP_FBGT_UN, "__emul_fcmp_gt_un", "uint32 double double", mono_fcmp_gt_un, FALSE);
11913         mono_register_opcode_emulation (OP_FBLE_UN, "__emul_fcmp_le_un", "uint32 double double", mono_fcmp_le_un, FALSE);
11914         mono_register_opcode_emulation (OP_FBGE_UN, "__emul_fcmp_ge_un", "uint32 double double", mono_fcmp_ge_un, FALSE);
11915
11916         mono_register_opcode_emulation (OP_FCEQ, "__emul_fcmp_ceq", "uint32 double double", mono_fceq, FALSE);
11917         mono_register_opcode_emulation (OP_FCGT, "__emul_fcmp_cgt", "uint32 double double", mono_fcgt, FALSE);
11918         mono_register_opcode_emulation (OP_FCGT_UN, "__emul_fcmp_cgt_un", "uint32 double double", mono_fcgt_un, FALSE);
11919         mono_register_opcode_emulation (OP_FCLT, "__emul_fcmp_clt", "uint32 double double", mono_fclt, FALSE);
11920         mono_register_opcode_emulation (OP_FCLT_UN, "__emul_fcmp_clt_un", "uint32 double double", mono_fclt_un, FALSE);
11921
11922         register_icall (mono_fload_r4, "mono_fload_r4", "double ptr", FALSE);
11923         register_icall (mono_fstore_r4, "mono_fstore_r4", "void double ptr", FALSE);
11924         register_icall (mono_fload_r4_arg, "mono_fload_r4_arg", "uint32 double", FALSE);
11925 #endif
11926
11927 #if SIZEOF_VOID_P == 4
11928         mono_register_opcode_emulation (OP_FCONV_TO_U, "__emul_fconv_to_u", "uint32 double", mono_fconv_u4, TRUE);
11929 #endif
11930
11931         /* other jit icalls */
11932         register_icall (mono_delegate_ctor, "mono_delegate_ctor", "void object object ptr", FALSE);
11933         register_icall (mono_class_static_field_address , "mono_class_static_field_address", 
11934                                  "ptr ptr ptr", FALSE);
11935         register_icall (mono_ldtoken_wrapper, "mono_ldtoken_wrapper", "ptr ptr ptr ptr", FALSE);
11936         register_icall (mono_get_special_static_data, "mono_get_special_static_data", "ptr int", FALSE);
11937         register_icall (mono_ldstr, "mono_ldstr", "object ptr ptr int32", FALSE);
11938         register_icall (mono_helper_stelem_ref_check, "helper_stelem_ref_check", "void object object", FALSE);
11939         register_icall (mono_object_new, "mono_object_new", "object ptr ptr", FALSE);
11940         register_icall (mono_object_new_specific, "mono_object_new_specific", "object ptr", FALSE);
11941         register_icall (mono_array_new, "mono_array_new", "object ptr ptr int32", FALSE);
11942         register_icall (mono_array_new_specific, "mono_array_new_specific", "object ptr int32", FALSE);
11943         register_icall (mono_runtime_class_init, "mono_runtime_class_init", "void ptr", FALSE);
11944         register_icall (mono_ldftn, "mono_ldftn", "ptr ptr", FALSE);
11945         register_icall (mono_ldftn_nosync, "mono_ldftn_nosync", "ptr ptr", FALSE);
11946         register_icall (mono_ldvirtfn, "mono_ldvirtfn", "ptr object ptr", FALSE);
11947         register_icall (mono_helper_compile_generic_method, "compile_generic_method", "ptr object ptr ptr ptr", FALSE);
11948         register_icall (mono_helper_ldstr, "helper_ldstr", "object ptr int", FALSE);
11949         register_icall (mono_helper_ldstr_mscorlib, "helper_ldstr_mscorlib", "object int", FALSE);
11950         register_icall (mono_helper_newobj_mscorlib, "helper_newobj_mscorlib", "object int", FALSE);
11951         register_icall (mono_value_copy, "mono_value_copy", "void ptr ptr ptr", FALSE);
11952 #endif
11953
11954 #define JIT_RUNTIME_WORKS
11955 #ifdef JIT_RUNTIME_WORKS
11956         mono_install_runtime_cleanup ((MonoDomainFunc)mini_cleanup);
11957         mono_runtime_init (domain, mono_thread_start_cb, mono_thread_attach_cb);
11958 #endif
11959
11960         mono_thread_attach (domain);
11961         return domain;
11962 }
11963
11964 MonoJitStats mono_jit_stats = {0};
11965
11966 static void 
11967 print_jit_stats (void)
11968 {
11969         if (mono_jit_stats.enabled) {
11970                 g_print ("Mono Jit statistics\n");
11971                 g_print ("Compiled methods:       %ld\n", mono_jit_stats.methods_compiled);
11972                 g_print ("Methods from AOT:       %ld\n", mono_jit_stats.methods_aot);
11973                 g_print ("Methods cache lookup:   %ld\n", mono_jit_stats.methods_lookups);
11974                 g_print ("Method trampolines:     %ld\n", mono_jit_stats.method_trampolines);
11975                 g_print ("Basic blocks:           %ld\n", mono_jit_stats.basic_blocks);
11976                 g_print ("Max basic blocks:       %ld\n", mono_jit_stats.max_basic_blocks);
11977                 g_print ("Allocated vars:         %ld\n", mono_jit_stats.allocate_var);
11978                 g_print ("Analyze stack repeat:   %ld\n", mono_jit_stats.analyze_stack_repeat);
11979                 g_print ("Compiled CIL code size: %ld\n", mono_jit_stats.cil_code_size);
11980                 g_print ("Native code size:       %ld\n", mono_jit_stats.native_code_size);
11981                 g_print ("Max code size ratio:    %.2f (%s::%s)\n", mono_jit_stats.max_code_size_ratio/100.0,
11982                                 mono_jit_stats.max_ratio_method->klass->name, mono_jit_stats.max_ratio_method->name);
11983                 g_print ("Biggest method:         %ld (%s::%s)\n", mono_jit_stats.biggest_method_size,
11984                                 mono_jit_stats.biggest_method->klass->name, mono_jit_stats.biggest_method->name);
11985                 g_print ("Code reallocs:          %ld\n", mono_jit_stats.code_reallocs);
11986                 g_print ("Allocated code size:    %ld\n", mono_jit_stats.allocated_code_size);
11987                 g_print ("Inlineable methods:     %ld\n", mono_jit_stats.inlineable_methods);
11988                 g_print ("Inlined methods:        %ld\n", mono_jit_stats.inlined_methods);
11989                 g_print ("Locals stack size:      %ld\n", mono_jit_stats.locals_stack_size);
11990
11991                 g_print ("\nCreated object count:   %ld\n", mono_stats.new_object_count);
11992                 g_print ("Initialized classes:    %ld\n", mono_stats.initialized_class_count);
11993                 g_print ("Used classes:           %ld\n", mono_stats.used_class_count);
11994                 g_print ("Generic vtables:        %ld\n", mono_stats.generic_vtable_count);
11995                 g_print ("Methods:                %ld\n", mono_stats.method_count);
11996                 g_print ("Static data size:       %ld\n", mono_stats.class_static_data_size);
11997                 g_print ("VTable data size:       %ld\n", mono_stats.class_vtable_size);
11998                 g_print ("Mscorlib mempool size:  %d\n", mono_mempool_get_allocated (mono_defaults.corlib->mempool));
11999
12000                 g_print ("\nGeneric instances:      %ld\n", mono_stats.generic_instance_count);
12001                 g_print ("Initialized classes:    %ld\n", mono_stats.generic_class_count);
12002                 g_print ("Inflated methods:       %ld / %ld\n", mono_stats.inflated_method_count_2,
12003                          mono_stats.inflated_method_count);
12004                 g_print ("Inflated types:         %ld\n", mono_stats.inflated_type_count);
12005                 g_print ("Generics metadata size: %ld\n", mono_stats.generics_metadata_size);
12006
12007                 if (mono_use_security_manager) {
12008                         g_print ("\nDecl security check   : %ld\n", mono_jit_stats.cas_declsec_check);
12009                         g_print ("LinkDemand (user)     : %ld\n", mono_jit_stats.cas_linkdemand);
12010                         g_print ("LinkDemand (icall)    : %ld\n", mono_jit_stats.cas_linkdemand_icall);
12011                         g_print ("LinkDemand (pinvoke)  : %ld\n", mono_jit_stats.cas_linkdemand_pinvoke);
12012                         g_print ("LinkDemand (aptc)     : %ld\n", mono_jit_stats.cas_linkdemand_aptc);
12013                         g_print ("Demand (code gen)     : %ld\n", mono_jit_stats.cas_demand_generation);
12014                 }
12015                 if (debug_options.collect_pagefault_stats) {
12016                         g_print ("Metadata pagefaults   : %d\n", mono_raw_buffer_get_n_pagefaults ());
12017                         g_print ("AOT pagefaults        : %d\n", mono_aot_get_n_pagefaults ());
12018                 }
12019         }
12020 }
12021
12022 void
12023 mini_cleanup (MonoDomain *domain)
12024 {
12025 #ifdef HAVE_LINUX_RTC_H
12026         if (rtc_fd >= 0)
12027                 enable_rtc_timer (FALSE);
12028 #endif
12029
12030         /* 
12031          * mono_runtime_cleanup() and mono_domain_finalize () need to
12032          * be called early since they need the execution engine still
12033          * fully working (mono_domain_finalize may invoke managed finalizers
12034          * and mono_runtime_cleanup will wait for other threads to finish).
12035          */
12036         mono_domain_finalize (domain, 2000);
12037
12038         /* This accesses metadata so needs to be called before runtime shutdown */
12039         print_jit_stats ();
12040
12041         mono_runtime_cleanup (domain);
12042
12043         mono_profiler_shutdown ();
12044
12045         mono_debug_cleanup ();
12046
12047         mono_icall_cleanup ();
12048
12049         mono_runtime_cleanup_handlers ();
12050
12051         mono_domain_free (domain, TRUE);
12052
12053         mono_code_manager_destroy (global_codeman);
12054         g_hash_table_destroy (jit_icall_name_hash);
12055         if (class_init_hash_addr)
12056                 g_hash_table_destroy (class_init_hash_addr);
12057         g_free (emul_opcode_map);
12058
12059         mono_cleanup ();
12060
12061         mono_trace_cleanup ();
12062
12063         mono_counters_dump (-1, stdout);
12064
12065         TlsFree(mono_jit_tls_id);
12066
12067         DeleteCriticalSection (&jit_mutex);
12068
12069         DeleteCriticalSection (&mono_delegate_section);
12070 }
12071
12072 void
12073 mono_set_defaults (int verbose_level, guint32 opts)
12074 {
12075         mini_verbose = verbose_level;
12076         default_opt = opts;
12077         default_opt_set = TRUE;
12078 }
12079
12080 static void
12081 mono_precompile_assembly (MonoAssembly *ass, void *user_data)
12082 {
12083         GHashTable *assemblies = (GHashTable*)user_data;
12084         MonoImage *image = mono_assembly_get_image (ass);
12085         MonoMethod *method, *invoke;
12086         int i, count = 0;
12087
12088         if (g_hash_table_lookup (assemblies, ass))
12089                 return;
12090
12091         g_hash_table_insert (assemblies, ass, ass);
12092
12093         if (mini_verbose > 0)
12094                 printf ("PRECOMPILE: %s.\n", mono_image_get_filename (image));
12095
12096         for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_METHOD); ++i) {
12097                 method = mono_get_method (image, MONO_TOKEN_METHOD_DEF | (i + 1), NULL);
12098                 if (method->flags & METHOD_ATTRIBUTE_ABSTRACT)
12099                         continue;
12100
12101                 count++;
12102                 if (mini_verbose > 1) {
12103                         char * desc = mono_method_full_name (method, TRUE);
12104                         g_print ("Compiling %d %s\n", count, desc);
12105                         g_free (desc);
12106                 }
12107                 mono_compile_method (method);
12108                 if (strcmp (method->name, "Finalize") == 0) {
12109                         invoke = mono_marshal_get_runtime_invoke (method);
12110                         mono_compile_method (invoke);
12111                 }
12112                 if (method->klass->marshalbyref && mono_method_signature (method)->hasthis) {
12113                         invoke = mono_marshal_get_remoting_invoke_with_check (method);
12114                         mono_compile_method (invoke);
12115                 }
12116         }
12117
12118         /* Load and precompile referenced assemblies as well */
12119         for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_ASSEMBLYREF); ++i) {
12120                 mono_assembly_load_reference (image, i);
12121                 if (image->references [i])
12122                         mono_precompile_assembly (image->references [i], assemblies);
12123         }
12124 }
12125
12126 void mono_precompile_assemblies ()
12127 {
12128         GHashTable *assemblies = g_hash_table_new (NULL, NULL);
12129
12130         mono_assembly_foreach ((GFunc)mono_precompile_assembly, assemblies);
12131
12132         g_hash_table_destroy (assemblies);
12133 }