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