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