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