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