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