Another small fix.
[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
2462 #define TYPE_PARAM_TO_TYPE(num) (method->klass->generic_inst->data.generic_inst->type_argv [(num)])
2463 #define TYPE_PARAM_TO_CLASS(num) (mono_class_from_mono_type (TYPE_PARAM_TO_TYPE ((num))))
2464
2465 #define MTYPE_PARAM_TO_TYPE(num) (((MonoMethodNormal *) method)->header->geninst->type_argv [(num)])
2466 #define MTYPE_PARAM_TO_CLASS(num) (mono_class_from_mono_type (MTYPE_PARAM_TO_TYPE ((num))))
2467
2468
2469 /* offset from br.s -> br like opcodes */
2470 #define BIG_BRANCH_OFFSET 13
2471
2472 static int
2473 get_basic_blocks (MonoCompile *cfg, GHashTable *bbhash, MonoMethodHeader* header, guint real_offset, unsigned char *start, unsigned char *end, unsigned char **pos)
2474 {
2475         unsigned char *ip = start;
2476         unsigned char *target;
2477         int i;
2478         guint cli_addr;
2479         MonoBasicBlock *bblock;
2480         const MonoOpcode *opcode;
2481
2482         while (ip < end) {
2483                 cli_addr = ip - start;
2484                 i = mono_opcode_value ((const guint8 **)&ip);
2485                 opcode = &mono_opcodes [i];
2486                 switch (opcode->argument) {
2487                 case MonoInlineNone:
2488                         ip++; 
2489                         break;
2490                 case MonoInlineString:
2491                 case MonoInlineType:
2492                 case MonoInlineField:
2493                 case MonoInlineMethod:
2494                 case MonoInlineTok:
2495                 case MonoInlineSig:
2496                 case MonoShortInlineR:
2497                 case MonoInlineI:
2498                         ip += 5;
2499                         break;
2500                 case MonoInlineVar:
2501                         ip += 3;
2502                         break;
2503                 case MonoShortInlineVar:
2504                 case MonoShortInlineI:
2505                         ip += 2;
2506                         break;
2507                 case MonoShortInlineBrTarget:
2508                         target = start + cli_addr + 2 + (signed char)ip [1];
2509                         GET_BBLOCK (cfg, bbhash, bblock, target);
2510                         ip += 2;
2511                         break;
2512                 case MonoInlineBrTarget:
2513                         target = start + cli_addr + 5 + (gint32)read32 (ip + 1);
2514                         GET_BBLOCK (cfg, bbhash, bblock, target);
2515                         ip += 5;
2516                         break;
2517                 case MonoInlineSwitch: {
2518                         guint32 n = read32 (ip + 1);
2519                         guint32 j;
2520                         ip += 5;
2521                         cli_addr += 5 + 4 * n;
2522                         target = start + cli_addr;
2523                         GET_BBLOCK (cfg, bbhash, bblock, target);
2524                         
2525                         for (j = 0; j < n; ++j) {
2526                                 target = start + cli_addr + (gint32)read32 (ip);
2527                                 GET_BBLOCK (cfg, bbhash, bblock, target);
2528                                 ip += 4;
2529                         }
2530                         break;
2531                 }
2532                 case MonoInlineR:
2533                 case MonoInlineI8:
2534                         ip += 9;
2535                         break;
2536                 default:
2537                         g_assert_not_reached ();
2538                 }
2539         }
2540         return 0;
2541 unverified:
2542         *pos = ip;
2543         return 1;
2544 }
2545
2546 static MonoClassField *
2547 get_generic_field_inst (MonoClassField *field, MonoClass *klass, MonoClass **retclass)
2548 {
2549         int i;
2550         for (i = 0; i < field->parent->field.count; ++i) {
2551                 if (field == &field->parent->fields [i]) {
2552                         *retclass = klass;
2553                         return &klass->fields [i];
2554                 }
2555         }
2556         return NULL;
2557 }
2558
2559 static MonoClassField *
2560 inflate_generic_field (MonoClassField *field, MonoClass *klass, MonoClass **retclass)
2561 {
2562         MonoGenericInst *ginst;
2563         MonoClassField *res;
2564
2565         res = g_new0 (MonoClassField, 1);
2566         *res = *field;
2567         ginst = klass->generic_inst->data.generic_inst;
2568         res->type = mono_class_inflate_generic_type (field->type, ginst);
2569         return res;
2570 }
2571
2572 /*
2573  * mono_method_to_ir: translates IL into basic blocks containing trees
2574  */
2575 static int
2576 mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock, 
2577                    int locals_offset, MonoInst *return_var, GList *dont_inline, MonoInst **inline_args, 
2578                    guint inline_offset, gboolean is_virtual_call)
2579 {
2580         MonoInst *zero_int32, *zero_int64, *zero_ptr, *zero_obj, *zero_r8;
2581         MonoInst *ins, **sp, **stack_start;
2582         MonoBasicBlock *bblock, *tblock = NULL, *init_localsbb = NULL;
2583         GHashTable *bbhash;
2584         MonoMethod *cmethod;
2585         MonoInst **arg_array;
2586         MonoMethodHeader *header;
2587         MonoImage *image;
2588         guint32 token, ins_flag;
2589         MonoClass *klass;
2590         unsigned char *ip, *end, *target, *err_pos;
2591         static double r8_0 = 0.0;
2592         MonoMethodSignature *sig;
2593         MonoType **param_types;
2594         GList *bb_recheck = NULL, *tmp;
2595         int i, n, start_new_bblock, align;
2596         int num_calls = 0, inline_costs = 0;
2597         int *filter_lengths = NULL;
2598         int breakpoint_id = 0;
2599         guint real_offset;
2600
2601         image = method->klass->image;
2602         header = ((MonoMethodNormal *)method)->header;
2603         sig = method->signature;
2604         ip = (unsigned char*)header->code;
2605         end = ip + header->code_size;
2606         mono_jit_stats.cil_code_size += header->code_size;
2607
2608         if (cfg->method == method) {
2609                 real_offset = 0;
2610                 bbhash = cfg->bb_hash;
2611         } else {
2612                 real_offset = inline_offset;
2613                 bbhash = g_hash_table_new (g_direct_hash, NULL);
2614         }
2615
2616         if (cfg->verbose_level > 2)
2617                 g_print ("method to IR %s\n", mono_method_full_name (method, TRUE));
2618
2619         if (cfg->prof_options & MONO_PROFILE_INS_COVERAGE)
2620                 cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, header->code_size);
2621
2622         dont_inline = g_list_prepend (dont_inline, method);
2623         if (cfg->method == method) {
2624
2625                 /* ENTRY BLOCK */
2626                 cfg->bb_entry = start_bblock = NEW_BBLOCK (cfg);
2627                 start_bblock->cil_code = NULL;
2628                 start_bblock->cil_length = 0;
2629                 start_bblock->block_num = cfg->num_bblocks++;
2630
2631                 /* EXIT BLOCK */
2632                 cfg->bb_exit = end_bblock = NEW_BBLOCK (cfg);
2633                 end_bblock->cil_code = NULL;
2634                 end_bblock->cil_length = 0;
2635                 end_bblock->block_num = cfg->num_bblocks++;
2636                 g_assert (cfg->num_bblocks == 2);
2637
2638                 arg_array = alloca (sizeof (MonoInst *) * (sig->hasthis + sig->param_count));
2639                 for (i = sig->hasthis + sig->param_count - 1; i >= 0; i--)
2640                         arg_array [i] = cfg->varinfo [i];
2641
2642                 if (header->num_clauses) {
2643                         int size = sizeof (int) * header->num_clauses;
2644                         filter_lengths = alloca (size);
2645                         memset (filter_lengths, 0, size);
2646
2647                         cfg->spvars = g_hash_table_new (NULL, NULL);
2648                 }
2649                 /* handle exception clauses */
2650                 for (i = 0; i < header->num_clauses; ++i) {
2651                         //unsigned char *p = ip;
2652                         MonoExceptionClause *clause = &header->clauses [i];
2653                         GET_BBLOCK (cfg, bbhash, tblock, ip + clause->try_offset);
2654                         tblock->real_offset = clause->try_offset;
2655                         GET_BBLOCK (cfg, bbhash, tblock, ip + clause->handler_offset);
2656                         tblock->real_offset = clause->handler_offset;
2657
2658                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY ||
2659                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
2660                                 MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
2661                                 MONO_ADD_INS (tblock, ins);
2662                         }
2663
2664                         /*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);
2665                           while (p < end) {
2666                           g_print ("%s", mono_disasm_code_one (NULL, method, p, &p));
2667                           }*/
2668                         /* catch and filter blocks get the exception object on the stack */
2669                         if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE ||
2670                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
2671                                 /* mostly like handle_stack_args (), but just sets the input args */
2672                                 /* g_print ("handling clause at IL_%04x\n", clause->handler_offset); */
2673                                 if (!cfg->exvar) {
2674                                         cfg->exvar = mono_compile_create_var (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL);
2675                                         /* prevent it from being register allocated */
2676                                         cfg->exvar->flags |= MONO_INST_INDIRECT;
2677                                 }
2678                                 tblock->in_scount = 1;
2679                                 tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
2680                                 tblock->in_stack [0] = cfg->exvar;
2681                                 
2682                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
2683                                         GET_BBLOCK (cfg, bbhash, tblock, ip + clause->token_or_filter);
2684                                         tblock->real_offset = clause->token_or_filter;
2685                                         tblock->in_scount = 1;
2686                                         tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
2687                                         tblock->in_stack [0] = cfg->exvar;
2688                                         MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
2689                                         MONO_ADD_INS (tblock, ins);
2690                                 }
2691                         }
2692                 }
2693
2694         } else {
2695                 arg_array = alloca (sizeof (MonoInst *) * (sig->hasthis + sig->param_count));
2696                 mono_save_args (cfg, start_bblock, sig, inline_args, arg_array);
2697         }
2698
2699         /* FIRST CODE BLOCK */
2700         bblock = NEW_BBLOCK (cfg);
2701         bblock->cil_code = ip;
2702
2703         ADD_BBLOCK (cfg, bbhash, bblock);
2704
2705         if (cfg->method == method) {
2706                 breakpoint_id = mono_debugger_method_has_breakpoint (method);
2707                 if (breakpoint_id && (mono_debug_format != MONO_DEBUG_FORMAT_DEBUGGER)) {
2708                         MONO_INST_NEW (cfg, ins, CEE_BREAK);
2709                         MONO_ADD_INS (bblock, ins);
2710                 }
2711         }
2712         
2713         if ((header->init_locals || (cfg->method == method && (cfg->opt & MONO_OPT_SHARED))) || mono_compile_aot) {
2714                 /* we use a separate basic block for the initialization code */
2715                 cfg->bb_init = init_localsbb = NEW_BBLOCK (cfg);
2716                 init_localsbb->real_offset = real_offset;
2717                 start_bblock->next_bb = init_localsbb;
2718                 init_localsbb->next_bb = bblock;
2719                 link_bblock (cfg, start_bblock, init_localsbb);
2720                 link_bblock (cfg, init_localsbb, bblock);
2721                 init_localsbb->block_num = cfg->num_bblocks++;
2722         } else {
2723                 start_bblock->next_bb = bblock;
2724                 link_bblock (cfg, start_bblock, bblock);
2725         }
2726
2727         if (get_basic_blocks (cfg, bbhash, header, real_offset, ip, end, &err_pos)) {
2728                 ip = err_pos;
2729                 goto unverified;
2730         }
2731
2732         mono_debug_init_method (cfg, bblock, breakpoint_id);
2733
2734         param_types = mono_mempool_alloc (cfg->mempool, sizeof (MonoType*) * (sig->hasthis + sig->param_count));
2735         if (sig->hasthis)
2736                 param_types [0] = method->klass->valuetype?&method->klass->this_arg:&method->klass->byval_arg;
2737         for (n = 0; n < sig->param_count; ++n)
2738                 param_types [n + sig->hasthis] = sig->params [n];
2739
2740         /* do this somewhere outside - not here */
2741         NEW_ICONST (cfg, zero_int32, 0);
2742         NEW_ICONST (cfg, zero_int64, 0);
2743         zero_int64->type = STACK_I8;
2744         NEW_PCONST (cfg, zero_ptr, 0);
2745         NEW_PCONST (cfg, zero_obj, 0);
2746         zero_obj->type = STACK_OBJ;
2747
2748         MONO_INST_NEW (cfg, zero_r8, OP_R8CONST);
2749         zero_r8->type = STACK_R8;
2750         zero_r8->inst_p0 = &r8_0;
2751
2752         /* add a check for this != NULL to inlined methods */
2753         if (is_virtual_call) {
2754                 MONO_INST_NEW (cfg, ins, OP_CHECK_THIS);
2755                 NEW_ARGLOAD (cfg, ins->inst_left, 0);
2756                 ins->cil_code = ip;
2757                 MONO_ADD_INS (bblock, ins);
2758         }
2759
2760         /* we use a spare stack slot in SWITCH and NEWOBJ and others */
2761         stack_start = sp = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (header->max_stack + 1));
2762
2763         ins_flag = 0;
2764         start_new_bblock = 0;
2765         while (ip < end) {
2766
2767                 if (cfg->method == method)
2768                         real_offset = ip - header->code;
2769                 else
2770                         real_offset = inline_offset;
2771
2772                 if (start_new_bblock) {
2773                         bblock->cil_length = ip - bblock->cil_code;
2774                         if (start_new_bblock == 2) {
2775                                 g_assert (ip == tblock->cil_code);
2776                         } else {
2777                                 GET_BBLOCK (cfg, bbhash, tblock, ip);
2778                         }
2779                         bblock->next_bb = tblock;
2780                         bblock = tblock;
2781                         start_new_bblock = 0;
2782                         for (i = 0; i < bblock->in_scount; ++i) {
2783                                 NEW_TEMPLOAD (cfg, ins, bblock->in_stack [i]->inst_c0);
2784                                 *sp++ = ins;
2785                         }
2786                 } else {
2787                         if ((tblock = g_hash_table_lookup (bbhash, ip)) && (tblock != bblock)) {
2788                                 link_bblock (cfg, bblock, tblock);
2789                                 if (sp != stack_start) {
2790                                         handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
2791                                         sp = stack_start;
2792                                 }
2793                                 bblock->next_bb = tblock;
2794                                 bblock = tblock;
2795                                 for (i = 0; i < bblock->in_scount; ++i) {
2796                                         NEW_TEMPLOAD (cfg, ins, bblock->in_stack [i]->inst_c0);
2797                                         *sp++ = ins;
2798                                 }
2799                         }
2800                 }
2801
2802                 if (cfg->coverage_info) {
2803                         MonoInst *store, *one;
2804                         guint32 cil_offset = ip - header->code;
2805                         cfg->coverage_info->data [cil_offset].cil_code = ip;
2806
2807                         /* TODO: Use an increment here */
2808                         NEW_ICONST (cfg, one, 1);
2809                         one->cil_code = ip;
2810
2811                         NEW_PCONST (cfg, ins, &(cfg->coverage_info->data [cil_offset].count));
2812                         ins->cil_code = ip;
2813
2814                         MONO_INST_NEW (cfg, store, CEE_STIND_I);
2815                         store->cil_code = ip;
2816                         store->inst_left = ins;
2817                         store->inst_right = one;
2818
2819                         MONO_ADD_INS (bblock, store);
2820                 }
2821
2822                 if (cfg->verbose_level > 3)
2823                         g_print ("converting (in B%d: stack: %d) %s", bblock->block_num, sp-stack_start, mono_disasm_code_one (NULL, method, ip, NULL));
2824
2825                 switch (*ip) {
2826                 case CEE_NOP:
2827                         ++ip;
2828                         break;
2829                 case CEE_BREAK:
2830                         MONO_INST_NEW (cfg, ins, CEE_BREAK);
2831                         ins->cil_code = ip++;
2832                         MONO_ADD_INS (bblock, ins);
2833                         break;
2834                 case CEE_LDARG_0:
2835                 case CEE_LDARG_1:
2836                 case CEE_LDARG_2:
2837                 case CEE_LDARG_3:
2838                         CHECK_STACK_OVF (1);
2839                         n = (*ip)-CEE_LDARG_0;
2840                         NEW_ARGLOAD (cfg, ins, n);
2841                         ins->cil_code = ip++;
2842                         *sp++ = ins;
2843                         break;
2844                 case CEE_LDLOC_0:
2845                 case CEE_LDLOC_1:
2846                 case CEE_LDLOC_2:
2847                 case CEE_LDLOC_3:
2848                         CHECK_STACK_OVF (1);
2849                         n = (*ip)-CEE_LDLOC_0;
2850                         NEW_LOCLOAD (cfg, ins, n);
2851                         ins->cil_code = ip++;
2852                         *sp++ = ins;
2853                         break;
2854                 case CEE_STLOC_0:
2855                 case CEE_STLOC_1:
2856                 case CEE_STLOC_2:
2857                 case CEE_STLOC_3:
2858                         CHECK_STACK (1);
2859                         n = (*ip)-CEE_STLOC_0;
2860                         --sp;
2861                         handle_loaded_temps (cfg, bblock, stack_start, sp);
2862                         NEW_LOCSTORE (cfg, ins, n, *sp);
2863                         ins->cil_code = ip;
2864                         if (ins->opcode == CEE_STOBJ) {
2865                                 NEW_LOCLOADA (cfg, ins, n);
2866                                 handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE);
2867                         } else
2868                                 MONO_ADD_INS (bblock, ins);
2869                         ++ip;
2870                         inline_costs += 1;
2871                         break;
2872                 case CEE_LDARG_S:
2873                         CHECK_STACK_OVF (1);
2874                         NEW_ARGLOAD (cfg, ins, ip [1]);
2875                         ins->cil_code = ip;
2876                         *sp++ = ins;
2877                         ip += 2;
2878                         break;
2879                 case CEE_LDARGA_S:
2880                         CHECK_STACK_OVF (1);
2881                         NEW_ARGLOADA (cfg, ins, ip [1]);
2882                         ins->cil_code = ip;
2883                         *sp++ = ins;
2884                         ip += 2;
2885                         break;
2886                 case CEE_STARG_S:
2887                         CHECK_STACK (1);
2888                         --sp;
2889                         NEW_ARGSTORE (cfg, ins, ip [1], *sp);
2890                         handle_loaded_temps (cfg, bblock, stack_start, sp);
2891                         ins->cil_code = ip;
2892                         if (ins->opcode == CEE_STOBJ) {
2893                                 NEW_ARGLOADA (cfg, ins, ip [1]);
2894                                 handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE);
2895                         } else
2896                                 MONO_ADD_INS (bblock, ins);
2897                         ip += 2;
2898                         break;
2899                 case CEE_LDLOC_S:
2900                         CHECK_STACK_OVF (1);
2901                         NEW_LOCLOAD (cfg, ins, ip [1]);
2902                         ins->cil_code = ip;
2903                         *sp++ = ins;
2904                         ip += 2;
2905                         break;
2906                 case CEE_LDLOCA_S:
2907                         CHECK_STACK_OVF (1);
2908                         NEW_LOCLOADA (cfg, ins, ip [1]);
2909                         ins->cil_code = ip;
2910                         *sp++ = ins;
2911                         ip += 2;
2912                         break;
2913                 case CEE_STLOC_S:
2914                         CHECK_STACK (1);
2915                         --sp;
2916                         handle_loaded_temps (cfg, bblock, stack_start, sp);
2917                         NEW_LOCSTORE (cfg, ins, ip [1], *sp);
2918                         ins->cil_code = ip;
2919                         if (ins->opcode == CEE_STOBJ) {
2920                                 NEW_LOCLOADA (cfg, ins, ip [1]);
2921                                 handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE);
2922                         } else
2923                                 MONO_ADD_INS (bblock, ins);
2924                         ip += 2;
2925                         inline_costs += 1;
2926                         break;
2927                 case CEE_LDNULL:
2928                         CHECK_STACK_OVF (1);
2929                         NEW_PCONST (cfg, ins, NULL);
2930                         ins->cil_code = ip;
2931                         ins->type = STACK_OBJ;
2932                         ++ip;
2933                         *sp++ = ins;
2934                         break;
2935                 case CEE_LDC_I4_M1:
2936                         CHECK_STACK_OVF (1);
2937                         NEW_ICONST (cfg, ins, -1);
2938                         ins->cil_code = ip;
2939                         ++ip;
2940                         *sp++ = ins;
2941                         break;
2942                 case CEE_LDC_I4_0:
2943                 case CEE_LDC_I4_1:
2944                 case CEE_LDC_I4_2:
2945                 case CEE_LDC_I4_3:
2946                 case CEE_LDC_I4_4:
2947                 case CEE_LDC_I4_5:
2948                 case CEE_LDC_I4_6:
2949                 case CEE_LDC_I4_7:
2950                 case CEE_LDC_I4_8:
2951                         CHECK_STACK_OVF (1);
2952                         NEW_ICONST (cfg, ins, (*ip) - CEE_LDC_I4_0);
2953                         ins->cil_code = ip;
2954                         ++ip;
2955                         *sp++ = ins;
2956                         break;
2957                 case CEE_LDC_I4_S:
2958                         CHECK_STACK_OVF (1);
2959                         ++ip;
2960                         NEW_ICONST (cfg, ins, *((signed char*)ip));
2961                         ins->cil_code = ip;
2962                         ++ip;
2963                         *sp++ = ins;
2964                         break;
2965                 case CEE_LDC_I4:
2966                         CHECK_STACK_OVF (1);
2967                         NEW_ICONST (cfg, ins, (gint32)read32 (ip + 1));
2968                         ins->cil_code = ip;
2969                         ip += 5;
2970                         *sp++ = ins;
2971                         break;
2972                 case CEE_LDC_I8:
2973                         CHECK_STACK_OVF (1);
2974                         MONO_INST_NEW (cfg, ins, OP_I8CONST);
2975                         ins->cil_code = ip;
2976                         ins->type = STACK_I8;
2977                         ++ip;
2978                         ins->inst_l = (gint64)read64 (ip);
2979                         ip += 8;
2980                         *sp++ = ins;
2981                         break;
2982                 case CEE_LDC_R4: {
2983                         float *f = g_malloc (sizeof (float));
2984                         CHECK_STACK_OVF (1);
2985                         MONO_INST_NEW (cfg, ins, OP_R4CONST);
2986                         ins->type = STACK_R8;
2987                         ++ip;
2988                         readr4 (ip, f);
2989                         ins->inst_p0 = f;
2990                         ip += 4;
2991                         *sp++ = ins;                    
2992                         break;
2993                 }
2994                 case CEE_LDC_R8: {
2995                         double *d = g_malloc (sizeof (double));
2996                         CHECK_STACK_OVF (1);
2997                         MONO_INST_NEW (cfg, ins, OP_R8CONST);
2998                         ins->type = STACK_R8;
2999                         ++ip;
3000                         readr8 (ip, d);
3001                         ins->inst_p0 = d;
3002                         ip += 8;
3003                         *sp++ = ins;                    
3004                         break;
3005                 }
3006                 case CEE_DUP: {
3007                         MonoInst *temp, *store;
3008                         CHECK_STACK (1);
3009                         CHECK_STACK_OVF (1);
3010                         sp--;
3011                         ins = *sp;
3012                 
3013                         /* 
3014                          * small optimization: if the loaded value was from a local already,
3015                          * just load it twice.
3016                          */
3017                         if (ins->ssa_op == MONO_SSA_LOAD && 
3018                             (ins->inst_i0->opcode == OP_LOCAL || ins->inst_i0->opcode == OP_ARG)) {
3019                                 sp++;
3020                                 MONO_INST_NEW (cfg, temp, 0);
3021                                 *temp = *ins;
3022                                 temp->cil_code = ip;
3023                                 *sp++ = temp;
3024                         } else {
3025                                 temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
3026                                 temp->cil_code = ip;
3027                                 NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
3028                                 store->cil_code = ip;
3029                                 MONO_ADD_INS (bblock, store);
3030                                 NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
3031                                 *sp++ = ins;
3032                                 ins->cil_code = ip;
3033                                 NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
3034                                 *sp++ = ins;
3035                                 ins->cil_code = ip;
3036                         }
3037                         ++ip;
3038                         inline_costs += 2;
3039                         break;
3040                 }
3041                 case CEE_POP:
3042                         CHECK_STACK (1);
3043                         MONO_INST_NEW (cfg, ins, CEE_POP);
3044                         MONO_ADD_INS (bblock, ins);
3045                         ins->cil_code = ip++;
3046                         --sp;
3047                         ins->inst_i0 = *sp;
3048                         break;
3049                 case CEE_JMP:
3050                         if (stack_start != sp)
3051                                 goto unverified;
3052                         MONO_INST_NEW (cfg, ins, CEE_JMP);
3053                         token = read32 (ip + 1);
3054                         /* FIXME: check the signature matches */
3055                         cmethod = mono_get_method (image, token, NULL);
3056                         ins->inst_p0 = cmethod;
3057                         MONO_ADD_INS (bblock, ins);
3058                         ip += 5;
3059                         start_new_bblock = 1;
3060                         break;
3061                 case CEE_CALLI:
3062                 case CEE_CALL:
3063                 case CEE_CALLVIRT: {
3064                         MonoInst *addr = NULL;
3065                         MonoMethodSignature *fsig = NULL;
3066                         int temp, array_rank = 0;
3067                         int virtual = *ip == CEE_CALLVIRT;
3068
3069                         token = read32 (ip + 1);
3070
3071                         if (*ip == CEE_CALLI) {
3072                                 cmethod = NULL;
3073                                 CHECK_STACK (1);
3074                                 --sp;
3075                                 addr = *sp;
3076                                 if (method->wrapper_type != MONO_WRAPPER_NONE)
3077                                         fsig = (MonoMethodSignature *)mono_method_get_wrapper_data (method, token);
3078                                 else
3079                                         fsig = mono_metadata_parse_signature (image, token);
3080
3081                                 n = fsig->param_count + fsig->hasthis;
3082                         } else {
3083                                 if (method->wrapper_type != MONO_WRAPPER_NONE) {
3084                                         cmethod =  (MonoMethod *)mono_method_get_wrapper_data (method, token);
3085                                 } else {
3086                                         cmethod = mono_get_method (image, token, NULL);
3087                                 }
3088
3089                                 if (!cmethod->klass->inited)
3090                                         mono_class_init (cmethod->klass);
3091
3092                                 if (cmethod->signature->pinvoke) {
3093 #ifdef MONO_USE_EXC_TABLES
3094                                         if (mono_method_blittable (cmethod)) {
3095                                                 fsig = cmethod->signature;
3096                                         } else {
3097 #endif
3098                                                 MonoMethod *wrapper = mono_marshal_get_native_wrapper (cmethod);
3099                                                 fsig = wrapper->signature;
3100 #ifdef MONO_USE_EXC_TABLES
3101                                         }
3102 #endif
3103                                 } else {
3104                                         fsig = mono_method_get_signature (cmethod, image, token);
3105                                 }
3106
3107                                 n = fsig->param_count + fsig->hasthis;
3108
3109                                 if (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL &&
3110                                     cmethod->klass->parent == mono_defaults.array_class) {
3111                                         array_rank = cmethod->klass->rank;
3112                                 }
3113
3114                                 if (cmethod->string_ctor)
3115                                         g_assert_not_reached ();
3116
3117                         }
3118
3119                         CHECK_STACK (n);
3120
3121                         //g_assert (!virtual || fsig->hasthis);
3122
3123                         sp -= n;
3124
3125                         if (*ip != CEE_CALLI && check_call_signature (cfg, fsig, sp))
3126                                 goto unverified;
3127
3128                         if ((ins_flag & MONO_INST_TAILCALL) && cmethod && (*ip == CEE_CALL) && (mono_metadata_signature_equal (method->signature, cmethod->signature))) {
3129                                 int i;
3130                                 /* FIXME: This assumes the two methods has the same number and type of arguments */
3131                                 for (i = 0; i < n; ++i) {
3132                                         /* Check if argument is the same */
3133                                         NEW_ARGLOAD (cfg, ins, i);
3134                                         if ((ins->opcode == sp [i]->opcode) && (ins->inst_i0 == sp [i]->inst_i0))
3135                                                 continue;
3136
3137                                         NEW_ARGSTORE (cfg, ins, i, sp [i]);
3138                                         ins->cil_code = ip;
3139                                         if (ins->opcode == CEE_STOBJ) {
3140                                                 NEW_ARGLOADA (cfg, ins, i);
3141                                                 handle_stobj (cfg, bblock, ins, sp [i], sp [i]->cil_code, ins->klass, FALSE, FALSE);
3142                                         }
3143                                         else
3144                                                 MONO_ADD_INS (bblock, ins);
3145                                 }
3146                                 MONO_INST_NEW (cfg, ins, CEE_JMP);
3147                                 ins->cil_code = ip;
3148                                 ins->inst_p0 = cmethod;
3149                                 ins->inst_p1 = arg_array [0];
3150                                 MONO_ADD_INS (bblock, ins);
3151                                 start_new_bblock = 1;
3152                                 /* skip CEE_RET as well */
3153                                 ip += 6;
3154                                 ins_flag = 0;
3155                                 break;
3156                         }
3157                         if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_get_opcode_for_method (cfg, cmethod, fsig, sp))) {
3158                                 ins->cil_code = ip;
3159
3160                                 if (MONO_TYPE_IS_VOID (fsig->ret)) {
3161                                         MONO_ADD_INS (bblock, ins);
3162                                 } else {
3163                                         type_to_eval_stack_type (fsig->ret, ins);
3164                                         *sp = ins;
3165                                         sp++;
3166                                 }
3167
3168                                 ip += 5;
3169                                 break;
3170                         }
3171
3172                         handle_loaded_temps (cfg, bblock, stack_start, sp);
3173
3174                         if ((cfg->opt & MONO_OPT_INLINE) && cmethod &&
3175                             (!virtual || !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) || (cmethod->flags & METHOD_ATTRIBUTE_FINAL)) && 
3176                             mono_method_check_inlining (cfg, cmethod) &&
3177                             !g_list_find (dont_inline, cmethod)) {
3178                                 int costs;
3179                                 MonoBasicBlock *ebblock;
3180
3181                                 if ((costs = inline_method (cfg, cmethod, fsig, bblock, sp, ip, real_offset, dont_inline, &ebblock))) {
3182                                         ip += 5;
3183                                         real_offset += 5;
3184
3185                                         GET_BBLOCK (cfg, bbhash, bblock, ip);
3186                                         ebblock->next_bb = bblock;
3187                                         link_bblock (cfg, ebblock, bblock);
3188
3189                                         if (!MONO_TYPE_IS_VOID (fsig->ret))
3190                                                 sp++;
3191
3192                                         /* indicates start of a new block, and triggers a load of all 
3193                                            stack arguments at bb boundarie */
3194                                         bblock = ebblock;
3195
3196                                         inline_costs += costs;
3197                                         break;
3198                                 }
3199                         }
3200                         
3201                         inline_costs += 10 * num_calls++;
3202
3203                         /* tail recursion elimination */
3204                         if ((cfg->opt & MONO_OPT_TAILC) && *ip == CEE_CALL && cmethod == method && ip [5] == CEE_RET) {
3205                                 gboolean has_vtargs = FALSE;
3206                                 int i;
3207                                 
3208                                 /* keep it simple */
3209                                 for (i =  fsig->param_count - 1; i >= 0; i--) {
3210                                         if (MONO_TYPE_ISSTRUCT (cmethod->signature->params [i])) 
3211                                                 has_vtargs = TRUE;
3212                                 }
3213
3214                                 if (!has_vtargs) {
3215                                         for (i = 0; i < n; ++i) {
3216                                                 NEW_ARGSTORE (cfg, ins, i, sp [i]);
3217                                                 ins->cil_code = ip;
3218                                                 MONO_ADD_INS (bblock, ins);
3219                                         }
3220                                         MONO_INST_NEW (cfg, ins, CEE_BR);
3221                                         ins->cil_code = ip;
3222                                         MONO_ADD_INS (bblock, ins);
3223                                         tblock = start_bblock->out_bb [0];
3224                                         link_bblock (cfg, bblock, tblock);
3225                                         ins->inst_target_bb = tblock;
3226                                         start_new_bblock = 1;
3227                                         ip += 5;
3228                                         
3229                                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
3230                                                 /* just create a dummy - the value is never used */
3231                                                 ins = mono_compile_create_var (cfg, fsig->ret, OP_LOCAL);
3232                                                 NEW_TEMPLOAD (cfg, *sp, ins->inst_c0);
3233                                                 sp++;
3234                                         }
3235
3236                                         break;
3237                                 }
3238                         }
3239
3240                         if (*ip == CEE_CALLI) {
3241
3242                                 if ((temp = mono_emit_calli (cfg, bblock, fsig, sp, addr, ip)) != -1) {
3243                                         NEW_TEMPLOAD (cfg, *sp, temp);
3244                                         sp++;
3245                                 }
3246                                         
3247                         } else if (array_rank) {
3248                                 MonoInst *addr;
3249
3250                                 if (strcmp (cmethod->name, "Set") == 0) { /* array Set */ 
3251                                         addr = mini_get_ldelema_ins (cfg, bblock, cmethod, sp, ip, TRUE);
3252                                         NEW_INDSTORE (cfg, ins, addr, sp [fsig->param_count], fsig->params [fsig->param_count - 1]);
3253                                         ins->cil_code = ip;
3254                                         if (ins->opcode == CEE_STOBJ) {
3255                                                 handle_stobj (cfg, bblock, addr, sp [fsig->param_count], ip, mono_class_from_mono_type (fsig->params [fsig->param_count-1]), FALSE, FALSE);
3256                                         } else {
3257                                                 MONO_ADD_INS (bblock, ins);
3258                                         }
3259
3260                                 } else if (strcmp (cmethod->name, "Get") == 0) { /* array Get */
3261                                         addr = mini_get_ldelema_ins (cfg, bblock, cmethod, sp, ip, FALSE);
3262                                         NEW_INDLOAD (cfg, ins, addr, fsig->ret);
3263                                         ins->cil_code = ip;
3264
3265                                         *sp++ = ins;
3266                                 } else if (strcmp (cmethod->name, "Address") == 0) { /* array Address */
3267                                         addr = mini_get_ldelema_ins (cfg, bblock, cmethod, sp, ip, FALSE);
3268                                         *sp++ = addr;
3269                                 } else {
3270                                         g_assert_not_reached ();
3271                                 }
3272
3273                         } else {
3274                                 if (0 && CODE_IS_STLOC (ip + 5) && (!MONO_TYPE_ISSTRUCT (fsig->ret)) && (!MONO_TYPE_IS_VOID (fsig->ret) || cmethod->string_ctor)) {
3275                                         /* no need to spill */
3276                                         ins = (MonoInst*)mono_emit_method_call (cfg, bblock, cmethod, fsig, sp, ip, virtual ? sp [0] : NULL);
3277                                         *sp++ = ins;
3278                                 } else {
3279                                         if ((temp = mono_emit_method_call_spilled (cfg, bblock, cmethod, fsig, sp, ip, virtual ? sp [0] : NULL)) != -1) {
3280                                                 NEW_TEMPLOAD (cfg, *sp, temp);
3281                                                 sp++;
3282                                         }
3283                                 }
3284                         }
3285
3286                         ip += 5;
3287                         break;
3288                 }
3289                 case CEE_RET:
3290                         if (cfg->method != method) {
3291                                 /* return from inlined methode */
3292                                 if (return_var) {
3293                                         MonoInst *store;
3294                                         CHECK_STACK (1);
3295                                         --sp;
3296                                         //g_assert (returnvar != -1);
3297                                         NEW_TEMPSTORE (cfg, store, return_var->inst_c0, *sp);
3298                                         store->cil_code = sp [0]->cil_code;
3299                                         if (store->opcode == CEE_STOBJ) {
3300                                                 g_assert_not_reached ();
3301                                                 NEW_TEMPLOADA (cfg, store, return_var->inst_c0);
3302                                                 handle_stobj (cfg, bblock, store, *sp, sp [0]->cil_code, return_var->klass, FALSE, FALSE);
3303                                         } else
3304                                                 MONO_ADD_INS (bblock, store);
3305                                 } 
3306                         } else {
3307                                 if (cfg->ret) {
3308                                         g_assert (!return_var);
3309                                         CHECK_STACK (1);
3310                                         --sp;
3311                                         MONO_INST_NEW (cfg, ins, CEE_NOP);
3312                                         ins->opcode = mono_type_to_stind (method->signature->ret);
3313                                         if (ins->opcode == CEE_STOBJ) {
3314                                                 NEW_RETLOADA (cfg, ins);
3315                                                 handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE);
3316                                         } else {
3317                                                 ins->opcode = OP_SETRET;
3318                                                 ins->cil_code = ip;
3319                                                 ins->inst_i0 = *sp;;
3320                                                 ins->inst_i1 = NULL;
3321                                                 MONO_ADD_INS (bblock, ins);
3322                                         }
3323                                 }
3324                         }
3325                         if (sp != stack_start)
3326                                 goto unverified;
3327                         MONO_INST_NEW (cfg, ins, CEE_BR);
3328                         ins->cil_code = ip++;
3329                         ins->inst_target_bb = end_bblock;
3330                         MONO_ADD_INS (bblock, ins);
3331                         link_bblock (cfg, bblock, end_bblock);
3332                         start_new_bblock = 1;
3333                         break;
3334                 case CEE_BR_S:
3335                         MONO_INST_NEW (cfg, ins, CEE_BR);
3336                         ins->cil_code = ip++;
3337                         MONO_ADD_INS (bblock, ins);
3338                         target = ip + 1 + (signed char)(*ip);
3339                         ++ip;
3340                         GET_BBLOCK (cfg, bbhash, tblock, target);
3341                         link_bblock (cfg, bblock, tblock);
3342                         CHECK_BBLOCK (target, ip, tblock);
3343                         ins->inst_target_bb = tblock;
3344                         if (sp != stack_start) {
3345                                 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
3346                                 sp = stack_start;
3347                         }
3348                         start_new_bblock = 1;
3349                         inline_costs += 10;
3350                         break;
3351                 case CEE_BRFALSE_S:
3352                 case CEE_BRTRUE_S:
3353                         CHECK_STACK (1);
3354                         MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
3355                         ins->cil_code = ip++;
3356                         target = ip + 1 + *(signed char*)ip;
3357                         ip++;
3358                         ADD_UNCOND (ins->opcode == CEE_BRTRUE);
3359                         if (sp != stack_start) {
3360                                 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
3361                                 sp = stack_start;
3362                         }
3363                         inline_costs += 10;
3364                         break;
3365                 case CEE_BEQ_S:
3366                 case CEE_BGE_S:
3367                 case CEE_BGT_S:
3368                 case CEE_BLE_S:
3369                 case CEE_BLT_S:
3370                 case CEE_BNE_UN_S:
3371                 case CEE_BGE_UN_S:
3372                 case CEE_BGT_UN_S:
3373                 case CEE_BLE_UN_S:
3374                 case CEE_BLT_UN_S:
3375                         CHECK_STACK (2);
3376                         MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
3377                         ins->cil_code = ip++;
3378                         target = ip + 1 + *(signed char*)ip;
3379                         ip++;
3380                         ADD_BINCOND (NULL);
3381                         if (sp != stack_start) {
3382                                 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
3383                                 sp = stack_start;
3384                         }
3385                         inline_costs += 10;
3386                         break;
3387                 case CEE_BR:
3388                         MONO_INST_NEW (cfg, ins, CEE_BR);
3389                         ins->cil_code = ip++;
3390                         MONO_ADD_INS (bblock, ins);
3391                         target = ip + 4 + (gint32)read32(ip);
3392                         ip += 4;
3393                         GET_BBLOCK (cfg, bbhash, tblock, target);
3394                         link_bblock (cfg, bblock, tblock);
3395                         CHECK_BBLOCK (target, ip, tblock);
3396                         ins->inst_target_bb = tblock;
3397                         if (sp != stack_start) {
3398                                 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
3399                                 sp = stack_start;
3400                         }
3401                         start_new_bblock = 1;
3402                         inline_costs += 10;
3403                         break;
3404                 case CEE_BRFALSE:
3405                 case CEE_BRTRUE:
3406                         CHECK_STACK (1);
3407                         MONO_INST_NEW (cfg, ins, *ip);
3408                         ins->cil_code = ip++;
3409                         target = ip + 4 + (gint32)read32(ip);
3410                         ip += 4;
3411                         ADD_UNCOND(ins->opcode == CEE_BRTRUE);
3412                         if (sp != stack_start) {
3413                                 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
3414                                 sp = stack_start;
3415                         }
3416                         inline_costs += 10;
3417                         break;
3418                 case CEE_BEQ:
3419                 case CEE_BGE:
3420                 case CEE_BGT:
3421                 case CEE_BLE:
3422                 case CEE_BLT:
3423                 case CEE_BNE_UN:
3424                 case CEE_BGE_UN:
3425                 case CEE_BGT_UN:
3426                 case CEE_BLE_UN:
3427                 case CEE_BLT_UN:
3428                         CHECK_STACK (2);
3429                         MONO_INST_NEW (cfg, ins, *ip);
3430                         ins->cil_code = ip++;
3431                         target = ip + 4 + (gint32)read32(ip);
3432                         ip += 4;
3433                         ADD_BINCOND(NULL);
3434                         if (sp != stack_start) {
3435                                 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
3436                                 sp = stack_start;
3437                         }
3438                         inline_costs += 10;
3439                         break;
3440                 case CEE_SWITCH:
3441                         CHECK_STACK (1);
3442                         n = read32 (ip + 1);
3443                         MONO_INST_NEW (cfg, ins, *ip);
3444                         --sp;
3445                         ins->inst_left = *sp;
3446                         if (ins->inst_left->type != STACK_I4) goto unverified;
3447                         ins->cil_code = ip;
3448                         ip += 5;
3449                         target = ip + n * sizeof (guint32);
3450                         MONO_ADD_INS (bblock, ins);
3451                         GET_BBLOCK (cfg, bbhash, tblock, target);
3452                         link_bblock (cfg, bblock, tblock);
3453                         ins->klass = GUINT_TO_POINTER (n);
3454                         ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * (n + 1));
3455                         ins->inst_many_bb [n] = tblock;
3456
3457                         for (i = 0; i < n; ++i) {
3458                                 GET_BBLOCK (cfg, bbhash, tblock, target + (gint32)read32(ip));
3459                                 link_bblock (cfg, bblock, tblock);
3460                                 ins->inst_many_bb [i] = tblock;
3461                                 ip += 4;
3462                         }
3463                         /* FIXME: handle stack args */
3464                         inline_costs += 20;
3465                         break;
3466                 case CEE_LDIND_I1:
3467                 case CEE_LDIND_U1:
3468                 case CEE_LDIND_I2:
3469                 case CEE_LDIND_U2:
3470                 case CEE_LDIND_I4:
3471                 case CEE_LDIND_U4:
3472                 case CEE_LDIND_I8:
3473                 case CEE_LDIND_I:
3474                 case CEE_LDIND_R4:
3475                 case CEE_LDIND_R8:
3476                 case CEE_LDIND_REF:
3477                         CHECK_STACK (1);
3478                         MONO_INST_NEW (cfg, ins, *ip);
3479                         ins->cil_code = ip;
3480                         --sp;
3481                         ins->inst_i0 = *sp;
3482                         *sp++ = ins;
3483                         ins->type = ldind_type [*ip - CEE_LDIND_I1];
3484                         ins->flags |= ins_flag;
3485                         ins_flag = 0;
3486                         ++ip;
3487                         break;
3488                 case CEE_STIND_REF:
3489                 case CEE_STIND_I1:
3490                 case CEE_STIND_I2:
3491                 case CEE_STIND_I4:
3492                 case CEE_STIND_I8:
3493                 case CEE_STIND_R4:
3494                 case CEE_STIND_R8:
3495                         CHECK_STACK (2);
3496                         MONO_INST_NEW (cfg, ins, *ip);
3497                         ins->cil_code = ip++;
3498                         sp -= 2;
3499                         handle_loaded_temps (cfg, bblock, stack_start, sp);
3500                         MONO_ADD_INS (bblock, ins);
3501                         ins->inst_i0 = sp [0];
3502                         ins->inst_i1 = sp [1];
3503                         ins->flags |= ins_flag;
3504                         ins_flag = 0;
3505                         inline_costs += 1;
3506                         break;
3507                 case CEE_ADD:
3508                 case CEE_SUB:
3509                 case CEE_MUL:
3510                 case CEE_DIV:
3511                 case CEE_DIV_UN:
3512                 case CEE_REM:
3513                 case CEE_REM_UN:
3514                 case CEE_AND:
3515                 case CEE_OR:
3516                 case CEE_XOR:
3517                 case CEE_SHL:
3518                 case CEE_SHR:
3519                 case CEE_SHR_UN:
3520                         CHECK_STACK (2);
3521                         ADD_BINOP (*ip);
3522                         ip++;
3523                         break;
3524                 case CEE_NEG:
3525                 case CEE_NOT:
3526                 case CEE_CONV_I1:
3527                 case CEE_CONV_I2:
3528                 case CEE_CONV_I4:
3529                 case CEE_CONV_R4:
3530                 case CEE_CONV_R8:
3531                 case CEE_CONV_U4:
3532                 case CEE_CONV_I8:
3533                 case CEE_CONV_U8:
3534                 case CEE_CONV_OVF_I8:
3535                 case CEE_CONV_OVF_U8:
3536                 case CEE_CONV_R_UN:
3537                         CHECK_STACK (1);
3538                         ADD_UNOP (*ip);
3539                         ip++;                   
3540                         break;
3541                 case CEE_CONV_OVF_I4:
3542                 case CEE_CONV_OVF_I1:
3543                 case CEE_CONV_OVF_I2:
3544                 case CEE_CONV_OVF_I:
3545                 case CEE_CONV_OVF_U:
3546                         CHECK_STACK (1);
3547
3548                         if (sp [-1]->type == STACK_R8) {
3549                                 ADD_UNOP (CEE_CONV_OVF_I8);
3550                                 ADD_UNOP (*ip);
3551                         } else {
3552                                 ADD_UNOP (*ip);
3553                         }
3554
3555                         ip++;
3556                         break;
3557                 case CEE_CONV_OVF_U1:
3558                 case CEE_CONV_OVF_U2:
3559                 case CEE_CONV_OVF_U4:
3560                         CHECK_STACK (1);
3561
3562                         if (sp [-1]->type == STACK_R8) {
3563                                 ADD_UNOP (CEE_CONV_OVF_U8);
3564                                 ADD_UNOP (*ip);
3565                         } else {
3566                                 ADD_UNOP (*ip);
3567                         }
3568
3569                         ip++;
3570                         break;
3571                 case CEE_CONV_OVF_I1_UN:
3572                 case CEE_CONV_OVF_I2_UN:
3573                 case CEE_CONV_OVF_I4_UN:
3574                 case CEE_CONV_OVF_I8_UN:
3575                 case CEE_CONV_OVF_U1_UN:
3576                 case CEE_CONV_OVF_U2_UN:
3577                 case CEE_CONV_OVF_U4_UN:
3578                 case CEE_CONV_OVF_U8_UN:
3579                 case CEE_CONV_OVF_I_UN:
3580                 case CEE_CONV_OVF_U_UN:
3581                         CHECK_STACK (1);
3582                         ADD_UNOP (*ip);
3583                         ip++;
3584                         break;
3585                 case CEE_CPOBJ:
3586                         CHECK_STACK (2);
3587                         token = read32 (ip + 1);
3588                         if (method->wrapper_type != MONO_WRAPPER_NONE)
3589                                 klass = mono_method_get_wrapper_data (method, token);
3590                         else
3591                                 klass = mono_class_get (image, token);
3592
3593                         mono_class_init (klass);
3594                         if (klass->byval_arg.type == MONO_TYPE_VAR)
3595                                 klass = TYPE_PARAM_TO_CLASS (klass->byval_arg.data.generic_param->num);
3596                         else if (klass->byval_arg.type == MONO_TYPE_MVAR)
3597                                 klass = MTYPE_PARAM_TO_CLASS (klass->byval_arg.data.generic_param->num);
3598                         sp -= 2;
3599                         if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
3600                                 MonoInst *store, *load;
3601                                 MONO_INST_NEW (cfg, load, CEE_LDIND_REF);
3602                                 load->cil_code = ip;
3603                                 load->inst_i0 = sp [1];
3604                                 load->type = ldind_type [CEE_LDIND_REF];
3605                                 load->flags |= ins_flag;
3606                                 MONO_INST_NEW (cfg, store, CEE_STIND_REF);
3607                                 store->cil_code = ip;
3608                                 handle_loaded_temps (cfg, bblock, stack_start, sp);
3609                                 MONO_ADD_INS (bblock, store);
3610                                 store->inst_i0 = sp [0];
3611                                 store->inst_i1 = load;
3612                                 store->flags |= ins_flag;
3613                         } else {
3614                                 n = mono_class_value_size (klass, NULL);
3615                                 if ((cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 5) {
3616                                         MonoInst *copy;
3617                                         MONO_INST_NEW (cfg, copy, OP_MEMCPY);
3618                                         copy->inst_left = sp [0];
3619                                         copy->inst_right = sp [1];
3620                                         copy->cil_code = ip;
3621                                         copy->unused = n;
3622                                         MONO_ADD_INS (bblock, copy);
3623                                 } else {
3624                                         MonoInst *iargs [3];
3625                                         iargs [0] = sp [0];
3626                                         iargs [1] = sp [1];
3627                                         NEW_ICONST (cfg, iargs [2], n);
3628                                         iargs [2]->cil_code = ip;
3629
3630                                         mono_emit_jit_icall (cfg, bblock, helper_memcpy, iargs, ip);
3631                                 }
3632                         }
3633                         ins_flag = 0;
3634                         ip += 5;
3635                         break;
3636                 case CEE_LDOBJ: {
3637                         MonoInst *iargs [3];
3638                         CHECK_STACK (1);
3639                         --sp;
3640                         token = read32 (ip + 1);
3641                         if (method->wrapper_type != MONO_WRAPPER_NONE)
3642                                 klass = mono_method_get_wrapper_data (method, token);
3643                         else
3644                                 klass = mono_class_get (image, token);
3645
3646                         mono_class_init (klass);
3647                         if (klass->byval_arg.type == MONO_TYPE_VAR)
3648                                 klass = TYPE_PARAM_TO_CLASS (klass->byval_arg.data.generic_param->num);
3649                         else if (klass->byval_arg.type == MONO_TYPE_MVAR)
3650                                 klass = MTYPE_PARAM_TO_CLASS (klass->byval_arg.data.generic_param->num);
3651                         if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
3652                                 MONO_INST_NEW (cfg, ins, CEE_LDIND_REF);
3653                                 ins->cil_code = ip;
3654                                 ins->inst_i0 = sp [0];
3655                                 ins->type = ldind_type [CEE_LDIND_REF];
3656                                 ins->flags |= ins_flag;
3657                                 ins_flag = 0;
3658                                 *sp++ = ins;
3659                                 ip += 5;
3660                                 break;
3661                         }
3662                         n = mono_class_value_size (klass, NULL);
3663                         ins = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
3664                         NEW_TEMPLOADA (cfg, iargs [0], ins->inst_c0);
3665                         if ((cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 5) {
3666                                 MonoInst *copy;
3667                                 MONO_INST_NEW (cfg, copy, OP_MEMCPY);
3668                                 copy->inst_left = iargs [0];
3669                                 copy->inst_right = *sp;
3670                                 copy->cil_code = ip;
3671                                 copy->unused = n;
3672                                 MONO_ADD_INS (bblock, copy);
3673                         } else {
3674                                 iargs [1] = *sp;
3675                                 NEW_ICONST (cfg, iargs [2], n);
3676                                 iargs [2]->cil_code = ip;
3677
3678                                 mono_emit_jit_icall (cfg, bblock, helper_memcpy, iargs, ip);
3679                         }
3680                         NEW_TEMPLOAD (cfg, *sp, ins->inst_c0);
3681                         ++sp;
3682                         ip += 5;
3683                         ins_flag = 0;
3684                         inline_costs += 1;
3685                         break;
3686                 }
3687                 case CEE_LDSTR:
3688                         CHECK_STACK_OVF (1);
3689                         n = read32 (ip + 1);
3690
3691                         if (method->wrapper_type != MONO_WRAPPER_NONE) {
3692                                 int temp;
3693                                 MonoInst *iargs [1];
3694
3695                                 NEW_PCONST (cfg, iargs [0], mono_method_get_wrapper_data (method, n));                          
3696                                 temp = mono_emit_jit_icall (cfg, bblock, mono_string_new_wrapper, iargs, ip);
3697                                 NEW_TEMPLOAD (cfg, *sp, temp);
3698
3699                         } else {
3700
3701                                 if (cfg->opt & MONO_OPT_SHARED) {
3702                                         int temp;
3703                                         MonoInst *iargs [3];
3704
3705                                         if (mono_compile_aot) {
3706                                                 cfg->ldstr_list = g_list_prepend (cfg->ldstr_list, (gpointer)n);
3707                                         }
3708
3709                                         NEW_TEMPLOAD (cfg, iargs [0], mono_get_domainvar (cfg)->inst_c0);
3710                                         NEW_IMAGECONST (cfg, iargs [1], image);
3711                                         NEW_ICONST (cfg, iargs [2], mono_metadata_token_index (n));
3712                                         temp = mono_emit_jit_icall (cfg, bblock, mono_ldstr, iargs, ip);
3713                                         NEW_TEMPLOAD (cfg, *sp, temp);
3714                                         mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
3715                                 } else {
3716                                         if (mono_compile_aot)
3717                                                 NEW_LDSTRCONST (cfg, ins, image, n);
3718                                         else {
3719                                                 NEW_PCONST (cfg, ins, NULL);
3720                                                 ins->cil_code = ip;
3721                                                 ins->type = STACK_OBJ;
3722                                                 ins->inst_p0 = mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
3723                                         }
3724                                         *sp = ins;
3725                                 }
3726                         }
3727
3728                         sp++;
3729                         ip += 5;
3730                         break;
3731                 case CEE_NEWOBJ: {
3732                         MonoInst *iargs [2];
3733                         MonoMethodSignature *fsig;
3734                         int temp;
3735
3736                         token = read32 (ip + 1);
3737                         if (method->wrapper_type != MONO_WRAPPER_NONE) {
3738                                 cmethod = mono_method_get_wrapper_data (method, token);
3739                         } else
3740                                 cmethod = mono_get_method (image, token, NULL);
3741                         fsig = mono_method_get_signature (cmethod, image, token);
3742
3743                         mono_class_init (cmethod->klass);
3744
3745                         n = fsig->param_count;
3746                         CHECK_STACK (n);
3747
3748                         /* move the args to allow room for 'this' in the first position */
3749                         while (n--) {
3750                                 --sp;
3751                                 sp [1] = sp [0];
3752                         }
3753
3754                         handle_loaded_temps (cfg, bblock, stack_start, sp);
3755                         
3756
3757                         if (cmethod->klass->parent == mono_defaults.array_class) {
3758                                 NEW_METHODCONST (cfg, *sp, cmethod);
3759                                 temp = mono_emit_native_call (cfg, bblock, mono_array_new_va, fsig, sp, ip, FALSE);
3760
3761                         } else if (cmethod->string_ctor) {
3762                                 /* we simply pass a null pointer */
3763                                 NEW_PCONST (cfg, *sp, NULL); 
3764                                 /* now call the string ctor */
3765                                 temp = mono_emit_method_call_spilled (cfg, bblock, cmethod, fsig, sp, ip, NULL);
3766                         } else {
3767                                 if (cmethod->klass->valuetype) {
3768                                         iargs [0] = mono_compile_create_var (cfg, &cmethod->klass->byval_arg, OP_LOCAL);
3769                                         temp = iargs [0]->inst_c0;
3770                                         NEW_TEMPLOADA (cfg, *sp, temp);
3771                                 } else {
3772                                         if (cfg->opt & MONO_OPT_SHARED) {
3773                                                 NEW_DOMAINCONST (cfg, iargs [0]);
3774                                                 NEW_CLASSCONST (cfg, iargs [1], cmethod->klass);
3775
3776                                                 temp = mono_emit_jit_icall (cfg, bblock, mono_object_new, iargs, ip);
3777                                         } else {
3778                                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
3779                                                 NEW_VTABLECONST (cfg, iargs [0], vtable);
3780                                                 if (cmethod->klass->has_finalize || cmethod->klass->marshalbyref || (cfg->prof_options & MONO_PROFILE_ALLOCATIONS))
3781                                                         temp = mono_emit_jit_icall (cfg, bblock, mono_object_new_specific, iargs, ip);
3782                                                 else
3783                                                         temp = mono_emit_jit_icall (cfg, bblock, mono_object_new_fast, iargs, ip);
3784                                         }
3785                                         NEW_TEMPLOAD (cfg, *sp, temp);
3786                                 }
3787
3788                                 if ((cfg->opt & MONO_OPT_INLINE) && cmethod &&
3789                                     mono_method_check_inlining (cfg, cmethod) &&
3790                                     !mono_class_is_subclass_of (cmethod->klass, mono_defaults.exception_class, FALSE) &&
3791                                     !g_list_find (dont_inline, cmethod)) {
3792                                         int costs;
3793                                         MonoBasicBlock *ebblock;
3794                                         if ((costs = inline_method (cfg, cmethod, fsig, bblock, sp, ip, real_offset, dont_inline, &ebblock))) {
3795
3796                                                 ip += 5;
3797                                                 real_offset += 5;
3798                                                 
3799                                                 GET_BBLOCK (cfg, bbhash, bblock, ip);
3800                                                 ebblock->next_bb = bblock;
3801                                                 link_bblock (cfg, ebblock, bblock);
3802
3803                                                 NEW_TEMPLOAD (cfg, *sp, temp);
3804                                                 sp++;
3805
3806                                                 /* indicates start of a new block, and triggers a load 
3807                                                    of all stack arguments at bb boundarie */
3808                                                 bblock = ebblock;
3809
3810                                                 inline_costs += costs;
3811                                                 break;
3812                                                 
3813                                         } else {
3814                                                 mono_emit_method_call_spilled (cfg, bblock, cmethod, fsig, sp, ip, sp[0]);
3815                                         }
3816                                 } else {
3817                                         /* now call the actual ctor */
3818                                         mono_emit_method_call_spilled (cfg, bblock, cmethod, fsig, sp, ip, sp[0]);
3819                                 }
3820                         }
3821
3822                         NEW_TEMPLOAD (cfg, *sp, temp);
3823                         sp++;
3824                         
3825                         ip += 5;
3826                         inline_costs += 5;
3827                         break;
3828                 }
3829                 case CEE_ISINST:
3830                         CHECK_STACK (1);
3831                         MONO_INST_NEW (cfg, ins, *ip);
3832                         --sp;
3833                         klass = mono_class_get (image, read32 (ip + 1));
3834                         mono_class_init (klass);
3835                         ins->type = STACK_OBJ;
3836                         ins->inst_left = *sp;
3837                         ins->inst_newa_class = klass;
3838                         ins->cil_code = ip;
3839                         ip += 5;
3840                         *sp++ = ins;
3841                         break;
3842                 case CEE_UNBOX_ANY: {
3843                         MonoInst *add, *vtoffset;
3844                         MonoInst *iargs [3];
3845
3846                         CHECK_STACK (1);
3847                         --sp;
3848                         token = read32 (ip + 1);
3849                         if (method->wrapper_type != MONO_WRAPPER_NONE)
3850                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
3851                         else 
3852                                 klass = mono_class_get (image, token);
3853                         mono_class_init (klass);
3854
3855                         if (klass->byval_arg.type == MONO_TYPE_VAR)
3856                                 klass = TYPE_PARAM_TO_CLASS (klass->byval_arg.data.generic_param->num);
3857                         else if (klass->byval_arg.type == MONO_TYPE_MVAR)
3858                                 klass = MTYPE_PARAM_TO_CLASS (klass->byval_arg.data.generic_param->num);
3859
3860                         if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
3861                                 /* CASTCLASS */
3862                                 MONO_INST_NEW (cfg, ins, CEE_CASTCLASS);
3863                                 ins->type = STACK_OBJ;
3864                                 ins->inst_left = *sp;
3865                                 ins->klass = klass;
3866                                 ins->inst_newa_class = klass;
3867                                 ins->cil_code = ip;
3868                                 *sp++ = ins;
3869                                 ip += 5;
3870                                 break;
3871                         }
3872
3873                         MONO_INST_NEW (cfg, ins, OP_UNBOXCAST);
3874                         ins->type = STACK_OBJ;
3875                         ins->inst_left = *sp;
3876                         ins->klass = klass;
3877                         ins->inst_newa_class = klass;
3878                         ins->cil_code = ip;
3879
3880                         MONO_INST_NEW (cfg, add, CEE_ADD);
3881                         NEW_ICONST (cfg, vtoffset, sizeof (MonoObject));
3882                         add->inst_left = ins;
3883                         add->inst_right = vtoffset;
3884                         add->type = STACK_MP;
3885                         *sp = add;
3886                         ip += 5;
3887                         /* LDOBJ impl */
3888                         n = mono_class_value_size (klass, NULL);
3889                         ins = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
3890                         NEW_TEMPLOADA (cfg, iargs [0], ins->inst_c0);
3891                         if ((cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 5) {
3892                                 MonoInst *copy;
3893                                 MONO_INST_NEW (cfg, copy, OP_MEMCPY);
3894                                 copy->inst_left = iargs [0];
3895                                 copy->inst_right = *sp;
3896                                 copy->cil_code = ip;
3897                                 copy->unused = n;
3898                                 MONO_ADD_INS (bblock, copy);
3899                         } else {
3900                                 iargs [1] = *sp;
3901                                 NEW_ICONST (cfg, iargs [2], n);
3902                                 iargs [2]->cil_code = ip;
3903
3904                                 mono_emit_jit_icall (cfg, bblock, helper_memcpy, iargs, ip);
3905                         }
3906                         NEW_TEMPLOAD (cfg, *sp, ins->inst_c0);
3907                         ++sp;
3908                         inline_costs += 2;
3909                         break;
3910                 }
3911                 case CEE_UNBOX: {
3912                         MonoInst *add, *vtoffset;
3913
3914                         CHECK_STACK (1);
3915                         --sp;
3916                         token = read32 (ip + 1);
3917                         if (method->wrapper_type != MONO_WRAPPER_NONE)
3918                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
3919                         else 
3920                                 klass = mono_class_get (image, token);
3921                         mono_class_init (klass);
3922
3923                         if (klass->byval_arg.type == MONO_TYPE_VAR)
3924                                 klass = TYPE_PARAM_TO_CLASS (klass->byval_arg.data.generic_param->num);
3925                         else if (klass->byval_arg.type == MONO_TYPE_MVAR)
3926                                 klass = MTYPE_PARAM_TO_CLASS (klass->byval_arg.data.generic_param->num);
3927
3928                         MONO_INST_NEW (cfg, ins, OP_UNBOXCAST);
3929                         ins->type = STACK_OBJ;
3930                         ins->inst_left = *sp;
3931                         ins->klass = klass;
3932                         ins->inst_newa_class = klass;
3933                         ins->cil_code = ip;
3934
3935                         MONO_INST_NEW (cfg, add, CEE_ADD);
3936                         NEW_ICONST (cfg, vtoffset, sizeof (MonoObject));
3937                         add->inst_left = ins;
3938                         add->inst_right = vtoffset;
3939                         add->type = STACK_MP;
3940                         *sp++ = add;
3941                         ip += 5;
3942                         inline_costs += 2;
3943                         break;
3944                 }
3945                 case CEE_CASTCLASS:
3946                         CHECK_STACK (1);
3947                         MONO_INST_NEW (cfg, ins, *ip);
3948                         --sp;
3949                         klass = mono_class_get (image, read32 (ip + 1));
3950                         mono_class_init (klass);
3951                         if (klass->byval_arg.type == MONO_TYPE_VAR)
3952                                 klass = TYPE_PARAM_TO_CLASS (klass->byval_arg.data.generic_param->num);
3953                         else if (klass->byval_arg.type == MONO_TYPE_MVAR)
3954                                 klass = MTYPE_PARAM_TO_CLASS (klass->byval_arg.data.generic_param->num);
3955                         ins->type = STACK_OBJ;
3956                         ins->inst_left = *sp;
3957                         ins->klass = klass;
3958                         ins->inst_newa_class = klass;
3959                         ins->cil_code = ip;
3960                         ip += 5;
3961                         *sp++ = ins;
3962                         break;
3963                 case CEE_THROW:
3964                         CHECK_STACK (1);
3965                         MONO_INST_NEW (cfg, ins, *ip);
3966                         --sp;
3967                         ins->inst_left = *sp;
3968                         ins->cil_code = ip++;
3969                         MONO_ADD_INS (bblock, ins);
3970                         sp = stack_start;
3971                         start_new_bblock = 1;
3972                         break;
3973                 case CEE_LDFLD:
3974                 case CEE_LDFLDA:
3975                 case CEE_STFLD: {
3976                         MonoInst *offset_ins;
3977                         MonoClassField *field;
3978                         MonoBasicBlock *ebblock;
3979                         int costs;
3980                         guint foffset;
3981
3982                         if (*ip == CEE_STFLD) {
3983                                 CHECK_STACK (2);
3984                                 sp -= 2;
3985                         } else {
3986                                 CHECK_STACK (1);
3987                                 --sp;
3988                         }
3989                         // FIXME: enable this test later.
3990                         //if (sp [0]->type != STACK_OBJ && sp [0]->type != STACK_MP)
3991                         //      goto unverified;
3992                         token = read32 (ip + 1);
3993                         field = mono_field_from_token (image, token, &klass);
3994                         if (field->parent->gen_params)
3995                                 field = get_generic_field_inst (field, method->klass, &klass);
3996                         else if (field->parent->generic_inst && method->klass->generic_inst)
3997                                 field = inflate_generic_field (field, method->klass, &klass);
3998                         mono_class_init (klass);
3999
4000                         foffset = klass->valuetype? field->offset - sizeof (MonoObject): field->offset;
4001                         /* FIXME: mark instructions for use in SSA */
4002                         if (*ip == CEE_STFLD) {
4003                                 if (klass->marshalbyref && !MONO_CHECK_THIS (sp [0])) {
4004                                         MonoMethod *stfld_wrapper = mono_marshal_get_stfld_wrapper (field->type); 
4005                                         MonoInst *iargs [5];
4006
4007                                         iargs [0] = sp [0];
4008                                         NEW_CLASSCONST (cfg, iargs [1], klass);
4009                                         NEW_FIELDCONST (cfg, iargs [2], field);
4010                                         NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : 
4011                                                     field->offset);
4012                                         iargs [4] = sp [1];
4013
4014                                         if (cfg->opt & MONO_OPT_INLINE) {
4015                                                 costs = inline_method (cfg, stfld_wrapper, stfld_wrapper->signature, bblock, 
4016                                                                        iargs, ip, real_offset, dont_inline, &ebblock);
4017                                                 g_assert (costs > 0);
4018                                                       
4019                                                 ip += 5;
4020                                                 real_offset += 5;
4021
4022                                                 GET_BBLOCK (cfg, bbhash, bblock, ip);
4023                                                 ebblock->next_bb = bblock;
4024                                                 link_bblock (cfg, ebblock, bblock);
4025
4026                                                 /* indicates start of a new block, and triggers a load 
4027                                                    of all stack arguments at bb boundarie */
4028                                                 bblock = ebblock;
4029
4030                                                 inline_costs += costs;
4031                                                 break;
4032                                         } else {
4033                                                 mono_emit_method_call_spilled (cfg, bblock, stfld_wrapper, stfld_wrapper->signature, iargs, ip, NULL);
4034                                         }
4035                                 } else {
4036                                         MonoInst *store;
4037                                         NEW_ICONST (cfg, offset_ins, foffset);
4038                                         MONO_INST_NEW (cfg, ins, CEE_ADD);
4039                                         ins->cil_code = ip;
4040                                         ins->inst_left = *sp;
4041                                         ins->inst_right = offset_ins;
4042                                         ins->type = STACK_MP;
4043
4044                                         MONO_INST_NEW (cfg, store, mono_type_to_stind (field->type));
4045                                         store->cil_code = ip;
4046                                         store->inst_left = ins;
4047                                         store->inst_right = sp [1];
4048                                         handle_loaded_temps (cfg, bblock, stack_start, sp);
4049                                         store->flags |= ins_flag;
4050                                         ins_flag = 0;
4051                                         if (store->opcode == CEE_STOBJ) {
4052                                                 handle_stobj (cfg, bblock, ins, sp [1], ip, 
4053                                                               mono_class_from_mono_type (field->type), FALSE, FALSE);
4054                                         } else
4055                                                 MONO_ADD_INS (bblock, store);
4056                                 }
4057                         } else {
4058                                 if (klass->marshalbyref && !MONO_CHECK_THIS (sp [0])) {
4059                                         /* fixme: we need to inline that call somehow */
4060                                         MonoMethod *ldfld_wrapper = mono_marshal_get_ldfld_wrapper (field->type); 
4061                                         MonoInst *iargs [4];
4062                                         int temp;
4063                                         
4064                                         iargs [0] = sp [0];
4065                                         NEW_CLASSCONST (cfg, iargs [1], klass);
4066                                         NEW_FIELDCONST (cfg, iargs [2], field);
4067                                         NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset);
4068                                         if (cfg->opt & MONO_OPT_INLINE) {
4069                                                 costs = inline_method (cfg, ldfld_wrapper, ldfld_wrapper->signature, bblock, 
4070                                                                        iargs, ip, real_offset, dont_inline, &ebblock);
4071                                                 g_assert (costs > 0);
4072                                                       
4073                                                 ip += 5;
4074                                                 real_offset += 5;
4075
4076                                                 GET_BBLOCK (cfg, bbhash, bblock, ip);
4077                                                 ebblock->next_bb = bblock;
4078                                                 link_bblock (cfg, ebblock, bblock);
4079
4080                                                 temp = iargs [0]->inst_i0->inst_c0;
4081
4082                                                 if (*ip == CEE_LDFLDA) {
4083                                                         /* not sure howto handle this */
4084                                                         NEW_TEMPLOADA (cfg, *sp, temp);
4085                                                 } else {
4086                                                         NEW_TEMPLOAD (cfg, *sp, temp);
4087                                                 }
4088                                                 sp++;
4089
4090                                                 /* indicates start of a new block, and triggers a load of
4091                                                    all stack arguments at bb boundarie */
4092                                                 bblock = ebblock;
4093                                                 
4094                                                 inline_costs += costs;
4095                                                 break;
4096                                         } else {
4097                                                 temp = mono_emit_method_call_spilled (cfg, bblock, ldfld_wrapper, ldfld_wrapper->signature, iargs, ip, NULL);
4098                                                 if (*ip == CEE_LDFLDA) {
4099                                                         /* not sure howto handle this */
4100                                                         NEW_TEMPLOADA (cfg, *sp, temp);
4101                                                 } else {
4102                                                         NEW_TEMPLOAD (cfg, *sp, temp);
4103                                                 }
4104                                                 sp++;
4105                                         }
4106                                 } else {
4107                                         NEW_ICONST (cfg, offset_ins, foffset);
4108                                         MONO_INST_NEW (cfg, ins, CEE_ADD);
4109                                         ins->cil_code = ip;
4110                                         ins->inst_left = *sp;
4111                                         ins->inst_right = offset_ins;
4112                                         ins->type = STACK_MP;
4113
4114                                         if (*ip == CEE_LDFLDA) {
4115                                                 *sp++ = ins;
4116                                         } else {
4117                                                 MonoInst *load;
4118                                                 MONO_INST_NEW (cfg, load, mono_type_to_ldind (field->type));
4119                                                 type_to_eval_stack_type (field->type, load);
4120                                                 load->cil_code = ip;
4121                                                 load->inst_left = ins;
4122                                                 load->flags |= ins_flag;
4123                                                 ins_flag = 0;
4124                                                 *sp++ = load;
4125                                         }
4126                                 }
4127                         }
4128                         ip += 5;
4129                         break;
4130                 }
4131                 case CEE_LDSFLD:
4132                 case CEE_LDSFLDA:
4133                 case CEE_STSFLD: {
4134                         MonoClassField *field;
4135                         gpointer addr = NULL;
4136
4137                         token = read32 (ip + 1);
4138
4139                         field = mono_field_from_token (image, token, &klass);
4140                         if (field->parent->gen_params)
4141                                 field = get_generic_field_inst (field, method->klass, &klass);
4142                         else if (field->parent->generic_inst && method->klass->generic_inst)
4143                                 field = inflate_generic_field (field, method->klass, &klass);
4144                         mono_class_init (klass);
4145
4146                         handle_loaded_temps (cfg, bblock, stack_start, sp);
4147
4148                         if (cfg->domain->special_static_fields)
4149                                 addr = g_hash_table_lookup (cfg->domain->special_static_fields, field);
4150
4151                         if ((cfg->opt & MONO_OPT_SHARED) || (mono_compile_aot && addr)) {
4152                                 int temp;
4153                                 MonoInst *iargs [2];
4154                                 g_assert (field->parent);
4155                                 NEW_TEMPLOAD (cfg, iargs [0], mono_get_domainvar (cfg)->inst_c0);
4156                                 NEW_FIELDCONST (cfg, iargs [1], field);
4157                                 temp = mono_emit_jit_icall (cfg, bblock, mono_class_static_field_address, iargs, ip);
4158                                 NEW_TEMPLOAD (cfg, ins, temp);
4159                         } else {
4160                                 MonoVTable *vtable;
4161                                 vtable = mono_class_vtable (cfg->domain, klass);
4162                                 if (!addr) {
4163                                         if ((!vtable->initialized || mono_compile_aot) && !(klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) && mono_class_needs_cctor_run (klass, method)) {
4164                                                 guint8 *tramp = mono_create_class_init_trampoline (vtable);
4165                                                 mono_emit_native_call (cfg, bblock, tramp, 
4166                                                                                            helper_sig_class_init_trampoline,
4167                                                                                            NULL, ip, FALSE);
4168                                                 if (cfg->verbose_level > 2)
4169                                                         g_print ("class %s.%s needs init call for %s\n", klass->name_space, klass->name, field->name);
4170                                         } else {
4171                                                 mono_runtime_class_init (vtable);
4172                                         }
4173                                         addr = (char*)vtable->data + field->offset;
4174
4175                                         if (mono_compile_aot)
4176                                                 NEW_SFLDACONST (cfg, ins, field);
4177                                         else
4178                                                 NEW_PCONST (cfg, ins, addr);
4179                                         ins->cil_code = ip;
4180                                 } else {
4181                                         /* 
4182                                          * insert call to mono_threads_get_static_data (GPOINTER_TO_UINT (addr)) 
4183                                          * This could be later optimized to do just a couple of
4184                                          * memory dereferences with constant offsets.
4185                                          */
4186                                         int temp;
4187                                         MonoInst *iargs [1];
4188                                         NEW_ICONST (cfg, iargs [0], GPOINTER_TO_UINT (addr));
4189                                         temp = mono_emit_jit_icall (cfg, bblock, mono_get_special_static_data, iargs, ip);
4190                                         NEW_TEMPLOAD (cfg, ins, temp);
4191                                 }
4192                         }
4193
4194                         /* FIXME: mark instructions for use in SSA */
4195                         if (*ip == CEE_LDSFLDA) {
4196                                 *sp++ = ins;
4197                         } else if (*ip == CEE_STSFLD) {
4198                                 MonoInst *store;
4199                                 CHECK_STACK (1);
4200                                 sp--;
4201                                 MONO_INST_NEW (cfg, store, mono_type_to_stind (field->type));
4202                                 store->cil_code = ip;
4203                                 store->inst_left = ins;
4204                                 store->inst_right = sp [0];
4205                                 store->flags |= ins_flag;
4206                                 ins_flag = 0;
4207
4208                                 if (store->opcode == CEE_STOBJ) {
4209                                         handle_stobj (cfg, bblock, ins, sp [0], ip, mono_class_from_mono_type (field->type), FALSE, FALSE);
4210                                 } else
4211                                         MONO_ADD_INS (bblock, store);
4212                         } else {
4213                                 gboolean is_const = FALSE;
4214                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
4215                                 if (!((cfg->opt & MONO_OPT_SHARED) || mono_compile_aot) && 
4216                                     vtable->initialized && (field->type->attrs & FIELD_ATTRIBUTE_INIT_ONLY)) {
4217                                         gpointer addr = (char*)vtable->data + field->offset;
4218                                         /* g_print ("RO-FIELD %s.%s:%s\n", klass->name_space, klass->name, field->name);*/
4219                                         is_const = TRUE;
4220                                         switch (field->type->type) {
4221                                         case MONO_TYPE_BOOLEAN:
4222                                         case MONO_TYPE_U1:
4223                                                 NEW_ICONST (cfg, *sp, *((guint8 *)addr));
4224                                                 sp++;
4225                                                 break;
4226                                         case MONO_TYPE_I1:
4227                                                 NEW_ICONST (cfg, *sp, *((gint8 *)addr));
4228                                                 sp++;
4229                                                 break;                                          
4230                                         case MONO_TYPE_CHAR:
4231                                         case MONO_TYPE_U2:
4232                                                 NEW_ICONST (cfg, *sp, *((guint16 *)addr));
4233                                                 sp++;
4234                                                 break;
4235                                         case MONO_TYPE_I2:
4236                                                 NEW_ICONST (cfg, *sp, *((gint16 *)addr));
4237                                                 sp++;
4238                                                 break;
4239                                                 break;
4240                                         case MONO_TYPE_I4:
4241                                                 NEW_ICONST (cfg, *sp, *((gint32 *)addr));
4242                                                 sp++;
4243                                                 break;                                          
4244                                         case MONO_TYPE_U4:
4245                                                 NEW_ICONST (cfg, *sp, *((guint32 *)addr));
4246                                                 sp++;
4247                                                 break;
4248                                         case MONO_TYPE_I:
4249                                         case MONO_TYPE_U:
4250                                         case MONO_TYPE_STRING:
4251                                         case MONO_TYPE_OBJECT:
4252                                         case MONO_TYPE_CLASS:
4253                                         case MONO_TYPE_SZARRAY:
4254                                         case MONO_TYPE_PTR:
4255                                         case MONO_TYPE_FNPTR:
4256                                         case MONO_TYPE_ARRAY:
4257                                                 NEW_PCONST (cfg, *sp, *((gpointer *)addr));
4258                                                 type_to_eval_stack_type (field->type, *sp);
4259                                                 sp++;
4260                                                 break;
4261                                         case MONO_TYPE_I8:
4262                                         case MONO_TYPE_U8:
4263                                                 MONO_INST_NEW (cfg, *sp, OP_I8CONST);
4264                                                 sp [0]->type = STACK_I8;
4265                                                 sp [0]->inst_l = *((gint64 *)addr);
4266                                                 sp++;
4267                                                 break;
4268                                         case MONO_TYPE_R4:
4269                                         case MONO_TYPE_R8:
4270                                         case MONO_TYPE_VALUETYPE:
4271                                         default:
4272                                                 is_const = FALSE;
4273                                                 break;
4274                                         }
4275                                 }
4276
4277                                 if (!is_const) {
4278                                         MonoInst *load;
4279                                         CHECK_STACK_OVF (1);
4280                                         MONO_INST_NEW (cfg, load, mono_type_to_ldind (field->type));
4281                                         type_to_eval_stack_type (field->type, load);
4282                                         load->cil_code = ip;
4283                                         load->inst_left = ins;
4284                                         *sp++ = load;
4285                                         load->flags |= ins_flag;
4286                                         ins_flag = 0;
4287                                         /* fixme: dont see the problem why this does not work */
4288                                         //cfg->disable_aot = TRUE;
4289                                 }
4290                         }
4291                         ip += 5;
4292                         break;
4293                 }
4294                 case CEE_STOBJ:
4295                         CHECK_STACK (2);
4296                         sp -= 2;
4297                         token = read32 (ip + 1);
4298                         if (method->wrapper_type != MONO_WRAPPER_NONE)
4299                                 klass = mono_method_get_wrapper_data (method, token);
4300                         else
4301                                 klass = mono_class_get (image, token);
4302                         mono_class_init (klass);
4303                         if (klass->byval_arg.type == MONO_TYPE_VAR)
4304                                 klass = TYPE_PARAM_TO_CLASS (klass->byval_arg.data.generic_param->num);
4305                         else if (klass->byval_arg.type == MONO_TYPE_MVAR)
4306                                 klass = MTYPE_PARAM_TO_CLASS (klass->byval_arg.data.generic_param->num);
4307                         n = mono_type_to_stind (&klass->byval_arg);
4308                         if (n == CEE_STOBJ) {
4309                                 handle_stobj (cfg, bblock, sp [0], sp [1], ip, klass, FALSE, FALSE);
4310                         } else {
4311                                 /* FIXME: should check item at sp [1] is compatible with the type of the store. */
4312                                 MonoInst *store;
4313                                 MONO_INST_NEW (cfg, store, n);
4314                                 store->cil_code = ip;
4315                                 store->inst_left = sp [0];
4316                                 store->inst_right = sp [1];
4317                                 store->flags |= ins_flag;
4318                                 MONO_ADD_INS (bblock, store);
4319                         }
4320                         ins_flag = 0;
4321                         ip += 5;
4322                         inline_costs += 1;
4323                         break;
4324                 case CEE_BOX: {
4325                         MonoInst *iargs [2];
4326                         MonoInst *load, *vtoffset, *add, *val, *vstore;
4327                         int temp;
4328                         CHECK_STACK (1);
4329                         --sp;
4330                         val = *sp;
4331                         token = read32 (ip + 1);
4332                         if (method->wrapper_type != MONO_WRAPPER_NONE)
4333                                 klass = mono_method_get_wrapper_data (method, token);
4334                         else
4335                                 klass = mono_class_get (image, token);
4336                         mono_class_init (klass);
4337                         if (klass->byval_arg.type == MONO_TYPE_VAR)
4338                                 klass = TYPE_PARAM_TO_CLASS (klass->byval_arg.data.generic_param->num);
4339                         else if (klass->byval_arg.type == MONO_TYPE_MVAR)
4340                                 klass = MTYPE_PARAM_TO_CLASS (klass->byval_arg.data.generic_param->num);
4341
4342                         if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
4343                                 *sp = val;
4344                                 ip += 5;
4345                                 break;
4346                         }
4347                         /* much like NEWOBJ */
4348                         if (cfg->opt & MONO_OPT_SHARED) {
4349                                 NEW_DOMAINCONST (cfg, iargs [0]);
4350                                 NEW_CLASSCONST (cfg, iargs [1], klass);
4351
4352                                 temp = mono_emit_jit_icall (cfg, bblock, mono_object_new, iargs, ip);
4353                         } else {
4354                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
4355                                 NEW_VTABLECONST (cfg, iargs [0], vtable);
4356                                 if (1 || klass->has_finalize || (cfg->prof_options & MONO_PROFILE_ALLOCATIONS))
4357                                         temp = mono_emit_jit_icall (cfg, bblock, mono_object_new_specific, iargs, ip);
4358                                 else
4359                                         temp = mono_emit_jit_icall (cfg, bblock, mono_object_new_fast, iargs, ip);
4360                         }
4361                         NEW_TEMPLOAD (cfg, load, temp);
4362                         NEW_ICONST (cfg, vtoffset, sizeof (MonoObject));
4363                         MONO_INST_NEW (cfg, add, CEE_ADD);
4364                         add->inst_left = load;
4365                         add->inst_right = vtoffset;
4366                         add->cil_code = ip;
4367                         add->klass = klass;
4368                         MONO_INST_NEW (cfg, vstore, CEE_STIND_I);
4369                         vstore->opcode = mono_type_to_stind (&klass->byval_arg);
4370                         vstore->cil_code = ip;
4371                         vstore->inst_left = add;
4372                         vstore->inst_right = val;
4373
4374                         if (vstore->opcode == CEE_STOBJ) {
4375                                 handle_stobj (cfg, bblock, add, val, ip, klass, FALSE, FALSE);
4376                         } else
4377                                 MONO_ADD_INS (bblock, vstore);
4378
4379                         NEW_TEMPLOAD (cfg, load, temp);
4380                         *sp++ = load;
4381                         ip += 5;
4382                         inline_costs += 1;
4383                         break;
4384                 }
4385                 case CEE_NEWARR:
4386                         CHECK_STACK (1);
4387                         MONO_INST_NEW (cfg, ins, *ip);
4388                         ins->cil_code = ip;
4389                         --sp;
4390
4391                         token = read32 (ip + 1);
4392
4393                         /* allocate the domainvar - becaus this is used in decompose_foreach */
4394                         if (cfg->opt & MONO_OPT_SHARED)
4395                                 mono_get_domainvar (cfg);
4396                         
4397                         if (method->wrapper_type != MONO_WRAPPER_NONE)
4398                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
4399                         else
4400                                 klass = mono_class_get (image, token);
4401
4402                         mono_class_init (klass);
4403                         if (klass->byval_arg.type == MONO_TYPE_VAR)
4404                                 klass = TYPE_PARAM_TO_CLASS (klass->byval_arg.data.generic_param->num);
4405                         else if (klass->byval_arg.type == MONO_TYPE_MVAR)
4406                                 klass = MTYPE_PARAM_TO_CLASS (klass->byval_arg.data.generic_param->num);
4407                         ins->inst_newa_class = klass;
4408                         ins->inst_newa_len = *sp;
4409                         ins->type = STACK_OBJ;
4410                         ip += 5;
4411                         *sp++ = ins;
4412                         inline_costs += 1;
4413                         break;
4414                 case CEE_LDLEN:
4415                         CHECK_STACK (1);
4416                         MONO_INST_NEW (cfg, ins, *ip);
4417                         ins->cil_code = ip++;
4418                         --sp;
4419                         ins->inst_left = *sp;
4420                         ins->type = STACK_PTR;
4421                         *sp++ = ins;
4422                         break;
4423                 case CEE_LDELEMA:
4424                         CHECK_STACK (2);
4425                         sp -= 2;
4426
4427                         if (method->wrapper_type != MONO_WRAPPER_NONE)
4428                                 klass = (MonoClass*)mono_method_get_wrapper_data (method, read32 (ip + 1));
4429                         else
4430                                 klass = mono_class_get (image, read32 (ip + 1));
4431                         mono_class_init (klass);
4432                         if (klass->byval_arg.type == MONO_TYPE_VAR)
4433                                 klass = TYPE_PARAM_TO_CLASS (klass->byval_arg.data.generic_param->num);
4434                         else if (klass->byval_arg.type == MONO_TYPE_MVAR)
4435                                 klass = MTYPE_PARAM_TO_CLASS (klass->byval_arg.data.generic_param->num);
4436                         NEW_LDELEMA (cfg, ins, sp, klass);
4437                         ins->cil_code = ip;
4438                         *sp++ = ins;
4439                         ip += 5;
4440                         break;
4441                 case CEE_LDELEM: {
4442                         MonoInst *load;
4443                         CHECK_STACK (2);
4444                         sp -= 2;
4445                         token = read32 (ip + 1);
4446                         klass = mono_class_get (image, token);
4447                         mono_class_init (klass);
4448                         if (klass->byval_arg.type == MONO_TYPE_VAR)
4449                                 klass = TYPE_PARAM_TO_CLASS (klass->byval_arg.data.generic_param->num);
4450                         else if (klass->byval_arg.type == MONO_TYPE_MVAR)
4451                                 klass = MTYPE_PARAM_TO_CLASS (klass->byval_arg.data.generic_param->num);
4452                         NEW_LDELEMA (cfg, load, sp, klass);
4453                         load->cil_code = ip;
4454                         MONO_INST_NEW (cfg, ins, mono_type_to_ldind (&klass->byval_arg));
4455                         ins->cil_code = ip;
4456                         ins->inst_left = load;
4457                         *sp++ = ins;
4458                         type_to_eval_stack_type (&klass->byval_arg, ins);
4459                         ip += 5;
4460                         break;
4461                 }
4462                 case CEE_LDELEM_I1:
4463                 case CEE_LDELEM_U1:
4464                 case CEE_LDELEM_I2:
4465                 case CEE_LDELEM_U2:
4466                 case CEE_LDELEM_I4:
4467                 case CEE_LDELEM_U4:
4468                 case CEE_LDELEM_I8:
4469                 case CEE_LDELEM_I:
4470                 case CEE_LDELEM_R4:
4471                 case CEE_LDELEM_R8:
4472                 case CEE_LDELEM_REF: {
4473                         MonoInst *load;
4474                         /*
4475                          * translate to:
4476                          * ldind.x (ldelema (array, index))
4477                          * ldelema does the bounds check
4478                          */
4479                         CHECK_STACK (2);
4480                         sp -= 2;
4481                         klass = array_access_to_klass (*ip);
4482                         NEW_LDELEMA (cfg, load, sp, klass);
4483                         load->cil_code = ip;
4484                         MONO_INST_NEW (cfg, ins, ldelem_to_ldind [*ip - CEE_LDELEM_I1]);
4485                         ins->cil_code = ip;
4486                         ins->inst_left = load;
4487                         *sp++ = ins;
4488                         ins->type = ldind_type [ins->opcode - CEE_LDIND_I1];
4489                         ++ip;
4490                         break;
4491                 }
4492                 case CEE_STELEM_I:
4493                 case CEE_STELEM_I1:
4494                 case CEE_STELEM_I2:
4495                 case CEE_STELEM_I4:
4496                 case CEE_STELEM_I8:
4497                 case CEE_STELEM_R4:
4498                 case CEE_STELEM_R8: {
4499                         MonoInst *load;
4500                         /*
4501                          * translate to:
4502                          * stind.x (ldelema (array, index), val)
4503                          * ldelema does the bounds check
4504                          */
4505                         CHECK_STACK (3);
4506                         sp -= 3;
4507                         klass = array_access_to_klass (*ip);
4508                         NEW_LDELEMA (cfg, load, sp, klass);
4509                         load->cil_code = ip;
4510                         MONO_INST_NEW (cfg, ins, stelem_to_stind [*ip - CEE_STELEM_I]);
4511                         ins->cil_code = ip;
4512                         ins->inst_left = load;
4513                         ins->inst_right = sp [2];
4514                         ++ip;
4515                         handle_loaded_temps (cfg, bblock, stack_start, sp);
4516                         MONO_ADD_INS (bblock, ins);
4517                         inline_costs += 1;
4518                         cfg->disable_ssa = TRUE;
4519                         break;
4520                 }
4521                 case CEE_STELEM: {
4522                         MonoInst *load;
4523                         /*
4524                          * translate to:
4525                          * stind.x (ldelema (array, index), val)
4526                          * ldelema does the bounds check
4527                          */
4528                         CHECK_STACK (3);
4529                         sp -= 3;
4530                         token = read32 (ip + 1);
4531                         klass = mono_class_get (image, token);
4532                         mono_class_init (klass);
4533                         if (klass->byval_arg.type == MONO_TYPE_VAR)
4534                                 klass = TYPE_PARAM_TO_CLASS (klass->byval_arg.data.generic_param->num);
4535                         else if (klass->byval_arg.type == MONO_TYPE_MVAR)
4536                                 klass = MTYPE_PARAM_TO_CLASS (klass->byval_arg.data.generic_param->num);
4537                         if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
4538                                 MonoInst *iargs [3];
4539                                 handle_loaded_temps (cfg, bblock, stack_start, sp);
4540
4541                                 iargs [2] = sp [2];
4542                                 iargs [1] = sp [1];
4543                                 iargs [0] = sp [0];
4544                         
4545                                 mono_emit_jit_icall (cfg, bblock, helper_stelem_ref, iargs, ip);
4546                         } else {
4547                                 NEW_LDELEMA (cfg, load, sp, klass);
4548                                 load->cil_code = ip;
4549                                 MONO_INST_NEW (cfg, ins, mono_type_to_stind (&klass->byval_arg));
4550                                 ins->cil_code = ip;
4551                                 ins->inst_left = load;
4552                                 ins->inst_right = sp [2];
4553                                 handle_loaded_temps (cfg, bblock, stack_start, sp);
4554                                 MONO_ADD_INS (bblock, ins);
4555                         }
4556                         ip += 5;
4557                         inline_costs += 1;
4558                         cfg->disable_ssa = TRUE;
4559                         break;
4560                 }
4561                 case CEE_STELEM_REF: {
4562                         MonoInst *iargs [3];
4563
4564                         CHECK_STACK (3);
4565                         sp -= 3;
4566
4567                         handle_loaded_temps (cfg, bblock, stack_start, sp);
4568
4569                         iargs [2] = sp [2];
4570                         iargs [1] = sp [1];
4571                         iargs [0] = sp [0];
4572                         
4573                         mono_emit_jit_icall (cfg, bblock, helper_stelem_ref, iargs, ip);
4574
4575                         /*
4576                         MonoInst *group;
4577                         NEW_GROUP (cfg, group, sp [0], sp [1]);
4578                         MONO_INST_NEW (cfg, ins, CEE_STELEM_REF);
4579                         ins->cil_code = ip;
4580                         ins->inst_left = group;
4581                         ins->inst_right = sp [2];
4582                         MONO_ADD_INS (bblock, ins);
4583                         */
4584
4585                         ++ip;
4586                         inline_costs += 1;
4587                         cfg->disable_ssa = TRUE;
4588                         break;
4589                 }
4590                 case CEE_CKFINITE: {
4591                         MonoInst *store, *temp;
4592                         CHECK_STACK (1);
4593
4594                         /* this instr. can throw exceptions as side effect,
4595                          * so we cant eliminate dead code which contains CKFINITE opdodes.
4596                          * Spilling to memory makes sure that we always perform
4597                          * this check */
4598
4599                         
4600                         MONO_INST_NEW (cfg, ins, CEE_CKFINITE);
4601                         ins->cil_code = ip;
4602                         ins->inst_left = sp [-1];
4603                         temp = mono_compile_create_var (cfg, &mono_defaults.double_class->byval_arg, OP_LOCAL);
4604
4605                         NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
4606                         store->cil_code = ip;
4607                         MONO_ADD_INS (bblock, store);
4608
4609                         NEW_TEMPLOAD (cfg, sp [-1], temp->inst_c0);
4610                        
4611                         ++ip;
4612                         break;
4613                 }
4614                 case CEE_REFANYVAL:
4615                         CHECK_STACK (1);
4616                         MONO_INST_NEW (cfg, ins, *ip);
4617                         --sp;
4618                         klass = mono_class_get (image, read32 (ip + 1));
4619                         mono_class_init (klass);
4620                         if (klass->byval_arg.type == MONO_TYPE_VAR)
4621                                 klass = TYPE_PARAM_TO_CLASS (klass->byval_arg.data.generic_param->num);
4622                         else if (klass->byval_arg.type == MONO_TYPE_MVAR)
4623                                 klass = MTYPE_PARAM_TO_CLASS (klass->byval_arg.data.generic_param->num);
4624                         ins->type = STACK_MP;
4625                         ins->inst_left = *sp;
4626                         ins->klass = klass;
4627                         ins->inst_newa_class = klass;
4628                         ins->cil_code = ip;
4629                         ip += 5;
4630                         *sp++ = ins;
4631                         break;
4632                 case CEE_MKREFANY: {
4633                         MonoInst *loc, *klassconst;
4634
4635                         CHECK_STACK (1);
4636                         MONO_INST_NEW (cfg, ins, *ip);
4637                         --sp;
4638                         klass = mono_class_get (image, read32 (ip + 1));
4639                         mono_class_init (klass);
4640                         if (klass->byval_arg.type == MONO_TYPE_VAR)
4641                                 klass = TYPE_PARAM_TO_CLASS (klass->byval_arg.data.generic_param->num);
4642                         else if (klass->byval_arg.type == MONO_TYPE_MVAR)
4643                                 klass = MTYPE_PARAM_TO_CLASS (klass->byval_arg.data.generic_param->num);
4644                         ins->cil_code = ip;
4645
4646                         loc = mono_compile_create_var (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL);
4647                         NEW_TEMPLOADA (cfg, ins->inst_right, loc->inst_c0);
4648
4649                         NEW_PCONST (cfg, klassconst, klass);
4650                         NEW_GROUP (cfg, ins->inst_left, *sp, klassconst);
4651                         
4652                         MONO_ADD_INS (bblock, ins);
4653
4654                         NEW_TEMPLOAD (cfg, *sp, loc->inst_c0);
4655                         ++sp;
4656                         ip += 5;
4657                         break;
4658                 }
4659                 case CEE_LDTOKEN: {
4660                         gpointer handle;
4661                         MonoClass *handle_class;
4662
4663                         CHECK_STACK_OVF (1);
4664
4665                         n = read32 (ip + 1);
4666
4667                         handle = mono_ldtoken (image, n, &handle_class);
4668                         mono_class_init (handle_class);
4669
4670                         if (cfg->opt & MONO_OPT_SHARED) {
4671                                 int temp;
4672                                 MonoInst *res, *store, *addr, *vtvar, *iargs [2];
4673
4674                                 vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL); 
4675
4676                                 NEW_IMAGECONST (cfg, iargs [0], image);
4677                                 NEW_ICONST (cfg, iargs [1], n);
4678                                 temp = mono_emit_jit_icall (cfg, bblock, mono_ldtoken_wrapper, iargs, ip);
4679                                 NEW_TEMPLOAD (cfg, res, temp);
4680                                 NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
4681                                 NEW_INDSTORE (cfg, store, addr, res, &mono_defaults.int_class->byval_arg);
4682                                 MONO_ADD_INS (bblock, store);
4683                                 NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
4684                         } else {
4685                                 if ((ip [5] == CEE_CALL) && (cmethod = mono_get_method (image, read32 (ip + 6), NULL)) &&
4686                                                 (cmethod->klass == mono_defaults.monotype_class->parent) &&
4687                                                 (strcmp (cmethod->name, "GetTypeFromHandle") == 0)) {
4688                                         MonoClass *tclass = mono_class_from_mono_type (handle);
4689                                         mono_class_init (tclass);
4690                                         if (mono_compile_aot)
4691                                                 NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, image, n);
4692                                         else
4693                                                 NEW_PCONST (cfg, ins, mono_type_get_object (cfg->domain, handle));
4694                                         ins->type = STACK_OBJ;
4695                                         ins->klass = cmethod->klass;
4696                                         ip += 5;
4697                                 } else {
4698                                         if (mono_compile_aot)
4699                                                 NEW_LDTOKENCONST (cfg, ins, image, n);
4700                                         else
4701                                                 NEW_PCONST (cfg, ins, handle);
4702                                         ins->type = STACK_VTYPE;
4703                                         ins->klass = handle_class;
4704                                 }
4705                         }
4706
4707                         *sp++ = ins;
4708                         ip += 5;
4709                         break;
4710                 }
4711                 case CEE_CONV_U2:
4712                 case CEE_CONV_U1:
4713                 case CEE_CONV_I:
4714                         CHECK_STACK (1);
4715                         ADD_UNOP (*ip);
4716                         ip++;
4717                         break;
4718                 case CEE_ADD_OVF:
4719                 case CEE_ADD_OVF_UN:
4720                 case CEE_MUL_OVF:
4721                 case CEE_MUL_OVF_UN:
4722                 case CEE_SUB_OVF:
4723                 case CEE_SUB_OVF_UN:
4724                         CHECK_STACK (2);
4725                         ADD_BINOP (*ip);
4726                         ip++;
4727                         break;
4728                 case CEE_ENDFINALLY:
4729                         /* FIXME: check stack state */
4730                         MONO_INST_NEW (cfg, ins, *ip);
4731                         MONO_ADD_INS (bblock, ins);
4732                         ins->cil_code = ip++;
4733                         start_new_bblock = 1;
4734                         break;
4735                 case CEE_LEAVE:
4736                 case CEE_LEAVE_S: {
4737                         GList *handlers;
4738                         if (*ip == CEE_LEAVE) {
4739                                 target = ip + 5 + (gint32)read32(ip + 1);
4740                         } else {
4741                                 target = ip + 2 + (signed char)(ip [1]);
4742                         }
4743
4744                         /* empty the stack */
4745                         while (sp != stack_start) {
4746                                 MONO_INST_NEW (cfg, ins, CEE_POP);
4747                                 ins->cil_code = ip;
4748                                 sp--;
4749                                 ins->inst_i0 = *sp;
4750                                 MONO_ADD_INS (bblock, ins);
4751                         }
4752
4753                         /* 
4754                          * If this leave statement is in a catch block, check for a
4755                          * pending exception, and rethrow it if necessary.
4756                          */
4757                         for (i = 0; i < header->num_clauses; ++i) {
4758                                 MonoExceptionClause *clause = &header->clauses [i];
4759                                 if (MONO_OFFSET_IN_HANDLER (clause, ip - header->code)) {
4760                                         int temp;
4761
4762                                         temp = mono_emit_jit_icall (cfg, bblock, mono_thread_get_pending_exception, NULL, ip);
4763                                         NEW_TEMPLOAD (cfg, *sp, temp);
4764
4765                                         MONO_INST_NEW (cfg, ins, OP_THROW_OR_NULL);
4766                                         ins->inst_left = *sp;
4767                                         ins->cil_code = ip;
4768                                         MONO_ADD_INS (bblock, ins);
4769                                 }
4770                         }
4771
4772                         /* fixme: call fault handler ? */
4773
4774                         if ((handlers = mono_find_final_block (cfg, ip, target, MONO_EXCEPTION_CLAUSE_FINALLY))) {
4775                                 GList *tmp;
4776                                 for (tmp = handlers; tmp; tmp = tmp->next) {
4777                                         tblock = tmp->data;
4778                                         link_bblock (cfg, bblock, tblock);
4779                                         MONO_INST_NEW (cfg, ins, OP_CALL_HANDLER);
4780                                         ins->cil_code = ip;
4781                                         ins->inst_target_bb = tblock;
4782                                         MONO_ADD_INS (bblock, ins);
4783                                 }
4784                                 g_list_free (handlers);
4785                         } 
4786
4787                         MONO_INST_NEW (cfg, ins, CEE_BR);
4788                         ins->cil_code = ip;
4789                         MONO_ADD_INS (bblock, ins);
4790                         GET_BBLOCK (cfg, bbhash, tblock, target);
4791                         link_bblock (cfg, bblock, tblock);
4792                         CHECK_BBLOCK (target, ip, tblock);
4793                         ins->inst_target_bb = tblock;
4794                         start_new_bblock = 1;
4795
4796                         if (*ip == CEE_LEAVE)
4797                                 ip += 5;
4798                         else
4799                                 ip += 2;
4800
4801                         break;
4802                 }
4803                 case CEE_STIND_I:
4804                         CHECK_STACK (2);
4805                         MONO_INST_NEW (cfg, ins, *ip);
4806                         sp -= 2;
4807                         handle_loaded_temps (cfg, bblock, stack_start, sp);
4808                         MONO_ADD_INS (bblock, ins);
4809                         ins->cil_code = ip++;
4810                         ins->inst_i0 = sp [0];
4811                         ins->inst_i1 = sp [1];
4812                         inline_costs += 1;
4813                         break;
4814                 case CEE_CONV_U:
4815                         CHECK_STACK (1);
4816                         ADD_UNOP (*ip);
4817                         ip++;
4818                         break;
4819                 /* trampoline mono specific opcodes */
4820                 case MONO_CUSTOM_PREFIX: {
4821
4822                         g_assert (method->wrapper_type != MONO_WRAPPER_NONE);
4823
4824                         switch (ip [1]) {
4825
4826                         case CEE_MONO_FUNC1: {
4827                                 int temp;
4828                                 gpointer func = NULL;
4829                                 CHECK_STACK (1);
4830                                 sp--;
4831
4832                                 switch (ip [2]) {
4833                                 case MONO_MARSHAL_CONV_STR_LPWSTR:
4834                                         func = mono_string_to_utf16;
4835                                         break;
4836                                 case MONO_MARSHAL_CONV_LPWSTR_STR:
4837                                         func = mono_string_from_utf16;
4838                                         break;
4839                                 case MONO_MARSHAL_CONV_LPSTR_STR:
4840                                         func = mono_string_new_wrapper;
4841                                         break;
4842                                 case MONO_MARSHAL_CONV_STR_LPTSTR:
4843                                 case MONO_MARSHAL_CONV_STR_LPSTR:
4844                                         func = mono_string_to_utf8;
4845                                         break;
4846                                 case MONO_MARSHAL_CONV_STR_BSTR:
4847                                         func = mono_string_to_bstr;
4848                                         break;
4849                                 case MONO_MARSHAL_CONV_STR_TBSTR:
4850                                 case MONO_MARSHAL_CONV_STR_ANSIBSTR:
4851                                         func = mono_string_to_ansibstr;
4852                                         break;
4853                                 case MONO_MARSHAL_CONV_SB_LPSTR:
4854                                         func = mono_string_builder_to_utf8;
4855                                         break;
4856                                 case MONO_MARSHAL_CONV_ARRAY_SAVEARRAY:
4857                                         func = mono_array_to_savearray;
4858                                         break;
4859                                 case MONO_MARSHAL_CONV_ARRAY_LPARRAY:
4860                                         func = mono_array_to_lparray;
4861                                         break;
4862                                 case MONO_MARSHAL_CONV_DEL_FTN:
4863                                         func = mono_delegate_to_ftnptr;
4864                                         break;
4865                                 case MONO_MARSHAL_CONV_STRARRAY_STRLPARRAY:
4866                                         func = mono_marshal_string_array;
4867                                         break;
4868                                 default:
4869                                         g_warning ("unknown conversion %d\n", ip [2]);
4870                                         g_assert_not_reached ();
4871                                 }
4872
4873                                 temp = mono_emit_jit_icall (cfg, bblock, func, sp, ip);
4874                                 NEW_TEMPLOAD (cfg, *sp, temp);
4875                                 sp++;
4876
4877                                 ip += 3;
4878                                 inline_costs += 10 * num_calls++;
4879                                 break;
4880                         }
4881                         case CEE_MONO_PROC2: {
4882                                 gpointer func = NULL;
4883                                 CHECK_STACK (2);
4884                                 sp -= 2;
4885
4886                                 switch (ip [2]) {
4887                                 case MONO_MARSHAL_CONV_LPSTR_SB:
4888                                         func = mono_string_utf8_to_builder;
4889                                         break;
4890                                 case MONO_MARSHAL_FREE_ARRAY:
4891                                         func = mono_marshal_free_array;
4892                                         break;
4893                                 default:
4894                                         g_assert_not_reached ();
4895                                 }
4896
4897                                 mono_emit_jit_icall (cfg, bblock, func, sp, ip);
4898                                 ip += 3;
4899                                 inline_costs += 10 * num_calls++;
4900                                 break;
4901                         }
4902                         case CEE_MONO_PROC3: {
4903                                 gpointer func = NULL;
4904                                 CHECK_STACK (3);
4905                                 sp -= 3;
4906
4907                                 switch (ip [2]) {
4908                                 case MONO_MARSHAL_CONV_STR_BYVALSTR:
4909                                         func = mono_string_to_byvalstr;
4910                                         break;
4911                                 case MONO_MARSHAL_CONV_STR_BYVALWSTR:
4912                                         func = mono_string_to_byvalwstr;
4913                                         break;
4914                                 default:
4915                                         g_assert_not_reached ();
4916                                 }
4917
4918                                 mono_emit_jit_icall (cfg, bblock, func, sp, ip);
4919                                 ip += 3;
4920                                 inline_costs += 10 * num_calls++;
4921                                 break;
4922                         }
4923                         case CEE_MONO_FREE:
4924                                 CHECK_STACK (1);
4925                                 sp -= 1;
4926                                 mono_emit_jit_icall (cfg, bblock, g_free, sp, ip);
4927                                 ip += 2;
4928                                 inline_costs += 10 * num_calls++;
4929                                 break;
4930                         case CEE_MONO_LDPTR:
4931                                 CHECK_STACK_OVF (1);
4932                                 token = read32 (ip + 2);
4933                                 NEW_PCONST (cfg, ins, mono_method_get_wrapper_data (method, token));
4934                                 ins->cil_code = ip;
4935                                 *sp++ = ins;
4936                                 ip += 6;
4937                                 inline_costs += 10 * num_calls++;
4938                                 break;
4939                         case CEE_MONO_VTADDR:
4940                                 CHECK_STACK (1);
4941                                 --sp;
4942                                 MONO_INST_NEW (cfg, ins, OP_VTADDR);
4943                                 ins->cil_code = ip;
4944                                 ins->type = STACK_MP;
4945                                 ins->inst_left = *sp;
4946                                 *sp++ = ins;
4947                                 ip += 2;
4948                                 break;
4949                         case CEE_MONO_NEWOBJ: {
4950                                 MonoInst *iargs [2];
4951                                 int temp;
4952                                 CHECK_STACK_OVF (1);
4953                                 token = read32 (ip + 2);
4954                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
4955                                 mono_class_init (klass);
4956                                 NEW_DOMAINCONST (cfg, iargs [0]);
4957                                 NEW_CLASSCONST (cfg, iargs [1], klass);
4958                                 temp = mono_emit_jit_icall (cfg, bblock, mono_object_new, iargs, ip);
4959                                 NEW_TEMPLOAD (cfg, *sp, temp);
4960                                 sp++;
4961                                 ip += 6;
4962                                 inline_costs += 10 * num_calls++;
4963                                 break;
4964                         }
4965                         case CEE_MONO_OBJADDR:
4966                                 CHECK_STACK (1);
4967                                 --sp;
4968                                 MONO_INST_NEW (cfg, ins, OP_OBJADDR);
4969                                 ins->cil_code = ip;
4970                                 ins->type = STACK_MP;
4971                                 ins->inst_left = *sp;
4972                                 *sp++ = ins;
4973                                 ip += 2;
4974                                 break;
4975                         case CEE_MONO_LDNATIVEOBJ:
4976                                 CHECK_STACK (1);
4977                                 token = read32 (ip + 2);
4978                                 klass = mono_method_get_wrapper_data (method, token);
4979                                 g_assert (klass->valuetype);
4980                                 mono_class_init (klass);
4981                                 NEW_INDLOAD (cfg, ins, sp [-1], &klass->byval_arg);
4982                                 sp [-1] = ins;
4983                                 ip += 6;
4984                                 break;
4985                         case CEE_MONO_RETOBJ:
4986                                 g_assert (cfg->ret);
4987                                 g_assert (method->signature->pinvoke); 
4988                                 CHECK_STACK (1);
4989                                 --sp;
4990                                 
4991                                 token = read32 (ip + 2);    
4992                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
4993
4994                                 NEW_RETLOADA (cfg, ins);
4995                                 handle_stobj (cfg, bblock, ins, *sp, ip, klass, FALSE, TRUE);
4996                                 
4997                                 if (sp != stack_start)
4998                                         goto unverified;
4999                                 
5000                                 MONO_INST_NEW (cfg, ins, CEE_BR);
5001                                 ins->cil_code = ip;
5002                                 ins->inst_target_bb = end_bblock;
5003                                 MONO_ADD_INS (bblock, ins);
5004                                 link_bblock (cfg, bblock, end_bblock);
5005                                 start_new_bblock = 1;
5006                                 ip += 6;
5007                                 break;
5008                         default:
5009                                 g_error ("opcode 0x%02x 0x%02x not handled", MONO_CUSTOM_PREFIX, ip [1]);
5010                                 break;
5011                         }
5012                         break;
5013                 }
5014                 case CEE_PREFIX1: {
5015                         switch (ip [1]) {
5016                         case CEE_ARGLIST: {
5017                                 /* somewhat similar to LDTOKEN */
5018                                 MonoInst *addr, *vtvar;
5019                                 CHECK_STACK_OVF (1);
5020                                 vtvar = mono_compile_create_var (cfg, &mono_defaults.argumenthandle_class->byval_arg, OP_LOCAL); 
5021
5022                                 NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
5023                                 addr->cil_code = ip;
5024                                 MONO_INST_NEW (cfg, ins, OP_ARGLIST);
5025                                 ins->cil_code = ip;
5026                                 ins->inst_left = addr;
5027                                 MONO_ADD_INS (bblock, ins);
5028                                 NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
5029                                 ins->cil_code = ip;
5030                                 *sp++ = ins;
5031                                 ip += 2;
5032                                 break;
5033                         }
5034                         case CEE_CEQ:
5035                         case CEE_CGT:
5036                         case CEE_CGT_UN:
5037                         case CEE_CLT:
5038                         case CEE_CLT_UN: {
5039                                 MonoInst *cmp;
5040                                 CHECK_STACK (2);
5041                                 MONO_INST_NEW (cfg, cmp, 256 + ip [1]);
5042                                 MONO_INST_NEW (cfg, ins, cmp->opcode);
5043                                 sp -= 2;
5044                                 cmp->inst_i0 = sp [0];
5045                                 cmp->inst_i1 = sp [1];
5046                                 cmp->cil_code = ip;
5047                                 type_from_op (cmp);
5048                                 CHECK_TYPE (cmp);
5049                                 cmp->opcode = OP_COMPARE;
5050                                 ins->cil_code = ip;
5051                                 ins->type = STACK_I4;
5052                                 ins->inst_i0 = cmp;
5053                                 *sp++ = ins;
5054                                 ip += 2;
5055                                 break;
5056                         }
5057                         case CEE_LDFTN: {
5058                                 MonoInst *argconst;
5059                                 int temp;
5060
5061                                 CHECK_STACK_OVF (1);
5062                                 n = read32 (ip + 2);
5063                                 if (method->wrapper_type != MONO_WRAPPER_NONE)
5064                                         cmethod = mono_method_get_wrapper_data (method, n);
5065                                 else {
5066                                         cmethod = mono_get_method (image, n, NULL);
5067
5068                                         /*
5069                                          * We can't do this in mono_ldftn, since it is used in
5070                                          * the synchronized wrapper, leading to an infinite loop.
5071                                          */
5072                                         if (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
5073                                                 cmethod = mono_marshal_get_synchronized_wrapper (cmethod);
5074                                 }
5075
5076                                 mono_class_init (cmethod->klass);
5077                                 handle_loaded_temps (cfg, bblock, stack_start, sp);
5078
5079                                 NEW_METHODCONST (cfg, argconst, cmethod);
5080                                 temp = mono_emit_jit_icall (cfg, bblock, mono_ldftn, &argconst, ip);
5081                                 NEW_TEMPLOAD (cfg, *sp, temp);
5082                                 sp ++;
5083                                 
5084                                 ip += 6;
5085                                 inline_costs += 10 * num_calls++;
5086                                 break;
5087                         }
5088                         case CEE_LDVIRTFTN: {
5089                                 MonoInst *args [2];
5090                                 int temp;
5091
5092                                 CHECK_STACK (1);
5093                                 n = read32 (ip + 2);
5094                                 if (method->wrapper_type != MONO_WRAPPER_NONE)
5095                                         cmethod = mono_method_get_wrapper_data (method, n);
5096                                 else
5097                                         cmethod = mono_get_method (image, n, NULL);
5098
5099                                 mono_class_init (cmethod->klass);
5100                                 handle_loaded_temps (cfg, bblock, stack_start, sp);
5101
5102                                 --sp;
5103                                 args [0] = *sp;
5104                                 NEW_METHODCONST (cfg, args [1], cmethod);
5105                                 temp = mono_emit_jit_icall (cfg, bblock, mono_ldvirtfn, args, ip);
5106                                 NEW_TEMPLOAD (cfg, *sp, temp);
5107                                 sp ++;
5108
5109                                 ip += 6;
5110                                 inline_costs += 10 * num_calls++;
5111                                 break;
5112                         }
5113                         case CEE_LDARG:
5114                                 CHECK_STACK_OVF (1);
5115                                 NEW_ARGLOAD (cfg, ins, read16 (ip + 2));
5116                                 ins->cil_code = ip;
5117                                 *sp++ = ins;
5118                                 ip += 4;
5119                                 break;
5120                         case CEE_LDARGA:
5121                                 CHECK_STACK_OVF (1);
5122                                 NEW_ARGLOADA (cfg, ins, read16 (ip + 2));
5123                                 ins->cil_code = ip;
5124                                 *sp++ = ins;
5125                                 ip += 4;
5126                                 break;
5127                         case CEE_STARG:
5128                                 CHECK_STACK (1);
5129                                 --sp;
5130                                 handle_loaded_temps (cfg, bblock, stack_start, sp);
5131                                 n = read16 (ip + 2);
5132                                 NEW_ARGSTORE (cfg, ins, n, *sp);
5133                                 ins->cil_code = ip;
5134                                 if (ins->opcode == CEE_STOBJ) {
5135                                         NEW_ARGLOADA (cfg, ins, n);
5136                                         handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE);
5137                                 } else
5138                                         MONO_ADD_INS (bblock, ins);
5139                                 ip += 4;
5140                                 break;
5141                         case CEE_LDLOC:
5142                                 CHECK_STACK_OVF (1);
5143                                 NEW_LOCLOAD (cfg, ins, read16 (ip + 2));
5144                                 ins->cil_code = ip;
5145                                 *sp++ = ins;
5146                                 ip += 4;
5147                                 break;
5148                         case CEE_LDLOCA:
5149                                 CHECK_STACK_OVF (1);
5150                                 NEW_LOCLOADA (cfg, ins, read16 (ip + 2));
5151                                 ins->cil_code = ip;
5152                                 *sp++ = ins;
5153                                 ip += 4;
5154                                 break;
5155                         case CEE_STLOC:
5156                                 CHECK_STACK (1);
5157                                 --sp;
5158                                 n = read16 (ip + 2);
5159                                 handle_loaded_temps (cfg, bblock, stack_start, sp);
5160                                 NEW_LOCSTORE (cfg, ins, n, *sp);
5161                                 ins->cil_code = ip;
5162                                 if (ins->opcode == CEE_STOBJ) {
5163                                         NEW_LOCLOADA (cfg, ins, n);
5164                                         handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE);
5165                                 } else
5166                                         MONO_ADD_INS (bblock, ins);
5167                                 ip += 4;
5168                                 inline_costs += 1;
5169                                 break;
5170                         case CEE_LOCALLOC:
5171                                 CHECK_STACK (1);
5172                                 --sp;
5173                                 if (sp != stack_start) 
5174                                         goto unverified;
5175                                 MONO_INST_NEW (cfg, ins, 256 + ip [1]);
5176                                 ins->inst_left = *sp;
5177                                 ins->cil_code = ip;
5178
5179                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
5180                                 if (header->init_locals)
5181                                         ins->flags |= MONO_INST_INIT;
5182
5183                                 *sp++ = ins;
5184                                 ip += 2;
5185                                 /* FIXME: set init flag if locals init is set in this method */
5186                                 break;
5187                         case CEE_ENDFILTER: {
5188                                 MonoExceptionClause *clause, *nearest;
5189                                 int cc, nearest_num;
5190
5191                                 CHECK_STACK (1);
5192                                 --sp;
5193                                 if ((sp != stack_start) || (sp [0]->type != STACK_I4)) 
5194                                         goto unverified;
5195                                 MONO_INST_NEW (cfg, ins, OP_ENDFILTER);
5196                                 ins->inst_left = *sp;
5197                                 ins->cil_code = ip;
5198                                 MONO_ADD_INS (bblock, ins);
5199                                 start_new_bblock = 1;
5200                                 ip += 2;
5201
5202                                 nearest = NULL;
5203                                 nearest_num = 0;
5204                                 for (cc = 0; cc < header->num_clauses; ++cc) {
5205                                         clause = &header->clauses [cc];
5206                                         if ((clause->flags & MONO_EXCEPTION_CLAUSE_FILTER) &&
5207                                             (!nearest || (clause->token_or_filter > nearest->token_or_filter))) {
5208                                                 nearest = clause;
5209                                                 nearest_num = cc;
5210                                         }
5211                                 }
5212                                 g_assert (nearest);
5213                                 filter_lengths [nearest_num] = (ip - header->code) -  nearest->token_or_filter;
5214
5215                                 break;
5216                         }
5217                         case CEE_UNALIGNED_:
5218                                 ins_flag |= MONO_INST_UNALIGNED;
5219                                 ip += 3;
5220                                 break;
5221                         case CEE_VOLATILE_:
5222                                 ins_flag |= MONO_INST_VOLATILE;
5223                                 ip += 2;
5224                                 break;
5225                         case CEE_TAIL_:
5226                                 ins_flag |= MONO_INST_TAILCALL;
5227                                 /* Can't inline tail calls at this time */
5228                                 inline_costs += 100000;
5229                                 ip += 2;
5230                                 break;
5231                         case CEE_INITOBJ:
5232                                 CHECK_STACK (1);
5233                                 --sp;
5234                                 token = read32 (ip + 2);
5235                                 if (method->wrapper_type != MONO_WRAPPER_NONE)
5236                                         klass = mono_method_get_wrapper_data (method, token);
5237                                 else
5238                                         klass = mono_class_get (image, token);
5239                                 if (klass->byval_arg.type == MONO_TYPE_VAR)
5240                                         klass = TYPE_PARAM_TO_CLASS (klass->byval_arg.data.generic_param->num);
5241                                 else if (klass->byval_arg.type == MONO_TYPE_MVAR)
5242                                         klass = MTYPE_PARAM_TO_CLASS (klass->byval_arg.data.generic_param->num);
5243
5244                                 if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
5245                                         MonoInst *store, *load;
5246                                         NEW_PCONST (cfg, load, NULL);
5247                                         load->cil_code = ip;
5248                                         load->type = STACK_OBJ;
5249                                         MONO_INST_NEW (cfg, store, CEE_STIND_REF);
5250                                         store->cil_code = ip;
5251                                         handle_loaded_temps (cfg, bblock, stack_start, sp);
5252                                         MONO_ADD_INS (bblock, store);
5253                                         store->inst_i0 = sp [0];
5254                                         store->inst_i1 = load;
5255                                         break;
5256                                 } else {
5257                                         handle_initobj (cfg, bblock, *sp, NULL, klass, stack_start, sp);
5258                                 }
5259                                 ip += 6;
5260                                 inline_costs += 1;
5261                                 break;
5262                         case CEE_CONSTRAINED_:
5263                                 /* FIXME: implement */
5264                                 token = read32 (ip + 2);
5265                                 ip += 6;
5266                                 break;
5267                         case CEE_CPBLK:
5268                         case CEE_INITBLK: {
5269                                 MonoInst *iargs [3];
5270                                 CHECK_STACK (3);
5271                                 sp -= 3;
5272                                 iargs [0] = sp [0];
5273                                 iargs [1] = sp [1];
5274                                 iargs [2] = sp [2];
5275                                 handle_loaded_temps (cfg, bblock, stack_start, sp);
5276                                 if (ip [1] == CEE_CPBLK) {
5277                                         mono_emit_jit_icall (cfg, bblock, helper_memcpy, iargs, ip);
5278                                 } else {
5279                                         mono_emit_jit_icall (cfg, bblock, helper_memset, iargs, ip);
5280                                 }
5281                                 ip += 2;
5282                                 inline_costs += 1;
5283                                 break;
5284                         }
5285                         case CEE_NO_:
5286                                 if (ip [2] & 0x1)
5287                                         ins_flag |= MONO_INST_NOTYPECHECK;
5288                                 if (ip [2] & 0x2)
5289                                         ins_flag |= MONO_INST_NORANGECHECK;
5290                                 /* we ignore the no-nullcheck for now since we
5291                                  * really do it explicitly only when doing callvirt->call
5292                                  */
5293                                 ip += 3;
5294                                 break;
5295                         case CEE_RETHROW: {
5296                                 MonoInst *load;
5297                                 /* FIXME: check we are in a catch handler */
5298                                 NEW_TEMPLOAD (cfg, load, cfg->exvar->inst_c0);
5299                                 load->cil_code = ip;
5300                                 MONO_INST_NEW (cfg, ins, CEE_THROW);
5301                                 ins->inst_left = load;
5302                                 ins->cil_code = ip;
5303                                 MONO_ADD_INS (bblock, ins);
5304                                 sp = stack_start;
5305                                 start_new_bblock = 1;
5306                                 ip += 2;
5307                                 break;
5308                         }
5309                         case CEE_SIZEOF:
5310                                 CHECK_STACK_OVF (1);
5311                                 token = read32 (ip + 2);
5312                                 /* FIXXME: handle generics. */
5313                                 if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC) {
5314                                         MonoType *type = mono_type_create_from_typespec (image, token);
5315                                         token = mono_type_size (type, &align);
5316                                 } else {
5317                                         MonoClass *szclass = mono_class_get (image, token);
5318                                         mono_class_init (szclass);
5319                                         token = mono_class_value_size (szclass, &align);
5320                                 }
5321                                 NEW_ICONST (cfg, ins, token);
5322                                 ins->cil_code = ip;
5323                                 *sp++= ins;
5324                                 ip += 6;
5325                                 break;
5326                         case CEE_REFANYTYPE:
5327                                 CHECK_STACK (1);
5328                                 MONO_INST_NEW (cfg, ins, ip [1]);
5329                                 --sp;
5330                                 ins->type = STACK_MP;
5331                                 ins->inst_left = *sp;
5332                                 ins->type = STACK_VTYPE;
5333                                 ins->klass = mono_defaults.typehandle_class;
5334                                 ins->cil_code = ip;
5335                                 ip += 2;
5336                                 *sp++ = ins;
5337                                 break;
5338                         case CEE_READONLY_:
5339                                 ip += 2;
5340                                 break;
5341                         default:
5342                                 g_error ("opcode 0xfe 0x%02x not handled", ip [1]);
5343                         }
5344                         break;
5345                 }
5346                 default:
5347                         g_error ("opcode 0x%02x not handled", *ip);
5348                 }
5349         }
5350         if (start_new_bblock != 1)
5351                 goto unverified;
5352
5353         bblock->cil_length = ip - bblock->cil_code;
5354         bblock->next_bb = end_bblock;
5355         link_bblock (cfg, bblock, end_bblock);
5356
5357         if (cfg->method == method && cfg->domainvar) {
5358                 MonoCallInst *call;
5359                 MonoInst *store;
5360
5361                 MONO_INST_NEW_CALL (cfg, call, CEE_CALL);
5362                 call->signature = helper_sig_domain_get;
5363                 call->inst.type = STACK_PTR;
5364                 call->fptr = mono_domain_get;
5365                 NEW_TEMPSTORE (cfg, store, cfg->domainvar->inst_c0, (MonoInst*)call);
5366                 
5367                 MONO_ADD_INS (init_localsbb, store);
5368         }
5369
5370         if (header->init_locals) {
5371                 MonoInst *store;
5372                 for (i = 0; i < header->num_locals; ++i) {
5373                         int t = header->locals [i]->type;
5374                         if (t == MONO_TYPE_VALUETYPE && header->locals [i]->data.klass->enumtype)
5375                                 t = header->locals [i]->data.klass->enum_basetype->type;
5376                         /* FIXME: use initobj for valuetypes, handle pointers, long, float. */
5377                         if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
5378                                 NEW_ICONST (cfg, ins, 0);
5379                                 NEW_LOCSTORE (cfg, store, i, ins);
5380                                 MONO_ADD_INS (init_localsbb, store);
5381                         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
5382                                 MONO_INST_NEW (cfg, ins, OP_I8CONST);
5383                                 ins->type = STACK_I8;
5384                                 ins->inst_l = 0;
5385                                 NEW_LOCSTORE (cfg, store, i, ins);
5386                                 MONO_ADD_INS (init_localsbb, store);
5387                         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
5388                                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
5389                                 ins->type = STACK_R8;
5390                                 ins->inst_p0 = (void*)&r8_0;
5391                                 NEW_LOCSTORE (cfg, store, i, ins);
5392                                 MONO_ADD_INS (init_localsbb, store);
5393                         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF)) {
5394                                 NEW_LOCLOADA (cfg, ins, i);
5395                                 handle_initobj (cfg, init_localsbb, ins, NULL, mono_class_from_mono_type (header->locals [i]), NULL, NULL);
5396                                 break;
5397                         } else {
5398                                 NEW_PCONST (cfg, ins, NULL);
5399                                 NEW_LOCSTORE (cfg, store, i, ins);
5400                                 MONO_ADD_INS (init_localsbb, store);
5401                         }
5402                 }
5403         }
5404
5405         
5406         /* resolve backward branches in the middle of an existing basic block */
5407         for (tmp = bb_recheck; tmp; tmp = tmp->next) {
5408                 bblock = tmp->data;
5409                 /*g_print ("need recheck in %s at IL_%04x\n", method->name, bblock->cil_code - header->code);*/
5410                 tblock = find_previous (bbhash, start_bblock, bblock->cil_code);
5411                 if (tblock != start_bblock) {
5412                         int l;
5413                         split_bblock (cfg, tblock, bblock);
5414                         l = bblock->cil_code - header->code;
5415                         bblock->cil_length = tblock->cil_length - l;
5416                         tblock->cil_length = l;
5417                 } else {
5418                         g_print ("recheck failed.\n");
5419                 }
5420         }
5421
5422         /* we compute regions here, because the length of filter clauses is not known in advance.
5423         * It is computed in the CEE_ENDFILTER case in the above switch statement*/
5424         if (cfg->method == method) {
5425                 MonoBasicBlock *bb;
5426                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
5427                         bb->region = mono_find_block_region (cfg, bb->real_offset, filter_lengths);
5428                         if (cfg->spvars)
5429                                 mono_create_spvar_for_region (cfg, bb->region);
5430                         if (cfg->verbose_level > 2)
5431                                 g_print ("REGION BB%d IL_%04x ID_%08X\n", bb->block_num, bb->real_offset, bb->region);
5432                 }
5433         } else {
5434                 g_hash_table_destroy (bbhash);
5435         }
5436
5437         dont_inline = g_list_remove (dont_inline, method);
5438         return inline_costs;
5439
5440  inline_failure:
5441         if (cfg->method != method) 
5442                 g_hash_table_destroy (bbhash);
5443         dont_inline = g_list_remove (dont_inline, method);
5444         return -1;
5445
5446  unverified:
5447         if (cfg->method != method) 
5448                 g_hash_table_destroy (bbhash);
5449         g_error ("Invalid IL code at IL%04x in %s: %s\n", ip - header->code, 
5450                  mono_method_full_name (method, TRUE), mono_disasm_code_one (NULL, method, ip, NULL));
5451         dont_inline = g_list_remove (dont_inline, method);
5452         return -1;
5453 }
5454
5455 void
5456 mono_print_tree (MonoInst *tree) {
5457         int arity;
5458
5459         if (!tree)
5460                 return;
5461
5462         arity = mono_burg_arity [tree->opcode];
5463
5464         printf (" %s%s", arity?"(":"",  mono_inst_name (tree->opcode));
5465
5466         switch (tree->opcode) {
5467         case OP_ICONST:
5468                 printf ("[%d]", tree->inst_c0);
5469                 break;
5470         case OP_I8CONST:
5471                 printf ("[%lld]", tree->inst_l);
5472                 break;
5473         case OP_R8CONST:
5474                 printf ("[%f]", *(double*)tree->inst_p0);
5475                 break;
5476         case OP_R4CONST:
5477                 printf ("[%f]", *(float*)tree->inst_p0);
5478                 break;
5479         case OP_ARG:
5480         case OP_LOCAL:
5481                 printf ("[%d]", tree->inst_c0);
5482                 break;
5483         case OP_REGOFFSET:
5484                 printf ("[0x%x(%s)]", tree->inst_offset, mono_arch_regname (tree->inst_basereg));
5485                 break;
5486         case OP_REGVAR:
5487                 printf ("[%s]", mono_arch_regname (tree->dreg));
5488                 break;
5489         case CEE_NEWARR:
5490                 printf ("[%s]",  tree->inst_newa_class->name);
5491                 mono_print_tree (tree->inst_newa_len);
5492                 break;
5493         case CEE_CALL:
5494         case CEE_CALLVIRT:
5495         case OP_FCALL:
5496         case OP_FCALLVIRT:
5497         case OP_LCALL:
5498         case OP_LCALLVIRT:
5499         case OP_VCALL:
5500         case OP_VCALLVIRT:
5501         case OP_VOIDCALL:
5502         case OP_VOIDCALLVIRT: {
5503                 MonoCallInst *call = (MonoCallInst*)tree;
5504                 if (call->method)
5505                         printf ("[%s]", call->method->name);
5506                 break;
5507         }
5508         case OP_PHI: {
5509                 int i;
5510                 printf ("[%d (", tree->inst_c0);
5511                 for (i = 0; i < tree->inst_phi_args [0]; i++) {
5512                         if (i)
5513                                 printf (", ");
5514                         printf ("%d", tree->inst_phi_args [i + 1]);
5515                 }
5516                 printf (")]");
5517                 break;
5518         }
5519         case OP_RENAME:
5520         case OP_RETARG:
5521         case CEE_NOP:
5522         case CEE_JMP:
5523         case CEE_BREAK:
5524                 break;
5525         case CEE_BR:
5526                 printf ("[B%d]", tree->inst_target_bb->block_num);
5527                 break;
5528         case CEE_SWITCH:
5529         case CEE_ISINST:
5530         case CEE_CASTCLASS:
5531         case OP_OUTARG:
5532         case OP_CALL_REG:
5533         case OP_FCALL_REG:
5534         case OP_LCALL_REG:
5535         case OP_VCALL_REG:
5536         case OP_VOIDCALL_REG:
5537                 mono_print_tree (tree->inst_left);
5538                 break;
5539         case CEE_BNE_UN:
5540         case CEE_BEQ:
5541         case CEE_BLT:
5542         case CEE_BLT_UN:
5543         case CEE_BGT:
5544         case CEE_BGT_UN:
5545         case CEE_BGE:
5546         case CEE_BGE_UN:
5547         case CEE_BLE:
5548         case CEE_BLE_UN:
5549                 printf ("[B%dB%d]", tree->inst_true_bb->block_num, tree->inst_false_bb->block_num);
5550                 mono_print_tree (tree->inst_left);
5551                 break;
5552         default:
5553                 if (arity) {
5554                         mono_print_tree (tree->inst_left);
5555                         if (arity > 1)
5556                                 mono_print_tree (tree->inst_right);
5557                 }
5558                 break;
5559         }
5560
5561         if (arity)
5562                 printf (")");
5563 }
5564
5565 void
5566 mono_print_tree_nl (MonoInst *tree)
5567 {
5568         mono_print_tree (tree);
5569         printf ("\n");
5570 }
5571
5572 static void
5573 create_helper_signature (void)
5574 {
5575         /* FIXME: set call conv */
5576         /* MonoArray * mono_array_new (MonoDomain *domain, MonoClass *klass, gint32 len) */
5577         helper_sig_newarr = mono_metadata_signature_alloc (mono_defaults.corlib, 3);
5578         helper_sig_newarr->params [0] = helper_sig_newarr->params [1] = &mono_defaults.int_class->byval_arg;
5579         helper_sig_newarr->ret = &mono_defaults.object_class->byval_arg;
5580         helper_sig_newarr->params [2] = &mono_defaults.int32_class->byval_arg;
5581         helper_sig_newarr->pinvoke = 1;
5582
5583         /* MonoArray * mono_array_new_specific (MonoVTable *vtable, guint32 len) */
5584         helper_sig_newarr_specific = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
5585         helper_sig_newarr_specific->params [0] = &mono_defaults.int_class->byval_arg;
5586         helper_sig_newarr_specific->params [1] = &mono_defaults.int32_class->byval_arg;
5587         helper_sig_newarr_specific->ret = &mono_defaults.object_class->byval_arg;
5588         helper_sig_newarr_specific->pinvoke = 1;
5589
5590         /* MonoObject * mono_object_new (MonoDomain *domain, MonoClass *klass) */
5591         helper_sig_object_new = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
5592         helper_sig_object_new->params [0] = helper_sig_object_new->params [1] = &mono_defaults.int_class->byval_arg;
5593         helper_sig_object_new->ret = &mono_defaults.object_class->byval_arg;
5594         helper_sig_object_new->pinvoke = 1;
5595
5596         /* MonoObject * mono_object_new_specific (MonoVTable *vtable) */
5597         helper_sig_object_new_specific = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
5598         helper_sig_object_new_specific->params [0] = &mono_defaults.int_class->byval_arg;
5599         helper_sig_object_new_specific->ret = &mono_defaults.object_class->byval_arg;
5600         helper_sig_object_new_specific->pinvoke = 1;
5601
5602         /* void* mono_method_compile (MonoMethod*) */
5603         helper_sig_compile = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
5604         helper_sig_compile->params [0] = helper_sig_compile->ret = &mono_defaults.int_class->byval_arg;
5605         helper_sig_compile->pinvoke = 1;
5606
5607         /* void* mono_ldvirtfn (MonoObject *, MonoMethod*) */
5608         helper_sig_compile_virt = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
5609         helper_sig_compile_virt->params [0] = &mono_defaults.object_class->byval_arg;
5610         helper_sig_compile_virt->params [1] = helper_sig_compile_virt->ret = &mono_defaults.int_class->byval_arg;
5611         helper_sig_compile_virt->pinvoke = 1;
5612
5613         /* MonoString* mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 str_index) */
5614         helper_sig_ldstr = mono_metadata_signature_alloc (mono_defaults.corlib, 3);
5615         helper_sig_ldstr->params [0] = helper_sig_ldstr->params [1] = &mono_defaults.int_class->byval_arg;
5616         helper_sig_ldstr->params [2] = &mono_defaults.int32_class->byval_arg;
5617         helper_sig_ldstr->ret = &mono_defaults.object_class->byval_arg;
5618         helper_sig_ldstr->pinvoke = 1;
5619
5620         /* MonoDomain *mono_domain_get (void) */
5621         helper_sig_domain_get = mono_metadata_signature_alloc (mono_defaults.corlib, 0);
5622         helper_sig_domain_get->ret = &mono_defaults.int_class->byval_arg;
5623         helper_sig_domain_get->pinvoke = 1;
5624
5625         /* void* stelem_ref (MonoArray *, int index, MonoObject *) */
5626         helper_sig_stelem_ref = mono_metadata_signature_alloc (mono_defaults.corlib, 3);
5627         helper_sig_stelem_ref->params [0] = &mono_defaults.array_class->byval_arg;
5628         helper_sig_stelem_ref->params [1] = &mono_defaults.int32_class->byval_arg;
5629         helper_sig_stelem_ref->params [2] = &mono_defaults.object_class->byval_arg;
5630         helper_sig_stelem_ref->ret = &mono_defaults.void_class->byval_arg;
5631         helper_sig_stelem_ref->pinvoke = 1;
5632
5633         /* long amethod (long, long) */
5634         helper_sig_long_long_long = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
5635         helper_sig_long_long_long->params [0] = helper_sig_long_long_long->params [1] = 
5636                 &mono_defaults.int64_class->byval_arg;
5637         helper_sig_long_long_long->ret = &mono_defaults.int64_class->byval_arg;
5638         helper_sig_long_long_long->pinvoke = 1;
5639
5640         /* object  amethod (intptr) */
5641         helper_sig_obj_ptr = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
5642         helper_sig_obj_ptr->params [0] = &mono_defaults.int_class->byval_arg;
5643         helper_sig_obj_ptr->ret = &mono_defaults.object_class->byval_arg;
5644         helper_sig_obj_ptr->pinvoke = 1;
5645
5646         /* void amethod (intptr) */
5647         helper_sig_void_ptr = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
5648         helper_sig_void_ptr->params [0] = &mono_defaults.int_class->byval_arg;
5649         helper_sig_void_ptr->ret = &mono_defaults.void_class->byval_arg;
5650         helper_sig_void_ptr->pinvoke = 1;
5651
5652         /* void amethod (MonoObject *obj) */
5653         helper_sig_void_obj = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
5654         helper_sig_void_obj->params [0] = &mono_defaults.object_class->byval_arg;
5655         helper_sig_void_obj->ret = &mono_defaults.void_class->byval_arg;
5656         helper_sig_void_obj->pinvoke = 1;
5657
5658         /* intptr amethod (void) */
5659         helper_sig_ptr_void = mono_metadata_signature_alloc (mono_defaults.corlib, 0);
5660         helper_sig_ptr_void->ret = &mono_defaults.int_class->byval_arg;
5661         helper_sig_ptr_void->pinvoke = 1;
5662
5663         /* object amethod (void) */
5664         helper_sig_obj_void = mono_metadata_signature_alloc (mono_defaults.corlib, 0);
5665         helper_sig_obj_void->ret = &mono_defaults.object_class->byval_arg;
5666         helper_sig_obj_void->pinvoke = 1;
5667
5668         /* void  amethod (intptr, intptr) */
5669         helper_sig_void_ptr_ptr = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
5670         helper_sig_void_ptr_ptr->params [0] = &mono_defaults.int_class->byval_arg;
5671         helper_sig_void_ptr_ptr->params [1] = &mono_defaults.int_class->byval_arg;
5672         helper_sig_void_ptr_ptr->ret = &mono_defaults.void_class->byval_arg;
5673         helper_sig_void_ptr_ptr->pinvoke = 1;
5674
5675         /* void  amethod (intptr, intptr, intptr) */
5676         helper_sig_void_ptr_ptr_ptr = mono_metadata_signature_alloc (mono_defaults.corlib, 3);
5677         helper_sig_void_ptr_ptr_ptr->params [0] = &mono_defaults.int_class->byval_arg;
5678         helper_sig_void_ptr_ptr_ptr->params [1] = &mono_defaults.int_class->byval_arg;
5679         helper_sig_void_ptr_ptr_ptr->params [2] = &mono_defaults.int_class->byval_arg;
5680         helper_sig_void_ptr_ptr_ptr->ret = &mono_defaults.void_class->byval_arg;
5681         helper_sig_void_ptr_ptr_ptr->pinvoke = 1;
5682
5683         /* intptr  amethod (intptr, intptr) */
5684         helper_sig_ptr_ptr_ptr = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
5685         helper_sig_ptr_ptr_ptr->params [0] = &mono_defaults.int_class->byval_arg;
5686         helper_sig_ptr_ptr_ptr->params [1] = &mono_defaults.int_class->byval_arg;
5687         helper_sig_ptr_ptr_ptr->ret = &mono_defaults.int_class->byval_arg;
5688         helper_sig_ptr_ptr_ptr->pinvoke = 1;
5689
5690         /* IntPtr  amethod (object) */
5691         helper_sig_ptr_obj = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
5692         helper_sig_ptr_obj->params [0] = &mono_defaults.object_class->byval_arg;
5693         helper_sig_ptr_obj->ret = &mono_defaults.int_class->byval_arg;
5694         helper_sig_ptr_obj->pinvoke = 1;
5695
5696         /* IntPtr  amethod (int) */
5697         helper_sig_ptr_int = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
5698         helper_sig_ptr_int->params [0] = &mono_defaults.int32_class->byval_arg;
5699         helper_sig_ptr_int->ret = &mono_defaults.int_class->byval_arg;
5700         helper_sig_ptr_int->pinvoke = 1;
5701
5702         /* long amethod (long, guint32) */
5703         helper_sig_long_long_int = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
5704         helper_sig_long_long_int->params [0] = &mono_defaults.int64_class->byval_arg;
5705         helper_sig_long_long_int->params [1] = &mono_defaults.int32_class->byval_arg;
5706         helper_sig_long_long_int->ret = &mono_defaults.int64_class->byval_arg;
5707         helper_sig_long_long_int->pinvoke = 1;
5708
5709         /* ulong amethod (double) */
5710         helper_sig_ulong_double = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
5711         helper_sig_ulong_double->params [0] = &mono_defaults.double_class->byval_arg;
5712         helper_sig_ulong_double->ret = &mono_defaults.uint64_class->byval_arg;
5713         helper_sig_ulong_double->pinvoke = 1;
5714
5715         /* long amethod (double) */
5716         helper_sig_long_double = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
5717         helper_sig_long_double->params [0] = &mono_defaults.double_class->byval_arg;
5718         helper_sig_long_double->ret = &mono_defaults.int64_class->byval_arg;
5719         helper_sig_long_double->pinvoke = 1;
5720
5721         /* double amethod (long) */
5722         helper_sig_double_long = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
5723         helper_sig_double_long->params [0] = &mono_defaults.int64_class->byval_arg;
5724         helper_sig_double_long->ret = &mono_defaults.double_class->byval_arg;
5725         helper_sig_double_long->pinvoke = 1;
5726
5727         /* float amethod (long) */
5728         helper_sig_float_long = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
5729         helper_sig_float_long->params [0] = &mono_defaults.int64_class->byval_arg;
5730         helper_sig_float_long->ret = &mono_defaults.single_class->byval_arg;
5731         helper_sig_float_long->pinvoke = 1;
5732
5733         /* double amethod (double, double) */
5734         helper_sig_double_double_double = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
5735         helper_sig_double_double_double->params [0] = &mono_defaults.double_class->byval_arg;
5736         helper_sig_double_double_double->params [1] = &mono_defaults.double_class->byval_arg;
5737         helper_sig_double_double_double->ret = &mono_defaults.double_class->byval_arg;
5738         helper_sig_double_double_double->pinvoke = 1;
5739
5740         /* uint amethod (double) */
5741         helper_sig_uint_double = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
5742         helper_sig_uint_double->params [0] = &mono_defaults.double_class->byval_arg;
5743         helper_sig_uint_double->ret = &mono_defaults.uint32_class->byval_arg;
5744         helper_sig_uint_double->pinvoke = 1;
5745
5746         /* int amethod (double) */
5747         helper_sig_int_double = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
5748         helper_sig_int_double->params [0] = &mono_defaults.double_class->byval_arg;
5749         helper_sig_int_double->ret = &mono_defaults.int32_class->byval_arg;
5750         helper_sig_int_double->pinvoke = 1;
5751
5752         /* void  initobj (intptr, int size) */
5753         helper_sig_initobj = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
5754         helper_sig_initobj->params [0] = &mono_defaults.int_class->byval_arg;
5755         helper_sig_initobj->params [1] = &mono_defaults.int32_class->byval_arg;
5756         helper_sig_initobj->ret = &mono_defaults.void_class->byval_arg;
5757         helper_sig_initobj->pinvoke = 1;
5758
5759         /* void  memcpy (intptr, intptr, int size) */
5760         helper_sig_memcpy = mono_metadata_signature_alloc (mono_defaults.corlib, 3);
5761         helper_sig_memcpy->params [0] = &mono_defaults.int_class->byval_arg;
5762         helper_sig_memcpy->params [1] = &mono_defaults.int_class->byval_arg;
5763         helper_sig_memcpy->params [2] = &mono_defaults.int32_class->byval_arg;
5764         helper_sig_memcpy->ret = &mono_defaults.void_class->byval_arg;
5765         helper_sig_memcpy->pinvoke = 1;
5766
5767         /* void  memset (intptr, int val, int size) */
5768         helper_sig_memset = mono_metadata_signature_alloc (mono_defaults.corlib, 3);
5769         helper_sig_memset->params [0] = &mono_defaults.int_class->byval_arg;
5770         helper_sig_memset->params [1] = &mono_defaults.int32_class->byval_arg;
5771         helper_sig_memset->params [2] = &mono_defaults.int32_class->byval_arg;
5772         helper_sig_memset->ret = &mono_defaults.void_class->byval_arg;
5773         helper_sig_memset->pinvoke = 1;
5774
5775         helper_sig_class_init_trampoline = mono_metadata_signature_alloc (mono_defaults.corlib, 0);
5776         helper_sig_class_init_trampoline->ret = &mono_defaults.void_class->byval_arg;
5777         helper_sig_class_init_trampoline->pinvoke = 1;  
5778 }
5779
5780 static GHashTable *jit_icall_hash_name = NULL;
5781 static GHashTable *jit_icall_hash_addr = NULL;
5782
5783 MonoJitICallInfo *
5784 mono_find_jit_icall_by_name (const char *name)
5785 {
5786         g_assert (jit_icall_hash_name);
5787
5788         //printf ("lookup addr %s %p\n", name, g_hash_table_lookup (jit_icall_hash_name, name));
5789         return g_hash_table_lookup (jit_icall_hash_name, name);
5790 }
5791
5792 MonoJitICallInfo *
5793 mono_find_jit_icall_by_addr (gconstpointer addr)
5794 {
5795         g_assert (jit_icall_hash_addr);
5796
5797         return g_hash_table_lookup (jit_icall_hash_addr, (gpointer)addr);
5798 }
5799
5800 gconstpointer
5801 mono_icall_get_wrapper (MonoJitICallInfo* callinfo)
5802 {
5803         char *name;
5804         MonoMethod *wrapper;
5805         
5806         if (callinfo->wrapper)
5807                 return callinfo->wrapper;
5808         name = g_strdup_printf ("__icall_wrapper_%s", callinfo->name);
5809         wrapper = mono_marshal_get_icall_wrapper (callinfo->sig, name, callinfo->func);
5810         callinfo->wrapper = mono_jit_compile_method (wrapper);
5811         g_free (name);
5812         return callinfo->wrapper;
5813 }
5814
5815 MonoJitICallInfo *
5816 mono_register_jit_icall (gconstpointer func, const char *name, MonoMethodSignature *sig, gboolean is_save)
5817 {
5818         MonoJitICallInfo *info;
5819         
5820         g_assert (func);
5821         g_assert (name);
5822
5823         if (!jit_icall_hash_name) {
5824                 jit_icall_hash_name = g_hash_table_new (g_str_hash, g_str_equal);
5825                 jit_icall_hash_addr = g_hash_table_new (NULL, NULL);
5826         }
5827
5828         if (g_hash_table_lookup (jit_icall_hash_name, name)) {
5829                 g_warning ("jit icall already defined \"%s\"\n", name);
5830                 g_assert_not_reached ();
5831         }
5832
5833         info = g_new (MonoJitICallInfo, 1);
5834         
5835         info->name = name;
5836         info->func = func;
5837         info->sig = sig;
5838
5839         if (is_save
5840 #ifdef MONO_USE_EXC_TABLES
5841             || mono_arch_has_unwind_info (func)
5842 #endif
5843             ) {
5844                 info->wrapper = func;
5845         } else {
5846                 info->wrapper = NULL;
5847                 mono_icall_get_wrapper (info);
5848         }
5849
5850         g_hash_table_insert (jit_icall_hash_name, (gpointer)info->name, info);
5851         g_hash_table_insert (jit_icall_hash_addr, (gpointer)func, info);
5852         if (func != info->wrapper)
5853                 g_hash_table_insert (jit_icall_hash_addr, (gpointer)info->wrapper, info);
5854
5855         return info;
5856 }
5857
5858 gpointer
5859 mono_create_class_init_trampoline (MonoVTable *vtable)
5860 {
5861         gpointer code;
5862
5863         /* previously created trampoline code */
5864         mono_domain_lock (vtable->domain);
5865         code = 
5866                 mono_g_hash_table_lookup (vtable->domain->class_init_trampoline_hash,
5867                                                                   vtable);
5868         mono_domain_unlock (vtable->domain);
5869         if (code)
5870                 return code;
5871
5872         code = mono_arch_create_class_init_trampoline (vtable);
5873
5874         /* store trampoline address */
5875         mono_domain_lock (vtable->domain);
5876         mono_g_hash_table_insert (vtable->domain->class_init_trampoline_hash,
5877                                                           vtable, code);
5878         mono_domain_unlock (vtable->domain);
5879
5880         EnterCriticalSection (&class_init_hash_mutex);
5881         if (!class_init_hash_addr)
5882                 class_init_hash_addr = g_hash_table_new (NULL, NULL);
5883         g_hash_table_insert (class_init_hash_addr, code, vtable);
5884         LeaveCriticalSection (&class_init_hash_mutex);
5885
5886         return code;
5887 }
5888
5889 MonoVTable*
5890 mono_find_class_init_trampoline_by_addr (gconstpointer addr)
5891 {
5892         MonoVTable *res;
5893
5894         EnterCriticalSection (&class_init_hash_mutex);
5895         if (class_init_hash_addr)
5896                 res = g_hash_table_lookup (class_init_hash_addr, addr);
5897         else
5898                 res = NULL;
5899         LeaveCriticalSection (&class_init_hash_mutex);
5900         return res;
5901 }
5902
5903 static GHashTable *emul_opcode_hash = NULL;
5904
5905 static MonoJitICallInfo *
5906 mono_find_jit_opcode_emulation (int opcode)
5907 {
5908         if  (emul_opcode_hash)
5909                 return g_hash_table_lookup (emul_opcode_hash, (gpointer)opcode);
5910         else
5911                 return NULL;
5912 }
5913
5914 void
5915 mono_register_opcode_emulation (int opcode, const char *name, MonoMethodSignature *sig, gpointer func, gboolean no_throw)
5916 {
5917         MonoJitICallInfo *info;
5918
5919         if (!emul_opcode_hash)
5920                 emul_opcode_hash = g_hash_table_new (NULL, NULL);
5921
5922         g_assert (!sig->hasthis);
5923         g_assert (sig->param_count < 3);
5924
5925         info = mono_register_jit_icall (func, name, sig, no_throw);
5926
5927         g_hash_table_insert (emul_opcode_hash, (gpointer)opcode, info);
5928 }
5929
5930 static void
5931 decompose_foreach (MonoInst *tree, gpointer data) 
5932 {
5933         static MonoJitICallInfo *newarr_info = NULL;
5934         static MonoJitICallInfo *newarr_specific_info = NULL;
5935         MonoJitICallInfo *info;
5936         int i;
5937
5938         switch (tree->opcode) {
5939         case CEE_NEWARR: {
5940                 MonoCompile *cfg = data;
5941                 MonoInst *iargs [3];
5942
5943                 if (!newarr_info) {
5944                         newarr_info = mono_find_jit_icall_by_addr (mono_array_new);
5945                         g_assert (newarr_info);
5946                         newarr_specific_info = mono_find_jit_icall_by_addr (mono_array_new_specific);
5947                         g_assert (newarr_specific_info);
5948                 }
5949
5950                 if (cfg->opt & MONO_OPT_SHARED) {
5951                         NEW_DOMAINCONST (cfg, iargs [0]);
5952                         NEW_CLASSCONST (cfg, iargs [1], tree->inst_newa_class);
5953                         iargs [2] = tree->inst_newa_len;
5954
5955                         info = newarr_info;
5956                 }
5957                 else {
5958                         MonoVTable *vtable = mono_class_vtable (cfg->domain, mono_array_class_get (tree->inst_newa_class, 1));
5959
5960                         NEW_VTABLECONST (cfg, iargs [0], vtable);
5961                         iargs [1] = tree->inst_newa_len;
5962
5963                         info = newarr_specific_info;
5964                 }
5965
5966                 mono_emulate_opcode (cfg, tree, iargs, info);
5967
5968                 /* Need to decompose arguments after the the opcode is decomposed */
5969                 for (i = 0; i < info->sig->param_count; ++i)
5970                         dec_foreach (iargs [i], cfg);
5971                 break;
5972         }
5973
5974         default:
5975                 break;
5976         }
5977 }
5978
5979 void
5980 mono_inst_foreach (MonoInst *tree, MonoInstFunc func, gpointer data) {
5981
5982         switch (mono_burg_arity [tree->opcode]) {
5983         case 0: break;
5984         case 1: 
5985                 mono_inst_foreach (tree->inst_left, func, data);
5986                 break;
5987         case 2: 
5988                 mono_inst_foreach (tree->inst_left, func, data);
5989                 mono_inst_foreach (tree->inst_right, func, data);
5990                 break;
5991         default:
5992                 g_assert_not_reached ();
5993         }
5994         func (tree, data);
5995 }
5996
5997 G_GNUC_UNUSED
5998 static void
5999 mono_print_bb_code (MonoBasicBlock *bb) {
6000         if (bb->code) {
6001                 MonoInst *c = bb->code;
6002                 while (c) {
6003                         mono_print_tree (c);
6004                         g_print ("\n");
6005                         c = c->next;
6006                 }
6007         }
6008 }
6009
6010 static void
6011 print_dfn (MonoCompile *cfg) {
6012         int i, j;
6013         char *code;
6014         MonoBasicBlock *bb;
6015
6016         g_print ("IR code for method %s\n", mono_method_full_name (cfg->method, TRUE));
6017
6018         for (i = 0; i < cfg->num_bblocks; ++i) {
6019                 bb = cfg->bblocks [i];
6020                 if (bb->cil_code) {
6021                         char* code1, *code2;
6022                         code1 = mono_disasm_code_one (NULL, cfg->method, bb->cil_code, NULL);
6023                         if (bb->last_ins->cil_code)
6024                                 code2 = mono_disasm_code_one (NULL, cfg->method, bb->last_ins->cil_code, NULL);
6025                         else
6026                                 code2 = g_strdup ("");
6027
6028                         code1 [strlen (code1) - 1] = 0;
6029                         code = g_strdup_printf ("%s -> %s", code1, code2);
6030                         g_free (code1);
6031                         g_free (code2);
6032                 } else
6033                         code = g_strdup ("\n");
6034                 g_print ("\nBB%d DFN%d (len: %d): %s", bb->block_num, i, bb->cil_length, code);
6035                 if (bb->code) {
6036                         MonoInst *c = bb->code;
6037                         while (c) {
6038                                 mono_print_tree (c);
6039                                 g_print ("\n");
6040                                 c = c->next;
6041                         }
6042                 } else {
6043
6044                 }
6045
6046                 g_print ("\tprev:");
6047                 for (j = 0; j < bb->in_count; ++j) {
6048                         g_print (" BB%d", bb->in_bb [j]->block_num);
6049                 }
6050                 g_print ("\t\tsucc:");
6051                 for (j = 0; j < bb->out_count; ++j) {
6052                         g_print (" BB%d", bb->out_bb [j]->block_num);
6053                 }
6054                 g_print ("\n\tidom: BB%d\n", bb->idom? bb->idom->block_num: -1);
6055
6056                 if (bb->idom)
6057                         g_assert (mono_bitset_test_fast (bb->dominators, bb->idom->dfn));
6058
6059                 if (bb->dominators)
6060                         mono_blockset_print (cfg, bb->dominators, "\tdominators", bb->idom? bb->idom->dfn: -1);
6061                 if (bb->dfrontier)
6062                         mono_blockset_print (cfg, bb->dfrontier, "\tdfrontier", -1);
6063                 g_free (code);
6064         }
6065
6066         g_print ("\n");
6067 }
6068
6069 void
6070 mono_bblock_add_inst (MonoBasicBlock *bb, MonoInst *inst)
6071 {
6072         inst->next = NULL;
6073         if (bb->last_ins) {
6074                 g_assert (bb->code);
6075                 bb->last_ins->next = inst;
6076                 bb->last_ins = inst;
6077         } else {
6078                 bb->last_ins = bb->code = inst;
6079         }
6080 }
6081
6082 void
6083 mono_destroy_compile (MonoCompile *cfg)
6084 {
6085         //mono_mempool_stats (cfg->mempool);
6086         g_hash_table_destroy (cfg->bb_hash);
6087         if (cfg->rs)
6088                 mono_regstate_free (cfg->rs);
6089         if (cfg->spvars)
6090                 g_hash_table_destroy (cfg->spvars);
6091         mono_mempool_destroy (cfg->mempool);
6092         g_list_free (cfg->ldstr_list);
6093
6094         g_free (cfg->varinfo);
6095         g_free (cfg->vars);
6096         g_free (cfg);
6097 }
6098
6099 MonoLMF **
6100 mono_get_lmf_addr (void)
6101 {
6102         MonoJitTlsData *jit_tls;
6103
6104         if ((jit_tls = TlsGetValue (mono_jit_tls_id)))
6105                 return &jit_tls->lmf;
6106
6107         g_assert_not_reached ();
6108         return NULL;
6109 }
6110
6111 /**
6112  * mono_thread_abort:
6113  * @obj: exception object
6114  *
6115  * abort the thread, print exception information and stack trace
6116  */
6117 static void
6118 mono_thread_abort (MonoObject *obj)
6119 {
6120         /* MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id); */
6121         
6122         /* handle_remove should be eventually called for this thread, too
6123         g_free (jit_tls);*/
6124
6125         ExitThread (-1);
6126 }
6127
6128 static void*
6129 setup_jit_tls_data (gpointer stack_start, gpointer abort_func)
6130 {
6131         MonoJitTlsData *jit_tls;
6132         MonoLMF *lmf;
6133
6134         jit_tls = g_new0 (MonoJitTlsData, 1);
6135
6136         TlsSetValue (mono_jit_tls_id, jit_tls);
6137
6138         jit_tls->abort_func = abort_func;
6139         jit_tls->end_of_stack = stack_start;
6140
6141         lmf = g_new0 (MonoLMF, 1);
6142         lmf->ebp = -1;
6143
6144         jit_tls->lmf = jit_tls->first_lmf = lmf;
6145
6146         mono_arch_setup_jit_tls_data (jit_tls);
6147
6148         return jit_tls;
6149 }
6150
6151 static void
6152 mono_thread_start_cb (guint32 tid, gpointer stack_start, gpointer func)
6153 {
6154         MonoThread *thread;
6155         void *jit_tls = setup_jit_tls_data (stack_start, mono_thread_abort);
6156         thread = mono_thread_current ();
6157         if (thread)
6158                 thread->jit_data = jit_tls;
6159 }
6160
6161 void (*mono_thread_attach_aborted_cb ) (MonoObject *obj) = NULL;
6162
6163 static void
6164 mono_thread_abort_dummy (MonoObject *obj)
6165 {
6166   if (mono_thread_attach_aborted_cb)
6167     mono_thread_attach_aborted_cb (obj);
6168   else
6169     mono_thread_abort (obj);
6170 }
6171
6172 static void
6173 mono_thread_attach_cb (guint32 tid, gpointer stack_start)
6174 {
6175         MonoThread *thread;
6176         void *jit_tls = setup_jit_tls_data (stack_start, mono_thread_abort_dummy);
6177         thread = mono_thread_current ();
6178         if (thread)
6179                 thread->jit_data = jit_tls;
6180 }
6181
6182 static void
6183 mini_thread_cleanup (MonoThread *thread)
6184 {
6185         MonoJitTlsData *jit_tls = thread->jit_data;
6186
6187         if (jit_tls) {
6188                 g_free (jit_tls->first_lmf);
6189                 g_free (jit_tls);
6190                 thread->jit_data = NULL;
6191         }
6192 }
6193
6194 void
6195 mono_add_patch_info (MonoCompile *cfg, int ip, MonoJumpInfoType type, gconstpointer target)
6196 {
6197         MonoJumpInfo *ji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo));
6198
6199         ji->ip.i = ip;
6200         ji->type = type;
6201         ji->data.target = target;
6202         ji->next = cfg->patch_info;
6203
6204         cfg->patch_info = ji;
6205 }
6206
6207 void
6208 mono_remove_patch_info (MonoCompile *cfg, int ip)
6209 {
6210         MonoJumpInfo **ji = &cfg->patch_info;
6211
6212         while (*ji) {
6213                 if ((*ji)->ip.i == ip)
6214                         *ji = (*ji)->next;
6215                 else
6216                         ji = &((*ji)->next);
6217         }
6218 }
6219
6220 static void
6221 dec_foreach (MonoInst *tree, MonoCompile *cfg) {
6222         MonoJitICallInfo *info;
6223
6224         decompose_foreach (tree, cfg);
6225
6226         switch (mono_burg_arity [tree->opcode]) {
6227         case 0: break;
6228         case 1: 
6229                 dec_foreach (tree->inst_left, cfg);
6230
6231                 if ((info = mono_find_jit_opcode_emulation (tree->opcode))) {
6232                         MonoInst *iargs [2];
6233                 
6234                         iargs [0] = tree->inst_left;
6235
6236                         mono_emulate_opcode (cfg, tree, iargs, info);
6237                         return;
6238                 }
6239
6240                 break;
6241         case 2:
6242 #ifdef MONO_ARCH_BIGMUL_INTRINS
6243                 if (tree->opcode == OP_LMUL
6244                                 && (cfg->opt & MONO_OPT_INTRINS)
6245                                 && (tree->inst_left->opcode == CEE_CONV_I8 
6246                                         || tree->inst_left->opcode == CEE_CONV_U8)
6247                                 && tree->inst_left->inst_left->type == STACK_I4
6248                                 && (tree->inst_right->opcode == CEE_CONV_I8 
6249                                         || tree->inst_right->opcode == CEE_CONV_U8)
6250                                 && tree->inst_right->inst_left->type == STACK_I4) {
6251                         tree->opcode = (tree->inst_left->opcode == CEE_CONV_I8 ? OP_BIGMUL: OP_BIGMUL_UN);
6252                         tree->inst_left = tree->inst_left->inst_left;
6253                         tree->inst_right = tree->inst_right->inst_left;
6254                         dec_foreach (tree, cfg);
6255                 } else 
6256 #endif
6257                         if ((info = mono_find_jit_opcode_emulation (tree->opcode))) {
6258                         MonoInst *iargs [2];
6259                 
6260                         iargs [0] = tree->inst_i0;
6261                         iargs [1] = tree->inst_i1;
6262                 
6263                         mono_emulate_opcode (cfg, tree, iargs, info);
6264
6265                         dec_foreach (iargs [0], cfg);
6266                         dec_foreach (iargs [1], cfg);
6267                         return;
6268                 } else {
6269                         dec_foreach (tree->inst_left, cfg);
6270                         dec_foreach (tree->inst_right, cfg);
6271                 }
6272                 break;
6273         default:
6274                 g_assert_not_reached ();
6275         }
6276 }
6277
6278 static void
6279 decompose_pass (MonoCompile *cfg) {
6280         MonoBasicBlock *bb;
6281
6282         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
6283                 MonoInst *tree;
6284                 cfg->cbb = bb;
6285                 cfg->prev_ins = NULL;
6286                 for (tree = cfg->cbb->code; tree; tree = tree->next) {
6287                         dec_foreach (tree, cfg);
6288                         cfg->prev_ins = tree;
6289                 }
6290         }
6291 }
6292
6293 static void
6294 nullify_basic_block (MonoBasicBlock *bb) 
6295 {
6296         bb->in_count = 0;
6297         bb->out_count = 0;
6298         bb->in_bb = NULL;
6299         bb->out_bb = NULL;
6300         bb->next_bb = NULL;
6301         bb->code = bb->last_ins = NULL;
6302         bb->cil_code = NULL;
6303 }
6304
6305 static void 
6306 replace_out_block (MonoBasicBlock *bb, MonoBasicBlock *orig,  MonoBasicBlock *repl)
6307 {
6308         int i;
6309
6310         for (i = 0; i < bb->out_count; i++) {
6311                 MonoBasicBlock *ob = bb->out_bb [i];
6312                 if (ob == orig) {
6313                         if (!repl) {
6314                                 if (bb->out_count > 1) {
6315                                         bb->out_bb [i] = bb->out_bb [bb->out_count - 1];
6316                                 }
6317                                 bb->out_count--;
6318                         } else {
6319                                 bb->out_bb [i] = repl;
6320                         }
6321                 }
6322         }
6323 }
6324
6325 static void 
6326 replace_in_block (MonoBasicBlock *bb, MonoBasicBlock *orig, MonoBasicBlock *repl)
6327 {
6328         int i;
6329
6330         for (i = 0; i < bb->in_count; i++) {
6331                 MonoBasicBlock *ib = bb->in_bb [i];
6332                 if (ib == orig) {
6333                         if (!repl) {
6334                                 if (bb->in_count > 1) {
6335                                         bb->in_bb [i] = bb->in_bb [bb->in_count - 1];
6336                                 }
6337                                 bb->in_count--;
6338                         } else {
6339                                 bb->in_bb [i] = repl;
6340                         }
6341                 }
6342         }
6343 }
6344
6345 static void 
6346 replace_basic_block (MonoBasicBlock *bb, MonoBasicBlock *orig,  MonoBasicBlock *repl)
6347 {
6348         int i, j;
6349
6350         for (i = 0; i < bb->out_count; i++) {
6351                 MonoBasicBlock *ob = bb->out_bb [i];
6352                 for (j = 0; j < ob->in_count; j++) {
6353                         if (ob->in_bb [j] == orig) {
6354                                 ob->in_bb [j] = repl;
6355                         }
6356                 }
6357         }
6358
6359 }
6360
6361
6362 static void
6363 merge_basic_blocks (MonoBasicBlock *bb, MonoBasicBlock *bbn) 
6364 {
6365         bb->out_count = bbn->out_count;
6366         bb->out_bb = bbn->out_bb;
6367
6368         replace_basic_block (bb, bbn, bb);
6369
6370         if (bb->last_ins) {
6371                 if (bbn->code) {
6372                         bb->last_ins->next = bbn->code;
6373                         bb->last_ins = bbn->last_ins;
6374                 }
6375         } else {
6376                 bb->code = bbn->code;
6377                 bb->last_ins = bbn->last_ins;
6378         }
6379         bb->next_bb = bbn->next_bb;
6380         nullify_basic_block (bbn);
6381 }
6382
6383 static void
6384 optimize_branches (MonoCompile *cfg) {
6385         int i, changed = FALSE;
6386         MonoBasicBlock *bb, *bbn;
6387
6388         do {
6389                 changed = FALSE;
6390
6391                 /* we skip the entry block (exit is handled specially instead ) */
6392                 for (bb = cfg->bb_entry->next_bb; bb; bb = bb->next_bb) {
6393
6394                         /* dont touch code inside exception clauses */
6395                         if (bb->region != -1)
6396                                 continue;
6397
6398                         if ((bbn = bb->next_bb) && bbn->in_count == 0 && bb->region == bbn->region) {
6399                                 if (cfg->verbose_level > 2)
6400                                         g_print ("nullify block triggered %d\n", bbn->block_num);
6401
6402                                 bb->next_bb = bbn->next_bb;
6403
6404                                 for (i = 0; i < bbn->out_count; i++)
6405                                         replace_in_block (bbn->out_bb [i], bbn, NULL);
6406
6407                                 nullify_basic_block (bbn);                      
6408                                 changed = TRUE;
6409                         }
6410
6411                         if (bb->out_count == 1) {
6412                                 bbn = bb->out_bb [0];
6413
6414                                 /* conditional branches where true and false targets are the same can be also replaced with CEE_BR */
6415                                 if (bb->last_ins && MONO_IS_COND_BRANCH (bb->last_ins->opcode)) {
6416                                         bb->last_ins->opcode = CEE_BR;
6417                                         bb->last_ins->inst_target_bb = bb->last_ins->inst_true_bb;
6418                                         changed = TRUE;
6419                                         if (cfg->verbose_level > 2)
6420                                                 g_print ("cond branch removal triggered in %d %d\n", bb->block_num, bb->out_count);
6421                                 }
6422
6423                                 if (bb->region == bbn->region && bb->next_bb == bbn) {
6424                                         /* the block are in sequence anyway ... */
6425
6426                                         /* branches to the following block can be removed */
6427                                         if (bb->last_ins && bb->last_ins->opcode == CEE_BR) {
6428                                                 bb->last_ins->opcode = CEE_NOP;
6429                                                 changed = TRUE;
6430                                                 if (cfg->verbose_level > 2)
6431                                                         g_print ("br removal triggered %d -> %d\n", bb->block_num, bbn->block_num);
6432                                         }
6433
6434                                         if (bbn->in_count == 1) {
6435
6436                                                 if (bbn != cfg->bb_exit) {
6437                                                         if (cfg->verbose_level > 2)
6438                                                                 g_print ("block merge triggered %d -> %d\n", bb->block_num, bbn->block_num);
6439                                                         merge_basic_blocks (bb, bbn);
6440                                                         changed = TRUE;
6441                                                 }
6442
6443                                                 //mono_print_bb_code (bb);
6444                                         }
6445                                 }                               
6446                         }
6447                 }
6448         } while (changed);
6449
6450         do {
6451                 changed = FALSE;
6452
6453                 /* we skip the entry block (exit is handled specially instead ) */
6454                 for (bb = cfg->bb_entry->next_bb; bb; bb = bb->next_bb) {
6455
6456                         /* dont touch code inside exception clauses */
6457                         if (bb->region != -1)
6458                                 continue;
6459
6460                         if ((bbn = bb->next_bb) && bbn->in_count == 0 && bb->region == bbn->region) {
6461                                 if (cfg->verbose_level > 2) {
6462                                         g_print ("nullify block triggered %d\n", bbn->block_num);
6463                                 }
6464                                 bb->next_bb = bbn->next_bb;
6465
6466                                 for (i = 0; i < bbn->out_count; i++)
6467                                         replace_in_block (bbn->out_bb [i], bbn, NULL);
6468
6469                                 nullify_basic_block (bbn);                      
6470                                 changed = TRUE;
6471                                 break;
6472                         }
6473
6474
6475                         if (bb->out_count == 1) {
6476                                 bbn = bb->out_bb [0];
6477
6478                                 if (bb->last_ins && bb->last_ins->opcode == CEE_BR) {
6479                                         bbn = bb->last_ins->inst_target_bb;
6480                                         if (bb->region == bbn->region && bbn->code && bbn->code->opcode == CEE_BR &&
6481                                             bbn->code->inst_target_bb->region == bb->region) {
6482                                                 
6483                                                 if (cfg->verbose_level > 2)
6484                                                         g_print ("in %s branch to branch triggered %d -> %d\n", cfg->method->name, 
6485                                                                  bb->block_num, bbn->block_num);
6486                                                 
6487                                                 replace_basic_block (bb, bb->out_bb [0], bbn->code->inst_target_bb);
6488                                                 bb->last_ins->inst_target_bb = bbn->code->inst_target_bb;
6489                                                 changed = TRUE;
6490                                                 break;
6491                                         }
6492                                 }
6493                         } else if (bb->out_count == 2) {
6494                                 if (bb->last_ins && MONO_IS_COND_BRANCH (bb->last_ins->opcode)) {
6495                                         bbn = bb->last_ins->inst_true_bb;
6496                                         if (bb->region == bbn->region && bbn->code && bbn->code->opcode == CEE_BR &&
6497                                             bbn->code->inst_target_bb->region == bb->region) {
6498                                                 if (cfg->verbose_level > 2)             
6499                                                         g_print ("cbranch1 to branch triggered %d -> (%d) %d (0x%02x)\n", 
6500                                                                  bb->block_num, bbn->block_num, bbn->code->inst_target_bb->block_num, 
6501                                                                  bbn->code->opcode);
6502
6503                                                 bb->last_ins->inst_true_bb = bbn->code->inst_target_bb;
6504
6505                                                 replace_in_block (bbn, bb, NULL);
6506                                                 if (!bbn->in_count)
6507                                                         replace_in_block (bbn->code->inst_target_bb, bbn, bb);
6508                                                 replace_out_block (bb, bbn, bbn->code->inst_target_bb);
6509
6510                                                 link_bblock (cfg, bb, bbn->code->inst_target_bb);
6511
6512                                                 changed = TRUE;
6513                                                 break;
6514                                         }
6515
6516                                         bbn = bb->last_ins->inst_false_bb;
6517                                         if (bb->region == bbn->region && bbn->code && bbn->code->opcode == CEE_BR &&
6518                                             bbn->code->inst_target_bb->region == bb->region) {
6519                                                 if (cfg->verbose_level > 2)
6520                                                         g_print ("cbranch2 to branch triggered %d -> (%d) %d (0x%02x)\n", 
6521                                                                  bb->block_num, bbn->block_num, bbn->code->inst_target_bb->block_num, 
6522                                                                  bbn->code->opcode);
6523
6524                                                 bb->last_ins->inst_false_bb = bbn->code->inst_target_bb;
6525
6526                                                 replace_in_block (bbn, bb, NULL);
6527                                                 if (!bbn->in_count)
6528                                                         replace_in_block (bbn->code->inst_target_bb, bbn, bb);
6529                                                 replace_out_block (bb, bbn, bbn->code->inst_target_bb);
6530
6531                                                 link_bblock (cfg, bb, bbn->code->inst_target_bb);
6532
6533                                                 changed = TRUE;
6534                                                 break;
6535                                         }
6536                                 }
6537                         }
6538                 }
6539         } while (changed);
6540
6541 }
6542
6543 static void
6544 mono_compile_create_vars (MonoCompile *cfg)
6545 {
6546         MonoMethodSignature *sig;
6547         MonoMethodHeader *header;
6548         int i;
6549
6550         header = ((MonoMethodNormal *)cfg->method)->header;
6551
6552         sig = cfg->method->signature;
6553         
6554         if (!MONO_TYPE_IS_VOID (sig->ret)) {
6555                 cfg->ret = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst));
6556                 cfg->ret->opcode = OP_RETARG;
6557                 cfg->ret->inst_vtype = sig->ret;
6558                 cfg->ret->klass = mono_class_from_mono_type (sig->ret);
6559         }
6560         if (cfg->verbose_level > 2)
6561                 g_print ("creating vars\n");
6562
6563         if (sig->hasthis)
6564                 mono_compile_create_var (cfg, &cfg->method->klass->this_arg, OP_ARG);
6565
6566         for (i = 0; i < sig->param_count; ++i)
6567                 mono_compile_create_var (cfg, sig->params [i], OP_ARG);
6568
6569         cfg->locals_start = cfg->num_varinfo;
6570
6571         if (cfg->verbose_level > 2)
6572                 g_print ("creating locals\n");
6573         for (i = 0; i < header->num_locals; ++i)
6574                 mono_compile_create_var (cfg, header->locals [i], OP_LOCAL);
6575         if (cfg->verbose_level > 2)
6576                 g_print ("locals done\n");
6577 }
6578
6579 void
6580 mono_print_code (MonoCompile *cfg)
6581 {
6582         MonoBasicBlock *bb;
6583         
6584         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
6585                 MonoInst *tree = bb->code;      
6586
6587                 if (!tree)
6588                         continue;
6589                 
6590                 g_print ("CODE BLOCK %d (nesting %d):\n", bb->block_num, bb->nesting);
6591
6592                 for (; tree; tree = tree->next) {
6593                         mono_print_tree (tree);
6594                         g_print ("\n");
6595                 }
6596
6597                 if (bb->last_ins)
6598                         bb->last_ins->next = NULL;
6599         }
6600 }
6601
6602 extern const char * const mono_burg_rule_string [];
6603
6604 static void
6605 emit_state (MonoCompile *cfg, MBState *state, int goal)
6606 {
6607         MBState *kids [10];
6608         int ern = mono_burg_rule (state, goal);
6609         const guint16 *nts = mono_burg_nts [ern];
6610         MBEmitFunc emit;
6611
6612         //g_print ("rule: %s\n", mono_burg_rule_string [ern]);
6613         switch (goal) {
6614         case MB_NTERM_reg:
6615                 //if (state->reg2)
6616                 //      state->reg1 = state->reg2; /* chain rule */
6617                 //else
6618                 state->reg1 = mono_regstate_next_int (cfg->rs);
6619                 //g_print ("alloc symbolic R%d (reg2: R%d) in block %d\n", state->reg1, state->reg2, cfg->cbb->block_num);
6620                 break;
6621         case MB_NTERM_lreg:
6622                 state->reg1 = mono_regstate_next_int (cfg->rs);
6623                 state->reg2 = mono_regstate_next_int (cfg->rs);
6624                 break;
6625         case MB_NTERM_freg:
6626                 state->reg1 = mono_regstate_next_float (cfg->rs);
6627                 break;
6628         default:
6629                 /* do nothing */
6630                 break;
6631         }
6632         if (nts [0]) {
6633                 mono_burg_kids (state, ern, kids);
6634
6635                 emit_state (cfg, kids [0], nts [0]);
6636                 if (nts [1]) {
6637                         emit_state (cfg, kids [1], nts [1]);
6638                         if (nts [2]) {
6639                                 g_assert (!nts [3]);
6640                                 emit_state (cfg, kids [2], nts [2]);
6641                         }
6642                 }
6643         }
6644
6645 //      g_print ("emit: %s (%p)\n", mono_burg_rule_string [ern], state);
6646         if ((emit = mono_burg_func [ern]))
6647                 emit (state, state->tree, cfg); 
6648 }
6649
6650 #define DEBUG_SELECTION
6651
6652 static void 
6653 mini_select_instructions (MonoCompile *cfg)
6654 {
6655         static int reverse_map [] = {
6656                 CEE_BNE_UN, CEE_BLT, CEE_BLE, CEE_BGT, CEE_BGE,
6657                 CEE_BEQ, CEE_BLT_UN, CEE_BLE_UN, CEE_BGT_UN, CEE_BGE_UN
6658         };
6659         static int reverse_fmap [] = {
6660                 OP_FBNE_UN, OP_FBLT, OP_FBLE, OP_FBGT, OP_FBGE,
6661                 OP_FBEQ, OP_FBLT_UN, OP_FBLE_UN, OP_FBGT_UN, OP_FBGE_UN
6662         };
6663         static int reverse_lmap [] = {
6664                 OP_LBNE_UN, OP_LBLT, OP_LBLE, OP_LBGT, OP_LBGE,
6665                 OP_LBEQ, OP_LBLT_UN, OP_LBLE_UN, OP_LBGT_UN, OP_LBGE_UN
6666         };
6667
6668         MonoBasicBlock *bb;
6669         
6670         cfg->state_pool = mono_mempool_new ();
6671         cfg->rs = mono_regstate_new ();
6672
6673         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
6674                 if (bb->last_ins && MONO_IS_COND_BRANCH (bb->last_ins->opcode) &&
6675                     bb->next_bb != bb->last_ins->inst_false_bb) {
6676
6677                         if (bb->next_bb ==  bb->last_ins->inst_true_bb) {
6678                                 MonoBasicBlock *tmp =  bb->last_ins->inst_true_bb;
6679                                 bb->last_ins->inst_true_bb = bb->last_ins->inst_false_bb;
6680                                 bb->last_ins->inst_false_bb = tmp;
6681                                 
6682                                 if (bb->last_ins->opcode >= CEE_BEQ && bb->last_ins->opcode <= CEE_BLT_UN) {
6683                                         bb->last_ins->opcode = reverse_map [bb->last_ins->opcode - CEE_BEQ];
6684                                 } else if (bb->last_ins->opcode >= OP_FBEQ && bb->last_ins->opcode <= OP_FBLT_UN) {
6685                                         bb->last_ins->opcode = reverse_fmap [bb->last_ins->opcode - OP_FBEQ];
6686                                 } else if (bb->last_ins->opcode >= OP_LBEQ && bb->last_ins->opcode <= OP_LBLT_UN) {
6687                                         bb->last_ins->opcode = reverse_lmap [bb->last_ins->opcode - OP_LBEQ];
6688                                 }
6689                         } else {                        
6690                                 MonoInst *inst = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst));
6691                                 inst->opcode = CEE_BR;
6692                                 inst->inst_target_bb = bb->last_ins->inst_false_bb;
6693                                 mono_bblock_add_inst (bb, inst);
6694                         }
6695                 }
6696         }
6697
6698 #ifdef DEBUG_SELECTION
6699         if (cfg->verbose_level >= 4) {
6700         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
6701                 MonoInst *tree = bb->code;      
6702                 g_print ("DUMP BLOCK %d:\n", bb->block_num);
6703                 if (!tree)
6704                         continue;
6705                 for (; tree; tree = tree->next) {
6706                         mono_print_tree (tree);
6707                         g_print ("\n");
6708                 }
6709         }
6710         }
6711 #endif
6712
6713         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
6714                 MonoInst *tree = bb->code, *next;       
6715                 MBState *mbstate;
6716
6717                 if (!tree)
6718                         continue;
6719                 bb->code = NULL;
6720                 bb->last_ins = NULL;
6721                 
6722                 cfg->cbb = bb;
6723                 mono_regstate_reset (cfg->rs);
6724
6725 #ifdef DEBUG_SELECTION
6726                 if (cfg->verbose_level >= 3)
6727                         g_print ("LABEL BLOCK %d:\n", bb->block_num);
6728 #endif
6729                 for (; tree; tree = next) {
6730                         next = tree->next;
6731 #ifdef DEBUG_SELECTION
6732                         if (cfg->verbose_level >= 3) {
6733                                 mono_print_tree (tree);
6734                                 g_print ("\n");
6735                         }
6736 #endif
6737
6738                         if (!(mbstate = mono_burg_label (tree, cfg))) {
6739                                 g_warning ("unable to label tree %p", tree);
6740                                 mono_print_tree (tree);
6741                                 g_print ("\n");                         
6742                                 g_assert_not_reached ();
6743                         }
6744                         emit_state (cfg, mbstate, MB_NTERM_stmt);
6745                 }
6746                 bb->max_ireg = cfg->rs->next_vireg;
6747                 bb->max_freg = cfg->rs->next_vfreg;
6748
6749                 if (bb->last_ins)
6750                         bb->last_ins->next = NULL;
6751
6752                 mono_mempool_empty (cfg->state_pool); 
6753         }
6754         mono_mempool_destroy (cfg->state_pool); 
6755 }
6756
6757 void
6758 mono_codegen (MonoCompile *cfg)
6759 {
6760         MonoJumpInfo *patch_info;
6761         MonoBasicBlock *bb;
6762         int i, max_epilog_size;
6763         guint8 *code;
6764
6765         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
6766                 cfg->spill_count = 0;
6767                 /* we reuse dfn here */
6768                 /* bb->dfn = bb_count++; */
6769                 mono_arch_local_regalloc (cfg, bb);
6770         }
6771
6772         if (cfg->prof_options & MONO_PROFILE_COVERAGE)
6773                 cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, cfg->num_bblocks);
6774
6775         code = mono_arch_emit_prolog (cfg);
6776
6777         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
6778                 code = mono_arch_instrument_prolog (cfg, mono_profiler_method_enter, code, FALSE);
6779
6780         cfg->code_len = code - cfg->native_code;
6781         cfg->prolog_end = cfg->code_len;
6782
6783         mono_debug_open_method (cfg);
6784
6785         /* emit code all basic blocks */
6786         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
6787                 bb->native_offset = cfg->code_len;
6788                 mono_arch_output_basic_block (cfg, bb);
6789         }
6790         cfg->bb_exit->native_offset = cfg->code_len;
6791
6792         code = cfg->native_code + cfg->code_len;
6793
6794         max_epilog_size = mono_arch_max_epilog_size (cfg);
6795
6796         /* we always allocate code in cfg->domain->code_mp to increase locality */
6797         cfg->code_size = cfg->code_len + max_epilog_size;
6798         /* fixme: align to MONO_ARCH_CODE_ALIGNMENT */
6799         code = mono_mempool_alloc (cfg->domain->code_mp, cfg->code_size);
6800         memcpy (code, cfg->native_code, cfg->code_len);
6801         g_free (cfg->native_code);
6802         cfg->native_code = code;
6803         code = cfg->native_code + cfg->code_len;
6804   
6805         /* g_assert (((int)cfg->native_code & (MONO_ARCH_CODE_ALIGNMENT - 1)) == 0); */
6806
6807         cfg->epilog_begin = cfg->code_len;
6808
6809         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
6810                 code = mono_arch_instrument_epilog (cfg, mono_profiler_method_leave, code, FALSE);
6811
6812         cfg->code_len = code - cfg->native_code;
6813
6814         mono_arch_emit_epilog (cfg);
6815
6816         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
6817                 switch (patch_info->type) {
6818                 case MONO_PATCH_INFO_ABS: {
6819                         MonoJitICallInfo *info = mono_find_jit_icall_by_addr (patch_info->data.target);
6820                         if (info) {
6821                                 //printf ("TEST %s %p\n", info->name, patch_info->data.target);
6822                                 patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
6823                                 patch_info->data.name = info->name;
6824                         }
6825                         else {
6826                                 MonoVTable *vtable = mono_find_class_init_trampoline_by_addr (patch_info->data.target);
6827                                 if (vtable) {
6828                                         patch_info->type = MONO_PATCH_INFO_CLASS_INIT;
6829                                         patch_info->data.klass = vtable->klass;
6830                                 }
6831                         }
6832                         break;
6833                 }
6834                 case MONO_PATCH_INFO_SWITCH: {
6835                         gpointer *table = mono_mempool_alloc (cfg->domain->code_mp, sizeof (gpointer) * patch_info->table_size);
6836                         patch_info->ip.i = patch_info->ip.label->inst_c0;
6837                         for (i = 0; i < patch_info->table_size; i++) {
6838                                 table [i] = (gpointer)patch_info->data.table [i]->native_offset;
6839                         }
6840                         patch_info->data.target = table;
6841                         break;
6842                 }
6843                 default:
6844                         /* do nothing */
6845                         break;
6846                 }
6847         }
6848        
6849         if (cfg->verbose_level > 0)
6850                 g_print ("Method %s emitted at %p to %p [%s]\n", 
6851                                  mono_method_full_name (cfg->method, TRUE), 
6852                                  cfg->native_code, cfg->native_code + cfg->code_len, cfg->domain->friendly_name);
6853
6854         mono_arch_patch_code (cfg->method, cfg->domain, cfg->native_code, cfg->patch_info);
6855
6856         mono_arch_flush_icache (cfg->native_code, cfg->code_len);
6857
6858         mono_debug_close_method (cfg);
6859 }
6860
6861 static void
6862 mono_cprop_copy_values (MonoCompile *cfg, MonoInst *tree, MonoInst **acp)
6863 {
6864         MonoInst *cp;
6865         int arity;
6866
6867         if (tree->ssa_op == MONO_SSA_LOAD && (tree->inst_i0->opcode == OP_LOCAL || tree->inst_i0->opcode == OP_ARG) && 
6868             (cp = acp [tree->inst_i0->inst_c0]) && !tree->inst_i0->flags) {
6869
6870                 if (cp->opcode == OP_ICONST) {
6871                         if (cfg->opt & MONO_OPT_CONSPROP) {
6872                                 //{ static int c = 0; printf ("CCOPY %d %d %s\n", c++, cp->inst_c0, mono_method_full_name (cfg->method, TRUE)); }
6873                                 *tree = *cp;
6874                         }
6875                 } else {
6876                         if (tree->inst_i0->inst_vtype->type == cp->inst_vtype->type) {
6877                                 if (cfg->opt & MONO_OPT_COPYPROP) {
6878                                         //{ static int c = 0; printf ("VCOPY %d\n", ++c); }
6879                                         tree->inst_i0 = cp;
6880                                 } 
6881                         }
6882                 } 
6883         } else {
6884                 arity = mono_burg_arity [tree->opcode];
6885
6886                 if (arity) {
6887                         mono_cprop_copy_values (cfg, tree->inst_i0, acp);
6888                         if (cfg->opt & MONO_OPT_CFOLD)
6889                                 mono_constant_fold_inst (tree, NULL); 
6890                         if (arity > 1) {
6891                                 mono_cprop_copy_values (cfg, tree->inst_i1, acp);
6892                                 if (cfg->opt & MONO_OPT_CFOLD)
6893                                         mono_constant_fold_inst (tree, NULL); 
6894                         }
6895                         mono_constant_fold_inst (tree, NULL); 
6896                 }
6897         }
6898 }
6899
6900 static void
6901 mono_cprop_invalidate_values (MonoInst *tree, MonoInst **acp, int acp_size)
6902 {
6903         int arity;
6904
6905         switch (tree->opcode) {
6906         case CEE_STIND_I:
6907         case CEE_STIND_I1:
6908         case CEE_STIND_I2:
6909         case CEE_STIND_I4:
6910         case CEE_STIND_REF:
6911         case CEE_STIND_I8:
6912         case CEE_STIND_R4:
6913         case CEE_STIND_R8:
6914         case CEE_STOBJ:
6915                 if (tree->ssa_op == MONO_SSA_NOP) {
6916                         memset (acp, 0, sizeof (MonoInst *) * acp_size);
6917                         return;
6918                 }
6919
6920                 break;
6921         case CEE_CALL:
6922         case OP_CALL_REG:
6923         case CEE_CALLVIRT:
6924         case OP_LCALL_REG:
6925         case OP_LCALLVIRT:
6926         case OP_LCALL:
6927         case OP_FCALL_REG:
6928         case OP_FCALLVIRT:
6929         case OP_FCALL:
6930         case OP_VCALL_REG:
6931         case OP_VCALLVIRT:
6932         case OP_VCALL:
6933         case OP_VOIDCALL_REG:
6934         case OP_VOIDCALLVIRT:
6935         case OP_VOIDCALL: {
6936                 MonoCallInst *call = (MonoCallInst *)tree;
6937                 MonoMethodSignature *sig = call->signature;
6938                 int i, byref = FALSE;
6939
6940                 for (i = 0; i < sig->param_count; i++) {
6941                         if (sig->params [i]->byref) {
6942                                 byref = TRUE;
6943                                 break;
6944                         }
6945                 }
6946
6947                 if (byref)
6948                         memset (acp, 0, sizeof (MonoInst *) * acp_size);
6949
6950                 return;
6951         }
6952         default:
6953                 break;
6954         }
6955
6956         arity = mono_burg_arity [tree->opcode];
6957
6958         switch (arity) {
6959         case 0:
6960                 break;
6961         case 1:
6962                 mono_cprop_invalidate_values (tree->inst_i0, acp, acp_size);
6963                 break;
6964         case 2:
6965                 mono_cprop_invalidate_values (tree->inst_i0, acp, acp_size);
6966                 mono_cprop_invalidate_values (tree->inst_i1, acp, acp_size);
6967                 break;
6968         default:
6969                 g_assert_not_reached ();
6970         }
6971 }
6972
6973 static void
6974 mono_local_cprop_bb (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst **acp, int acp_size)
6975 {
6976         MonoInst *tree = bb->code;      
6977         int i;
6978
6979         if (!tree)
6980                 return;
6981
6982         for (; tree; tree = tree->next) {
6983
6984                 mono_cprop_copy_values (cfg, tree, acp);
6985
6986                 mono_cprop_invalidate_values (tree, acp, acp_size);
6987
6988                 if (tree->ssa_op == MONO_SSA_STORE  && 
6989                     (tree->inst_i0->opcode == OP_LOCAL || tree->inst_i0->opcode == OP_ARG)) {
6990                         MonoInst *i1 = tree->inst_i1;
6991
6992                         acp [tree->inst_i0->inst_c0] = NULL;
6993
6994                         for (i = 0; i < acp_size; i++) {
6995                                 if (acp [i] && acp [i]->opcode != OP_ICONST && 
6996                                     acp [i]->inst_c0 == tree->inst_i0->inst_c0) {
6997                                         acp [i] = NULL;
6998                                 }
6999                         }
7000
7001                         if (i1->opcode == OP_ICONST) {
7002                                 acp [tree->inst_i0->inst_c0] = i1;
7003                                 //printf ("DEF1 BB%d %d\n", bb->block_num,tree->inst_i0->inst_c0);
7004                         }
7005                         if (i1->ssa_op == MONO_SSA_LOAD && 
7006                             (i1->inst_i0->opcode == OP_LOCAL || i1->inst_i0->opcode == OP_ARG) &&
7007                             (i1->inst_i0->inst_c0 != tree->inst_i0->inst_c0)) {
7008                                 acp [tree->inst_i0->inst_c0] = i1->inst_i0;
7009                                 //printf ("DEF2 BB%d %d %d\n", bb->block_num,tree->inst_i0->inst_c0,i1->inst_i0->inst_c0);
7010                         }
7011                 }
7012
7013                 /*
7014                   if (tree->opcode == CEE_BEQ) {
7015                   g_assert (tree->inst_i0->opcode == OP_COMPARE);
7016                   if (tree->inst_i0->inst_i0->opcode == OP_ICONST &&
7017                   tree->inst_i0->inst_i1->opcode == OP_ICONST) {
7018                   
7019                   tree->opcode = CEE_BR;
7020                   if (tree->inst_i0->inst_i0->opcode == tree->inst_i0->inst_i1->opcode) {
7021                   tree->inst_target_bb = tree->inst_true_bb;
7022                   } else {
7023                   tree->inst_target_bb = tree->inst_false_bb;
7024                   }
7025                   }
7026                   }
7027                 */
7028         }
7029 }
7030
7031 static void
7032 mono_local_cprop (MonoCompile *cfg)
7033 {
7034         MonoBasicBlock *bb;
7035         MonoInst **acp;
7036
7037         acp = alloca (sizeof (MonoInst *) * cfg->num_varinfo);
7038
7039         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
7040                 memset (acp, 0, sizeof (MonoInst *) * cfg->num_varinfo);
7041                 mono_local_cprop_bb (cfg, bb, acp, cfg->num_varinfo);
7042         }
7043 }
7044
7045 MonoCompile*
7046 mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, int parts)
7047 {
7048         MonoMethodHeader *header = ((MonoMethodNormal *)method)->header;
7049         guint8 *ip = (guint8 *)header->code;
7050         MonoCompile *cfg;
7051         MonoJitInfo *jinfo;
7052         int dfn = 0, i, code_size_ratio;
7053
7054         mono_jit_stats.methods_compiled++;
7055         if (mono_profiler_get_events () & MONO_PROFILE_JIT_COMPILATION)
7056                 mono_profiler_method_jit (method);
7057
7058         cfg = g_new0 (MonoCompile, 1);
7059         cfg->method = method;
7060         cfg->mempool = mono_mempool_new ();
7061         cfg->opt = opts;
7062         cfg->prof_options = mono_profiler_get_events ();
7063         cfg->bb_hash = g_hash_table_new (NULL, NULL);
7064         cfg->domain = domain;
7065         cfg->verbose_level = mini_verbose;
7066         cfg->intvars = mono_mempool_alloc0 (cfg->mempool, sizeof (guint16) * STACK_MAX * 
7067                                             ((MonoMethodNormal *)method)->header->max_stack);
7068
7069         if (cfg->verbose_level > 2)
7070                 g_print ("converting method %s\n", mono_method_full_name (method, TRUE));
7071
7072         /*
7073          * create MonoInst* which represents arguments and local variables
7074          */
7075         mono_compile_create_vars (cfg);
7076
7077         if ((i = mono_method_to_ir (cfg, method, NULL, NULL, cfg->locals_start, NULL, NULL, NULL, 0, FALSE)) < 0) {
7078                 if (cfg->prof_options & MONO_PROFILE_JIT_COMPILATION)
7079                         mono_profiler_method_end_jit (method, MONO_PROFILE_FAILED);
7080                 mono_destroy_compile (cfg);
7081                 return NULL;
7082         }
7083
7084         mono_jit_stats.basic_blocks += cfg->num_bblocks;
7085         mono_jit_stats.max_basic_blocks = MAX (cfg->num_bblocks, mono_jit_stats.max_basic_blocks);
7086
7087         if (cfg->num_varinfo > 2000) {
7088                 /* 
7089                  * we disable some optimizations if there are too many variables
7090                  * because JIT time may become too expensive. The actual number needs 
7091                  * to be tweaked and eventually the non-linear algorithms should be fixed.
7092                  */
7093                 cfg->opt &= ~ (MONO_OPT_LINEARS | MONO_OPT_COPYPROP | MONO_OPT_CONSPROP);
7094                 cfg->disable_ssa = TRUE;
7095         }
7096         /*g_print ("numblocks = %d\n", cfg->num_bblocks);*/
7097
7098         /* Depth-first ordering on basic blocks */
7099         cfg->bblocks = mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * (cfg->num_bblocks + 1));
7100
7101         if (cfg->opt & MONO_OPT_BRANCH)
7102                 optimize_branches (cfg);
7103
7104         df_visit (cfg->bb_entry, &dfn, cfg->bblocks);
7105         if (cfg->num_bblocks != dfn + 1) {
7106                 MonoBasicBlock *bb;
7107
7108                 cfg->num_bblocks = dfn + 1;
7109
7110                 if (!header->clauses) {
7111                         /* remove unreachable code, because the code in them may be 
7112                          * inconsistent  (access to dead variables for example) */
7113                         for (bb = cfg->bb_entry; bb;) {
7114                                 MonoBasicBlock *bbn = bb->next_bb;
7115
7116                                 if (bbn && bbn->region == -1 && !bbn->dfn) {
7117                                         if (cfg->verbose_level > 1)
7118                                                 g_print ("found unreachabel code in BB%d\n", bbn->block_num);
7119                                         bb->next_bb = bbn->next_bb;
7120                                         nullify_basic_block (bbn);                      
7121                                 } else {
7122                                         bb = bb->next_bb;
7123                                 }
7124                         }
7125                 }
7126         }
7127
7128         if (cfg->opt & MONO_OPT_LOOP) {
7129                 mono_compile_dominator_info (cfg, MONO_COMP_DOM | MONO_COMP_IDOM);
7130                 mono_compute_natural_loops (cfg);
7131         }
7132
7133         /* after method_to_ir */
7134         if (parts == 1)
7135                 return cfg;
7136
7137 //#define DEBUGSSA "logic_run"
7138 #define DEBUGSSA_CLASS "Tests"
7139 #ifdef DEBUGSSA
7140
7141         if (!header->num_clauses && !cfg->disable_ssa) {
7142                 mono_local_cprop (cfg);
7143                 mono_ssa_compute (cfg);
7144         }
7145 #else 
7146
7147         /* fixme: add all optimizations which requires SSA */
7148         if (cfg->opt & (MONO_OPT_DEADCE)) {
7149                 if (!(cfg->comp_done & MONO_COMP_SSA) && !header->num_clauses && !cfg->disable_ssa) {
7150                         mono_local_cprop (cfg);
7151                         mono_ssa_compute (cfg);
7152
7153                         if (cfg->verbose_level >= 2) {
7154                                 print_dfn (cfg);
7155                         }
7156                 }
7157         }
7158 #endif
7159
7160         /* after SSA translation */
7161         if (parts == 2)
7162                 return cfg;
7163
7164         if ((cfg->opt & MONO_OPT_CONSPROP) ||  (cfg->opt & MONO_OPT_COPYPROP)) {
7165                 if (cfg->comp_done & MONO_COMP_SSA) {
7166                         mono_ssa_cprop (cfg);
7167                 } else {
7168                         mono_local_cprop (cfg);
7169                 }
7170         }
7171
7172         if (cfg->comp_done & MONO_COMP_SSA) {                   
7173                 mono_ssa_deadce (cfg);
7174
7175                 //mono_ssa_strength_reduction (cfg);
7176
7177                 mono_ssa_remove (cfg);
7178
7179                 if (cfg->opt & MONO_OPT_BRANCH)
7180                         optimize_branches (cfg);
7181         }
7182
7183         /* after SSA removal */
7184         if (parts == 3)
7185                 return cfg;
7186
7187         decompose_pass (cfg);
7188
7189         /* FIXME: disabled with exception clauses: bug #42136 */
7190         if ((!header->num_clauses) && (cfg->opt & MONO_OPT_LINEARS)) {
7191                 GList *vars, *regs;
7192
7193                 /* fixme: maybe we can avoid to compute livenesss here if already computed ? */
7194                 cfg->comp_done &= ~MONO_COMP_LIVENESS;
7195                 if (!(cfg->comp_done & MONO_COMP_LIVENESS))
7196                         mono_analyze_liveness (cfg);
7197
7198                 if ((vars = mono_arch_get_allocatable_int_vars (cfg))) {
7199                         regs = mono_arch_get_global_int_regs (cfg);
7200                         mono_linear_scan (cfg, vars, regs, &cfg->used_int_regs);
7201                 }
7202         }
7203
7204         //mono_print_code (cfg);
7205
7206        //print_dfn (cfg);
7207         
7208         /* variables are allocated after decompose, since decompose could create temps */
7209         mono_arch_allocate_vars (cfg);
7210
7211         if (cfg->opt & MONO_OPT_CFOLD)
7212                 mono_constant_fold (cfg);
7213
7214         mini_select_instructions (cfg);
7215
7216         mono_codegen (cfg);
7217         if (cfg->verbose_level >= 2) {
7218                 char *id =  mono_method_full_name (cfg->method, FALSE);
7219                 mono_disassemble_code (cfg->native_code, cfg->code_len, id + 3);
7220                 g_free (id);
7221         }
7222         
7223         jinfo = mono_mempool_alloc0 (cfg->domain->mp, sizeof (MonoJitInfo));
7224
7225         jinfo = g_new0 (MonoJitInfo, 1);
7226         jinfo->method = method;
7227         jinfo->code_start = cfg->native_code;
7228         jinfo->code_size = cfg->code_len;
7229         jinfo->used_regs = cfg->used_int_regs;
7230         jinfo->domain_neutral = (cfg->opt & MONO_OPT_SHARED) != 0;
7231
7232         if (header->num_clauses) {
7233                 int i;
7234
7235                 jinfo->exvar_offset = cfg->exvar? cfg->exvar->inst_offset: 0;
7236                 jinfo->num_clauses = header->num_clauses;
7237                 jinfo->clauses = mono_mempool_alloc0 (cfg->domain->mp, 
7238                         sizeof (MonoJitExceptionInfo) * header->num_clauses);
7239
7240                 for (i = 0; i < header->num_clauses; i++) {
7241                         MonoExceptionClause *ec = &header->clauses [i];
7242                         MonoJitExceptionInfo *ei = &jinfo->clauses [i];
7243                         MonoBasicBlock *tblock;
7244
7245                         ei->flags = ec->flags;
7246
7247                         if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
7248                                 tblock = g_hash_table_lookup (cfg->bb_hash, ip + ec->token_or_filter);
7249                                 g_assert (tblock);
7250                                 ei->data.filter = cfg->native_code + tblock->native_offset;
7251                         } else {
7252                                 ei->data.token = ec->token_or_filter;
7253                         }
7254
7255                         tblock = g_hash_table_lookup (cfg->bb_hash, ip + ec->try_offset);
7256                         g_assert (tblock);
7257                         ei->try_start = cfg->native_code + tblock->native_offset;
7258                         g_assert (tblock->native_offset);
7259                         tblock = g_hash_table_lookup (cfg->bb_hash, ip + ec->try_offset + ec->try_len);
7260                         g_assert (tblock);
7261                         ei->try_end = cfg->native_code + tblock->native_offset;
7262                         g_assert (tblock->native_offset);
7263                         tblock = g_hash_table_lookup (cfg->bb_hash, ip + ec->handler_offset);
7264                         g_assert (tblock);
7265                         ei->handler_start = cfg->native_code + tblock->native_offset;
7266                 }
7267         }
7268
7269         cfg->jit_info = jinfo;
7270
7271         mono_jit_info_table_add (cfg->domain, jinfo);
7272
7273         /* collect statistics */
7274         mono_jit_stats.allocated_code_size += cfg->code_len;
7275         code_size_ratio = cfg->code_len;
7276         if (code_size_ratio > mono_jit_stats.biggest_method_size) {
7277                         mono_jit_stats.biggest_method_size = code_size_ratio;
7278                         mono_jit_stats.biggest_method = method;
7279         }
7280         code_size_ratio = (code_size_ratio * 100) / ((MonoMethodNormal *)method)->header->code_size;
7281         if (code_size_ratio > mono_jit_stats.max_code_size_ratio) {
7282                 mono_jit_stats.max_code_size_ratio = code_size_ratio;
7283                 mono_jit_stats.max_ratio_method = method;
7284         }
7285         mono_jit_stats.native_code_size += cfg->code_len;
7286
7287         if (cfg->prof_options & MONO_PROFILE_JIT_COMPILATION)
7288                 mono_profiler_method_end_jit (method, MONO_PROFILE_OK);
7289
7290         return cfg;
7291 }
7292
7293 static gpointer
7294 mono_jit_compile_method_inner (MonoMethod *method)
7295 {
7296         /* FIXME: later copy the code from mono */
7297         MonoDomain *target_domain, *domain = mono_domain_get ();
7298         MonoCompile *cfg;
7299         GHashTable *jit_code_hash;
7300         gpointer code;
7301         guint32 opt;
7302
7303         opt = default_opt;
7304
7305         if (opt & MONO_OPT_SHARED)
7306                 target_domain = mono_root_domain;
7307         else 
7308                 target_domain = domain;
7309
7310         jit_code_hash = target_domain->jit_code_hash;
7311
7312 #ifdef MONO_USE_AOT_COMPILER
7313         if (!mono_compile_aot && (opt & MONO_OPT_AOT)) {
7314                 MonoJitInfo *info;
7315
7316                 mono_domain_lock (domain);
7317
7318                 mono_class_init (method->klass);
7319                 if ((info = mono_aot_get_method (domain, method))) {
7320
7321                         g_hash_table_insert (domain->jit_code_hash, method, info);
7322
7323                         mono_domain_unlock (domain);
7324
7325                         /* make sure runtime_init is called */
7326                         mono_runtime_class_init (mono_class_vtable (domain, method->klass));
7327
7328                         return info->code_start;
7329                 }
7330
7331                 mono_domain_unlock (domain);
7332         }
7333 #endif
7334
7335         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
7336             (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
7337                 MonoMethod *nm;
7338
7339                 if (!method->addr) {
7340                         if (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL)
7341                                 method->addr = mono_lookup_internal_call (method);
7342                         else
7343                                 if (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
7344                                         mono_lookup_pinvoke_call (method);
7345                 }
7346 #ifdef MONO_USE_EXC_TABLES
7347                 if (mono_method_blittable (method)) {
7348                         return method->addr;
7349                 } else {
7350 #endif
7351                         nm = mono_marshal_get_native_wrapper (method);
7352                         return mono_compile_method (nm);
7353
7354                         //if (mono_debug_format != MONO_DEBUG_FORMAT_NONE) 
7355                         //mono_debug_add_wrapper (method, nm);
7356 #ifdef MONO_USE_EXC_TABLES
7357                 }
7358 #endif
7359         } else if ((method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME)) {
7360                 const char *name = method->name;
7361                 MonoMethod *nm;
7362
7363                 if (method->klass->parent == mono_defaults.multicastdelegate_class) {
7364                         if (*name == '.' && (strcmp (name, ".ctor") == 0)) {
7365                                 /* FIXME: uhm, we need a wrapper to handle exceptions? */
7366                                 return (gpointer)mono_delegate_ctor;
7367                         } else if (*name == 'I' && (strcmp (name, "Invoke") == 0)) {
7368                                 nm = mono_marshal_get_delegate_invoke (method);
7369                                 return mono_jit_compile_method (nm);
7370                         } else if (*name == 'B' && (strcmp (name, "BeginInvoke") == 0)) {
7371                                 nm = mono_marshal_get_delegate_begin_invoke (method);
7372                                 return mono_jit_compile_method (nm);
7373                         } else if (*name == 'E' && (strcmp (name, "EndInvoke") == 0)) {
7374                                 nm = mono_marshal_get_delegate_end_invoke (method);
7375                                 return mono_jit_compile_method (nm);
7376                         }
7377                 }
7378                 return NULL;
7379         }
7380
7381         cfg = mini_method_compile (method, opt, target_domain, 0);
7382         code = cfg->native_code;
7383
7384         g_hash_table_insert (jit_code_hash, method, cfg->jit_info);
7385
7386         mono_destroy_compile (cfg);
7387
7388         if (target_domain->jump_target_hash) {
7389                 MonoJumpInfo patch_info;
7390                 GSList *list, *tmp;
7391                 list = g_hash_table_lookup (target_domain->jump_target_hash, method);
7392                 if (list) {
7393                         patch_info.next = NULL;
7394                         patch_info.ip.i = 0;
7395                         patch_info.type = MONO_PATCH_INFO_METHOD_JUMP;
7396                         patch_info.data.method = method;
7397                         g_hash_table_remove (target_domain->jump_target_hash, method);
7398                 }
7399                 for (tmp = list; tmp; tmp = tmp->next)
7400                         mono_arch_patch_code (NULL, target_domain, tmp->data, &patch_info);
7401                 g_slist_free (list);
7402         }
7403         /* make sure runtime_init is called */
7404         mono_runtime_class_init (mono_class_vtable (target_domain, method->klass));
7405
7406         return code;
7407 }
7408
7409 static gpointer
7410 mono_jit_compile_method (MonoMethod *method)
7411 {
7412         /* FIXME: later copy the code from mono */
7413         MonoDomain *target_domain, *domain = mono_domain_get ();
7414         MonoJitInfo *info;
7415         gpointer code;
7416
7417         if (default_opt & MONO_OPT_SHARED)
7418                 target_domain = mono_root_domain;
7419         else 
7420                 target_domain = domain;
7421
7422         mono_domain_lock (target_domain);
7423
7424         if ((info = g_hash_table_lookup (target_domain->jit_code_hash, method))) {
7425                 /* We can't use a domain specific method in another domain */
7426                 if (! ((domain != target_domain) && !info->domain_neutral)) {
7427                         mono_domain_unlock (target_domain);
7428                         mono_jit_stats.methods_lookups++;
7429                         return info->code_start;
7430                 }
7431         }
7432
7433         code = mono_jit_compile_method_inner (method);
7434
7435         mono_domain_unlock (target_domain);
7436
7437         return code;
7438 }
7439
7440 /**
7441  * mono_jit_runtime_invoke:
7442  * @method: the method to invoke
7443  * @obj: this pointer
7444  * @params: array of parameter values.
7445  * @exc: used to catch exceptions objects
7446  */
7447 static MonoObject*
7448 mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
7449 {
7450         MonoMethod *invoke;
7451         MonoObject *(*runtime_invoke) (MonoObject *this, void **params, MonoObject **exc);
7452
7453         if (obj == NULL && !(method->flags & METHOD_ATTRIBUTE_STATIC) && !method->string_ctor && (method->wrapper_type == 0)) {
7454                 g_warning ("Ignoring invocation of an instance method on a NULL instance.\n");
7455                 return NULL;
7456         }
7457
7458         invoke = mono_marshal_get_runtime_invoke (method);
7459         runtime_invoke = mono_jit_compile_method (invoke);
7460         return runtime_invoke (obj, params, exc);
7461 }
7462
7463 #ifdef PLATFORM_WIN32
7464 #define GET_CONTEXT \
7465         struct sigcontext *ctx = (struct sigcontext*)_dummy;
7466 #else
7467 #define GET_CONTEXT \
7468         void **_p = (void **)&_dummy; \
7469         struct sigcontext *ctx = (struct sigcontext *)++_p;
7470 #endif
7471
7472 static void
7473 sigfpe_signal_handler (int _dummy)
7474 {
7475         MonoException *exc;
7476         GET_CONTEXT
7477
7478         exc = mono_get_exception_divide_by_zero ();
7479         
7480         mono_arch_handle_exception (ctx, exc, FALSE);
7481 }
7482
7483 static void
7484 sigill_signal_handler (int _dummy)
7485 {
7486         MonoException *exc;
7487         GET_CONTEXT
7488         exc = mono_get_exception_execution_engine ("SIGILL");
7489         
7490         mono_arch_handle_exception (ctx, exc, FALSE);
7491 }
7492
7493 static void
7494 sigsegv_signal_handler (int _dummy)
7495 {
7496         MonoException *exc;
7497         GET_CONTEXT
7498
7499         exc = mono_get_exception_null_reference ();
7500         
7501         mono_arch_handle_exception (ctx, exc, FALSE);
7502 }
7503
7504 static void
7505 sigusr1_signal_handler (int _dummy)
7506 {
7507         MonoThread *thread;
7508         GET_CONTEXT
7509         
7510         thread = mono_thread_current ();
7511
7512         thread->abort_exc = mono_get_exception_thread_abort ();        
7513
7514         mono_arch_handle_exception (ctx, thread->abort_exc, FALSE);
7515 }
7516
7517 static void
7518 sigquit_signal_handler (int _dummy)
7519 {
7520        MonoException *exc;
7521        GET_CONTEXT
7522
7523        exc = mono_get_exception_execution_engine ("Interrupted (SIGQUIT).");
7524        
7525        mono_arch_handle_exception (ctx, exc, FALSE);
7526 }
7527
7528 static void
7529 sigint_signal_handler (int _dummy)
7530 {
7531         MonoException *exc;
7532         GET_CONTEXT
7533
7534         exc = mono_get_exception_execution_engine ("Interrupted (SIGINT).");
7535         
7536         mono_arch_handle_exception (ctx, exc, FALSE);
7537 }
7538
7539 static void
7540 mono_runtime_install_handlers (void)
7541 {
7542         gboolean skip_sigabort = FALSE;
7543 #ifndef PLATFORM_WIN32
7544         struct sigaction sa;
7545 #endif
7546
7547 #ifdef PLATFORM_WIN32
7548         win32_seh_init();
7549         win32_seh_set_handler(SIGFPE, sigfpe_signal_handler);
7550         win32_seh_set_handler(SIGILL, sigill_signal_handler);
7551         win32_seh_set_handler(SIGSEGV, sigsegv_signal_handler);
7552         if (getenv ("MONO_DEBUG"))
7553                 win32_seh_set_handler(SIGINT, sigint_signal_handler);
7554 #else /* !PLATFORM_WIN32 */
7555
7556         /* libpthreads has its own implementation of sigaction(),
7557          * but it seems to work well with our current exception
7558          * handlers. If not we must call syscall directly instead 
7559          * of sigaction */
7560         
7561         if (getenv ("MONO_DEBUG")) {
7562                 /* catch SIGINT */
7563                 sa.sa_handler = sigint_signal_handler;
7564                 sigemptyset (&sa.sa_mask);
7565                 sa.sa_flags = 0;
7566                 //g_assert (syscall (SYS_sigaction, SIGINT, &sa, NULL) != -1);
7567                 g_assert (sigaction (SIGINT, &sa, NULL) != -1);
7568         }
7569
7570         /* catch SIGFPE */
7571         sa.sa_handler = sigfpe_signal_handler;
7572         sigemptyset (&sa.sa_mask);
7573         sa.sa_flags = 0;
7574         //g_assert (syscall (SYS_sigaction, SIGFPE, &sa, NULL) != -1);
7575         g_assert (sigaction (SIGFPE, &sa, NULL) != -1);
7576
7577         /* catch SIGQUIT */
7578         sa.sa_handler = sigquit_signal_handler;
7579         sigemptyset (&sa.sa_mask);
7580         sa.sa_flags = 0;
7581         g_assert (sigaction (SIGQUIT, &sa, NULL) != -1);
7582
7583         /* catch SIGILL */
7584         sa.sa_handler = sigill_signal_handler;
7585         sigemptyset (&sa.sa_mask);
7586         sa.sa_flags = 0;
7587         //g_assert (syscall (SYS_sigaction, SIGILL, &sa, NULL) != -1);
7588         g_assert (sigaction (SIGILL, &sa, NULL) != -1);
7589
7590         /* catch thread abort signal */
7591         sa.sa_handler = sigusr1_signal_handler;
7592         sigemptyset (&sa.sa_mask);
7593         sa.sa_flags = 0;
7594         //g_assert (syscall (SYS_sigaction, SIGILL, &sa, NULL) != -1);
7595
7596 #ifdef HAVE_VALGRIND_MEMCHECK_H
7597         if (RUNNING_ON_VALGRIND)
7598                 /* valgrind 20030725 and earlier aborts on this call so we skip it */
7599                 skip_sigabort = TRUE;
7600 #endif
7601
7602         if (!skip_sigabort)
7603                 g_assert (sigaction (mono_thread_get_abort_signal (), &sa, NULL) != -1);
7604
7605 #if 1
7606         /* catch SIGSEGV */
7607         sa.sa_handler = sigsegv_signal_handler;
7608         sigemptyset (&sa.sa_mask);
7609         sa.sa_flags = 0;
7610         //g_assert (syscall (SYS_sigaction, SIGSEGV, &sa, NULL) != -1);
7611         g_assert (sigaction (SIGSEGV, &sa, NULL) != -1);
7612 #endif
7613 #endif /* PLATFORM_WIN32 */
7614 }
7615
7616 /* mono_jit_create_remoting_trampoline:
7617  * @method: pointer to the method info
7618  *
7619  * Creates a trampoline which calls the remoting functions. This
7620  * is used in the vtable of transparent proxies.
7621  * 
7622  * Returns: a pointer to the newly created code 
7623  */
7624 static gpointer
7625 mono_jit_create_remoting_trampoline (MonoMethod *method)
7626 {
7627         MonoMethod *nm;
7628         guint8 *addr = NULL;
7629
7630         if ((method->flags & METHOD_ATTRIBUTE_ABSTRACT) || 
7631             (method->signature->hasthis && (method->klass->marshalbyref || method->klass == mono_defaults.object_class))) {
7632                 nm = mono_marshal_get_remoting_invoke (method);
7633                 addr = mono_compile_method (nm);
7634         } else {
7635                 addr = mono_compile_method (method);
7636         }
7637         return addr;
7638 }
7639
7640 MonoDomain *
7641 mini_init (const char *filename)
7642 {
7643         MonoDomain *domain;
7644
7645         mono_arch_cpu_init ();
7646
7647         g_thread_init (NULL);
7648
7649         mono_jit_tls_id = TlsAlloc ();
7650         setup_jit_tls_data ((gpointer)-1, mono_thread_abort);
7651
7652         InitializeCriticalSection (&class_init_hash_mutex);
7653
7654         mono_burg_init ();
7655
7656         if (default_opt & MONO_OPT_AOT)
7657                 mono_aot_init ();
7658
7659         mono_runtime_install_handlers ();
7660         mono_threads_install_cleanup (mini_thread_cleanup);
7661
7662 #define JIT_TRAMPOLINES_WORK
7663 #ifdef JIT_TRAMPOLINES_WORK
7664         mono_install_compile_method (mono_jit_compile_method);
7665         mono_install_trampoline (mono_arch_create_jit_trampoline);
7666         mono_install_remoting_trampoline (mono_jit_create_remoting_trampoline);
7667 #endif
7668 #define JIT_INVOKE_WORKS
7669 #ifdef JIT_INVOKE_WORKS
7670         mono_install_runtime_invoke (mono_jit_runtime_invoke);
7671         mono_install_handler (mono_arch_get_throw_exception ());
7672 #endif
7673         mono_install_stack_walk (mono_jit_walk_stack);
7674         mono_install_get_config_dir ();
7675
7676         domain = mono_init (filename);
7677         mono_init_icall ();
7678
7679         mono_add_internal_call ("System.Diagnostics.StackFrame::get_frame_info", 
7680                                 ves_icall_get_frame_info);
7681         mono_add_internal_call ("System.Diagnostics.StackTrace::get_trace", 
7682                                 ves_icall_get_trace);
7683         mono_add_internal_call ("Mono.Runtime::mono_runtime_install_handlers", 
7684                                 mono_runtime_install_handlers);
7685
7686
7687         create_helper_signature ();
7688
7689 #define JIT_CALLS_WORK
7690 #ifdef JIT_CALLS_WORK
7691         /* Needs to be called here since register_jit_icall depends on it */
7692         mono_marshal_init ();
7693
7694         mono_arch_register_lowlevel_calls ();
7695         mono_register_jit_icall (mono_profiler_method_enter, "mono_profiler_method_enter", NULL, TRUE);
7696         mono_register_jit_icall (mono_profiler_method_leave, "mono_profiler_method_leave", NULL, TRUE);
7697
7698         mono_register_jit_icall (mono_get_lmf_addr, "mono_get_lmf_addr", helper_sig_ptr_void, TRUE);
7699         mono_register_jit_icall (mono_domain_get, "mono_domain_get", helper_sig_domain_get, TRUE);
7700
7701         /* fixme: we cant hanlde vararg methods this way, because the signature is not constant */
7702         //mono_register_jit_icall (ves_array_element_address, "ves_array_element_address", NULL);
7703         //mono_register_jit_icall (mono_array_new_va, "mono_array_new_va", NULL);
7704
7705         mono_register_jit_icall (mono_arch_get_throw_exception (), "mono_arch_throw_exception", helper_sig_void_obj, TRUE);
7706         mono_register_jit_icall (mono_arch_get_throw_exception_by_name (), "mono_arch_throw_exception_by_name", 
7707                                  helper_sig_void_ptr, TRUE);
7708         mono_register_jit_icall (mono_thread_get_pending_exception, "mono_thread_get_pending_exception", helper_sig_obj_void, FALSE);
7709
7710         /* 
7711          * NOTE, NOTE, NOTE, NOTE:
7712          * when adding emulation for some opcodes, remember to also add a dummy
7713          * rule to the burg files, because we need the arity information to be correct.
7714          */
7715         mono_register_opcode_emulation (OP_LMUL, "__emul_lmul", helper_sig_long_long_long, mono_llmult, TRUE);
7716         mono_register_opcode_emulation (OP_LMUL_OVF_UN, "__emul_lmul_ovf_un", helper_sig_long_long_long, mono_llmult_ovf_un, FALSE);
7717         mono_register_opcode_emulation (OP_LMUL_OVF, "__emul_lmul_ovf", helper_sig_long_long_long, mono_llmult_ovf, FALSE);
7718         mono_register_opcode_emulation (OP_LDIV, "__emul_ldiv", helper_sig_long_long_long, mono_lldiv, FALSE);
7719         mono_register_opcode_emulation (OP_LDIV_UN, "__emul_ldiv_un", helper_sig_long_long_long, mono_lldiv_un, FALSE);
7720         mono_register_opcode_emulation (OP_LREM, "__emul_lrem", helper_sig_long_long_long, mono_llrem, FALSE);
7721         mono_register_opcode_emulation (OP_LREM_UN, "__emul_lrem_un", helper_sig_long_long_long, mono_llrem_un, FALSE);
7722
7723         mono_register_opcode_emulation (OP_LSHL, "__emul_lshl", helper_sig_long_long_int, mono_lshl, TRUE);
7724         mono_register_opcode_emulation (OP_LSHR, "__emul_lshr", helper_sig_long_long_int, mono_lshr, TRUE);
7725         mono_register_opcode_emulation (OP_LSHR_UN, "__emul_lshr_un", helper_sig_long_long_int, mono_lshr_un, TRUE);
7726
7727         mono_register_opcode_emulation (OP_FCONV_TO_U8, "__emul_fconv_to_u8", helper_sig_ulong_double, mono_fconv_u8, FALSE);
7728         mono_register_opcode_emulation (OP_FCONV_TO_U4, "__emul_fconv_to_u4", helper_sig_uint_double, mono_fconv_u4, FALSE);
7729         mono_register_opcode_emulation (OP_FCONV_TO_OVF_I8, "__emul_fconv_to_ovf_i8", helper_sig_long_double, mono_fconv_ovf_i8, TRUE);
7730         mono_register_opcode_emulation (OP_FCONV_TO_OVF_U8, "__emul_fconv_to_ovf_u8", helper_sig_ulong_double, mono_fconv_ovf_u8, TRUE);
7731
7732 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
7733         mono_register_opcode_emulation (OP_FCONV_TO_I8, "__emul_fconv_to_i8", helper_sig_long_double, mono_fconv_i8, FALSE);
7734 #endif
7735 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
7736         mono_register_opcode_emulation (OP_LCONV_TO_R8, "__emul_lconv_to_r8", helper_sig_double_long, mono_lconv_to_r8, FALSE);
7737 #endif
7738 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
7739         mono_register_opcode_emulation (OP_LCONV_TO_R4, "__emul_lconv_to_r4", helper_sig_float_long, mono_lconv_to_r4, FALSE);
7740 #endif
7741 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
7742         mono_register_opcode_emulation (OP_LCONV_TO_R_UN, "__emul_lconv_to_r8_un", helper_sig_double_long, mono_lconv_to_r8_un, FALSE);
7743 #endif
7744 #ifdef MONO_ARCH_EMULATE_FREM
7745         mono_register_opcode_emulation (OP_FREM, "__emul_frem", helper_sig_double_double_double, fmod, FALSE);
7746 #endif
7747
7748 #if SIZEOF_VOID_P == 4
7749         mono_register_opcode_emulation (OP_FCONV_TO_U, "__emul_fconv_to_u", helper_sig_uint_double, mono_fconv_u4, TRUE);
7750 #else
7751 #warning "fixme: add opcode emulation"
7752 #endif
7753
7754         /* other jit icalls */
7755         mono_register_jit_icall (mono_class_static_field_address , "mono_class_static_field_address", 
7756                                  helper_sig_ptr_ptr_ptr, FALSE);
7757         mono_register_jit_icall (mono_ldtoken_wrapper, "mono_ldtoken_wrapper", helper_sig_ptr_ptr_ptr, FALSE);
7758         mono_register_jit_icall (mono_get_special_static_data, "mono_get_special_static_data", helper_sig_ptr_int, FALSE);
7759         mono_register_jit_icall (mono_ldstr, "mono_ldstr", helper_sig_ldstr, FALSE);
7760         mono_register_jit_icall (helper_memcpy, "helper_memcpy", helper_sig_memcpy, FALSE);
7761         mono_register_jit_icall (helper_memset, "helper_memset", helper_sig_memset, FALSE);
7762         mono_register_jit_icall (helper_initobj, "helper_initobj", helper_sig_initobj, FALSE);
7763         mono_register_jit_icall (helper_stelem_ref, "helper_stelem_ref", helper_sig_stelem_ref, FALSE);
7764         mono_register_jit_icall (mono_object_new, "mono_object_new", helper_sig_object_new, FALSE);
7765         mono_register_jit_icall (mono_object_new_specific, "mono_object_new_specific", helper_sig_object_new_specific, FALSE);
7766         mono_register_jit_icall (mono_object_new_fast, "mono_object_new_fast", helper_sig_object_new_specific, FALSE);
7767         mono_register_jit_icall (mono_array_new, "mono_array_new", helper_sig_newarr, FALSE);
7768         mono_register_jit_icall (mono_array_new_specific, "mono_array_new_specific", helper_sig_newarr_specific, FALSE);
7769         mono_register_jit_icall (mono_string_to_utf16, "mono_string_to_utf16", helper_sig_ptr_obj, FALSE);
7770         mono_register_jit_icall (mono_string_from_utf16, "mono_string_from_utf16", helper_sig_obj_ptr, FALSE);
7771         mono_register_jit_icall (mono_string_new_wrapper, "mono_string_new_wrapper", helper_sig_obj_ptr, FALSE);
7772         mono_register_jit_icall (mono_string_to_utf8, "mono_string_to_utf8", helper_sig_ptr_obj, FALSE);
7773         mono_register_jit_icall (mono_string_to_bstr, "mono_string_to_bstr", helper_sig_ptr_obj, FALSE);
7774         mono_register_jit_icall (mono_string_to_ansibstr, "mono_string_to_ansibstr", helper_sig_ptr_obj, FALSE);
7775         mono_register_jit_icall (mono_string_builder_to_utf8, "mono_string_builder_to_utf8", helper_sig_ptr_obj, FALSE);
7776         mono_register_jit_icall (mono_array_to_savearray, "mono_array_to_savearray", helper_sig_ptr_obj, FALSE);
7777         mono_register_jit_icall (mono_array_to_lparray, "mono_array_to_lparray", helper_sig_ptr_obj, FALSE);
7778         mono_register_jit_icall (mono_delegate_to_ftnptr, "mono_delegate_to_ftnptr", helper_sig_ptr_obj, FALSE);
7779         mono_register_jit_icall (mono_marshal_string_array, "mono_marshal_string_array", helper_sig_ptr_obj, FALSE);
7780         mono_register_jit_icall (mono_string_utf8_to_builder, "mono_string_utf8_to_builder", helper_sig_void_ptr_ptr, FALSE);
7781         mono_register_jit_icall (mono_marshal_free_array, "mono_marshal_free_array", helper_sig_void_ptr_ptr, FALSE);
7782         mono_register_jit_icall (mono_string_to_byvalstr, "mono_string_to_byvalstr", helper_sig_void_ptr_ptr_ptr, FALSE);
7783         mono_register_jit_icall (mono_string_to_byvalwstr, "mono_string_to_byvalwstr", helper_sig_void_ptr_ptr_ptr, FALSE);
7784         mono_register_jit_icall (g_free, "g_free", helper_sig_void_ptr, FALSE);
7785         mono_register_jit_icall (mono_runtime_class_init, "mono_runtime_class_init", helper_sig_void_ptr, FALSE);
7786         mono_register_jit_icall (mono_ldftn, "mono_ldftn", helper_sig_compile, FALSE);
7787         mono_register_jit_icall (mono_ldvirtfn, "mono_ldvirtfn", helper_sig_compile_virt, FALSE);
7788 #endif
7789
7790 #define JIT_RUNTIME_WORKS
7791 #ifdef JIT_RUNTIME_WORKS
7792         mono_runtime_install_cleanup ((MonoDomainFunc)mini_cleanup);
7793         mono_runtime_init (domain, mono_thread_start_cb, mono_thread_attach_cb);
7794 #endif
7795
7796         //mono_thread_attach (domain);
7797         return domain;
7798 }
7799
7800 MonoJitStats mono_jit_stats = {0};
7801
7802 static void 
7803 print_jit_stats (void)
7804 {
7805         if (mono_jit_stats.enabled) {
7806                 g_print ("Mono Jit statistics\n");
7807                 g_print ("Compiled methods:       %ld\n", mono_jit_stats.methods_compiled);
7808                 g_print ("Methods from AOT:       %ld\n", mono_jit_stats.methods_aot);
7809                 g_print ("Methods cache lookup:   %ld\n", mono_jit_stats.methods_lookups);
7810                 g_print ("Method trampolines:     %ld\n", mono_jit_stats.method_trampolines);
7811                 g_print ("Basic blocks:           %ld\n", mono_jit_stats.basic_blocks);
7812                 g_print ("Max basic blocks:       %ld\n", mono_jit_stats.max_basic_blocks);
7813                 g_print ("Allocated vars:         %ld\n", mono_jit_stats.allocate_var);
7814                 g_print ("Analyze stack repeat:   %ld\n", mono_jit_stats.analyze_stack_repeat);
7815                 g_print ("Compiled CIL code size: %ld\n", mono_jit_stats.cil_code_size);
7816                 g_print ("Native code size:       %ld\n", mono_jit_stats.native_code_size);
7817                 g_print ("Max code size ratio:    %.2f (%s::%s)\n", mono_jit_stats.max_code_size_ratio/100.0,
7818                                 mono_jit_stats.max_ratio_method->klass->name, mono_jit_stats.max_ratio_method->name);
7819                 g_print ("Biggest method:         %ld (%s::%s)\n", mono_jit_stats.biggest_method_size,
7820                                 mono_jit_stats.biggest_method->klass->name, mono_jit_stats.biggest_method->name);
7821                 g_print ("Code reallocs:          %ld\n", mono_jit_stats.code_reallocs);
7822                 g_print ("Allocated code size:    %ld\n", mono_jit_stats.allocated_code_size);
7823                 g_print ("Inlineable methods:     %ld\n", mono_jit_stats.inlineable_methods);
7824                 g_print ("Inlined methods:        %ld\n", mono_jit_stats.inlined_methods);
7825                 
7826                 g_print ("\nCreated object count:   %ld\n", mono_stats.new_object_count);
7827                 g_print ("Initialized classes:    %ld\n", mono_stats.initialized_class_count);
7828                 g_print ("Used classes:           %ld\n", mono_stats.used_class_count);
7829                 g_print ("Static data size:       %ld\n", mono_stats.class_static_data_size);
7830                 g_print ("VTable data size:       %ld\n", mono_stats.class_vtable_size);
7831         }
7832 }
7833
7834 void
7835 mini_cleanup (MonoDomain *domain)
7836 {
7837         /* 
7838          * mono_runtime_cleanup() and mono_domain_finalize () need to
7839          * be called early since they need the execution engine still
7840          * fully working (mono_domain_finalize may invoke managed finalizers
7841          * and mono_runtime_cleanup will wait for other threads to finish).
7842          */
7843         mono_domain_finalize (domain, -1);
7844
7845         mono_runtime_cleanup (domain);
7846
7847         mono_profiler_shutdown ();
7848
7849         mono_debug_cleanup ();
7850
7851 #ifdef PLATFORM_WIN32
7852         win32_seh_cleanup();
7853 #endif
7854
7855         mono_domain_free (domain, TRUE);
7856
7857         print_jit_stats ();
7858 }
7859
7860 void
7861 mono_set_defaults (int verbose_level, guint32 opts)
7862 {
7863         mini_verbose = verbose_level;
7864         default_opt = opts;
7865 }
7866
7867 static void
7868 mono_precompile_assembly (MonoAssembly *ass, void *user_data)
7869 {
7870         MonoImage *image = ass->image;
7871         MonoMethod *method;
7872         int i, count = 0;
7873
7874         if (mini_verbose > 0)
7875                 printf ("PRECOMPILE: %s.\n", ass->image->name);
7876
7877         for (i = 0; i < image->tables [MONO_TABLE_METHOD].rows; ++i) {
7878                 method = mono_get_method (image, MONO_TOKEN_METHOD_DEF | (i + 1), NULL);
7879                 if (method->flags & METHOD_ATTRIBUTE_ABSTRACT)
7880                         continue;
7881                 if (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL)
7882                         continue;
7883
7884                 count++;
7885                 if (mini_verbose > 1) {
7886                         char * desc = mono_method_full_name (method, TRUE);
7887                         g_print ("Compiling %d %s\n", count, desc);
7888                         g_free (desc);
7889                 }
7890                 mono_compile_method (method);
7891         }
7892 }
7893
7894 void mono_precompile_assemblies ()
7895 {
7896         mono_assembly_foreach ((GFunc)mono_precompile_assembly, NULL);
7897 }