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