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