Fixed.
[mono.git] / mono / mini / method-to-ir.c
1 /*
2  * method-to-ir.c: Convert CIL to the JIT internal representation
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
14 #ifdef HAVE_UNISTD_H
15 #include <unistd.h>
16 #endif
17
18 #include <math.h>
19 #include <string.h>
20 #include <ctype.h>
21
22 #ifdef HAVE_SYS_TIME_H
23 #include <sys/time.h>
24 #endif
25
26 #ifdef HAVE_ALLOCA_H
27 #include <alloca.h>
28 #endif
29
30 #include <mono/utils/memcheck.h>
31
32 #include <mono/metadata/assembly.h>
33 #include <mono/metadata/loader.h>
34 #include <mono/metadata/tabledefs.h>
35 #include <mono/metadata/class.h>
36 #include <mono/metadata/object.h>
37 #include <mono/metadata/exception.h>
38 #include <mono/metadata/opcodes.h>
39 #include <mono/metadata/mono-endian.h>
40 #include <mono/metadata/tokentype.h>
41 #include <mono/metadata/tabledefs.h>
42 #include <mono/metadata/marshal.h>
43 #include <mono/metadata/debug-helpers.h>
44 #include <mono/metadata/mono-debug.h>
45 #include <mono/metadata/gc-internal.h>
46 #include <mono/metadata/security-manager.h>
47 #include <mono/metadata/threads-types.h>
48 #include <mono/metadata/security-core-clr.h>
49 #include <mono/metadata/monitor.h>
50 #include <mono/metadata/profiler-private.h>
51 #include <mono/metadata/profiler.h>
52 #include <mono/utils/mono-compiler.h>
53 #include <mono/metadata/mono-basic-block.h>
54
55 #include "mini.h"
56 #include "trace.h"
57
58 #include "ir-emit.h"
59
60 #include "jit-icalls.h"
61 #include "jit.h"
62 #include "debugger-agent.h"
63
64 #define BRANCH_COST 100
65 #define INLINE_LENGTH_LIMIT 20
66 #define INLINE_FAILURE do {\
67                 if ((cfg->method != method) && (method->wrapper_type == MONO_WRAPPER_NONE))\
68                         goto inline_failure;\
69         } while (0)
70 #define CHECK_CFG_EXCEPTION do {\
71                 if (cfg->exception_type != MONO_EXCEPTION_NONE)\
72                         goto exception_exit;\
73         } while (0)
74 #define METHOD_ACCESS_FAILURE do {      \
75                 char *method_fname = mono_method_full_name (method, TRUE);      \
76                 char *cil_method_fname = mono_method_full_name (cil_method, TRUE);      \
77                 cfg->exception_type = MONO_EXCEPTION_METHOD_ACCESS;     \
78                 cfg->exception_message = g_strdup_printf ("Method `%s' is inaccessible from method `%s'\n", cil_method_fname, method_fname);    \
79                 g_free (method_fname);  \
80                 g_free (cil_method_fname);      \
81                 goto exception_exit;    \
82         } while (0)
83 #define FIELD_ACCESS_FAILURE do {       \
84                 char *method_fname = mono_method_full_name (method, TRUE);      \
85                 char *field_fname = mono_field_full_name (field);       \
86                 cfg->exception_type = MONO_EXCEPTION_FIELD_ACCESS;      \
87                 cfg->exception_message = g_strdup_printf ("Field `%s' is inaccessible from method `%s'\n", field_fname, method_fname);  \
88                 g_free (method_fname);  \
89                 g_free (field_fname);   \
90                 goto exception_exit;    \
91         } while (0)
92 #define GENERIC_SHARING_FAILURE(opcode) do {            \
93                 if (cfg->generic_sharing_context) {     \
94             if (cfg->verbose_level > 2) \
95                             printf ("sharing failed for method %s.%s.%s/%d opcode %s line %d\n", method->klass->name_space, method->klass->name, method->name, method->signature->param_count, mono_opcode_name ((opcode)), __LINE__); \
96                         cfg->exception_type = MONO_EXCEPTION_GENERIC_SHARING_FAILED;    \
97                         goto exception_exit;    \
98                 }                       \
99         } while (0)
100
101 /* Determine whenever 'ins' represents a load of the 'this' argument */
102 #define MONO_CHECK_THIS(ins) (mono_method_signature (cfg->method)->hasthis && ((ins)->opcode == OP_MOVE) && ((ins)->sreg1 == cfg->args [0]->dreg))
103
104 static int ldind_to_load_membase (int opcode);
105 static int stind_to_store_membase (int opcode);
106
107 int mono_op_to_op_imm (int opcode);
108 int mono_op_to_op_imm_noemul (int opcode);
109
110 MonoInst* mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig, MonoInst **args);
111 void mini_emit_stobj (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *klass, gboolean native);
112 void mini_emit_initobj (MonoCompile *cfg, MonoInst *dest, const guchar *ip, MonoClass *klass);
113
114 /* helper methods signature */
115 extern MonoMethodSignature *helper_sig_class_init_trampoline;
116 extern MonoMethodSignature *helper_sig_domain_get;
117 extern MonoMethodSignature *helper_sig_generic_class_init_trampoline;
118 extern MonoMethodSignature *helper_sig_generic_class_init_trampoline_llvm;
119 extern MonoMethodSignature *helper_sig_rgctx_lazy_fetch_trampoline;
120 extern MonoMethodSignature *helper_sig_monitor_enter_exit_trampoline;
121 extern MonoMethodSignature *helper_sig_monitor_enter_exit_trampoline_llvm;
122
123 /*
124  * Instruction metadata
125  */
126 #ifdef MINI_OP
127 #undef MINI_OP
128 #endif
129 #ifdef MINI_OP3
130 #undef MINI_OP3
131 #endif
132 #define MINI_OP(a,b,dest,src1,src2) dest, src1, src2, ' ',
133 #define MINI_OP3(a,b,dest,src1,src2,src3) dest, src1, src2, src3,
134 #define NONE ' '
135 #define IREG 'i'
136 #define FREG 'f'
137 #define VREG 'v'
138 #define XREG 'x'
139 #if SIZEOF_REGISTER == 8
140 #define LREG IREG
141 #else
142 #define LREG 'l'
143 #endif
144 /* keep in sync with the enum in mini.h */
145 const char
146 ins_info[] = {
147 #include "mini-ops.h"
148 };
149 #undef MINI_OP
150 #undef MINI_OP3
151
152 #define MINI_OP(a,b,dest,src1,src2) ((src2) != NONE ? 2 : ((src1) != NONE ? 1 : 0)),
153 #define MINI_OP3(a,b,dest,src1,src2,src3) ((src3) != NONE ? 3 : ((src2) != NONE ? 2 : ((src1) != NONE ? 1 : 0))),
154 /* 
155  * This should contain the index of the last sreg + 1. This is not the same
156  * as the number of sregs for opcodes like IA64_CMP_EQ_IMM.
157  */
158 const gint8 ins_sreg_counts[] = {
159 #include "mini-ops.h"
160 };
161 #undef MINI_OP
162 #undef MINI_OP3
163
164 #define MONO_INIT_VARINFO(vi,id) do { \
165         (vi)->range.first_use.pos.bid = 0xffff; \
166         (vi)->reg = -1; \
167         (vi)->idx = (id); \
168 } while (0)
169
170 void
171 mono_inst_set_src_registers (MonoInst *ins, int *regs)
172 {
173         ins->sreg1 = regs [0];
174         ins->sreg2 = regs [1];
175         ins->sreg3 = regs [2];
176 }
177
178 guint32
179 mono_alloc_ireg (MonoCompile *cfg)
180 {
181         return alloc_ireg (cfg);
182 }
183
184 guint32
185 mono_alloc_freg (MonoCompile *cfg)
186 {
187         return alloc_freg (cfg);
188 }
189
190 guint32
191 mono_alloc_preg (MonoCompile *cfg)
192 {
193         return alloc_preg (cfg);
194 }
195
196 guint32
197 mono_alloc_dreg (MonoCompile *cfg, MonoStackType stack_type)
198 {
199         return alloc_dreg (cfg, stack_type);
200 }
201
202 guint
203 mono_type_to_regmove (MonoCompile *cfg, MonoType *type)
204 {
205         if (type->byref)
206                 return OP_MOVE;
207
208 handle_enum:
209         switch (type->type) {
210         case MONO_TYPE_I1:
211         case MONO_TYPE_U1:
212         case MONO_TYPE_BOOLEAN:
213                 return OP_MOVE;
214         case MONO_TYPE_I2:
215         case MONO_TYPE_U2:
216         case MONO_TYPE_CHAR:
217                 return OP_MOVE;
218         case MONO_TYPE_I4:
219         case MONO_TYPE_U4:
220                 return OP_MOVE;
221         case MONO_TYPE_I:
222         case MONO_TYPE_U:
223         case MONO_TYPE_PTR:
224         case MONO_TYPE_FNPTR:
225                 return OP_MOVE;
226         case MONO_TYPE_CLASS:
227         case MONO_TYPE_STRING:
228         case MONO_TYPE_OBJECT:
229         case MONO_TYPE_SZARRAY:
230         case MONO_TYPE_ARRAY:    
231                 return OP_MOVE;
232         case MONO_TYPE_I8:
233         case MONO_TYPE_U8:
234 #if SIZEOF_REGISTER == 8
235                 return OP_MOVE;
236 #else
237                 return OP_LMOVE;
238 #endif
239         case MONO_TYPE_R4:
240                 return OP_FMOVE;
241         case MONO_TYPE_R8:
242                 return OP_FMOVE;
243         case MONO_TYPE_VALUETYPE:
244                 if (type->data.klass->enumtype) {
245                         type = mono_class_enum_basetype (type->data.klass);
246                         goto handle_enum;
247                 }
248                 if (MONO_CLASS_IS_SIMD (cfg, mono_class_from_mono_type (type)))
249                         return OP_XMOVE;
250                 return OP_VMOVE;
251         case MONO_TYPE_TYPEDBYREF:
252                 return OP_VMOVE;
253         case MONO_TYPE_GENERICINST:
254                 type = &type->data.generic_class->container_class->byval_arg;
255                 goto handle_enum;
256         case MONO_TYPE_VAR:
257         case MONO_TYPE_MVAR:
258                 g_assert (cfg->generic_sharing_context);
259                 return OP_MOVE;
260         default:
261                 g_error ("unknown type 0x%02x in type_to_regstore", type->type);
262         }
263         return -1;
264 }
265
266 void
267 mono_print_bb (MonoBasicBlock *bb, const char *msg)
268 {
269         int i;
270         MonoInst *tree;
271
272         printf ("\n%s %d: [IN: ", msg, bb->block_num);
273         for (i = 0; i < bb->in_count; ++i)
274                 printf (" BB%d(%d)", bb->in_bb [i]->block_num, bb->in_bb [i]->dfn);
275         printf (", OUT: ");
276         for (i = 0; i < bb->out_count; ++i)
277                 printf (" BB%d(%d)", bb->out_bb [i]->block_num, bb->out_bb [i]->dfn);
278         printf (" ]\n");
279         for (tree = bb->code; tree; tree = tree->next)
280                 mono_print_ins_index (-1, tree);
281 }
282
283 /* 
284  * Can't put this at the beginning, since other files reference stuff from this
285  * file.
286  */
287 #ifndef DISABLE_JIT
288
289 #define UNVERIFIED do { if (mini_get_debug_options ()->break_on_unverified) G_BREAKPOINT (); else goto unverified; } while (0)
290
291 #define GET_BBLOCK(cfg,tblock,ip) do {  \
292                 (tblock) = cfg->cil_offset_to_bb [(ip) - cfg->cil_start]; \
293                 if (!(tblock)) {        \
294                         if ((ip) >= end || (ip) < header->code) UNVERIFIED; \
295             NEW_BBLOCK (cfg, (tblock)); \
296                         (tblock)->cil_code = (ip);      \
297                         ADD_BBLOCK (cfg, (tblock));     \
298                 } \
299         } while (0)
300
301 #if defined(TARGET_X86) || defined(TARGET_AMD64)
302 #define EMIT_NEW_X86_LEA(cfg,dest,sr1,sr2,shift,imm) do { \
303                 MONO_INST_NEW (cfg, dest, OP_X86_LEA); \
304                 (dest)->dreg = alloc_preg ((cfg)); \
305                 (dest)->sreg1 = (sr1); \
306                 (dest)->sreg2 = (sr2); \
307                 (dest)->inst_imm = (imm); \
308                 (dest)->backend.shift_amount = (shift); \
309                 MONO_ADD_INS ((cfg)->cbb, (dest)); \
310         } while (0)
311 #endif
312
313 #if SIZEOF_REGISTER == 8
314 #define ADD_WIDEN_OP(ins, arg1, arg2) do { \
315                 /* FIXME: Need to add many more cases */ \
316                 if ((arg1)->type == STACK_PTR && (arg2)->type == STACK_I4) {    \
317                         MonoInst *widen; \
318                         int dr = alloc_preg (cfg); \
319                         EMIT_NEW_UNALU (cfg, widen, OP_SEXT_I4, dr, (arg2)->dreg); \
320                         (ins)->sreg2 = widen->dreg; \
321                 } \
322         } while (0)
323 #else
324 #define ADD_WIDEN_OP(ins, arg1, arg2)
325 #endif
326
327 #define ADD_BINOP(op) do {      \
328                 MONO_INST_NEW (cfg, ins, (op)); \
329                 sp -= 2;        \
330                 ins->sreg1 = sp [0]->dreg;      \
331                 ins->sreg2 = sp [1]->dreg;      \
332                 type_from_op (ins, sp [0], sp [1]);     \
333                 CHECK_TYPE (ins);       \
334                 /* Have to insert a widening op */               \
335         ADD_WIDEN_OP (ins, sp [0], sp [1]); \
336         ins->dreg = alloc_dreg ((cfg), (ins)->type); \
337         MONO_ADD_INS ((cfg)->cbb, (ins)); \
338         *sp++ = mono_decompose_opcode ((cfg), (ins)); \
339         } while (0)
340
341 #define ADD_UNOP(op) do {       \
342                 MONO_INST_NEW (cfg, ins, (op)); \
343                 sp--;   \
344                 ins->sreg1 = sp [0]->dreg;      \
345                 type_from_op (ins, sp [0], NULL);       \
346                 CHECK_TYPE (ins);       \
347         (ins)->dreg = alloc_dreg ((cfg), (ins)->type); \
348         MONO_ADD_INS ((cfg)->cbb, (ins)); \
349                 *sp++ = mono_decompose_opcode (cfg, ins); \
350         } while (0)
351
352 #define ADD_BINCOND(next_block) do {    \
353                 MonoInst *cmp;  \
354                 sp -= 2; \
355                 MONO_INST_NEW(cfg, cmp, OP_COMPARE);    \
356                 cmp->sreg1 = sp [0]->dreg;      \
357                 cmp->sreg2 = sp [1]->dreg;      \
358                 type_from_op (cmp, sp [0], sp [1]);     \
359                 CHECK_TYPE (cmp);       \
360                 type_from_op (ins, sp [0], sp [1]);     \
361                 ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);      \
362                 GET_BBLOCK (cfg, tblock, target);               \
363                 link_bblock (cfg, bblock, tblock);      \
364                 ins->inst_true_bb = tblock;     \
365                 if ((next_block)) {     \
366                         link_bblock (cfg, bblock, (next_block));        \
367                         ins->inst_false_bb = (next_block);      \
368                         start_new_bblock = 1;   \
369                 } else {        \
370                         GET_BBLOCK (cfg, tblock, ip);           \
371                         link_bblock (cfg, bblock, tblock);      \
372                         ins->inst_false_bb = tblock;    \
373                         start_new_bblock = 2;   \
374                 }       \
375                 if (sp != stack_start) {                                                                        \
376                     handle_stack_args (cfg, stack_start, sp - stack_start); \
377                         CHECK_UNVERIFIABLE (cfg); \
378                 } \
379         MONO_ADD_INS (bblock, cmp); \
380                 MONO_ADD_INS (bblock, ins);     \
381         } while (0)
382
383 /* *
384  * link_bblock: Links two basic blocks
385  *
386  * links two basic blocks in the control flow graph, the 'from'
387  * argument is the starting block and the 'to' argument is the block
388  * the control flow ends to after 'from'.
389  */
390 static void
391 link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
392 {
393         MonoBasicBlock **newa;
394         int i, found;
395
396 #if 0
397         if (from->cil_code) {
398                 if (to->cil_code)
399                         printf ("edge from IL%04x to IL_%04x\n", from->cil_code - cfg->cil_code, to->cil_code - cfg->cil_code);
400                 else
401                         printf ("edge from IL%04x to exit\n", from->cil_code - cfg->cil_code);
402         } else {
403                 if (to->cil_code)
404                         printf ("edge from entry to IL_%04x\n", to->cil_code - cfg->cil_code);
405                 else
406                         printf ("edge from entry to exit\n");
407         }
408 #endif
409
410         found = FALSE;
411         for (i = 0; i < from->out_count; ++i) {
412                 if (to == from->out_bb [i]) {
413                         found = TRUE;
414                         break;
415                 }
416         }
417         if (!found) {
418                 newa = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (from->out_count + 1));
419                 for (i = 0; i < from->out_count; ++i) {
420                         newa [i] = from->out_bb [i];
421                 }
422                 newa [i] = to;
423                 from->out_count++;
424                 from->out_bb = newa;
425         }
426
427         found = FALSE;
428         for (i = 0; i < to->in_count; ++i) {
429                 if (from == to->in_bb [i]) {
430                         found = TRUE;
431                         break;
432                 }
433         }
434         if (!found) {
435                 newa = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (to->in_count + 1));
436                 for (i = 0; i < to->in_count; ++i) {
437                         newa [i] = to->in_bb [i];
438                 }
439                 newa [i] = from;
440                 to->in_count++;
441                 to->in_bb = newa;
442         }
443 }
444
445 void
446 mono_link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
447 {
448         link_bblock (cfg, from, to);
449 }
450
451 /**
452  * mono_find_block_region:
453  *
454  *   We mark each basic block with a region ID. We use that to avoid BB
455  *   optimizations when blocks are in different regions.
456  *
457  * Returns:
458  *   A region token that encodes where this region is, and information
459  *   about the clause owner for this block.
460  *
461  *   The region encodes the try/catch/filter clause that owns this block
462  *   as well as the type.  -1 is a special value that represents a block
463  *   that is in none of try/catch/filter.
464  */
465 static int
466 mono_find_block_region (MonoCompile *cfg, int offset)
467 {
468         MonoMethodHeader *header = cfg->header;
469         MonoExceptionClause *clause;
470         int i;
471
472         for (i = 0; i < header->num_clauses; ++i) {
473                 clause = &header->clauses [i];
474                 if ((clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) && (offset >= clause->data.filter_offset) &&
475                     (offset < (clause->handler_offset)))
476                         return ((i + 1) << 8) | MONO_REGION_FILTER | clause->flags;
477                            
478                 if (MONO_OFFSET_IN_HANDLER (clause, offset)) {
479                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY)
480                                 return ((i + 1) << 8) | MONO_REGION_FINALLY | clause->flags;
481                         else if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
482                                 return ((i + 1) << 8) | MONO_REGION_FAULT | clause->flags;
483                         else
484                                 return ((i + 1) << 8) | MONO_REGION_CATCH | clause->flags;
485                 }
486
487                 if (MONO_OFFSET_IN_CLAUSE (clause, offset))
488                         return ((i + 1) << 8) | clause->flags;
489         }
490
491         return -1;
492 }
493
494 static GList*
495 mono_find_final_block (MonoCompile *cfg, unsigned char *ip, unsigned char *target, int type)
496 {
497         MonoMethodHeader *header = cfg->header;
498         MonoExceptionClause *clause;
499         int i;
500         GList *res = NULL;
501
502         for (i = 0; i < header->num_clauses; ++i) {
503                 clause = &header->clauses [i];
504                 if (MONO_OFFSET_IN_CLAUSE (clause, (ip - header->code)) && 
505                     (!MONO_OFFSET_IN_CLAUSE (clause, (target - header->code)))) {
506                         if (clause->flags == type)
507                                 res = g_list_append (res, clause);
508                 }
509         }
510         return res;
511 }
512
513 static void
514 mono_create_spvar_for_region (MonoCompile *cfg, int region)
515 {
516         MonoInst *var;
517
518         var = g_hash_table_lookup (cfg->spvars, GINT_TO_POINTER (region));
519         if (var)
520                 return;
521
522         var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
523         /* prevent it from being register allocated */
524         var->flags |= MONO_INST_INDIRECT;
525
526         g_hash_table_insert (cfg->spvars, GINT_TO_POINTER (region), var);
527 }
528
529 MonoInst *
530 mono_find_exvar_for_offset (MonoCompile *cfg, int offset)
531 {
532         return g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
533 }
534
535 static MonoInst*
536 mono_create_exvar_for_offset (MonoCompile *cfg, int offset)
537 {
538         MonoInst *var;
539
540         var = g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
541         if (var)
542                 return var;
543
544         var = mono_compile_create_var (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL);
545         /* prevent it from being register allocated */
546         var->flags |= MONO_INST_INDIRECT;
547
548         g_hash_table_insert (cfg->exvars, GINT_TO_POINTER (offset), var);
549
550         return var;
551 }
552
553 /*
554  * Returns the type used in the eval stack when @type is loaded.
555  * FIXME: return a MonoType/MonoClass for the byref and VALUETYPE cases.
556  */
557 void
558 type_to_eval_stack_type (MonoCompile *cfg, MonoType *type, MonoInst *inst)
559 {
560         MonoClass *klass;
561
562         inst->klass = klass = mono_class_from_mono_type (type);
563         if (type->byref) {
564                 inst->type = STACK_MP;
565                 return;
566         }
567
568 handle_enum:
569         switch (type->type) {
570         case MONO_TYPE_VOID:
571                 inst->type = STACK_INV;
572                 return;
573         case MONO_TYPE_I1:
574         case MONO_TYPE_U1:
575         case MONO_TYPE_BOOLEAN:
576         case MONO_TYPE_I2:
577         case MONO_TYPE_U2:
578         case MONO_TYPE_CHAR:
579         case MONO_TYPE_I4:
580         case MONO_TYPE_U4:
581                 inst->type = STACK_I4;
582                 return;
583         case MONO_TYPE_I:
584         case MONO_TYPE_U:
585         case MONO_TYPE_PTR:
586         case MONO_TYPE_FNPTR:
587                 inst->type = STACK_PTR;
588                 return;
589         case MONO_TYPE_CLASS:
590         case MONO_TYPE_STRING:
591         case MONO_TYPE_OBJECT:
592         case MONO_TYPE_SZARRAY:
593         case MONO_TYPE_ARRAY:    
594                 inst->type = STACK_OBJ;
595                 return;
596         case MONO_TYPE_I8:
597         case MONO_TYPE_U8:
598                 inst->type = STACK_I8;
599                 return;
600         case MONO_TYPE_R4:
601         case MONO_TYPE_R8:
602                 inst->type = STACK_R8;
603                 return;
604         case MONO_TYPE_VALUETYPE:
605                 if (type->data.klass->enumtype) {
606                         type = mono_class_enum_basetype (type->data.klass);
607                         goto handle_enum;
608                 } else {
609                         inst->klass = klass;
610                         inst->type = STACK_VTYPE;
611                         return;
612                 }
613         case MONO_TYPE_TYPEDBYREF:
614                 inst->klass = mono_defaults.typed_reference_class;
615                 inst->type = STACK_VTYPE;
616                 return;
617         case MONO_TYPE_GENERICINST:
618                 type = &type->data.generic_class->container_class->byval_arg;
619                 goto handle_enum;
620         case MONO_TYPE_VAR :
621         case MONO_TYPE_MVAR :
622                 /* FIXME: all the arguments must be references for now,
623                  * later look inside cfg and see if the arg num is
624                  * really a reference
625                  */
626                 g_assert (cfg->generic_sharing_context);
627                 inst->type = STACK_OBJ;
628                 return;
629         default:
630                 g_error ("unknown type 0x%02x in eval stack type", type->type);
631         }
632 }
633
634 /*
635  * The following tables are used to quickly validate the IL code in type_from_op ().
636  */
637 static const char
638 bin_num_table [STACK_MAX] [STACK_MAX] = {
639         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
640         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
641         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
642         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
643         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_R8,  STACK_INV, STACK_INV, STACK_INV},
644         {STACK_INV, STACK_MP,  STACK_INV, STACK_MP,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV},
645         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
646         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
647 };
648
649 static const char 
650 neg_table [] = {
651         STACK_INV, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_INV, STACK_INV, STACK_INV
652 };
653
654 /* reduce the size of this table */
655 static const char
656 bin_int_table [STACK_MAX] [STACK_MAX] = {
657         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
658         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
659         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
660         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
661         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
662         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
663         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
664         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
665 };
666
667 static const char
668 bin_comp_table [STACK_MAX] [STACK_MAX] = {
669 /*      Inv i  L  p  F  &  O  vt */
670         {0},
671         {0, 1, 0, 1, 0, 0, 0, 0}, /* i, int32 */
672         {0, 0, 1, 0, 0, 0, 0, 0}, /* L, int64 */
673         {0, 1, 0, 1, 0, 2, 4, 0}, /* p, ptr */
674         {0, 0, 0, 0, 1, 0, 0, 0}, /* F, R8 */
675         {0, 0, 0, 2, 0, 1, 0, 0}, /* &, managed pointer */
676         {0, 0, 0, 4, 0, 0, 3, 0}, /* O, reference */
677         {0, 0, 0, 0, 0, 0, 0, 0}, /* vt value type */
678 };
679
680 /* reduce the size of this table */
681 static const char
682 shift_table [STACK_MAX] [STACK_MAX] = {
683         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
684         {STACK_INV, STACK_I4,  STACK_INV, STACK_I4,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
685         {STACK_INV, STACK_I8,  STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
686         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
687         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
688         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
689         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
690         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
691 };
692
693 /*
694  * Tables to map from the non-specific opcode to the matching
695  * type-specific opcode.
696  */
697 /* handles from CEE_ADD to CEE_SHR_UN (CEE_REM_UN for floats) */
698 static const guint16
699 binops_op_map [STACK_MAX] = {
700         0, OP_IADD-CEE_ADD, OP_LADD-CEE_ADD, OP_PADD-CEE_ADD, OP_FADD-CEE_ADD, OP_PADD-CEE_ADD
701 };
702
703 /* handles from CEE_NEG to CEE_CONV_U8 */
704 static const guint16
705 unops_op_map [STACK_MAX] = {
706         0, OP_INEG-CEE_NEG, OP_LNEG-CEE_NEG, OP_PNEG-CEE_NEG, OP_FNEG-CEE_NEG, OP_PNEG-CEE_NEG
707 };
708
709 /* handles from CEE_CONV_U2 to CEE_SUB_OVF_UN */
710 static const guint16
711 ovfops_op_map [STACK_MAX] = {
712         0, OP_ICONV_TO_U2-CEE_CONV_U2, OP_LCONV_TO_U2-CEE_CONV_U2, OP_PCONV_TO_U2-CEE_CONV_U2, OP_FCONV_TO_U2-CEE_CONV_U2, OP_PCONV_TO_U2-CEE_CONV_U2, OP_PCONV_TO_U2-CEE_CONV_U2
713 };
714
715 /* handles from CEE_CONV_OVF_I1_UN to CEE_CONV_OVF_U_UN */
716 static const guint16
717 ovf2ops_op_map [STACK_MAX] = {
718         0, OP_ICONV_TO_OVF_I1_UN-CEE_CONV_OVF_I1_UN, OP_LCONV_TO_OVF_I1_UN-CEE_CONV_OVF_I1_UN, OP_PCONV_TO_OVF_I1_UN-CEE_CONV_OVF_I1_UN, OP_FCONV_TO_OVF_I1_UN-CEE_CONV_OVF_I1_UN, OP_PCONV_TO_OVF_I1_UN-CEE_CONV_OVF_I1_UN
719 };
720
721 /* handles from CEE_CONV_OVF_I1 to CEE_CONV_OVF_U8 */
722 static const guint16
723 ovf3ops_op_map [STACK_MAX] = {
724         0, OP_ICONV_TO_OVF_I1-CEE_CONV_OVF_I1, OP_LCONV_TO_OVF_I1-CEE_CONV_OVF_I1, OP_PCONV_TO_OVF_I1-CEE_CONV_OVF_I1, OP_FCONV_TO_OVF_I1-CEE_CONV_OVF_I1, OP_PCONV_TO_OVF_I1-CEE_CONV_OVF_I1
725 };
726
727 /* handles from CEE_BEQ to CEE_BLT_UN */
728 static const guint16
729 beqops_op_map [STACK_MAX] = {
730         0, OP_IBEQ-CEE_BEQ, OP_LBEQ-CEE_BEQ, OP_PBEQ-CEE_BEQ, OP_FBEQ-CEE_BEQ, OP_PBEQ-CEE_BEQ, OP_PBEQ-CEE_BEQ
731 };
732
733 /* handles from CEE_CEQ to CEE_CLT_UN */
734 static const guint16
735 ceqops_op_map [STACK_MAX] = {
736         0, OP_ICEQ-OP_CEQ, OP_LCEQ-OP_CEQ, OP_PCEQ-OP_CEQ, OP_FCEQ-OP_CEQ, OP_PCEQ-OP_CEQ, OP_PCEQ-OP_CEQ
737 };
738
739 /*
740  * Sets ins->type (the type on the eval stack) according to the
741  * type of the opcode and the arguments to it.
742  * Invalid IL code is marked by setting ins->type to the invalid value STACK_INV.
743  *
744  * FIXME: this function sets ins->type unconditionally in some cases, but
745  * it should set it to invalid for some types (a conv.x on an object)
746  */
747 static void
748 type_from_op (MonoInst *ins, MonoInst *src1, MonoInst *src2) {
749
750         switch (ins->opcode) {
751         /* binops */
752         case CEE_ADD:
753         case CEE_SUB:
754         case CEE_MUL:
755         case CEE_DIV:
756         case CEE_REM:
757                 /* FIXME: check unverifiable args for STACK_MP */
758                 ins->type = bin_num_table [src1->type] [src2->type];
759                 ins->opcode += binops_op_map [ins->type];
760                 break;
761         case CEE_DIV_UN:
762         case CEE_REM_UN:
763         case CEE_AND:
764         case CEE_OR:
765         case CEE_XOR:
766                 ins->type = bin_int_table [src1->type] [src2->type];
767                 ins->opcode += binops_op_map [ins->type];
768                 break;
769         case CEE_SHL:
770         case CEE_SHR:
771         case CEE_SHR_UN:
772                 ins->type = shift_table [src1->type] [src2->type];
773                 ins->opcode += binops_op_map [ins->type];
774                 break;
775         case OP_COMPARE:
776         case OP_LCOMPARE:
777         case OP_ICOMPARE:
778                 ins->type = bin_comp_table [src1->type] [src2->type] ? STACK_I4: STACK_INV;
779                 if ((src1->type == STACK_I8) || ((SIZEOF_REGISTER == 8) && ((src1->type == STACK_PTR) || (src1->type == STACK_OBJ) || (src1->type == STACK_MP))))
780                         ins->opcode = OP_LCOMPARE;
781                 else if (src1->type == STACK_R8)
782                         ins->opcode = OP_FCOMPARE;
783                 else
784                         ins->opcode = OP_ICOMPARE;
785                 break;
786         case OP_ICOMPARE_IMM:
787                 ins->type = bin_comp_table [src1->type] [src1->type] ? STACK_I4 : STACK_INV;
788                 if ((src1->type == STACK_I8) || ((SIZEOF_REGISTER == 8) && ((src1->type == STACK_PTR) || (src1->type == STACK_OBJ) || (src1->type == STACK_MP))))
789                         ins->opcode = OP_LCOMPARE_IMM;          
790                 break;
791         case CEE_BEQ:
792         case CEE_BGE:
793         case CEE_BGT:
794         case CEE_BLE:
795         case CEE_BLT:
796         case CEE_BNE_UN:
797         case CEE_BGE_UN:
798         case CEE_BGT_UN:
799         case CEE_BLE_UN:
800         case CEE_BLT_UN:
801                 ins->opcode += beqops_op_map [src1->type];
802                 break;
803         case OP_CEQ:
804                 ins->type = bin_comp_table [src1->type] [src2->type] ? STACK_I4: STACK_INV;
805                 ins->opcode += ceqops_op_map [src1->type];
806                 break;
807         case OP_CGT:
808         case OP_CGT_UN:
809         case OP_CLT:
810         case OP_CLT_UN:
811                 ins->type = (bin_comp_table [src1->type] [src2->type] & 1) ? STACK_I4: STACK_INV;
812                 ins->opcode += ceqops_op_map [src1->type];
813                 break;
814         /* unops */
815         case CEE_NEG:
816                 ins->type = neg_table [src1->type];
817                 ins->opcode += unops_op_map [ins->type];
818                 break;
819         case CEE_NOT:
820                 if (src1->type >= STACK_I4 && src1->type <= STACK_PTR)
821                         ins->type = src1->type;
822                 else
823                         ins->type = STACK_INV;
824                 ins->opcode += unops_op_map [ins->type];
825                 break;
826         case CEE_CONV_I1:
827         case CEE_CONV_I2:
828         case CEE_CONV_I4:
829         case CEE_CONV_U4:
830                 ins->type = STACK_I4;
831                 ins->opcode += unops_op_map [src1->type];
832                 break;
833         case CEE_CONV_R_UN:
834                 ins->type = STACK_R8;
835                 switch (src1->type) {
836                 case STACK_I4:
837                 case STACK_PTR:
838                         ins->opcode = OP_ICONV_TO_R_UN;
839                         break;
840                 case STACK_I8:
841                         ins->opcode = OP_LCONV_TO_R_UN; 
842                         break;
843                 }
844                 break;
845         case CEE_CONV_OVF_I1:
846         case CEE_CONV_OVF_U1:
847         case CEE_CONV_OVF_I2:
848         case CEE_CONV_OVF_U2:
849         case CEE_CONV_OVF_I4:
850         case CEE_CONV_OVF_U4:
851                 ins->type = STACK_I4;
852                 ins->opcode += ovf3ops_op_map [src1->type];
853                 break;
854         case CEE_CONV_OVF_I_UN:
855         case CEE_CONV_OVF_U_UN:
856                 ins->type = STACK_PTR;
857                 ins->opcode += ovf2ops_op_map [src1->type];
858                 break;
859         case CEE_CONV_OVF_I1_UN:
860         case CEE_CONV_OVF_I2_UN:
861         case CEE_CONV_OVF_I4_UN:
862         case CEE_CONV_OVF_U1_UN:
863         case CEE_CONV_OVF_U2_UN:
864         case CEE_CONV_OVF_U4_UN:
865                 ins->type = STACK_I4;
866                 ins->opcode += ovf2ops_op_map [src1->type];
867                 break;
868         case CEE_CONV_U:
869                 ins->type = STACK_PTR;
870                 switch (src1->type) {
871                 case STACK_I4:
872                         ins->opcode = OP_ICONV_TO_U;
873                         break;
874                 case STACK_PTR:
875                 case STACK_MP:
876 #if SIZEOF_REGISTER == 8
877                         ins->opcode = OP_LCONV_TO_U;
878 #else
879                         ins->opcode = OP_MOVE;
880 #endif
881                         break;
882                 case STACK_I8:
883                         ins->opcode = OP_LCONV_TO_U;
884                         break;
885                 case STACK_R8:
886                         ins->opcode = OP_FCONV_TO_U;
887                         break;
888                 }
889                 break;
890         case CEE_CONV_I8:
891         case CEE_CONV_U8:
892                 ins->type = STACK_I8;
893                 ins->opcode += unops_op_map [src1->type];
894                 break;
895         case CEE_CONV_OVF_I8:
896         case CEE_CONV_OVF_U8:
897                 ins->type = STACK_I8;
898                 ins->opcode += ovf3ops_op_map [src1->type];
899                 break;
900         case CEE_CONV_OVF_U8_UN:
901         case CEE_CONV_OVF_I8_UN:
902                 ins->type = STACK_I8;
903                 ins->opcode += ovf2ops_op_map [src1->type];
904                 break;
905         case CEE_CONV_R4:
906         case CEE_CONV_R8:
907                 ins->type = STACK_R8;
908                 ins->opcode += unops_op_map [src1->type];
909                 break;
910         case OP_CKFINITE:
911                 ins->type = STACK_R8;           
912                 break;
913         case CEE_CONV_U2:
914         case CEE_CONV_U1:
915                 ins->type = STACK_I4;
916                 ins->opcode += ovfops_op_map [src1->type];
917                 break;
918         case CEE_CONV_I:
919         case CEE_CONV_OVF_I:
920         case CEE_CONV_OVF_U:
921                 ins->type = STACK_PTR;
922                 ins->opcode += ovfops_op_map [src1->type];
923                 break;
924         case CEE_ADD_OVF:
925         case CEE_ADD_OVF_UN:
926         case CEE_MUL_OVF:
927         case CEE_MUL_OVF_UN:
928         case CEE_SUB_OVF:
929         case CEE_SUB_OVF_UN:
930                 ins->type = bin_num_table [src1->type] [src2->type];
931                 ins->opcode += ovfops_op_map [src1->type];
932                 if (ins->type == STACK_R8)
933                         ins->type = STACK_INV;
934                 break;
935         case OP_LOAD_MEMBASE:
936                 ins->type = STACK_PTR;
937                 break;
938         case OP_LOADI1_MEMBASE:
939         case OP_LOADU1_MEMBASE:
940         case OP_LOADI2_MEMBASE:
941         case OP_LOADU2_MEMBASE:
942         case OP_LOADI4_MEMBASE:
943         case OP_LOADU4_MEMBASE:
944                 ins->type = STACK_PTR;
945                 break;
946         case OP_LOADI8_MEMBASE:
947                 ins->type = STACK_I8;
948                 break;
949         case OP_LOADR4_MEMBASE:
950         case OP_LOADR8_MEMBASE:
951                 ins->type = STACK_R8;
952                 break;
953         default:
954                 g_error ("opcode 0x%04x not handled in type from op", ins->opcode);
955                 break;
956         }
957
958         if (ins->type == STACK_MP)
959                 ins->klass = mono_defaults.object_class;
960 }
961
962 static const char 
963 ldind_type [] = {
964         STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_R8, STACK_OBJ
965 };
966
967 #if 0
968
969 static const char
970 param_table [STACK_MAX] [STACK_MAX] = {
971         {0},
972 };
973
974 static int
975 check_values_to_signature (MonoInst *args, MonoType *this, MonoMethodSignature *sig) {
976         int i;
977
978         if (sig->hasthis) {
979                 switch (args->type) {
980                 case STACK_I4:
981                 case STACK_I8:
982                 case STACK_R8:
983                 case STACK_VTYPE:
984                 case STACK_INV:
985                         return 0;
986                 }
987                 args++;
988         }
989         for (i = 0; i < sig->param_count; ++i) {
990                 switch (args [i].type) {
991                 case STACK_INV:
992                         return 0;
993                 case STACK_MP:
994                         if (!sig->params [i]->byref)
995                                 return 0;
996                         continue;
997                 case STACK_OBJ:
998                         if (sig->params [i]->byref)
999                                 return 0;
1000                         switch (sig->params [i]->type) {
1001                         case MONO_TYPE_CLASS:
1002                         case MONO_TYPE_STRING:
1003                         case MONO_TYPE_OBJECT:
1004                         case MONO_TYPE_SZARRAY:
1005                         case MONO_TYPE_ARRAY:
1006                                 break;
1007                         default:
1008                                 return 0;
1009                         }
1010                         continue;
1011                 case STACK_R8:
1012                         if (sig->params [i]->byref)
1013                                 return 0;
1014                         if (sig->params [i]->type != MONO_TYPE_R4 && sig->params [i]->type != MONO_TYPE_R8)
1015                                 return 0;
1016                         continue;
1017                 case STACK_PTR:
1018                 case STACK_I4:
1019                 case STACK_I8:
1020                 case STACK_VTYPE:
1021                         break;
1022                 }
1023                 /*if (!param_table [args [i].type] [sig->params [i]->type])
1024                         return 0;*/
1025         }
1026         return 1;
1027 }
1028 #endif
1029
1030 /*
1031  * When we need a pointer to the current domain many times in a method, we
1032  * call mono_domain_get() once and we store the result in a local variable.
1033  * This function returns the variable that represents the MonoDomain*.
1034  */
1035 inline static MonoInst *
1036 mono_get_domainvar (MonoCompile *cfg)
1037 {
1038         if (!cfg->domainvar)
1039                 cfg->domainvar = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1040         return cfg->domainvar;
1041 }
1042
1043 /*
1044  * The got_var contains the address of the Global Offset Table when AOT 
1045  * compiling.
1046  */
1047 MonoInst *
1048 mono_get_got_var (MonoCompile *cfg)
1049 {
1050 #ifdef MONO_ARCH_NEED_GOT_VAR
1051         if (!cfg->compile_aot)
1052                 return NULL;
1053         if (!cfg->got_var) {
1054                 cfg->got_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1055         }
1056         return cfg->got_var;
1057 #else
1058         return NULL;
1059 #endif
1060 }
1061
1062 static MonoInst *
1063 mono_get_vtable_var (MonoCompile *cfg)
1064 {
1065         g_assert (cfg->generic_sharing_context);
1066
1067         if (!cfg->rgctx_var) {
1068                 cfg->rgctx_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1069                 /* force the var to be stack allocated */
1070                 cfg->rgctx_var->flags |= MONO_INST_INDIRECT;
1071         }
1072
1073         return cfg->rgctx_var;
1074 }
1075
1076 static MonoType*
1077 type_from_stack_type (MonoInst *ins) {
1078         switch (ins->type) {
1079         case STACK_I4: return &mono_defaults.int32_class->byval_arg;
1080         case STACK_I8: return &mono_defaults.int64_class->byval_arg;
1081         case STACK_PTR: return &mono_defaults.int_class->byval_arg;
1082         case STACK_R8: return &mono_defaults.double_class->byval_arg;
1083         case STACK_MP:
1084                 return &ins->klass->this_arg;
1085         case STACK_OBJ: return &mono_defaults.object_class->byval_arg;
1086         case STACK_VTYPE: return &ins->klass->byval_arg;
1087         default:
1088                 g_error ("stack type %d to monotype not handled\n", ins->type);
1089         }
1090         return NULL;
1091 }
1092
1093 static G_GNUC_UNUSED int
1094 type_to_stack_type (MonoType *t)
1095 {
1096         t = mono_type_get_underlying_type (t);
1097         switch (t->type) {
1098         case MONO_TYPE_I1:
1099         case MONO_TYPE_U1:
1100         case MONO_TYPE_BOOLEAN:
1101         case MONO_TYPE_I2:
1102         case MONO_TYPE_U2:
1103         case MONO_TYPE_CHAR:
1104         case MONO_TYPE_I4:
1105         case MONO_TYPE_U4:
1106                 return STACK_I4;
1107         case MONO_TYPE_I:
1108         case MONO_TYPE_U:
1109         case MONO_TYPE_PTR:
1110         case MONO_TYPE_FNPTR:
1111                 return STACK_PTR;
1112         case MONO_TYPE_CLASS:
1113         case MONO_TYPE_STRING:
1114         case MONO_TYPE_OBJECT:
1115         case MONO_TYPE_SZARRAY:
1116         case MONO_TYPE_ARRAY:    
1117                 return STACK_OBJ;
1118         case MONO_TYPE_I8:
1119         case MONO_TYPE_U8:
1120                 return STACK_I8;
1121         case MONO_TYPE_R4:
1122         case MONO_TYPE_R8:
1123                 return STACK_R8;
1124         case MONO_TYPE_VALUETYPE:
1125         case MONO_TYPE_TYPEDBYREF:
1126                 return STACK_VTYPE;
1127         case MONO_TYPE_GENERICINST:
1128                 if (mono_type_generic_inst_is_valuetype (t))
1129                         return STACK_VTYPE;
1130                 else
1131                         return STACK_OBJ;
1132                 break;
1133         default:
1134                 g_assert_not_reached ();
1135         }
1136
1137         return -1;
1138 }
1139
1140 static MonoClass*
1141 array_access_to_klass (int opcode)
1142 {
1143         switch (opcode) {
1144         case CEE_LDELEM_U1:
1145                 return mono_defaults.byte_class;
1146         case CEE_LDELEM_U2:
1147                 return mono_defaults.uint16_class;
1148         case CEE_LDELEM_I:
1149         case CEE_STELEM_I:
1150                 return mono_defaults.int_class;
1151         case CEE_LDELEM_I1:
1152         case CEE_STELEM_I1:
1153                 return mono_defaults.sbyte_class;
1154         case CEE_LDELEM_I2:
1155         case CEE_STELEM_I2:
1156                 return mono_defaults.int16_class;
1157         case CEE_LDELEM_I4:
1158         case CEE_STELEM_I4:
1159                 return mono_defaults.int32_class;
1160         case CEE_LDELEM_U4:
1161                 return mono_defaults.uint32_class;
1162         case CEE_LDELEM_I8:
1163         case CEE_STELEM_I8:
1164                 return mono_defaults.int64_class;
1165         case CEE_LDELEM_R4:
1166         case CEE_STELEM_R4:
1167                 return mono_defaults.single_class;
1168         case CEE_LDELEM_R8:
1169         case CEE_STELEM_R8:
1170                 return mono_defaults.double_class;
1171         case CEE_LDELEM_REF:
1172         case CEE_STELEM_REF:
1173                 return mono_defaults.object_class;
1174         default:
1175                 g_assert_not_reached ();
1176         }
1177         return NULL;
1178 }
1179
1180 /*
1181  * We try to share variables when possible
1182  */
1183 static MonoInst *
1184 mono_compile_get_interface_var (MonoCompile *cfg, int slot, MonoInst *ins)
1185 {
1186         MonoInst *res;
1187         int pos, vnum;
1188
1189         /* inlining can result in deeper stacks */ 
1190         if (slot >= cfg->header->max_stack)
1191                 return mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1192
1193         pos = ins->type - 1 + slot * STACK_MAX;
1194
1195         switch (ins->type) {
1196         case STACK_I4:
1197         case STACK_I8:
1198         case STACK_R8:
1199         case STACK_PTR:
1200         case STACK_MP:
1201         case STACK_OBJ:
1202                 if ((vnum = cfg->intvars [pos]))
1203                         return cfg->varinfo [vnum];
1204                 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1205                 cfg->intvars [pos] = res->inst_c0;
1206                 break;
1207         default:
1208                 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1209         }
1210         return res;
1211 }
1212
1213 static void
1214 mono_save_token_info (MonoCompile *cfg, MonoImage *image, guint32 token, gpointer key)
1215 {
1216         /* 
1217          * Don't use this if a generic_context is set, since that means AOT can't
1218          * look up the method using just the image+token.
1219          * table == 0 means this is a reference made from a wrapper.
1220          */
1221         if (cfg->compile_aot && !cfg->generic_context && (mono_metadata_token_table (token) > 0)) {
1222                 MonoJumpInfoToken *jump_info_token = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoToken));
1223                 jump_info_token->image = image;
1224                 jump_info_token->token = token;
1225                 g_hash_table_insert (cfg->token_info_hash, key, jump_info_token);
1226         }
1227 }
1228
1229 /*
1230  * This function is called to handle items that are left on the evaluation stack
1231  * at basic block boundaries. What happens is that we save the values to local variables
1232  * and we reload them later when first entering the target basic block (with the
1233  * handle_loaded_temps () function).
1234  * A single joint point will use the same variables (stored in the array bb->out_stack or
1235  * bb->in_stack, if the basic block is before or after the joint point).
1236  *
1237  * This function needs to be called _before_ emitting the last instruction of
1238  * the bb (i.e. before emitting a branch).
1239  * If the stack merge fails at a join point, cfg->unverifiable is set.
1240  */
1241 static void
1242 handle_stack_args (MonoCompile *cfg, MonoInst **sp, int count)
1243 {
1244         int i, bindex;
1245         MonoBasicBlock *bb = cfg->cbb;
1246         MonoBasicBlock *outb;
1247         MonoInst *inst, **locals;
1248         gboolean found;
1249
1250         if (!count)
1251                 return;
1252         if (cfg->verbose_level > 3)
1253                 printf ("%d item(s) on exit from B%d\n", count, bb->block_num);
1254         if (!bb->out_scount) {
1255                 bb->out_scount = count;
1256                 //printf ("bblock %d has out:", bb->block_num);
1257                 found = FALSE;
1258                 for (i = 0; i < bb->out_count; ++i) {
1259                         outb = bb->out_bb [i];
1260                         /* exception handlers are linked, but they should not be considered for stack args */
1261                         if (outb->flags & BB_EXCEPTION_HANDLER)
1262                                 continue;
1263                         //printf (" %d", outb->block_num);
1264                         if (outb->in_stack) {
1265                                 found = TRUE;
1266                                 bb->out_stack = outb->in_stack;
1267                                 break;
1268                         }
1269                 }
1270                 //printf ("\n");
1271                 if (!found) {
1272                         bb->out_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * count);
1273                         for (i = 0; i < count; ++i) {
1274                                 /* 
1275                                  * try to reuse temps already allocated for this purpouse, if they occupy the same
1276                                  * stack slot and if they are of the same type.
1277                                  * This won't cause conflicts since if 'local' is used to 
1278                                  * store one of the values in the in_stack of a bblock, then
1279                                  * the same variable will be used for the same outgoing stack 
1280                                  * slot as well. 
1281                                  * This doesn't work when inlining methods, since the bblocks
1282                                  * in the inlined methods do not inherit their in_stack from
1283                                  * the bblock they are inlined to. See bug #58863 for an
1284                                  * example.
1285                                  */
1286                                 if (cfg->inlined_method)
1287                                         bb->out_stack [i] = mono_compile_create_var (cfg, type_from_stack_type (sp [i]), OP_LOCAL);
1288                                 else
1289                                         bb->out_stack [i] = mono_compile_get_interface_var (cfg, i, sp [i]);
1290                         }
1291                 }
1292         }
1293
1294         for (i = 0; i < bb->out_count; ++i) {
1295                 outb = bb->out_bb [i];
1296                 /* exception handlers are linked, but they should not be considered for stack args */
1297                 if (outb->flags & BB_EXCEPTION_HANDLER)
1298                         continue;
1299                 if (outb->in_scount) {
1300                         if (outb->in_scount != bb->out_scount) {
1301                                 cfg->unverifiable = TRUE;
1302                                 return;
1303                         }
1304                         continue; /* check they are the same locals */
1305                 }
1306                 outb->in_scount = count;
1307                 outb->in_stack = bb->out_stack;
1308         }
1309
1310         locals = bb->out_stack;
1311         cfg->cbb = bb;
1312         for (i = 0; i < count; ++i) {
1313                 EMIT_NEW_TEMPSTORE (cfg, inst, locals [i]->inst_c0, sp [i]);
1314                 inst->cil_code = sp [i]->cil_code;
1315                 sp [i] = locals [i];
1316                 if (cfg->verbose_level > 3)
1317                         printf ("storing %d to temp %d\n", i, (int)locals [i]->inst_c0);
1318         }
1319
1320         /*
1321          * It is possible that the out bblocks already have in_stack assigned, and
1322          * the in_stacks differ. In this case, we will store to all the different 
1323          * in_stacks.
1324          */
1325
1326         found = TRUE;
1327         bindex = 0;
1328         while (found) {
1329                 /* Find a bblock which has a different in_stack */
1330                 found = FALSE;
1331                 while (bindex < bb->out_count) {
1332                         outb = bb->out_bb [bindex];
1333                         /* exception handlers are linked, but they should not be considered for stack args */
1334                         if (outb->flags & BB_EXCEPTION_HANDLER) {
1335                                 bindex++;
1336                                 continue;
1337                         }
1338                         if (outb->in_stack != locals) {
1339                                 for (i = 0; i < count; ++i) {
1340                                         EMIT_NEW_TEMPSTORE (cfg, inst, outb->in_stack [i]->inst_c0, sp [i]);
1341                                         inst->cil_code = sp [i]->cil_code;
1342                                         sp [i] = locals [i];
1343                                         if (cfg->verbose_level > 3)
1344                                                 printf ("storing %d to temp %d\n", i, (int)outb->in_stack [i]->inst_c0);
1345                                 }
1346                                 locals = outb->in_stack;
1347                                 found = TRUE;
1348                                 break;
1349                         }
1350                         bindex ++;
1351                 }
1352         }
1353 }
1354
1355 /* Emit code which loads interface_offsets [klass->interface_id]
1356  * The array is stored in memory before vtable.
1357 */
1358 static void
1359 mini_emit_load_intf_reg_vtable (MonoCompile *cfg, int intf_reg, int vtable_reg, MonoClass *klass)
1360 {
1361         if (cfg->compile_aot) {
1362                 int ioffset_reg = alloc_preg (cfg);
1363                 int iid_reg = alloc_preg (cfg);
1364
1365                 MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_ADJUSTED_IID);
1366                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, ioffset_reg, iid_reg, vtable_reg);
1367                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, intf_reg, ioffset_reg, 0);
1368         }
1369         else {
1370                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, intf_reg, vtable_reg, -((klass->interface_id + 1) * SIZEOF_VOID_P));
1371         }
1372 }
1373
1374 static void
1375 mini_emit_interface_bitmap_check (MonoCompile *cfg, int intf_bit_reg, int base_reg, int offset, MonoClass *klass)
1376 {
1377         int ibitmap_reg = alloc_preg (cfg);
1378 #ifdef COMPRESSED_INTERFACE_BITMAP
1379         MonoInst *args [2];
1380         MonoInst *res, *ins;
1381         NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, ibitmap_reg, base_reg, offset);
1382         MONO_ADD_INS (cfg->cbb, ins);
1383         args [0] = ins;
1384         if (cfg->compile_aot)
1385                 EMIT_NEW_AOTCONST (cfg, args [1], MONO_PATCH_INFO_IID, klass);
1386         else
1387                 EMIT_NEW_ICONST (cfg, args [1], klass->interface_id);
1388         res = mono_emit_jit_icall (cfg, mono_class_interface_match, args);
1389         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, intf_bit_reg, res->dreg);
1390 #else
1391         int ibitmap_byte_reg = alloc_preg (cfg);
1392
1393         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, ibitmap_reg, base_reg, offset);
1394
1395         if (cfg->compile_aot) {
1396                 int iid_reg = alloc_preg (cfg);
1397                 int shifted_iid_reg = alloc_preg (cfg);
1398                 int ibitmap_byte_address_reg = alloc_preg (cfg);
1399                 int masked_iid_reg = alloc_preg (cfg);
1400                 int iid_one_bit_reg = alloc_preg (cfg);
1401                 int iid_bit_reg = alloc_preg (cfg);
1402                 MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_IID);
1403                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, shifted_iid_reg, iid_reg, 3);
1404                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, ibitmap_byte_address_reg, ibitmap_reg, shifted_iid_reg);
1405                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, ibitmap_byte_reg, ibitmap_byte_address_reg, 0);
1406                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, masked_iid_reg, iid_reg, 7);
1407                 MONO_EMIT_NEW_ICONST (cfg, iid_one_bit_reg, 1);
1408                 MONO_EMIT_NEW_BIALU (cfg, OP_ISHL, iid_bit_reg, iid_one_bit_reg, masked_iid_reg);
1409                 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, intf_bit_reg, ibitmap_byte_reg, iid_bit_reg);
1410         } else {
1411                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, ibitmap_byte_reg, ibitmap_reg, klass->interface_id >> 3);
1412                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, intf_bit_reg, ibitmap_byte_reg, 1 << (klass->interface_id & 7));
1413         }
1414 #endif
1415 }
1416
1417 /* 
1418  * Emit code which loads into "intf_bit_reg" a nonzero value if the MonoClass
1419  * stored in "klass_reg" implements the interface "klass".
1420  */
1421 static void
1422 mini_emit_load_intf_bit_reg_class (MonoCompile *cfg, int intf_bit_reg, int klass_reg, MonoClass *klass)
1423 {
1424         mini_emit_interface_bitmap_check (cfg, intf_bit_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, interface_bitmap), klass);
1425 }
1426
1427 /* 
1428  * Emit code which loads into "intf_bit_reg" a nonzero value if the MonoVTable
1429  * stored in "vtable_reg" implements the interface "klass".
1430  */
1431 static void
1432 mini_emit_load_intf_bit_reg_vtable (MonoCompile *cfg, int intf_bit_reg, int vtable_reg, MonoClass *klass)
1433 {
1434         mini_emit_interface_bitmap_check (cfg, intf_bit_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, interface_bitmap), klass);
1435 }
1436
1437 /* 
1438  * Emit code which checks whenever the interface id of @klass is smaller than
1439  * than the value given by max_iid_reg.
1440 */
1441 static void
1442 mini_emit_max_iid_check (MonoCompile *cfg, int max_iid_reg, MonoClass *klass,
1443                                                  MonoBasicBlock *false_target)
1444 {
1445         if (cfg->compile_aot) {
1446                 int iid_reg = alloc_preg (cfg);
1447                 MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_IID);
1448                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, max_iid_reg, iid_reg);
1449         }
1450         else
1451                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, max_iid_reg, klass->interface_id);
1452         if (false_target)
1453                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBLT_UN, false_target);
1454         else
1455                 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "InvalidCastException");
1456 }
1457
1458 /* Same as above, but obtains max_iid from a vtable */
1459 static void
1460 mini_emit_max_iid_check_vtable (MonoCompile *cfg, int vtable_reg, MonoClass *klass,
1461                                                                  MonoBasicBlock *false_target)
1462 {
1463         int max_iid_reg = alloc_preg (cfg);
1464                 
1465         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, max_iid_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, max_interface_id));
1466         mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target);
1467 }
1468
1469 /* Same as above, but obtains max_iid from a klass */
1470 static void
1471 mini_emit_max_iid_check_class (MonoCompile *cfg, int klass_reg, MonoClass *klass,
1472                                                                  MonoBasicBlock *false_target)
1473 {
1474         int max_iid_reg = alloc_preg (cfg);
1475
1476         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, max_iid_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, max_interface_id));          
1477         mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target);
1478 }
1479
1480 static void
1481 mini_emit_isninst_cast_inst (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoInst *klass_ins, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1482 {
1483         int idepth_reg = alloc_preg (cfg);
1484         int stypes_reg = alloc_preg (cfg);
1485         int stype = alloc_preg (cfg);
1486
1487         if (klass->idepth > MONO_DEFAULT_SUPERTABLE_SIZE) {
1488                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, idepth_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, idepth));
1489                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, idepth_reg, klass->idepth);
1490                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBLT_UN, false_target);
1491         }
1492         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stypes_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, supertypes));
1493         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stype, stypes_reg, ((klass->idepth - 1) * SIZEOF_VOID_P));
1494         if (klass_ins) {
1495                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, stype, klass_ins->dreg);
1496         } else if (cfg->compile_aot) {
1497                 int const_reg = alloc_preg (cfg);
1498                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
1499                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, stype, const_reg);
1500         } else {
1501                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, stype, klass);
1502         }
1503         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, true_target);
1504 }
1505
1506 static void
1507 mini_emit_isninst_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1508 {
1509         mini_emit_isninst_cast_inst (cfg, klass_reg, klass, NULL, false_target, true_target);
1510 }
1511
1512 static void
1513 mini_emit_iface_cast (MonoCompile *cfg, int vtable_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1514 {
1515         int intf_reg = alloc_preg (cfg);
1516
1517         mini_emit_max_iid_check_vtable (cfg, vtable_reg, klass, false_target);
1518         mini_emit_load_intf_bit_reg_vtable (cfg, intf_reg, vtable_reg, klass);
1519         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, intf_reg, 0);
1520         if (true_target)
1521                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, true_target);
1522         else
1523                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");               
1524 }
1525
1526 /*
1527  * Variant of the above that takes a register to the class, not the vtable.
1528  */
1529 static void
1530 mini_emit_iface_class_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1531 {
1532         int intf_bit_reg = alloc_preg (cfg);
1533
1534         mini_emit_max_iid_check_class (cfg, klass_reg, klass, false_target);
1535         mini_emit_load_intf_bit_reg_class (cfg, intf_bit_reg, klass_reg, klass);
1536         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, intf_bit_reg, 0);
1537         if (true_target)
1538                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, true_target);
1539         else
1540                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
1541 }
1542
1543 static inline void
1544 mini_emit_class_check_inst (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoInst *klass_inst)
1545 {
1546         if (klass_inst) {
1547                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_inst->dreg);
1548         } else if (cfg->compile_aot) {
1549                 int const_reg = alloc_preg (cfg);
1550                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
1551                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, const_reg);
1552         } else {
1553                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
1554         }
1555         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1556 }
1557
1558 static inline void
1559 mini_emit_class_check (MonoCompile *cfg, int klass_reg, MonoClass *klass)
1560 {
1561         return mini_emit_class_check_inst (cfg, klass_reg, klass, NULL);
1562 }
1563
1564 static inline void
1565 mini_emit_class_check_branch (MonoCompile *cfg, int klass_reg, MonoClass *klass, int branch_op, MonoBasicBlock *target)
1566 {
1567         if (cfg->compile_aot) {
1568                 int const_reg = alloc_preg (cfg);
1569                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
1570                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, const_reg);
1571         } else {
1572                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
1573         }
1574         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, branch_op, target);
1575 }
1576
1577 static void
1578 mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoBasicBlock *object_is_null);
1579         
1580 static void
1581 mini_emit_castclass_inst (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoInst *klass_inst, MonoBasicBlock *object_is_null)
1582 {
1583         if (klass->rank) {
1584                 int rank_reg = alloc_preg (cfg);
1585                 int eclass_reg = alloc_preg (cfg);
1586
1587                 g_assert (!klass_inst);
1588                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, rank));
1589                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank);
1590                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1591                 //              MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
1592                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, cast_class));
1593                 if (klass->cast_class == mono_defaults.object_class) {
1594                         int parent_reg = alloc_preg (cfg);
1595                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, parent_reg, eclass_reg, G_STRUCT_OFFSET (MonoClass, parent));
1596                         mini_emit_class_check_branch (cfg, parent_reg, mono_defaults.enum_class->parent, OP_PBNE_UN, object_is_null);
1597                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1598                 } else if (klass->cast_class == mono_defaults.enum_class->parent) {
1599                         mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class->parent, OP_PBEQ, object_is_null);
1600                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1601                 } else if (klass->cast_class == mono_defaults.enum_class) {
1602                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1603                 } else if (klass->cast_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1604                         mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, NULL, NULL);
1605                 } else {
1606                         // Pass -1 as obj_reg to skip the check below for arrays of arrays
1607                         mini_emit_castclass (cfg, -1, eclass_reg, klass->cast_class, object_is_null);
1608                 }
1609
1610                 if ((klass->rank == 1) && (klass->byval_arg.type == MONO_TYPE_SZARRAY) && (obj_reg != -1)) {
1611                         /* Check that the object is a vector too */
1612                         int bounds_reg = alloc_preg (cfg);
1613                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, obj_reg, G_STRUCT_OFFSET (MonoArray, bounds));
1614                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
1615                         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1616                 }
1617         } else {
1618                 int idepth_reg = alloc_preg (cfg);
1619                 int stypes_reg = alloc_preg (cfg);
1620                 int stype = alloc_preg (cfg);
1621
1622                 if (klass->idepth > MONO_DEFAULT_SUPERTABLE_SIZE) {
1623                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, idepth_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, idepth));
1624                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, idepth_reg, klass->idepth);
1625                         MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "InvalidCastException");
1626                 }
1627                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stypes_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, supertypes));
1628                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stype, stypes_reg, ((klass->idepth - 1) * SIZEOF_VOID_P));
1629                 mini_emit_class_check_inst (cfg, stype, klass, klass_inst);
1630         }
1631 }
1632
1633 static void
1634 mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoBasicBlock *object_is_null)
1635 {
1636         return mini_emit_castclass_inst (cfg, obj_reg, klass_reg, klass, NULL, object_is_null);
1637 }
1638
1639 static void 
1640 mini_emit_memset (MonoCompile *cfg, int destreg, int offset, int size, int val, int align)
1641 {
1642         int val_reg;
1643
1644         g_assert (val == 0);
1645
1646         if (align == 0)
1647                 align = 4;
1648
1649         if ((size <= 4) && (size <= align)) {
1650                 switch (size) {
1651                 case 1:
1652                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, destreg, offset, val);
1653                         return;
1654                 case 2:
1655                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI2_MEMBASE_IMM, destreg, offset, val);
1656                         return;
1657                 case 4:
1658                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI4_MEMBASE_IMM, destreg, offset, val);
1659                         return;
1660 #if SIZEOF_REGISTER == 8
1661                 case 8:
1662                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI8_MEMBASE_IMM, destreg, offset, val);
1663                         return;
1664 #endif
1665                 }
1666         }
1667
1668         val_reg = alloc_preg (cfg);
1669
1670         if (SIZEOF_REGISTER == 8)
1671                 MONO_EMIT_NEW_I8CONST (cfg, val_reg, val);
1672         else
1673                 MONO_EMIT_NEW_ICONST (cfg, val_reg, val);
1674
1675         if (align < 4) {
1676                 /* This could be optimized further if neccesary */
1677                 while (size >= 1) {
1678                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
1679                         offset += 1;
1680                         size -= 1;
1681                 }
1682                 return;
1683         }       
1684
1685 #if !NO_UNALIGNED_ACCESS
1686         if (SIZEOF_REGISTER == 8) {
1687                 if (offset % 8) {
1688                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
1689                         offset += 4;
1690                         size -= 4;
1691                 }
1692                 while (size >= 8) {
1693                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, destreg, offset, val_reg);
1694                         offset += 8;
1695                         size -= 8;
1696                 }
1697         }       
1698 #endif
1699
1700         while (size >= 4) {
1701                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
1702                 offset += 4;
1703                 size -= 4;
1704         }
1705         while (size >= 2) {
1706                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, offset, val_reg);
1707                 offset += 2;
1708                 size -= 2;
1709         }
1710         while (size >= 1) {
1711                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
1712                 offset += 1;
1713                 size -= 1;
1714         }
1715 }
1716
1717 void 
1718 mini_emit_memcpy (MonoCompile *cfg, int destreg, int doffset, int srcreg, int soffset, int size, int align)
1719 {
1720         int cur_reg;
1721
1722         if (align == 0)
1723                 align = 4;
1724
1725         /*FIXME arbitrary hack to avoid unbound code expansion.*/
1726         g_assert (size < 10000);
1727
1728         if (align < 4) {
1729                 /* This could be optimized further if neccesary */
1730                 while (size >= 1) {
1731                         cur_reg = alloc_preg (cfg);
1732                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, cur_reg, srcreg, soffset);
1733                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, doffset, cur_reg);
1734                         doffset += 1;
1735                         soffset += 1;
1736                         size -= 1;
1737                 }
1738         }
1739
1740 #if !NO_UNALIGNED_ACCESS
1741         if (SIZEOF_REGISTER == 8) {
1742                 while (size >= 8) {
1743                         cur_reg = alloc_preg (cfg);
1744                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI8_MEMBASE, cur_reg, srcreg, soffset);
1745                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, destreg, doffset, cur_reg);
1746                         doffset += 8;
1747                         soffset += 8;
1748                         size -= 8;
1749                 }
1750         }       
1751 #endif
1752
1753         while (size >= 4) {
1754                 cur_reg = alloc_preg (cfg);
1755                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, cur_reg, srcreg, soffset);
1756                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, doffset, cur_reg);
1757                 doffset += 4;
1758                 soffset += 4;
1759                 size -= 4;
1760         }
1761         while (size >= 2) {
1762                 cur_reg = alloc_preg (cfg);
1763                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, cur_reg, srcreg, soffset);
1764                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, doffset, cur_reg);
1765                 doffset += 2;
1766                 soffset += 2;
1767                 size -= 2;
1768         }
1769         while (size >= 1) {
1770                 cur_reg = alloc_preg (cfg);
1771                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, cur_reg, srcreg, soffset);
1772                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, doffset, cur_reg);
1773                 doffset += 1;
1774                 soffset += 1;
1775                 size -= 1;
1776         }
1777 }
1778
1779 static int
1780 ret_type_to_call_opcode (MonoType *type, int calli, int virt, MonoGenericSharingContext *gsctx)
1781 {
1782         if (type->byref)
1783                 return calli? OP_CALL_REG: virt? OP_CALLVIRT: OP_CALL;
1784
1785 handle_enum:
1786         type = mini_get_basic_type_from_generic (gsctx, type);
1787         switch (type->type) {
1788         case MONO_TYPE_VOID:
1789                 return calli? OP_VOIDCALL_REG: virt? OP_VOIDCALLVIRT: OP_VOIDCALL;
1790         case MONO_TYPE_I1:
1791         case MONO_TYPE_U1:
1792         case MONO_TYPE_BOOLEAN:
1793         case MONO_TYPE_I2:
1794         case MONO_TYPE_U2:
1795         case MONO_TYPE_CHAR:
1796         case MONO_TYPE_I4:
1797         case MONO_TYPE_U4:
1798                 return calli? OP_CALL_REG: virt? OP_CALLVIRT: OP_CALL;
1799         case MONO_TYPE_I:
1800         case MONO_TYPE_U:
1801         case MONO_TYPE_PTR:
1802         case MONO_TYPE_FNPTR:
1803                 return calli? OP_CALL_REG: virt? OP_CALLVIRT: OP_CALL;
1804         case MONO_TYPE_CLASS:
1805         case MONO_TYPE_STRING:
1806         case MONO_TYPE_OBJECT:
1807         case MONO_TYPE_SZARRAY:
1808         case MONO_TYPE_ARRAY:    
1809                 return calli? OP_CALL_REG: virt? OP_CALLVIRT: OP_CALL;
1810         case MONO_TYPE_I8:
1811         case MONO_TYPE_U8:
1812                 return calli? OP_LCALL_REG: virt? OP_LCALLVIRT: OP_LCALL;
1813         case MONO_TYPE_R4:
1814         case MONO_TYPE_R8:
1815                 return calli? OP_FCALL_REG: virt? OP_FCALLVIRT: OP_FCALL;
1816         case MONO_TYPE_VALUETYPE:
1817                 if (type->data.klass->enumtype) {
1818                         type = mono_class_enum_basetype (type->data.klass);
1819                         goto handle_enum;
1820                 } else
1821                         return calli? OP_VCALL_REG: virt? OP_VCALLVIRT: OP_VCALL;
1822         case MONO_TYPE_TYPEDBYREF:
1823                 return calli? OP_VCALL_REG: virt? OP_VCALLVIRT: OP_VCALL;
1824         case MONO_TYPE_GENERICINST:
1825                 type = &type->data.generic_class->container_class->byval_arg;
1826                 goto handle_enum;
1827         default:
1828                 g_error ("unknown type 0x%02x in ret_type_to_call_opcode", type->type);
1829         }
1830         return -1;
1831 }
1832
1833 /*
1834  * target_type_is_incompatible:
1835  * @cfg: MonoCompile context
1836  *
1837  * Check that the item @arg on the evaluation stack can be stored
1838  * in the target type (can be a local, or field, etc).
1839  * The cfg arg can be used to check if we need verification or just
1840  * validity checks.
1841  *
1842  * Returns: non-0 value if arg can't be stored on a target.
1843  */
1844 static int
1845 target_type_is_incompatible (MonoCompile *cfg, MonoType *target, MonoInst *arg)
1846 {
1847         MonoType *simple_type;
1848         MonoClass *klass;
1849
1850         if (target->byref) {
1851                 /* FIXME: check that the pointed to types match */
1852                 if (arg->type == STACK_MP)
1853                         return arg->klass != mono_class_from_mono_type (target);
1854                 if (arg->type == STACK_PTR)
1855                         return 0;
1856                 return 1;
1857         }
1858
1859         simple_type = mono_type_get_underlying_type (target);
1860         switch (simple_type->type) {
1861         case MONO_TYPE_VOID:
1862                 return 1;
1863         case MONO_TYPE_I1:
1864         case MONO_TYPE_U1:
1865         case MONO_TYPE_BOOLEAN:
1866         case MONO_TYPE_I2:
1867         case MONO_TYPE_U2:
1868         case MONO_TYPE_CHAR:
1869         case MONO_TYPE_I4:
1870         case MONO_TYPE_U4:
1871                 if (arg->type != STACK_I4 && arg->type != STACK_PTR)
1872                         return 1;
1873                 return 0;
1874         case MONO_TYPE_PTR:
1875                 /* STACK_MP is needed when setting pinned locals */
1876                 if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
1877                         return 1;
1878                 return 0;
1879         case MONO_TYPE_I:
1880         case MONO_TYPE_U:
1881         case MONO_TYPE_FNPTR:
1882                 if (arg->type != STACK_I4 && arg->type != STACK_PTR)
1883                         return 1;
1884                 return 0;
1885         case MONO_TYPE_CLASS:
1886         case MONO_TYPE_STRING:
1887         case MONO_TYPE_OBJECT:
1888         case MONO_TYPE_SZARRAY:
1889         case MONO_TYPE_ARRAY:    
1890                 if (arg->type != STACK_OBJ)
1891                         return 1;
1892                 /* FIXME: check type compatibility */
1893                 return 0;
1894         case MONO_TYPE_I8:
1895         case MONO_TYPE_U8:
1896                 if (arg->type != STACK_I8)
1897                         return 1;
1898                 return 0;
1899         case MONO_TYPE_R4:
1900         case MONO_TYPE_R8:
1901                 if (arg->type != STACK_R8)
1902                         return 1;
1903                 return 0;
1904         case MONO_TYPE_VALUETYPE:
1905                 if (arg->type != STACK_VTYPE)
1906                         return 1;
1907                 klass = mono_class_from_mono_type (simple_type);
1908                 if (klass != arg->klass)
1909                         return 1;
1910                 return 0;
1911         case MONO_TYPE_TYPEDBYREF:
1912                 if (arg->type != STACK_VTYPE)
1913                         return 1;
1914                 klass = mono_class_from_mono_type (simple_type);
1915                 if (klass != arg->klass)
1916                         return 1;
1917                 return 0;
1918         case MONO_TYPE_GENERICINST:
1919                 if (mono_type_generic_inst_is_valuetype (simple_type)) {
1920                         if (arg->type != STACK_VTYPE)
1921                                 return 1;
1922                         klass = mono_class_from_mono_type (simple_type);
1923                         if (klass != arg->klass)
1924                                 return 1;
1925                         return 0;
1926                 } else {
1927                         if (arg->type != STACK_OBJ)
1928                                 return 1;
1929                         /* FIXME: check type compatibility */
1930                         return 0;
1931                 }
1932         case MONO_TYPE_VAR:
1933         case MONO_TYPE_MVAR:
1934                 /* FIXME: all the arguments must be references for now,
1935                  * later look inside cfg and see if the arg num is
1936                  * really a reference
1937                  */
1938                 g_assert (cfg->generic_sharing_context);
1939                 if (arg->type != STACK_OBJ)
1940                         return 1;
1941                 return 0;
1942         default:
1943                 g_error ("unknown type 0x%02x in target_type_is_incompatible", simple_type->type);
1944         }
1945         return 1;
1946 }
1947
1948 /*
1949  * Prepare arguments for passing to a function call.
1950  * Return a non-zero value if the arguments can't be passed to the given
1951  * signature.
1952  * The type checks are not yet complete and some conversions may need
1953  * casts on 32 or 64 bit architectures.
1954  *
1955  * FIXME: implement this using target_type_is_incompatible ()
1956  */
1957 static int
1958 check_call_signature (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args)
1959 {
1960         MonoType *simple_type;
1961         int i;
1962
1963         if (sig->hasthis) {
1964                 if (args [0]->type != STACK_OBJ && args [0]->type != STACK_MP && args [0]->type != STACK_PTR)
1965                         return 1;
1966                 args++;
1967         }
1968         for (i = 0; i < sig->param_count; ++i) {
1969                 if (sig->params [i]->byref) {
1970                         if (args [i]->type != STACK_MP && args [i]->type != STACK_PTR)
1971                                 return 1;
1972                         continue;
1973                 }
1974                 simple_type = sig->params [i];
1975                 simple_type = mini_get_basic_type_from_generic (cfg->generic_sharing_context, simple_type);
1976 handle_enum:
1977                 switch (simple_type->type) {
1978                 case MONO_TYPE_VOID:
1979                         return 1;
1980                         continue;
1981                 case MONO_TYPE_I1:
1982                 case MONO_TYPE_U1:
1983                 case MONO_TYPE_BOOLEAN:
1984                 case MONO_TYPE_I2:
1985                 case MONO_TYPE_U2:
1986                 case MONO_TYPE_CHAR:
1987                 case MONO_TYPE_I4:
1988                 case MONO_TYPE_U4:
1989                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR)
1990                                 return 1;
1991                         continue;
1992                 case MONO_TYPE_I:
1993                 case MONO_TYPE_U:
1994                 case MONO_TYPE_PTR:
1995                 case MONO_TYPE_FNPTR:
1996                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR && args [i]->type != STACK_MP && args [i]->type != STACK_OBJ)
1997                                 return 1;
1998                         continue;
1999                 case MONO_TYPE_CLASS:
2000                 case MONO_TYPE_STRING:
2001                 case MONO_TYPE_OBJECT:
2002                 case MONO_TYPE_SZARRAY:
2003                 case MONO_TYPE_ARRAY:    
2004                         if (args [i]->type != STACK_OBJ)
2005                                 return 1;
2006                         continue;
2007                 case MONO_TYPE_I8:
2008                 case MONO_TYPE_U8:
2009                         if (args [i]->type != STACK_I8)
2010                                 return 1;
2011                         continue;
2012                 case MONO_TYPE_R4:
2013                 case MONO_TYPE_R8:
2014                         if (args [i]->type != STACK_R8)
2015                                 return 1;
2016                         continue;
2017                 case MONO_TYPE_VALUETYPE:
2018                         if (simple_type->data.klass->enumtype) {
2019                                 simple_type = mono_class_enum_basetype (simple_type->data.klass);
2020                                 goto handle_enum;
2021                         }
2022                         if (args [i]->type != STACK_VTYPE)
2023                                 return 1;
2024                         continue;
2025                 case MONO_TYPE_TYPEDBYREF:
2026                         if (args [i]->type != STACK_VTYPE)
2027                                 return 1;
2028                         continue;
2029                 case MONO_TYPE_GENERICINST:
2030                         simple_type = &simple_type->data.generic_class->container_class->byval_arg;
2031                         goto handle_enum;
2032
2033                 default:
2034                         g_error ("unknown type 0x%02x in check_call_signature",
2035                                  simple_type->type);
2036                 }
2037         }
2038         return 0;
2039 }
2040
2041 static int
2042 callvirt_to_call (int opcode)
2043 {
2044         switch (opcode) {
2045         case OP_CALLVIRT:
2046                 return OP_CALL;
2047         case OP_VOIDCALLVIRT:
2048                 return OP_VOIDCALL;
2049         case OP_FCALLVIRT:
2050                 return OP_FCALL;
2051         case OP_VCALLVIRT:
2052                 return OP_VCALL;
2053         case OP_LCALLVIRT:
2054                 return OP_LCALL;
2055         default:
2056                 g_assert_not_reached ();
2057         }
2058
2059         return -1;
2060 }
2061
2062 static int
2063 callvirt_to_call_membase (int opcode)
2064 {
2065         switch (opcode) {
2066         case OP_CALLVIRT:
2067                 return OP_CALL_MEMBASE;
2068         case OP_VOIDCALLVIRT:
2069                 return OP_VOIDCALL_MEMBASE;
2070         case OP_FCALLVIRT:
2071                 return OP_FCALL_MEMBASE;
2072         case OP_LCALLVIRT:
2073                 return OP_LCALL_MEMBASE;
2074         case OP_VCALLVIRT:
2075                 return OP_VCALL_MEMBASE;
2076         default:
2077                 g_assert_not_reached ();
2078         }
2079
2080         return -1;
2081 }
2082
2083 #ifdef MONO_ARCH_HAVE_IMT
2084 static void
2085 emit_imt_argument (MonoCompile *cfg, MonoCallInst *call, MonoInst *imt_arg)
2086 {
2087 #ifdef MONO_ARCH_IMT_REG
2088         int method_reg = alloc_preg (cfg);
2089
2090         if (imt_arg) {
2091                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
2092         } else if (cfg->compile_aot) {
2093                 MONO_EMIT_NEW_AOTCONST (cfg, method_reg, call->method, MONO_PATCH_INFO_METHODCONST);
2094         } else {
2095                 MonoInst *ins;
2096                 MONO_INST_NEW (cfg, ins, OP_PCONST);
2097                 ins->inst_p0 = call->method;
2098                 ins->dreg = method_reg;
2099                 MONO_ADD_INS (cfg->cbb, ins);
2100         }
2101
2102 #ifdef ENABLE_LLVM
2103         if (COMPILE_LLVM (cfg))
2104                 call->imt_arg_reg = method_reg;
2105 #endif
2106         mono_call_inst_add_outarg_reg (cfg, call, method_reg, MONO_ARCH_IMT_REG, FALSE);
2107 #else
2108         mono_arch_emit_imt_argument (cfg, call, imt_arg);
2109 #endif
2110 }
2111 #endif
2112
2113 static MonoJumpInfo *
2114 mono_patch_info_new (MonoMemPool *mp, int ip, MonoJumpInfoType type, gconstpointer target)
2115 {
2116         MonoJumpInfo *ji = mono_mempool_alloc (mp, sizeof (MonoJumpInfo));
2117
2118         ji->ip.i = ip;
2119         ji->type = type;
2120         ji->data.target = target;
2121
2122         return ji;
2123 }
2124
2125 inline static MonoCallInst *
2126 mono_emit_call_args (MonoCompile *cfg, MonoMethodSignature *sig, 
2127                                          MonoInst **args, int calli, int virtual, int tail)
2128 {
2129         MonoCallInst *call;
2130 #ifdef MONO_ARCH_SOFT_FLOAT
2131         int i;
2132 #endif
2133
2134         if (tail)
2135                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
2136         else
2137                 MONO_INST_NEW_CALL (cfg, call, ret_type_to_call_opcode (sig->ret, calli, virtual, cfg->generic_sharing_context));
2138
2139         call->args = args;
2140         call->signature = sig;
2141
2142         type_to_eval_stack_type ((cfg), sig->ret, &call->inst);
2143
2144         if (tail) {
2145                 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
2146                         call->vret_var = cfg->vret_addr;
2147                         //g_assert_not_reached ();
2148                 }
2149         } else if (MONO_TYPE_ISSTRUCT (sig->ret)) {
2150                 MonoInst *temp = mono_compile_create_var (cfg, sig->ret, OP_LOCAL);
2151                 MonoInst *loada;
2152
2153                 temp->backend.is_pinvoke = sig->pinvoke;
2154
2155                 /*
2156                  * We use a new opcode OP_OUTARG_VTRETADDR instead of LDADDR for emitting the
2157                  * address of return value to increase optimization opportunities.
2158                  * Before vtype decomposition, the dreg of the call ins itself represents the
2159                  * fact the call modifies the return value. After decomposition, the call will
2160                  * be transformed into one of the OP_VOIDCALL opcodes, and the VTRETADDR opcode
2161                  * will be transformed into an LDADDR.
2162                  */
2163                 MONO_INST_NEW (cfg, loada, OP_OUTARG_VTRETADDR);
2164                 loada->dreg = alloc_preg (cfg);
2165                 loada->inst_p0 = temp;
2166                 /* We reference the call too since call->dreg could change during optimization */
2167                 loada->inst_p1 = call;
2168                 MONO_ADD_INS (cfg->cbb, loada);
2169
2170                 call->inst.dreg = temp->dreg;
2171
2172                 call->vret_var = loada;
2173         } else if (!MONO_TYPE_IS_VOID (sig->ret))
2174                 call->inst.dreg = alloc_dreg (cfg, call->inst.type);
2175
2176 #ifdef MONO_ARCH_SOFT_FLOAT
2177         if (COMPILE_SOFT_FLOAT (cfg)) {
2178                 /* 
2179                  * If the call has a float argument, we would need to do an r8->r4 conversion using 
2180                  * an icall, but that cannot be done during the call sequence since it would clobber
2181                  * the call registers + the stack. So we do it before emitting the call.
2182                  */
2183                 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
2184                         MonoType *t;
2185                         MonoInst *in = call->args [i];
2186
2187                         if (i >= sig->hasthis)
2188                                 t = sig->params [i - sig->hasthis];
2189                         else
2190                                 t = &mono_defaults.int_class->byval_arg;
2191                         t = mono_type_get_underlying_type (t);
2192
2193                         if (!t->byref && t->type == MONO_TYPE_R4) {
2194                                 MonoInst *iargs [1];
2195                                 MonoInst *conv;
2196
2197                                 iargs [0] = in;
2198                                 conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
2199
2200                                 /* The result will be in an int vreg */
2201                                 call->args [i] = conv;
2202                         }
2203                 }
2204         }
2205 #endif
2206
2207 #ifdef ENABLE_LLVM
2208         if (COMPILE_LLVM (cfg))
2209                 mono_llvm_emit_call (cfg, call);
2210         else
2211                 mono_arch_emit_call (cfg, call);
2212 #else
2213         mono_arch_emit_call (cfg, call);
2214 #endif
2215
2216         cfg->param_area = MAX (cfg->param_area, call->stack_usage);
2217         cfg->flags |= MONO_CFG_HAS_CALLS;
2218         
2219         return call;
2220 }
2221
2222 inline static MonoInst*
2223 mono_emit_calli (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args, MonoInst *addr)
2224 {
2225         MonoCallInst *call = mono_emit_call_args (cfg, sig, args, TRUE, FALSE, FALSE);
2226
2227         call->inst.sreg1 = addr->dreg;
2228
2229         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2230
2231         return (MonoInst*)call;
2232 }
2233
2234 static void
2235 set_rgctx_arg (MonoCompile *cfg, MonoCallInst *call, int rgctx_reg, MonoInst *rgctx_arg)
2236 {
2237 #ifdef MONO_ARCH_RGCTX_REG
2238         mono_call_inst_add_outarg_reg (cfg, call, rgctx_reg, MONO_ARCH_RGCTX_REG, FALSE);
2239         cfg->uses_rgctx_reg = TRUE;
2240         call->rgctx_reg = TRUE;
2241 #ifdef ENABLE_LLVM
2242         call->rgctx_arg_reg = rgctx_reg;
2243 #endif
2244 #else
2245         NOT_IMPLEMENTED;
2246 #endif
2247 }       
2248
2249 inline static MonoInst*
2250 mono_emit_rgctx_calli (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args, MonoInst *addr, MonoInst *rgctx_arg)
2251 {
2252         MonoCallInst *call;
2253         int rgctx_reg = -1;
2254
2255         if (rgctx_arg) {
2256                 rgctx_reg = mono_alloc_preg (cfg);
2257                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, rgctx_arg->dreg);
2258         }
2259         call = (MonoCallInst*)mono_emit_calli (cfg, sig, args, addr);
2260         if (rgctx_arg)
2261                 set_rgctx_arg (cfg, call, rgctx_reg, rgctx_arg);
2262         return (MonoInst*)call;
2263 }
2264
2265 static MonoInst*
2266 emit_get_rgctx_method (MonoCompile *cfg, int context_used, MonoMethod *cmethod, int rgctx_type);
2267 static MonoInst*
2268 emit_get_rgctx_klass (MonoCompile *cfg, int context_used, MonoClass *klass, int rgctx_type);
2269
2270 static MonoInst*
2271 mono_emit_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSignature *sig,
2272                                                         MonoInst **args, MonoInst *this, MonoInst *imt_arg)
2273 {
2274         gboolean might_be_remote;
2275         gboolean virtual = this != NULL;
2276         gboolean enable_for_aot = TRUE;
2277         int context_used;
2278         MonoCallInst *call;
2279
2280         if (method->string_ctor) {
2281                 /* Create the real signature */
2282                 /* FIXME: Cache these */
2283                 MonoMethodSignature *ctor_sig = mono_metadata_signature_dup_mempool (cfg->mempool, sig);
2284                 ctor_sig->ret = &mono_defaults.string_class->byval_arg;
2285
2286                 sig = ctor_sig;
2287         }
2288
2289         might_be_remote = this && sig->hasthis &&
2290                 (method->klass->marshalbyref || method->klass == mono_defaults.object_class) &&
2291                 !(method->flags & METHOD_ATTRIBUTE_VIRTUAL) && !MONO_CHECK_THIS (this);
2292
2293         context_used = mono_method_check_context_used (method);
2294         if (might_be_remote && context_used) {
2295                 MonoInst *addr;
2296
2297                 g_assert (cfg->generic_sharing_context);
2298
2299                 addr = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK);
2300
2301                 return mono_emit_calli (cfg, sig, args, addr);
2302         }
2303
2304         call = mono_emit_call_args (cfg, sig, args, FALSE, virtual, FALSE);
2305
2306         if (might_be_remote)
2307                 call->method = mono_marshal_get_remoting_invoke_with_check (method);
2308         else
2309                 call->method = method;
2310         call->inst.flags |= MONO_INST_HAS_METHOD;
2311         call->inst.inst_left = this;
2312
2313         if (virtual) {
2314                 int vtable_reg, slot_reg, this_reg;
2315
2316                 this_reg = this->dreg;
2317
2318 #ifdef MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE
2319                 if ((method->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (method->name, "Invoke"))) {
2320                         MONO_EMIT_NULL_CHECK (cfg, this_reg);
2321
2322                         /* Make a call to delegate->invoke_impl */
2323                         call->inst.opcode = callvirt_to_call_membase (call->inst.opcode);
2324                         call->inst.inst_basereg = this_reg;
2325                         call->inst.inst_offset = G_STRUCT_OFFSET (MonoDelegate, invoke_impl);
2326                         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2327
2328                         return (MonoInst*)call;
2329                 }
2330 #endif
2331
2332                 if ((!cfg->compile_aot || enable_for_aot) && 
2333                         (!(method->flags & METHOD_ATTRIBUTE_VIRTUAL) || 
2334                          (MONO_METHOD_IS_FINAL (method) &&
2335                           method->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK)) &&
2336                         !(method->klass->marshalbyref && context_used)) {
2337                         /* 
2338                          * the method is not virtual, we just need to ensure this is not null
2339                          * and then we can call the method directly.
2340                          */
2341                         if (method->klass->marshalbyref || method->klass == mono_defaults.object_class) {
2342                                 /* 
2343                                  * The check above ensures method is not gshared, this is needed since
2344                                  * gshared methods can't have wrappers.
2345                                  */
2346                                 method = call->method = mono_marshal_get_remoting_invoke_with_check (method);
2347                         }
2348
2349                         if (!method->string_ctor)
2350                                 MONO_EMIT_NEW_CHECK_THIS (cfg, this_reg);
2351
2352                         call->inst.opcode = callvirt_to_call (call->inst.opcode);
2353
2354                         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2355
2356                         return (MonoInst*)call;
2357                 }
2358
2359                 if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) && MONO_METHOD_IS_FINAL (method)) {
2360                         /*
2361                          * the method is virtual, but we can statically dispatch since either
2362                          * it's class or the method itself are sealed.
2363                          * But first we need to ensure it's not a null reference.
2364                          */
2365                         MONO_EMIT_NEW_CHECK_THIS (cfg, this_reg);
2366
2367                         call->inst.opcode = callvirt_to_call (call->inst.opcode);
2368                         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2369
2370                         return (MonoInst*)call;
2371                 }
2372
2373                 call->inst.opcode = callvirt_to_call_membase (call->inst.opcode);
2374
2375                 vtable_reg = alloc_preg (cfg);
2376                 MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, this_reg, G_STRUCT_OFFSET (MonoObject, vtable));
2377                 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2378                         slot_reg = -1;
2379 #ifdef MONO_ARCH_HAVE_IMT
2380                         if (mono_use_imt) {
2381                                 guint32 imt_slot = mono_method_get_imt_slot (method);
2382                                 emit_imt_argument (cfg, call, imt_arg);
2383                                 slot_reg = vtable_reg;
2384                                 call->inst.inst_offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
2385                         }
2386 #endif
2387                         if (slot_reg == -1) {
2388                                 slot_reg = alloc_preg (cfg);
2389                                 mini_emit_load_intf_reg_vtable (cfg, slot_reg, vtable_reg, method->klass);
2390                                 call->inst.inst_offset = mono_method_get_vtable_index (method) * SIZEOF_VOID_P;
2391                         }
2392                 } else {
2393                         slot_reg = vtable_reg;
2394                         call->inst.inst_offset = G_STRUCT_OFFSET (MonoVTable, vtable) +
2395                                 ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
2396 #ifdef MONO_ARCH_HAVE_IMT
2397                         if (imt_arg) {
2398                                 g_assert (mono_method_signature (method)->generic_param_count);
2399                                 emit_imt_argument (cfg, call, imt_arg);
2400                         }
2401 #endif
2402                 }
2403
2404                 call->inst.sreg1 = slot_reg;
2405                 call->virtual = TRUE;
2406         }
2407
2408         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2409
2410         return (MonoInst*)call;
2411 }
2412
2413 static MonoInst*
2414 mono_emit_rgctx_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSignature *sig,
2415                 MonoInst **args, MonoInst *this, MonoInst *imt_arg, MonoInst *vtable_arg)
2416 {
2417         int rgctx_reg = 0;
2418         MonoInst *ins;
2419         MonoCallInst *call;
2420
2421         if (vtable_arg) {
2422                 rgctx_reg = mono_alloc_preg (cfg);
2423                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, vtable_arg->dreg);
2424         }
2425         ins = mono_emit_method_call_full (cfg, method, sig, args, this, imt_arg);
2426
2427         call = (MonoCallInst*)ins;
2428         if (vtable_arg)
2429                 set_rgctx_arg (cfg, call, rgctx_reg, vtable_arg);
2430
2431         return ins;
2432 }
2433
2434 MonoInst*
2435 mono_emit_method_call (MonoCompile *cfg, MonoMethod *method, MonoInst **args, MonoInst *this)
2436 {
2437         return mono_emit_method_call_full (cfg, method, mono_method_signature (method), args, this, NULL);
2438 }
2439
2440 MonoInst*
2441 mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig,
2442                                            MonoInst **args)
2443 {
2444         MonoCallInst *call;
2445
2446         g_assert (sig);
2447
2448         call = mono_emit_call_args (cfg, sig, args, FALSE, FALSE, FALSE);
2449         call->fptr = func;
2450
2451         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2452
2453         return (MonoInst*)call;
2454 }
2455
2456 MonoInst*
2457 mono_emit_jit_icall (MonoCompile *cfg, gconstpointer func, MonoInst **args)
2458 {
2459         MonoJitICallInfo *info = mono_find_jit_icall_by_addr (func);
2460
2461         g_assert (info);
2462
2463         return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
2464 }
2465
2466 /*
2467  * mono_emit_abs_call:
2468  *
2469  *   Emit a call to the runtime function described by PATCH_TYPE and DATA.
2470  */
2471 inline static MonoInst*
2472 mono_emit_abs_call (MonoCompile *cfg, MonoJumpInfoType patch_type, gconstpointer data, 
2473                                         MonoMethodSignature *sig, MonoInst **args)
2474 {
2475         MonoJumpInfo *ji = mono_patch_info_new (cfg->mempool, 0, patch_type, data);
2476         MonoInst *ins;
2477
2478         /* 
2479          * We pass ji as the call address, the PATCH_INFO_ABS resolving code will
2480          * handle it.
2481          */
2482         if (cfg->abs_patches == NULL)
2483                 cfg->abs_patches = g_hash_table_new (NULL, NULL);
2484         g_hash_table_insert (cfg->abs_patches, ji, ji);
2485         ins = mono_emit_native_call (cfg, ji, sig, args);
2486         ((MonoCallInst*)ins)->fptr_is_patch = TRUE;
2487         return ins;
2488 }
2489  
2490 static MonoInst*
2491 mono_emit_widen_call_res (MonoCompile *cfg, MonoInst *ins, MonoMethodSignature *fsig)
2492 {
2493         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
2494                 if ((fsig->pinvoke || LLVM_ENABLED) && !fsig->ret->byref) {
2495                         int widen_op = -1;
2496
2497                         /* 
2498                          * Native code might return non register sized integers 
2499                          * without initializing the upper bits.
2500                          */
2501                         switch (mono_type_to_load_membase (cfg, fsig->ret)) {
2502                         case OP_LOADI1_MEMBASE:
2503                                 widen_op = OP_ICONV_TO_I1;
2504                                 break;
2505                         case OP_LOADU1_MEMBASE:
2506                                 widen_op = OP_ICONV_TO_U1;
2507                                 break;
2508                         case OP_LOADI2_MEMBASE:
2509                                 widen_op = OP_ICONV_TO_I2;
2510                                 break;
2511                         case OP_LOADU2_MEMBASE:
2512                                 widen_op = OP_ICONV_TO_U2;
2513                                 break;
2514                         default:
2515                                 break;
2516                         }
2517
2518                         if (widen_op != -1) {
2519                                 int dreg = alloc_preg (cfg);
2520                                 MonoInst *widen;
2521
2522                                 EMIT_NEW_UNALU (cfg, widen, widen_op, dreg, ins->dreg);
2523                                 widen->type = ins->type;
2524                                 ins = widen;
2525                         }
2526                 }
2527         }
2528
2529         return ins;
2530 }
2531
2532 static MonoMethod*
2533 get_memcpy_method (void)
2534 {
2535         static MonoMethod *memcpy_method = NULL;
2536         if (!memcpy_method) {
2537                 memcpy_method = mono_class_get_method_from_name (mono_defaults.string_class, "memcpy", 3);
2538                 if (!memcpy_method)
2539                         g_error ("Old corlib found. Install a new one");
2540         }
2541         return memcpy_method;
2542 }
2543
2544 static void
2545 create_write_barrier_bitmap (MonoClass *klass, unsigned *wb_bitmap, int offset)
2546 {
2547         MonoClassField *field;
2548         gpointer iter = NULL;
2549
2550         while ((field = mono_class_get_fields (klass, &iter))) {
2551                 int foffset;
2552
2553                 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
2554                         continue;
2555                 foffset = klass->valuetype ? field->offset - sizeof (MonoObject): field->offset;
2556                 if (mono_type_is_reference (field->type)) {
2557                         g_assert ((foffset % SIZEOF_VOID_P) == 0);
2558                         *wb_bitmap |= 1 << ((offset + foffset) / SIZEOF_VOID_P);
2559                 } else {
2560                         /*FIXME support nested value types so this works for: struct X { Y y; int z;} struct Y { object a,b; }*/
2561                         MonoClass *field_class = mono_class_from_mono_type (field->type);
2562                         if (field_class->has_references)
2563                                 create_write_barrier_bitmap (field_class, wb_bitmap, offset + foffset);
2564                 }
2565         }
2566 }
2567
2568 static gboolean
2569 mono_emit_wb_aware_memcpy (MonoCompile *cfg, MonoClass *klass, MonoInst *iargs[4], int size, int align)
2570 {
2571         int dest_ptr_reg, tmp_reg, destreg, srcreg, offset;
2572         unsigned need_wb = 0;
2573
2574         if (align == 0)
2575                 align = 4;
2576
2577         /*types with references can't have alignment smaller than sizeof(void*) */
2578         if (align < SIZEOF_VOID_P)
2579                 return FALSE;
2580
2581         /*This value cannot be bigger than 32 due to the way we calculate the required wb bitmap.*/
2582         if (size > 32 * SIZEOF_VOID_P)
2583                 return FALSE;
2584
2585         create_write_barrier_bitmap (klass, &need_wb, 0);
2586
2587         /* We don't unroll more than 5 stores to avoid code bloat. */
2588         if (size > 5 * SIZEOF_VOID_P) {
2589                 /*This is harmless and simplify mono_gc_wbarrier_value_copy_bitmap */
2590                 size += (SIZEOF_VOID_P - 1);
2591                 size &= ~(SIZEOF_VOID_P - 1);
2592
2593                 EMIT_NEW_ICONST (cfg, iargs [2], size);
2594                 EMIT_NEW_ICONST (cfg, iargs [3], need_wb);
2595                 mono_emit_jit_icall (cfg, mono_gc_wbarrier_value_copy_bitmap, iargs);
2596                 return TRUE;
2597         }
2598
2599         destreg = iargs [0]->dreg;
2600         srcreg = iargs [1]->dreg;
2601         offset = 0;
2602
2603         dest_ptr_reg = alloc_preg (cfg);
2604         tmp_reg = alloc_preg (cfg);
2605
2606         /*tmp = dreg*/
2607         EMIT_NEW_UNALU (cfg, iargs [0], OP_MOVE, dest_ptr_reg, destreg);
2608
2609         while (size >= SIZEOF_VOID_P) {
2610                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOAD_MEMBASE, tmp_reg, srcreg, offset);
2611                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, dest_ptr_reg, 0, tmp_reg);
2612
2613                 if (need_wb & 0x1) {
2614                         MonoInst *dummy_use;
2615
2616                         MonoMethod *write_barrier = mono_gc_get_write_barrier ();
2617                         mono_emit_method_call (cfg, write_barrier, &iargs [0], NULL);
2618
2619                         MONO_INST_NEW (cfg, dummy_use, OP_DUMMY_USE);
2620                         dummy_use->sreg1 = dest_ptr_reg;
2621                         MONO_ADD_INS (cfg->cbb, dummy_use);
2622                 }
2623
2624
2625                 offset += SIZEOF_VOID_P;
2626                 size -= SIZEOF_VOID_P;
2627                 need_wb >>= 1;
2628
2629                 /*tmp += sizeof (void*)*/
2630                 if (size >= SIZEOF_VOID_P) {
2631                         NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, dest_ptr_reg, dest_ptr_reg, SIZEOF_VOID_P);
2632                         MONO_ADD_INS (cfg->cbb, iargs [0]);
2633                 }
2634         }
2635
2636         /* Those cannot be references since size < sizeof (void*) */
2637         while (size >= 4) {
2638                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, tmp_reg, srcreg, offset);
2639                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, tmp_reg);
2640                 offset += 4;
2641                 size -= 4;
2642         }
2643
2644         while (size >= 2) {
2645                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, tmp_reg, srcreg, offset);
2646                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, offset, tmp_reg);
2647                 offset += 2;
2648                 size -= 2;
2649         }
2650
2651         while (size >= 1) {
2652                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, tmp_reg, srcreg, offset);
2653                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, tmp_reg);
2654                 offset += 1;
2655                 size -= 1;
2656         }
2657
2658         return TRUE;
2659 }
2660
2661 /*
2662  * Emit code to copy a valuetype of type @klass whose address is stored in
2663  * @src->dreg to memory whose address is stored at @dest->dreg.
2664  */
2665 void
2666 mini_emit_stobj (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *klass, gboolean native)
2667 {
2668         MonoInst *iargs [4];
2669         int n;
2670         guint32 align = 0;
2671         MonoMethod *memcpy_method;
2672
2673         g_assert (klass);
2674         /*
2675          * This check breaks with spilled vars... need to handle it during verification anyway.
2676          * g_assert (klass && klass == src->klass && klass == dest->klass);
2677          */
2678
2679         if (native)
2680                 n = mono_class_native_size (klass, &align);
2681         else
2682                 n = mono_class_value_size (klass, &align);
2683
2684         /* if native is true there should be no references in the struct */
2685         if (cfg->gen_write_barriers && klass->has_references && !native) {
2686                 /* Avoid barriers when storing to the stack */
2687                 if (!((dest->opcode == OP_ADD_IMM && dest->sreg1 == cfg->frame_reg) ||
2688                           (dest->opcode == OP_LDADDR))) {
2689                         int context_used = 0;
2690
2691                         iargs [0] = dest;
2692                         iargs [1] = src;
2693
2694                         if (cfg->generic_sharing_context)
2695                                 context_used = mono_class_check_context_used (klass);
2696
2697                         /* It's ok to intrinsify under gsharing since shared code types are layout stable. */
2698                         if ((cfg->opt & MONO_OPT_INTRINS) && mono_emit_wb_aware_memcpy (cfg, klass, iargs, n, align)) {
2699                                 return;
2700                         } else if (context_used) {
2701                                 iargs [2] = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
2702                         }  else {
2703                                 if (cfg->compile_aot) {
2704                                         EMIT_NEW_CLASSCONST (cfg, iargs [2], klass);
2705                                 } else {
2706                                         EMIT_NEW_PCONST (cfg, iargs [2], klass);
2707                                         mono_class_compute_gc_descriptor (klass);
2708                                 }
2709                         }
2710
2711                         mono_emit_jit_icall (cfg, mono_value_copy, iargs);
2712                         return;
2713                 }
2714         }
2715
2716         if ((cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 5) {
2717                 /* FIXME: Optimize the case when src/dest is OP_LDADDR */
2718                 mini_emit_memcpy (cfg, dest->dreg, 0, src->dreg, 0, n, align);
2719         } else {
2720                 iargs [0] = dest;
2721                 iargs [1] = src;
2722                 EMIT_NEW_ICONST (cfg, iargs [2], n);
2723                 
2724                 memcpy_method = get_memcpy_method ();
2725                 mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
2726         }
2727 }
2728
2729 static MonoMethod*
2730 get_memset_method (void)
2731 {
2732         static MonoMethod *memset_method = NULL;
2733         if (!memset_method) {
2734                 memset_method = mono_class_get_method_from_name (mono_defaults.string_class, "memset", 3);
2735                 if (!memset_method)
2736                         g_error ("Old corlib found. Install a new one");
2737         }
2738         return memset_method;
2739 }
2740
2741 void
2742 mini_emit_initobj (MonoCompile *cfg, MonoInst *dest, const guchar *ip, MonoClass *klass)
2743 {
2744         MonoInst *iargs [3];
2745         int n;
2746         guint32 align;
2747         MonoMethod *memset_method;
2748
2749         /* FIXME: Optimize this for the case when dest is an LDADDR */
2750
2751         mono_class_init (klass);
2752         n = mono_class_value_size (klass, &align);
2753
2754         if (n <= sizeof (gpointer) * 5) {
2755                 mini_emit_memset (cfg, dest->dreg, 0, n, 0, align);
2756         }
2757         else {
2758                 memset_method = get_memset_method ();
2759                 iargs [0] = dest;
2760                 EMIT_NEW_ICONST (cfg, iargs [1], 0);
2761                 EMIT_NEW_ICONST (cfg, iargs [2], n);
2762                 mono_emit_method_call (cfg, memset_method, iargs, NULL);
2763         }
2764 }
2765
2766 static MonoInst*
2767 emit_get_rgctx (MonoCompile *cfg, MonoMethod *method, int context_used)
2768 {
2769         MonoInst *this = NULL;
2770
2771         g_assert (cfg->generic_sharing_context);
2772
2773         if (!(method->flags & METHOD_ATTRIBUTE_STATIC) &&
2774                         !(context_used & MONO_GENERIC_CONTEXT_USED_METHOD) &&
2775                         !method->klass->valuetype)
2776                 EMIT_NEW_ARGLOAD (cfg, this, 0);
2777
2778         if (context_used & MONO_GENERIC_CONTEXT_USED_METHOD) {
2779                 MonoInst *mrgctx_loc, *mrgctx_var;
2780
2781                 g_assert (!this);
2782                 g_assert (method->is_inflated && mono_method_get_context (method)->method_inst);
2783
2784                 mrgctx_loc = mono_get_vtable_var (cfg);
2785                 EMIT_NEW_TEMPLOAD (cfg, mrgctx_var, mrgctx_loc->inst_c0);
2786
2787                 return mrgctx_var;
2788         } else if (method->flags & METHOD_ATTRIBUTE_STATIC || method->klass->valuetype) {
2789                 MonoInst *vtable_loc, *vtable_var;
2790
2791                 g_assert (!this);
2792
2793                 vtable_loc = mono_get_vtable_var (cfg);
2794                 EMIT_NEW_TEMPLOAD (cfg, vtable_var, vtable_loc->inst_c0);
2795
2796                 if (method->is_inflated && mono_method_get_context (method)->method_inst) {
2797                         MonoInst *mrgctx_var = vtable_var;
2798                         int vtable_reg;
2799
2800                         vtable_reg = alloc_preg (cfg);
2801                         EMIT_NEW_LOAD_MEMBASE (cfg, vtable_var, OP_LOAD_MEMBASE, vtable_reg, mrgctx_var->dreg, G_STRUCT_OFFSET (MonoMethodRuntimeGenericContext, class_vtable));
2802                         vtable_var->type = STACK_PTR;
2803                 }
2804
2805                 return vtable_var;
2806         } else {
2807                 MonoInst *ins;
2808                 int vtable_reg, res_reg;
2809         
2810                 vtable_reg = alloc_preg (cfg);
2811                 res_reg = alloc_preg (cfg);
2812                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, vtable_reg, this->dreg, G_STRUCT_OFFSET (MonoObject, vtable));
2813                 return ins;
2814         }
2815 }
2816
2817 static MonoJumpInfoRgctxEntry *
2818 mono_patch_info_rgctx_entry_new (MonoMemPool *mp, MonoMethod *method, gboolean in_mrgctx, MonoJumpInfoType patch_type, gconstpointer patch_data, int info_type)
2819 {
2820         MonoJumpInfoRgctxEntry *res = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoRgctxEntry));
2821         res->method = method;
2822         res->in_mrgctx = in_mrgctx;
2823         res->data = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfo));
2824         res->data->type = patch_type;
2825         res->data->data.target = patch_data;
2826         res->info_type = info_type;
2827
2828         return res;
2829 }
2830
2831 static inline MonoInst*
2832 emit_rgctx_fetch (MonoCompile *cfg, MonoInst *rgctx, MonoJumpInfoRgctxEntry *entry)
2833 {
2834         return mono_emit_abs_call (cfg, MONO_PATCH_INFO_RGCTX_FETCH, entry, helper_sig_rgctx_lazy_fetch_trampoline, &rgctx);
2835 }
2836
2837 static MonoInst*
2838 emit_get_rgctx_klass (MonoCompile *cfg, int context_used,
2839                                           MonoClass *klass, int rgctx_type)
2840 {
2841         MonoJumpInfoRgctxEntry *entry = mono_patch_info_rgctx_entry_new (cfg->mempool, cfg->current_method, context_used & MONO_GENERIC_CONTEXT_USED_METHOD, MONO_PATCH_INFO_CLASS, klass, rgctx_type);
2842         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
2843
2844         return emit_rgctx_fetch (cfg, rgctx, entry);
2845 }
2846
2847 /*
2848  * emit_get_rgctx_method:
2849  *
2850  *   Emit IR to load the property RGCTX_TYPE of CMETHOD. If context_used is 0, emit
2851  * normal constants, else emit a load from the rgctx.
2852  */
2853 static MonoInst*
2854 emit_get_rgctx_method (MonoCompile *cfg, int context_used,
2855                                            MonoMethod *cmethod, int rgctx_type)
2856 {
2857         if (!context_used) {
2858                 MonoInst *ins;
2859
2860                 switch (rgctx_type) {
2861                 case MONO_RGCTX_INFO_METHOD:
2862                         EMIT_NEW_METHODCONST (cfg, ins, cmethod);
2863                         return ins;
2864                 case MONO_RGCTX_INFO_METHOD_RGCTX:
2865                         EMIT_NEW_METHOD_RGCTX_CONST (cfg, ins, cmethod);
2866                         return ins;
2867                 default:
2868                         g_assert_not_reached ();
2869                 }
2870         } else {
2871                 MonoJumpInfoRgctxEntry *entry = mono_patch_info_rgctx_entry_new (cfg->mempool, cfg->current_method, context_used & MONO_GENERIC_CONTEXT_USED_METHOD, MONO_PATCH_INFO_METHODCONST, cmethod, rgctx_type);
2872                 MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
2873
2874                 return emit_rgctx_fetch (cfg, rgctx, entry);
2875         }
2876 }
2877
2878 static MonoInst*
2879 emit_get_rgctx_field (MonoCompile *cfg, int context_used,
2880                                           MonoClassField *field, int rgctx_type)
2881 {
2882         MonoJumpInfoRgctxEntry *entry = mono_patch_info_rgctx_entry_new (cfg->mempool, cfg->current_method, context_used & MONO_GENERIC_CONTEXT_USED_METHOD, MONO_PATCH_INFO_FIELD, field, rgctx_type);
2883         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
2884
2885         return emit_rgctx_fetch (cfg, rgctx, entry);
2886 }
2887
2888 /*
2889  * On return the caller must check @klass for load errors.
2890  */
2891 static void
2892 emit_generic_class_init (MonoCompile *cfg, MonoClass *klass)
2893 {
2894         MonoInst *vtable_arg;
2895         MonoCallInst *call;
2896         int context_used = 0;
2897
2898         if (cfg->generic_sharing_context)
2899                 context_used = mono_class_check_context_used (klass);
2900
2901         if (context_used) {
2902                 vtable_arg = emit_get_rgctx_klass (cfg, context_used,
2903                                                                                    klass, MONO_RGCTX_INFO_VTABLE);
2904         } else {
2905                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
2906
2907                 if (!vtable)
2908                         return;
2909                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
2910         }
2911
2912         if (COMPILE_LLVM (cfg))
2913                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_GENERIC_CLASS_INIT, NULL, helper_sig_generic_class_init_trampoline_llvm, &vtable_arg);
2914         else
2915                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_GENERIC_CLASS_INIT, NULL, helper_sig_generic_class_init_trampoline, &vtable_arg);
2916 #ifdef MONO_ARCH_VTABLE_REG
2917         mono_call_inst_add_outarg_reg (cfg, call, vtable_arg->dreg, MONO_ARCH_VTABLE_REG, FALSE);
2918         cfg->uses_vtable_reg = TRUE;
2919 #else
2920         NOT_IMPLEMENTED;
2921 #endif
2922 }
2923
2924 /*
2925  * On return the caller must check @array_class for load errors
2926  */
2927 static void
2928 mini_emit_check_array_type (MonoCompile *cfg, MonoInst *obj, MonoClass *array_class)
2929 {
2930         int vtable_reg = alloc_preg (cfg);
2931         int context_used = 0;
2932
2933         if (cfg->generic_sharing_context)
2934                 context_used = mono_class_check_context_used (array_class);
2935
2936         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj->dreg, G_STRUCT_OFFSET (MonoObject, vtable));
2937                                        
2938         if (cfg->opt & MONO_OPT_SHARED) {
2939                 int class_reg = alloc_preg (cfg);
2940                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, class_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
2941                 if (cfg->compile_aot) {
2942                         int klass_reg = alloc_preg (cfg);
2943                         MONO_EMIT_NEW_CLASSCONST (cfg, klass_reg, array_class);
2944                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, class_reg, klass_reg);
2945                 } else {
2946                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, class_reg, array_class);
2947                 }
2948         } else if (context_used) {
2949                 MonoInst *vtable_ins;
2950
2951                 vtable_ins = emit_get_rgctx_klass (cfg, context_used, array_class, MONO_RGCTX_INFO_VTABLE);
2952                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, vtable_reg, vtable_ins->dreg);
2953         } else {
2954                 if (cfg->compile_aot) {
2955                         int vt_reg;
2956                         MonoVTable *vtable;
2957
2958                         if (!(vtable = mono_class_vtable (cfg->domain, array_class)))
2959                                 return;
2960                         vt_reg = alloc_preg (cfg);
2961                         MONO_EMIT_NEW_VTABLECONST (cfg, vt_reg, vtable);
2962                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, vtable_reg, vt_reg);
2963                 } else {
2964                         MonoVTable *vtable;
2965                         if (!(vtable = mono_class_vtable (cfg->domain, array_class)))
2966                                 return;
2967                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vtable);
2968                 }
2969         }
2970         
2971         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "ArrayTypeMismatchException");
2972 }
2973
2974 static void
2975 save_cast_details (MonoCompile *cfg, MonoClass *klass, int obj_reg)
2976 {
2977         if (mini_get_debug_options ()->better_cast_details) {
2978                 int to_klass_reg = alloc_preg (cfg);
2979                 int vtable_reg = alloc_preg (cfg);
2980                 int klass_reg = alloc_preg (cfg);
2981                 MonoInst *tls_get = mono_get_jit_tls_intrinsic (cfg);
2982
2983                 if (!tls_get) {
2984                         fprintf (stderr, "error: --debug=casts not supported on this platform.\n.");
2985                         exit (1);
2986                 }
2987
2988                 MONO_ADD_INS (cfg->cbb, tls_get);
2989                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
2990                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
2991
2992                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, G_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), klass_reg);
2993                 MONO_EMIT_NEW_PCONST (cfg, to_klass_reg, klass);
2994                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, G_STRUCT_OFFSET (MonoJitTlsData, class_cast_to), to_klass_reg);
2995         }
2996 }
2997
2998 static void
2999 reset_cast_details (MonoCompile *cfg)
3000 {
3001         /* Reset the variables holding the cast details */
3002         if (mini_get_debug_options ()->better_cast_details) {
3003                 MonoInst *tls_get = mono_get_jit_tls_intrinsic (cfg);
3004
3005                 MONO_ADD_INS (cfg->cbb, tls_get);
3006                 /* It is enough to reset the from field */
3007                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, tls_get->dreg, G_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), 0);
3008         }
3009 }
3010
3011 /**
3012  * Handles unbox of a Nullable<T>. If context_used is non zero, then shared 
3013  * generic code is generated.
3014  */
3015 static MonoInst*
3016 handle_unbox_nullable (MonoCompile* cfg, MonoInst* val, MonoClass* klass, int context_used)
3017 {
3018         MonoMethod* method = mono_class_get_method_from_name (klass, "Unbox", 1);
3019
3020         if (context_used) {
3021                 MonoInst *rgctx, *addr;
3022
3023                 /* FIXME: What if the class is shared?  We might not
3024                    have to get the address of the method from the
3025                    RGCTX. */
3026                 addr = emit_get_rgctx_method (cfg, context_used, method,
3027                                                                           MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
3028
3029                 rgctx = emit_get_rgctx (cfg, method, context_used);
3030
3031                 return mono_emit_rgctx_calli (cfg, mono_method_signature (method), &val, addr, rgctx);
3032         } else {
3033                 return mono_emit_method_call (cfg, method, &val, NULL);
3034         }
3035 }
3036
3037 static MonoInst*
3038 handle_unbox (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, int context_used)
3039 {
3040         MonoInst *add;
3041         int obj_reg;
3042         int vtable_reg = alloc_dreg (cfg ,STACK_PTR);
3043         int klass_reg = alloc_dreg (cfg ,STACK_PTR);
3044         int eclass_reg = alloc_dreg (cfg ,STACK_PTR);
3045         int rank_reg = alloc_dreg (cfg ,STACK_I4);
3046
3047         obj_reg = sp [0]->dreg;
3048         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
3049         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, rank));
3050
3051         /* FIXME: generics */
3052         g_assert (klass->rank == 0);
3053                         
3054         // Check rank == 0
3055         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, 0);
3056         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
3057
3058         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
3059         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, element_class));
3060
3061         if (context_used) {
3062                 MonoInst *element_class;
3063
3064                 /* This assertion is from the unboxcast insn */
3065                 g_assert (klass->rank == 0);
3066
3067                 element_class = emit_get_rgctx_klass (cfg, context_used,
3068                                 klass->element_class, MONO_RGCTX_INFO_KLASS);
3069
3070                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, eclass_reg, element_class->dreg);
3071                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
3072         } else {
3073                 save_cast_details (cfg, klass->element_class, obj_reg);
3074                 mini_emit_class_check (cfg, eclass_reg, klass->element_class);
3075                 reset_cast_details (cfg);
3076         }
3077
3078         NEW_BIALU_IMM (cfg, add, OP_ADD_IMM, alloc_dreg (cfg, STACK_PTR), obj_reg, sizeof (MonoObject));
3079         MONO_ADD_INS (cfg->cbb, add);
3080         add->type = STACK_MP;
3081         add->klass = klass;
3082
3083         return add;
3084 }
3085
3086 /*
3087  * Returns NULL and set the cfg exception on error.
3088  */
3089 static MonoInst*
3090 handle_alloc (MonoCompile *cfg, MonoClass *klass, gboolean for_box, int context_used)
3091 {
3092         MonoInst *iargs [2];
3093         void *alloc_ftn;
3094
3095         if (context_used) {
3096                 MonoInst *data;
3097                 int rgctx_info;
3098                 MonoInst *iargs [2];
3099
3100                 /*
3101                   FIXME: we cannot get managed_alloc here because we can't get
3102                   the class's vtable (because it's not a closed class)
3103
3104                   MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
3105                   MonoMethod *managed_alloc = mono_gc_get_managed_allocator (vtable, for_box);
3106                 */
3107
3108                 if (cfg->opt & MONO_OPT_SHARED)
3109                         rgctx_info = MONO_RGCTX_INFO_KLASS;
3110                 else
3111                         rgctx_info = MONO_RGCTX_INFO_VTABLE;
3112                 data = emit_get_rgctx_klass (cfg, context_used, klass, rgctx_info);
3113
3114                 if (cfg->opt & MONO_OPT_SHARED) {
3115                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
3116                         iargs [1] = data;
3117                         alloc_ftn = mono_object_new;
3118                 } else {
3119                         iargs [0] = data;
3120                         alloc_ftn = mono_object_new_specific;
3121                 }
3122
3123                 return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
3124         }
3125
3126         if (cfg->opt & MONO_OPT_SHARED) {
3127                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
3128                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
3129
3130                 alloc_ftn = mono_object_new;
3131         } else if (cfg->compile_aot && cfg->cbb->out_of_line && klass->type_token && klass->image == mono_defaults.corlib && !klass->generic_class) {
3132                 /* This happens often in argument checking code, eg. throw new FooException... */
3133                 /* Avoid relocations and save some space by calling a helper function specialized to mscorlib */
3134                 EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (klass->type_token));
3135                 return mono_emit_jit_icall (cfg, mono_helper_newobj_mscorlib, iargs);
3136         } else {
3137                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
3138                 MonoMethod *managed_alloc = NULL;
3139                 gboolean pass_lw;
3140
3141                 if (!vtable) {
3142                         cfg->exception_type = MONO_EXCEPTION_TYPE_LOAD;
3143                         cfg->exception_ptr = klass;
3144                         return NULL;
3145                 }
3146
3147 #ifndef MONO_CROSS_COMPILE
3148                 managed_alloc = mono_gc_get_managed_allocator (vtable, for_box);
3149 #endif
3150
3151                 if (managed_alloc) {
3152                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
3153                         return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
3154                 }
3155                 alloc_ftn = mono_class_get_allocation_ftn (vtable, for_box, &pass_lw);
3156                 if (pass_lw) {
3157                         guint32 lw = vtable->klass->instance_size;
3158                         lw = ((lw + (sizeof (gpointer) - 1)) & ~(sizeof (gpointer) - 1)) / sizeof (gpointer);
3159                         EMIT_NEW_ICONST (cfg, iargs [0], lw);
3160                         EMIT_NEW_VTABLECONST (cfg, iargs [1], vtable);
3161                 }
3162                 else {
3163                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
3164                 }
3165         }
3166
3167         return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
3168 }
3169         
3170 /*
3171  * Returns NULL and set the cfg exception on error.
3172  */     
3173 static MonoInst*
3174 handle_box (MonoCompile *cfg, MonoInst *val, MonoClass *klass, int context_used)
3175 {
3176         MonoInst *alloc, *ins;
3177
3178         if (mono_class_is_nullable (klass)) {
3179                 MonoMethod* method = mono_class_get_method_from_name (klass, "Box", 1);
3180
3181                 if (context_used) {
3182                         /* FIXME: What if the class is shared?  We might not
3183                            have to get the method address from the RGCTX. */
3184                         MonoInst *addr = emit_get_rgctx_method (cfg, context_used, method,
3185                                                                                                         MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
3186                         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3187
3188                         return mono_emit_rgctx_calli (cfg, mono_method_signature (method), &val, addr, rgctx);
3189                 } else {
3190                         return mono_emit_method_call (cfg, method, &val, NULL);
3191                 }
3192         }
3193
3194         alloc = handle_alloc (cfg, klass, TRUE, context_used);
3195         if (!alloc)
3196                 return NULL;
3197
3198         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
3199
3200         return alloc;
3201 }
3202
3203 // FIXME: This doesn't work yet (class libs tests fail?)
3204 #define is_complex_isinst(klass) (TRUE || (klass->flags & TYPE_ATTRIBUTE_INTERFACE) || klass->rank || mono_class_is_nullable (klass) || klass->marshalbyref || (klass->flags & TYPE_ATTRIBUTE_SEALED) || mono_class_has_variant_generic_params (klass) || klass->byval_arg.type == MONO_TYPE_VAR || klass->byval_arg.type == MONO_TYPE_MVAR)
3205
3206 /*
3207  * Returns NULL and set the cfg exception on error.
3208  */
3209 static MonoInst*
3210 handle_castclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context_used)
3211 {
3212         MonoBasicBlock *is_null_bb;
3213         int obj_reg = src->dreg;
3214         int vtable_reg = alloc_preg (cfg);
3215         MonoInst *klass_inst = NULL;
3216
3217         if (context_used) {
3218                 MonoInst *args [2];
3219
3220                 klass_inst = emit_get_rgctx_klass (cfg, context_used,
3221                                                                                    klass, MONO_RGCTX_INFO_KLASS);
3222
3223                 if (is_complex_isinst (klass)) {
3224                         /* Complex case, handle by an icall */
3225
3226                         /* obj */
3227                         args [0] = src;
3228
3229                         /* klass */
3230                         args [1] = klass_inst;
3231
3232                         return mono_emit_jit_icall (cfg, mono_object_castclass, args);
3233                 } else {
3234                         /* Simple case, handled by the code below */
3235                 }
3236         }
3237
3238         NEW_BBLOCK (cfg, is_null_bb);
3239
3240         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
3241         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3242
3243         save_cast_details (cfg, klass, obj_reg);
3244
3245         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
3246                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
3247                 mini_emit_iface_cast (cfg, vtable_reg, klass, NULL, NULL);
3248         } else {
3249                 int klass_reg = alloc_preg (cfg);
3250
3251                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
3252
3253                 if (!klass->rank && !cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && (klass->flags & TYPE_ATTRIBUTE_SEALED)) {
3254                         /* the remoting code is broken, access the class for now */
3255                         if (0) { /*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
3256                                 MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
3257                                 if (!vt) {
3258                                         cfg->exception_type = MONO_EXCEPTION_TYPE_LOAD;
3259                                         cfg->exception_ptr = klass;
3260                                         return NULL;
3261                                 }
3262                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vt);
3263                         } else {
3264                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
3265                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
3266                         }
3267                         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
3268                 } else {
3269                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
3270                         mini_emit_castclass_inst (cfg, obj_reg, klass_reg, klass, klass_inst, is_null_bb);
3271                 }
3272         }
3273
3274         MONO_START_BB (cfg, is_null_bb);
3275
3276         reset_cast_details (cfg);
3277
3278         return src;
3279 }
3280
3281 /*
3282  * Returns NULL and set the cfg exception on error.
3283  */
3284 static MonoInst*
3285 handle_isinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context_used)
3286 {
3287         MonoInst *ins;
3288         MonoBasicBlock *is_null_bb, *false_bb, *end_bb;
3289         int obj_reg = src->dreg;
3290         int vtable_reg = alloc_preg (cfg);
3291         int res_reg = alloc_preg (cfg);
3292         MonoInst *klass_inst = NULL;
3293
3294         if (context_used) {
3295                 klass_inst = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
3296
3297                 if (is_complex_isinst (klass)) {
3298                         MonoInst *args [2];
3299
3300                         /* Complex case, handle by an icall */
3301
3302                         /* obj */
3303                         args [0] = src;
3304
3305                         /* klass */
3306                         args [1] = klass_inst;
3307
3308                         return mono_emit_jit_icall (cfg, mono_object_isinst, args);
3309                 } else {
3310                         /* Simple case, the code below can handle it */
3311                 }
3312         }
3313
3314         NEW_BBLOCK (cfg, is_null_bb);
3315         NEW_BBLOCK (cfg, false_bb);
3316         NEW_BBLOCK (cfg, end_bb);
3317
3318         /* Do the assignment at the beginning, so the other assignment can be if converted */
3319         EMIT_NEW_UNALU (cfg, ins, OP_MOVE, res_reg, obj_reg);
3320         ins->type = STACK_OBJ;
3321         ins->klass = klass;
3322
3323         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
3324         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_null_bb);
3325
3326         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
3327
3328         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
3329                 g_assert (!context_used);
3330                 /* the is_null_bb target simply copies the input register to the output */
3331                 mini_emit_iface_cast (cfg, vtable_reg, klass, false_bb, is_null_bb);
3332         } else {
3333                 int klass_reg = alloc_preg (cfg);
3334
3335                 if (klass->rank) {
3336                         int rank_reg = alloc_preg (cfg);
3337                         int eclass_reg = alloc_preg (cfg);
3338
3339                         g_assert (!context_used);
3340                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, rank));
3341                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank);
3342                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
3343                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
3344                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, cast_class));
3345                         if (klass->cast_class == mono_defaults.object_class) {
3346                                 int parent_reg = alloc_preg (cfg);
3347                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, parent_reg, eclass_reg, G_STRUCT_OFFSET (MonoClass, parent));
3348                                 mini_emit_class_check_branch (cfg, parent_reg, mono_defaults.enum_class->parent, OP_PBNE_UN, is_null_bb);
3349                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);
3350                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
3351                         } else if (klass->cast_class == mono_defaults.enum_class->parent) {
3352                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class->parent, OP_PBEQ, is_null_bb);
3353                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);                          
3354                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
3355                         } else if (klass->cast_class == mono_defaults.enum_class) {
3356                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);
3357                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
3358                         } else if (klass->cast_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
3359                                 mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb);
3360                         } else {
3361                                 if ((klass->rank == 1) && (klass->byval_arg.type == MONO_TYPE_SZARRAY)) {
3362                                         /* Check that the object is a vector too */
3363                                         int bounds_reg = alloc_preg (cfg);
3364                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, obj_reg, G_STRUCT_OFFSET (MonoArray, bounds));
3365                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
3366                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
3367                                 }
3368
3369                                 /* the is_null_bb target simply copies the input register to the output */
3370                                 mini_emit_isninst_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb);
3371                         }
3372                 } else if (mono_class_is_nullable (klass)) {
3373                         g_assert (!context_used);
3374                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
3375                         /* the is_null_bb target simply copies the input register to the output */
3376                         mini_emit_isninst_cast (cfg, klass_reg, klass->cast_class, false_bb, is_null_bb);
3377                 } else {
3378                         if (!cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && (klass->flags & TYPE_ATTRIBUTE_SEALED)) {
3379                                 g_assert (!context_used);
3380                                 /* the remoting code is broken, access the class for now */
3381                                 if (0) {/*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
3382                                         MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
3383                                         if (!vt) {
3384                                                 cfg->exception_type = MONO_EXCEPTION_TYPE_LOAD;
3385                                                 cfg->exception_ptr = klass;
3386                                                 return NULL;
3387                                         }
3388                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vt);
3389                                 } else {
3390                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
3391                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
3392                                 }
3393                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
3394                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, is_null_bb);
3395                         } else {
3396                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
3397                                 /* the is_null_bb target simply copies the input register to the output */
3398                                 mini_emit_isninst_cast_inst (cfg, klass_reg, klass, klass_inst, false_bb, is_null_bb);
3399                         }
3400                 }
3401         }
3402
3403         MONO_START_BB (cfg, false_bb);
3404
3405         MONO_EMIT_NEW_PCONST (cfg, res_reg, 0);
3406         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3407
3408         MONO_START_BB (cfg, is_null_bb);
3409
3410         MONO_START_BB (cfg, end_bb);
3411
3412         return ins;
3413 }
3414
3415 static MonoInst*
3416 handle_cisinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
3417 {
3418         /* This opcode takes as input an object reference and a class, and returns:
3419         0) if the object is an instance of the class,
3420         1) if the object is not instance of the class,
3421         2) if the object is a proxy whose type cannot be determined */
3422
3423         MonoInst *ins;
3424         MonoBasicBlock *true_bb, *false_bb, *false2_bb, *end_bb, *no_proxy_bb, *interface_fail_bb;
3425         int obj_reg = src->dreg;
3426         int dreg = alloc_ireg (cfg);
3427         int tmp_reg;
3428         int klass_reg = alloc_preg (cfg);
3429
3430         NEW_BBLOCK (cfg, true_bb);
3431         NEW_BBLOCK (cfg, false_bb);
3432         NEW_BBLOCK (cfg, false2_bb);
3433         NEW_BBLOCK (cfg, end_bb);
3434         NEW_BBLOCK (cfg, no_proxy_bb);
3435
3436         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
3437         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, false_bb);
3438
3439         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
3440                 NEW_BBLOCK (cfg, interface_fail_bb);
3441
3442                 tmp_reg = alloc_preg (cfg);
3443                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
3444                 mini_emit_iface_cast (cfg, tmp_reg, klass, interface_fail_bb, true_bb);
3445                 MONO_START_BB (cfg, interface_fail_bb);
3446                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, G_STRUCT_OFFSET (MonoVTable, klass));
3447                 
3448                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, false_bb);
3449
3450                 tmp_reg = alloc_preg (cfg);
3451                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
3452                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
3453                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false2_bb);                
3454         } else {
3455                 tmp_reg = alloc_preg (cfg);
3456                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
3457                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, G_STRUCT_OFFSET (MonoVTable, klass));
3458
3459                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, no_proxy_bb);          
3460                 tmp_reg = alloc_preg (cfg);
3461                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoTransparentProxy, remote_class));
3462                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, G_STRUCT_OFFSET (MonoRemoteClass, proxy_class));
3463
3464                 tmp_reg = alloc_preg (cfg);             
3465                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
3466                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
3467                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, no_proxy_bb);
3468                 
3469                 mini_emit_isninst_cast (cfg, klass_reg, klass, false2_bb, true_bb);
3470                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false2_bb);
3471
3472                 MONO_START_BB (cfg, no_proxy_bb);
3473
3474                 mini_emit_isninst_cast (cfg, klass_reg, klass, false_bb, true_bb);
3475         }
3476
3477         MONO_START_BB (cfg, false_bb);
3478
3479         MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
3480         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3481
3482         MONO_START_BB (cfg, false2_bb);
3483
3484         MONO_EMIT_NEW_ICONST (cfg, dreg, 2);
3485         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3486
3487         MONO_START_BB (cfg, true_bb);
3488
3489         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
3490
3491         MONO_START_BB (cfg, end_bb);
3492
3493         /* FIXME: */
3494         MONO_INST_NEW (cfg, ins, OP_ICONST);
3495         ins->dreg = dreg;
3496         ins->type = STACK_I4;
3497
3498         return ins;
3499 }
3500
3501 static MonoInst*
3502 handle_ccastclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
3503 {
3504         /* This opcode takes as input an object reference and a class, and returns:
3505         0) if the object is an instance of the class,
3506         1) if the object is a proxy whose type cannot be determined
3507         an InvalidCastException exception is thrown otherwhise*/
3508         
3509         MonoInst *ins;
3510         MonoBasicBlock *end_bb, *ok_result_bb, *no_proxy_bb, *interface_fail_bb, *fail_1_bb;
3511         int obj_reg = src->dreg;
3512         int dreg = alloc_ireg (cfg);
3513         int tmp_reg = alloc_preg (cfg);
3514         int klass_reg = alloc_preg (cfg);
3515
3516         NEW_BBLOCK (cfg, end_bb);
3517         NEW_BBLOCK (cfg, ok_result_bb);
3518
3519         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
3520         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, ok_result_bb);
3521
3522         save_cast_details (cfg, klass, obj_reg);
3523
3524         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
3525                 NEW_BBLOCK (cfg, interface_fail_bb);
3526         
3527                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
3528                 mini_emit_iface_cast (cfg, tmp_reg, klass, interface_fail_bb, ok_result_bb);
3529                 MONO_START_BB (cfg, interface_fail_bb);
3530                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, G_STRUCT_OFFSET (MonoVTable, klass));
3531
3532                 mini_emit_class_check (cfg, klass_reg, mono_defaults.transparent_proxy_class);
3533
3534                 tmp_reg = alloc_preg (cfg);             
3535                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
3536                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
3537                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
3538                 
3539                 MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
3540                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3541                 
3542         } else {
3543                 NEW_BBLOCK (cfg, no_proxy_bb);
3544
3545                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
3546                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, G_STRUCT_OFFSET (MonoVTable, klass));
3547                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, no_proxy_bb);          
3548
3549                 tmp_reg = alloc_preg (cfg);
3550                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoTransparentProxy, remote_class));
3551                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, G_STRUCT_OFFSET (MonoRemoteClass, proxy_class));
3552
3553                 tmp_reg = alloc_preg (cfg);
3554                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
3555                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
3556                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, no_proxy_bb);
3557
3558                 NEW_BBLOCK (cfg, fail_1_bb);
3559                 
3560                 mini_emit_isninst_cast (cfg, klass_reg, klass, fail_1_bb, ok_result_bb);
3561
3562                 MONO_START_BB (cfg, fail_1_bb);
3563
3564                 MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
3565                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3566
3567                 MONO_START_BB (cfg, no_proxy_bb);
3568
3569                 mini_emit_castclass (cfg, obj_reg, klass_reg, klass, ok_result_bb);
3570         }
3571
3572         MONO_START_BB (cfg, ok_result_bb);
3573
3574         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
3575
3576         MONO_START_BB (cfg, end_bb);
3577
3578         /* FIXME: */
3579         MONO_INST_NEW (cfg, ins, OP_ICONST);
3580         ins->dreg = dreg;
3581         ins->type = STACK_I4;
3582
3583         return ins;
3584 }
3585
3586 /*
3587  * Returns NULL and set the cfg exception on error.
3588  */
3589 static G_GNUC_UNUSED MonoInst*
3590 handle_delegate_ctor (MonoCompile *cfg, MonoClass *klass, MonoInst *target, MonoMethod *method, int context_used)
3591 {
3592         gpointer *trampoline;
3593         MonoInst *obj, *method_ins, *tramp_ins;
3594         MonoDomain *domain;
3595         guint8 **code_slot;
3596
3597         obj = handle_alloc (cfg, klass, FALSE, 0);
3598         if (!obj)
3599                 return NULL;
3600
3601         /* Inline the contents of mono_delegate_ctor */
3602
3603         /* Set target field */
3604         /* Optimize away setting of NULL target */
3605         if (!(target->opcode == OP_PCONST && target->inst_p0 == 0))
3606                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, G_STRUCT_OFFSET (MonoDelegate, target), target->dreg);
3607
3608         /* Set method field */
3609         method_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD);
3610         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, G_STRUCT_OFFSET (MonoDelegate, method), method_ins->dreg);
3611
3612         /* 
3613          * To avoid looking up the compiled code belonging to the target method
3614          * in mono_delegate_trampoline (), we allocate a per-domain memory slot to
3615          * store it, and we fill it after the method has been compiled.
3616          */
3617         if (!cfg->compile_aot && !method->dynamic) {
3618                 MonoInst *code_slot_ins;
3619
3620                 if (context_used) {
3621                         code_slot_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD_DELEGATE_CODE);
3622                 } else {
3623                         domain = mono_domain_get ();
3624                         mono_domain_lock (domain);
3625                         if (!domain_jit_info (domain)->method_code_hash)
3626                                 domain_jit_info (domain)->method_code_hash = g_hash_table_new (NULL, NULL);
3627                         code_slot = g_hash_table_lookup (domain_jit_info (domain)->method_code_hash, method);
3628                         if (!code_slot) {
3629                                 code_slot = mono_domain_alloc0 (domain, sizeof (gpointer));
3630                                 g_hash_table_insert (domain_jit_info (domain)->method_code_hash, method, code_slot);
3631                         }
3632                         mono_domain_unlock (domain);
3633
3634                         EMIT_NEW_PCONST (cfg, code_slot_ins, code_slot);
3635                 }
3636                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, G_STRUCT_OFFSET (MonoDelegate, method_code), code_slot_ins->dreg);           
3637         }
3638
3639         /* Set invoke_impl field */
3640         if (cfg->compile_aot) {
3641                 EMIT_NEW_AOTCONST (cfg, tramp_ins, MONO_PATCH_INFO_DELEGATE_TRAMPOLINE, klass);
3642         } else {
3643                 trampoline = mono_create_delegate_trampoline (klass);
3644                 EMIT_NEW_PCONST (cfg, tramp_ins, trampoline);
3645         }
3646         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, G_STRUCT_OFFSET (MonoDelegate, invoke_impl), tramp_ins->dreg);
3647
3648         /* All the checks which are in mono_delegate_ctor () are done by the delegate trampoline */
3649
3650         return obj;
3651 }
3652
3653 static MonoInst*
3654 handle_array_new (MonoCompile *cfg, int rank, MonoInst **sp, unsigned char *ip)
3655 {
3656         MonoJitICallInfo *info;
3657
3658         /* Need to register the icall so it gets an icall wrapper */
3659         info = mono_get_array_new_va_icall (rank);
3660
3661         cfg->flags |= MONO_CFG_HAS_VARARGS;
3662
3663         /* mono_array_new_va () needs a vararg calling convention */
3664         cfg->disable_llvm = TRUE;
3665
3666         /* FIXME: This uses info->sig, but it should use the signature of the wrapper */
3667         return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, sp);
3668 }
3669
3670 static void
3671 mono_emit_load_got_addr (MonoCompile *cfg)
3672 {
3673         MonoInst *getaddr, *dummy_use;
3674
3675         if (!cfg->got_var || cfg->got_var_allocated)
3676                 return;
3677
3678         MONO_INST_NEW (cfg, getaddr, OP_LOAD_GOTADDR);
3679         getaddr->dreg = cfg->got_var->dreg;
3680
3681         /* Add it to the start of the first bblock */
3682         if (cfg->bb_entry->code) {
3683                 getaddr->next = cfg->bb_entry->code;
3684                 cfg->bb_entry->code = getaddr;
3685         }
3686         else
3687                 MONO_ADD_INS (cfg->bb_entry, getaddr);
3688
3689         cfg->got_var_allocated = TRUE;
3690
3691         /* 
3692          * Add a dummy use to keep the got_var alive, since real uses might
3693          * only be generated by the back ends.
3694          * Add it to end_bblock, so the variable's lifetime covers the whole
3695          * method.
3696          * It would be better to make the usage of the got var explicit in all
3697          * cases when the backend needs it (i.e. calls, throw etc.), so this
3698          * wouldn't be needed.
3699          */
3700         NEW_DUMMY_USE (cfg, dummy_use, cfg->got_var);
3701         MONO_ADD_INS (cfg->bb_exit, dummy_use);
3702 }
3703
3704 static int inline_limit;
3705 static gboolean inline_limit_inited;
3706
3707 static gboolean
3708 mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method)
3709 {
3710         MonoMethodHeaderSummary header;
3711         MonoVTable *vtable;
3712 #ifdef MONO_ARCH_SOFT_FLOAT
3713         MonoMethodSignature *sig = mono_method_signature (method);
3714         int i;
3715 #endif
3716
3717         if (cfg->generic_sharing_context)
3718                 return FALSE;
3719
3720         if (cfg->inline_depth > 10)
3721                 return FALSE;
3722
3723 #ifdef MONO_ARCH_HAVE_LMF_OPS
3724         if (((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
3725                  (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) &&
3726             !MONO_TYPE_ISSTRUCT (signature->ret) && !mini_class_is_system_array (method->klass))
3727                 return TRUE;
3728 #endif
3729
3730
3731         if (!mono_method_get_header_summary (method, &header))
3732                 return FALSE;
3733
3734         /*runtime, icall and pinvoke are checked by summary call*/
3735         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_NOINLINING) ||
3736             (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) ||
3737             (method->klass->marshalbyref) ||
3738             header.has_clauses)
3739                 return FALSE;
3740
3741         /* also consider num_locals? */
3742         /* Do the size check early to avoid creating vtables */
3743         if (!inline_limit_inited) {
3744                 if (getenv ("MONO_INLINELIMIT"))
3745                         inline_limit = atoi (getenv ("MONO_INLINELIMIT"));
3746                 else
3747                         inline_limit = INLINE_LENGTH_LIMIT;
3748                 inline_limit_inited = TRUE;
3749         }
3750         if (header.code_size >= inline_limit)
3751                 return FALSE;
3752
3753         /*
3754          * if we can initialize the class of the method right away, we do,
3755          * otherwise we don't allow inlining if the class needs initialization,
3756          * since it would mean inserting a call to mono_runtime_class_init()
3757          * inside the inlined code
3758          */
3759         if (!(cfg->opt & MONO_OPT_SHARED)) {
3760                 if (method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) {
3761                         if (cfg->run_cctors && method->klass->has_cctor) {
3762                                 /*FIXME it would easier and lazier to just use mono_class_try_get_vtable */
3763                                 if (!method->klass->runtime_info)
3764                                         /* No vtable created yet */
3765                                         return FALSE;
3766                                 vtable = mono_class_vtable (cfg->domain, method->klass);
3767                                 if (!vtable)
3768                                         return FALSE;
3769                                 /* This makes so that inline cannot trigger */
3770                                 /* .cctors: too many apps depend on them */
3771                                 /* running with a specific order... */
3772                                 if (! vtable->initialized)
3773                                         return FALSE;
3774                                 mono_runtime_class_init (vtable);
3775                         }
3776                 } else if (mono_class_needs_cctor_run (method->klass, NULL)) {
3777                         if (!method->klass->runtime_info)
3778                                 /* No vtable created yet */
3779                                 return FALSE;
3780                         vtable = mono_class_vtable (cfg->domain, method->klass);
3781                         if (!vtable)
3782                                 return FALSE;
3783                         if (!vtable->initialized)
3784                                 return FALSE;
3785                 }
3786         } else {
3787                 /* 
3788                  * If we're compiling for shared code
3789                  * the cctor will need to be run at aot method load time, for example,
3790                  * or at the end of the compilation of the inlining method.
3791                  */
3792                 if (mono_class_needs_cctor_run (method->klass, NULL) && !((method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT)))
3793                         return FALSE;
3794         }
3795
3796         /*
3797          * CAS - do not inline methods with declarative security
3798          * Note: this has to be before any possible return TRUE;
3799          */
3800         if (mono_method_has_declsec (method))
3801                 return FALSE;
3802
3803 #ifdef MONO_ARCH_SOFT_FLOAT
3804         /* FIXME: */
3805         if (sig->ret && sig->ret->type == MONO_TYPE_R4)
3806                 return FALSE;
3807         for (i = 0; i < sig->param_count; ++i)
3808                 if (!sig->params [i]->byref && sig->params [i]->type == MONO_TYPE_R4)
3809                         return FALSE;
3810 #endif
3811
3812         return TRUE;
3813 }
3814
3815 static gboolean
3816 mini_field_access_needs_cctor_run (MonoCompile *cfg, MonoMethod *method, MonoVTable *vtable)
3817 {
3818         if (vtable->initialized && !cfg->compile_aot)
3819                 return FALSE;
3820
3821         if (vtable->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT)
3822                 return FALSE;
3823
3824         if (!mono_class_needs_cctor_run (vtable->klass, method))
3825                 return FALSE;
3826
3827         if (! (method->flags & METHOD_ATTRIBUTE_STATIC) && (vtable->klass == method->klass))
3828                 /* The initialization is already done before the method is called */
3829                 return FALSE;
3830
3831         return TRUE;
3832 }
3833
3834 static MonoInst*
3835 mini_emit_ldelema_1_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index, gboolean bcheck)
3836 {
3837         MonoInst *ins;
3838         guint32 size;
3839         int mult_reg, add_reg, array_reg, index_reg, index2_reg;
3840
3841         mono_class_init (klass);
3842         size = mono_class_array_element_size (klass);
3843
3844         mult_reg = alloc_preg (cfg);
3845         array_reg = arr->dreg;
3846         index_reg = index->dreg;
3847
3848 #if SIZEOF_REGISTER == 8
3849         /* The array reg is 64 bits but the index reg is only 32 */
3850         if (COMPILE_LLVM (cfg)) {
3851                 /* Not needed */
3852                 index2_reg = index_reg;
3853         } else {
3854                 index2_reg = alloc_preg (cfg);
3855                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index2_reg, index_reg);
3856         }
3857 #else
3858         if (index->type == STACK_I8) {
3859                 index2_reg = alloc_preg (cfg);
3860                 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I4, index2_reg, index_reg);
3861         } else {
3862                 index2_reg = index_reg;
3863         }
3864 #endif
3865
3866         if (bcheck)
3867                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index2_reg);
3868
3869 #if defined(TARGET_X86) || defined(TARGET_AMD64)
3870         if (size == 1 || size == 2 || size == 4 || size == 8) {
3871                 static const int fast_log2 [] = { 1, 0, 1, -1, 2, -1, -1, -1, 3 };
3872
3873                 EMIT_NEW_X86_LEA (cfg, ins, array_reg, index2_reg, fast_log2 [size], G_STRUCT_OFFSET (MonoArray, vector));
3874                 ins->type = STACK_PTR;
3875
3876                 return ins;
3877         }
3878 #endif          
3879
3880         add_reg = alloc_preg (cfg);
3881
3882         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MUL_IMM, mult_reg, index2_reg, size);
3883         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, array_reg, mult_reg);
3884         NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, G_STRUCT_OFFSET (MonoArray, vector));
3885         ins->type = STACK_PTR;
3886         MONO_ADD_INS (cfg->cbb, ins);
3887
3888         return ins;
3889 }
3890
3891 #ifndef MONO_ARCH_EMULATE_MUL_DIV
3892 static MonoInst*
3893 mini_emit_ldelema_2_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index_ins1, MonoInst *index_ins2)
3894 {
3895         int bounds_reg = alloc_preg (cfg);
3896         int add_reg = alloc_preg (cfg);
3897         int mult_reg = alloc_preg (cfg);
3898         int mult2_reg = alloc_preg (cfg);
3899         int low1_reg = alloc_preg (cfg);
3900         int low2_reg = alloc_preg (cfg);
3901         int high1_reg = alloc_preg (cfg);
3902         int high2_reg = alloc_preg (cfg);
3903         int realidx1_reg = alloc_preg (cfg);
3904         int realidx2_reg = alloc_preg (cfg);
3905         int sum_reg = alloc_preg (cfg);
3906         int index1, index2;
3907         MonoInst *ins;
3908         guint32 size;
3909
3910         mono_class_init (klass);
3911         size = mono_class_array_element_size (klass);
3912
3913         index1 = index_ins1->dreg;
3914         index2 = index_ins2->dreg;
3915
3916         /* range checking */
3917         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, 
3918                                        arr->dreg, G_STRUCT_OFFSET (MonoArray, bounds));
3919
3920         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low1_reg, 
3921                                        bounds_reg, G_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
3922         MONO_EMIT_NEW_BIALU (cfg, OP_PSUB, realidx1_reg, index1, low1_reg);
3923         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high1_reg, 
3924                                        bounds_reg, G_STRUCT_OFFSET (MonoArrayBounds, length));
3925         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, high1_reg, realidx1_reg);
3926         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException");
3927
3928         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low2_reg, 
3929                                        bounds_reg, sizeof (MonoArrayBounds) + G_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
3930         MONO_EMIT_NEW_BIALU (cfg, OP_PSUB, realidx2_reg, index2, low2_reg);
3931         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high2_reg, 
3932                                        bounds_reg, sizeof (MonoArrayBounds) + G_STRUCT_OFFSET (MonoArrayBounds, length));
3933         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, high2_reg, realidx2_reg);
3934         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException");
3935
3936         MONO_EMIT_NEW_BIALU (cfg, OP_PMUL, mult_reg, high2_reg, realidx1_reg);
3937         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, mult_reg, realidx2_reg);
3938         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PMUL_IMM, mult2_reg, sum_reg, size);
3939         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult2_reg, arr->dreg);
3940         NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, G_STRUCT_OFFSET (MonoArray, vector));
3941
3942         ins->type = STACK_MP;
3943         ins->klass = klass;
3944         MONO_ADD_INS (cfg->cbb, ins);
3945
3946         return ins;
3947 }
3948 #endif
3949
3950 static MonoInst*
3951 mini_emit_ldelema_ins (MonoCompile *cfg, MonoMethod *cmethod, MonoInst **sp, unsigned char *ip, gboolean is_set)
3952 {
3953         int rank;
3954         MonoInst *addr;
3955         MonoMethod *addr_method;
3956         int element_size;
3957
3958         rank = mono_method_signature (cmethod)->param_count - (is_set? 1: 0);
3959
3960         if (rank == 1)
3961                 return mini_emit_ldelema_1_ins (cfg, cmethod->klass->element_class, sp [0], sp [1], TRUE);
3962
3963 #ifndef MONO_ARCH_EMULATE_MUL_DIV
3964         /* emit_ldelema_2 depends on OP_LMUL */
3965         if (rank == 2 && (cfg->opt & MONO_OPT_INTRINS)) {
3966                 return mini_emit_ldelema_2_ins (cfg, cmethod->klass->element_class, sp [0], sp [1], sp [2]);
3967         }
3968 #endif
3969
3970         element_size = mono_class_array_element_size (cmethod->klass->element_class);
3971         addr_method = mono_marshal_get_array_address (rank, element_size);
3972         addr = mono_emit_method_call (cfg, addr_method, sp, NULL);
3973
3974         return addr;
3975 }
3976
3977 static MonoBreakPolicy
3978 always_insert_breakpoint (MonoMethod *method)
3979 {
3980         return MONO_BREAK_POLICY_ALWAYS;
3981 }
3982
3983 static MonoBreakPolicyFunc break_policy_func = always_insert_breakpoint;
3984
3985 /**
3986  * mono_set_break_policy:
3987  * policy_callback: the new callback function
3988  *
3989  * Allow embedders to decide wherther to actually obey breakpoint instructions
3990  * (both break IL instructions and Debugger.Break () method calls), for example
3991  * to not allow an app to be aborted by a perfectly valid IL opcode when executing
3992  * untrusted or semi-trusted code.
3993  *
3994  * @policy_callback will be called every time a break point instruction needs to
3995  * be inserted with the method argument being the method that calls Debugger.Break()
3996  * or has the IL break instruction. The callback should return #MONO_BREAK_POLICY_NEVER
3997  * if it wants the breakpoint to not be effective in the given method.
3998  * #MONO_BREAK_POLICY_ALWAYS is the default.
3999  */
4000 void
4001 mono_set_break_policy (MonoBreakPolicyFunc policy_callback)
4002 {
4003         if (policy_callback)
4004                 break_policy_func = policy_callback;
4005         else
4006                 break_policy_func = always_insert_breakpoint;
4007 }
4008
4009 static gboolean
4010 should_insert_brekpoint (MonoMethod *method) {
4011         switch (break_policy_func (method)) {
4012         case MONO_BREAK_POLICY_ALWAYS:
4013                 return TRUE;
4014         case MONO_BREAK_POLICY_NEVER:
4015                 return FALSE;
4016         case MONO_BREAK_POLICY_ON_DBG:
4017                 return mono_debug_using_mono_debugger ();
4018         default:
4019                 g_warning ("Incorrect value returned from break policy callback");
4020                 return FALSE;
4021         }
4022 }
4023
4024 /* optimize the simple GetGenericValueImpl/SetGenericValueImpl generic icalls */
4025 static MonoInst*
4026 emit_array_generic_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set)
4027 {
4028         MonoInst *addr, *store, *load;
4029         MonoClass *eklass = mono_class_from_mono_type (fsig->params [2]);
4030
4031         /* the bounds check is already done by the callers */
4032         addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1], FALSE);
4033         if (is_set) {
4034                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, args [2]->dreg, 0);
4035                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, addr->dreg, 0, load->dreg);
4036         } else {
4037                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, addr->dreg, 0);
4038                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, args [2]->dreg, 0, load->dreg);
4039         }
4040         return store;
4041 }
4042
4043 static MonoInst*
4044 mini_emit_inst_for_ctor (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
4045 {
4046         MonoInst *ins = NULL;
4047 #ifdef MONO_ARCH_SIMD_INTRINSICS
4048         if (cfg->opt & MONO_OPT_SIMD) {
4049                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
4050                 if (ins)
4051                         return ins;
4052         }
4053 #endif
4054
4055         return ins;
4056 }
4057
4058 static MonoInst*
4059 mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
4060 {
4061         MonoInst *ins = NULL;
4062         
4063         static MonoClass *runtime_helpers_class = NULL;
4064         if (! runtime_helpers_class)
4065                 runtime_helpers_class = mono_class_from_name (mono_defaults.corlib,
4066                         "System.Runtime.CompilerServices", "RuntimeHelpers");
4067
4068         if (cmethod->klass == mono_defaults.string_class) {
4069                 if (strcmp (cmethod->name, "get_Chars") == 0) {
4070                         int dreg = alloc_ireg (cfg);
4071                         int index_reg = alloc_preg (cfg);
4072                         int mult_reg = alloc_preg (cfg);
4073                         int add_reg = alloc_preg (cfg);
4074
4075 #if SIZEOF_REGISTER == 8
4076                         /* The array reg is 64 bits but the index reg is only 32 */
4077                         MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index_reg, args [1]->dreg);
4078 #else
4079                         index_reg = args [1]->dreg;
4080 #endif  
4081                         MONO_EMIT_BOUNDS_CHECK (cfg, args [0]->dreg, MonoString, length, index_reg);
4082
4083 #if defined(TARGET_X86) || defined(TARGET_AMD64)
4084                         EMIT_NEW_X86_LEA (cfg, ins, args [0]->dreg, index_reg, 1, G_STRUCT_OFFSET (MonoString, chars));
4085                         add_reg = ins->dreg;
4086                         /* Avoid a warning */
4087                         mult_reg = 0;
4088                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
4089                                                                    add_reg, 0);
4090 #else
4091                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, mult_reg, index_reg, 1);
4092                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult_reg, args [0]->dreg);
4093                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
4094                                                                    add_reg, G_STRUCT_OFFSET (MonoString, chars));
4095 #endif
4096                         type_from_op (ins, NULL, NULL);
4097                         return ins;
4098                 } else if (strcmp (cmethod->name, "get_Length") == 0) {
4099                         int dreg = alloc_ireg (cfg);
4100                         /* Decompose later to allow more optimizations */
4101                         EMIT_NEW_UNALU (cfg, ins, OP_STRLEN, dreg, args [0]->dreg);
4102                         ins->type = STACK_I4;
4103                         cfg->cbb->has_array_access = TRUE;
4104                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
4105
4106                         return ins;
4107                 } else if (strcmp (cmethod->name, "InternalSetChar") == 0) {
4108                         int mult_reg = alloc_preg (cfg);
4109                         int add_reg = alloc_preg (cfg);
4110
4111                         /* The corlib functions check for oob already. */
4112                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, mult_reg, args [1]->dreg, 1);
4113                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult_reg, args [0]->dreg);
4114                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, add_reg, G_STRUCT_OFFSET (MonoString, chars), args [2]->dreg);
4115                         return cfg->cbb->last_ins;
4116                 } else 
4117                         return NULL;
4118         } else if (cmethod->klass == mono_defaults.object_class) {
4119
4120                 if (strcmp (cmethod->name, "GetType") == 0) {
4121                         int dreg = alloc_preg (cfg);
4122                         int vt_reg = alloc_preg (cfg);
4123                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vt_reg, args [0]->dreg, G_STRUCT_OFFSET (MonoObject, vtable));
4124                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, vt_reg, G_STRUCT_OFFSET (MonoVTable, type));
4125                         type_from_op (ins, NULL, NULL);
4126
4127                         return ins;
4128 #if !defined(MONO_ARCH_EMULATE_MUL_DIV) && !defined(HAVE_MOVING_COLLECTOR)
4129                 } else if (strcmp (cmethod->name, "InternalGetHashCode") == 0) {
4130                         int dreg = alloc_ireg (cfg);
4131                         int t1 = alloc_ireg (cfg);
4132         
4133                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, t1, args [0]->dreg, 3);
4134                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_MUL_IMM, dreg, t1, 2654435761u);
4135                         ins->type = STACK_I4;
4136
4137                         return ins;
4138 #endif
4139                 } else if (strcmp (cmethod->name, ".ctor") == 0) {
4140                         MONO_INST_NEW (cfg, ins, OP_NOP);
4141                         MONO_ADD_INS (cfg->cbb, ins);
4142                         return ins;
4143                 } else
4144                         return NULL;
4145         } else if (cmethod->klass == mono_defaults.array_class) {
4146                 if (strcmp (cmethod->name + 1, "etGenericValueImpl") == 0)
4147                         return emit_array_generic_access (cfg, fsig, args, *cmethod->name == 'S');
4148                 if (cmethod->name [0] != 'g')
4149                         return NULL;
4150
4151                 if (strcmp (cmethod->name, "get_Rank") == 0) {
4152                         int dreg = alloc_ireg (cfg);
4153                         int vtable_reg = alloc_preg (cfg);
4154                         MONO_EMIT_NEW_LOAD_MEMBASE_OP_FAULT (cfg, OP_LOAD_MEMBASE, vtable_reg, 
4155                                                                                                  args [0]->dreg, G_STRUCT_OFFSET (MonoObject, vtable));
4156                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU1_MEMBASE, dreg,
4157                                                                    vtable_reg, G_STRUCT_OFFSET (MonoVTable, rank));
4158                         type_from_op (ins, NULL, NULL);
4159
4160                         return ins;
4161                 } else if (strcmp (cmethod->name, "get_Length") == 0) {
4162                         int dreg = alloc_ireg (cfg);
4163
4164                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOADI4_MEMBASE, dreg, 
4165                                                                                  args [0]->dreg, G_STRUCT_OFFSET (MonoArray, max_length));
4166                         type_from_op (ins, NULL, NULL);
4167
4168                         return ins;
4169                 } else
4170                         return NULL;
4171         } else if (cmethod->klass == runtime_helpers_class) {
4172
4173                 if (strcmp (cmethod->name, "get_OffsetToStringData") == 0) {
4174                         EMIT_NEW_ICONST (cfg, ins, G_STRUCT_OFFSET (MonoString, chars));
4175                         return ins;
4176                 } else
4177                         return NULL;
4178         } else if (cmethod->klass == mono_defaults.thread_class) {
4179                 if (strcmp (cmethod->name, "SpinWait_nop") == 0) {
4180                         MONO_INST_NEW (cfg, ins, OP_RELAXED_NOP);
4181                         MONO_ADD_INS (cfg->cbb, ins);
4182                         return ins;
4183                 } else if (strcmp (cmethod->name, "MemoryBarrier") == 0) {
4184                         MONO_INST_NEW (cfg, ins, OP_MEMORY_BARRIER);
4185                         MONO_ADD_INS (cfg->cbb, ins);
4186                         return ins;
4187                 }
4188         } else if (cmethod->klass == mono_defaults.monitor_class) {
4189 #if defined(MONO_ARCH_MONITOR_OBJECT_REG)
4190                 if (strcmp (cmethod->name, "Enter") == 0) {
4191                         MonoCallInst *call;
4192
4193                         if (COMPILE_LLVM (cfg)) {
4194                                 /* 
4195                                  * Pass the argument normally, the LLVM backend will handle the
4196                                  * calling convention problems.
4197                                  */
4198                                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_ENTER, NULL, helper_sig_monitor_enter_exit_trampoline_llvm, args);
4199                         } else {
4200                                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_ENTER,
4201                                             NULL, helper_sig_monitor_enter_exit_trampoline, NULL);
4202                                 mono_call_inst_add_outarg_reg (cfg, call, args [0]->dreg,
4203                                                                                            MONO_ARCH_MONITOR_OBJECT_REG, FALSE);
4204                         }
4205
4206                         return (MonoInst*)call;
4207                 } else if (strcmp (cmethod->name, "Exit") == 0) {
4208                         MonoCallInst *call;
4209
4210                         if (COMPILE_LLVM (cfg)) {
4211                                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_EXIT, NULL, helper_sig_monitor_enter_exit_trampoline_llvm, args);
4212                         } else {
4213                                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_EXIT,
4214                                             NULL, helper_sig_monitor_enter_exit_trampoline, NULL);
4215                                 mono_call_inst_add_outarg_reg (cfg, call, args [0]->dreg,
4216                                                                                            MONO_ARCH_MONITOR_OBJECT_REG, FALSE);
4217                         }
4218
4219                         return (MonoInst*)call;
4220                 }
4221 #elif defined(MONO_ARCH_ENABLE_MONITOR_IL_FASTPATH)
4222                 MonoMethod *fast_method = NULL;
4223
4224                 /* Avoid infinite recursion */
4225                 if (cfg->method->wrapper_type == MONO_WRAPPER_UNKNOWN &&
4226                                 (strcmp (cfg->method->name, "FastMonitorEnter") == 0 ||
4227                                  strcmp (cfg->method->name, "FastMonitorExit") == 0))
4228                         return NULL;
4229
4230                 if (strcmp (cmethod->name, "Enter") == 0 ||
4231                                 strcmp (cmethod->name, "Exit") == 0)
4232                         fast_method = mono_monitor_get_fast_path (cmethod);
4233                 if (!fast_method)
4234                         return NULL;
4235
4236                 return (MonoInst*)mono_emit_method_call (cfg, fast_method, args, NULL);
4237 #endif
4238         } else if (cmethod->klass->image == mono_defaults.corlib &&
4239                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
4240                            (strcmp (cmethod->klass->name, "Interlocked") == 0)) {
4241                 ins = NULL;
4242
4243 #if SIZEOF_REGISTER == 8
4244                 if (strcmp (cmethod->name, "Read") == 0 && (fsig->params [0]->type == MONO_TYPE_I8)) {
4245                         /* 64 bit reads are already atomic */
4246                         MONO_INST_NEW (cfg, ins, OP_LOADI8_MEMBASE);
4247                         ins->dreg = mono_alloc_preg (cfg);
4248                         ins->inst_basereg = args [0]->dreg;
4249                         ins->inst_offset = 0;
4250                         MONO_ADD_INS (cfg->cbb, ins);
4251                 }
4252 #endif
4253
4254 #ifdef MONO_ARCH_HAVE_ATOMIC_ADD
4255                 if (strcmp (cmethod->name, "Increment") == 0) {
4256                         MonoInst *ins_iconst;
4257                         guint32 opcode = 0;
4258
4259                         if (fsig->params [0]->type == MONO_TYPE_I4)
4260                                 opcode = OP_ATOMIC_ADD_NEW_I4;
4261 #if SIZEOF_REGISTER == 8
4262                         else if (fsig->params [0]->type == MONO_TYPE_I8)
4263                                 opcode = OP_ATOMIC_ADD_NEW_I8;
4264 #endif
4265                         if (opcode) {
4266                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
4267                                 ins_iconst->inst_c0 = 1;
4268                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
4269                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
4270
4271                                 MONO_INST_NEW (cfg, ins, opcode);
4272                                 ins->dreg = mono_alloc_ireg (cfg);
4273                                 ins->inst_basereg = args [0]->dreg;
4274                                 ins->inst_offset = 0;
4275                                 ins->sreg2 = ins_iconst->dreg;
4276                                 ins->type = (opcode == OP_ATOMIC_ADD_NEW_I4) ? STACK_I4 : STACK_I8;
4277                                 MONO_ADD_INS (cfg->cbb, ins);
4278                         }
4279                 } else if (strcmp (cmethod->name, "Decrement") == 0) {
4280                         MonoInst *ins_iconst;
4281                         guint32 opcode = 0;
4282
4283                         if (fsig->params [0]->type == MONO_TYPE_I4)
4284                                 opcode = OP_ATOMIC_ADD_NEW_I4;
4285 #if SIZEOF_REGISTER == 8
4286                         else if (fsig->params [0]->type == MONO_TYPE_I8)
4287                                 opcode = OP_ATOMIC_ADD_NEW_I8;
4288 #endif
4289                         if (opcode) {
4290                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
4291                                 ins_iconst->inst_c0 = -1;
4292                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
4293                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
4294
4295                                 MONO_INST_NEW (cfg, ins, opcode);
4296                                 ins->dreg = mono_alloc_ireg (cfg);
4297                                 ins->inst_basereg = args [0]->dreg;
4298                                 ins->inst_offset = 0;
4299                                 ins->sreg2 = ins_iconst->dreg;
4300                                 ins->type = (opcode == OP_ATOMIC_ADD_NEW_I4) ? STACK_I4 : STACK_I8;
4301                                 MONO_ADD_INS (cfg->cbb, ins);
4302                         }
4303                 } else if (strcmp (cmethod->name, "Add") == 0) {
4304                         guint32 opcode = 0;
4305
4306                         if (fsig->params [0]->type == MONO_TYPE_I4)
4307                                 opcode = OP_ATOMIC_ADD_NEW_I4;
4308 #if SIZEOF_REGISTER == 8
4309                         else if (fsig->params [0]->type == MONO_TYPE_I8)
4310                                 opcode = OP_ATOMIC_ADD_NEW_I8;
4311 #endif
4312
4313                         if (opcode) {
4314                                 MONO_INST_NEW (cfg, ins, opcode);
4315                                 ins->dreg = mono_alloc_ireg (cfg);
4316                                 ins->inst_basereg = args [0]->dreg;
4317                                 ins->inst_offset = 0;
4318                                 ins->sreg2 = args [1]->dreg;
4319                                 ins->type = (opcode == OP_ATOMIC_ADD_NEW_I4) ? STACK_I4 : STACK_I8;
4320                                 MONO_ADD_INS (cfg->cbb, ins);
4321                         }
4322                 }
4323 #endif /* MONO_ARCH_HAVE_ATOMIC_ADD */
4324
4325 #ifdef MONO_ARCH_HAVE_ATOMIC_EXCHANGE
4326                 if (strcmp (cmethod->name, "Exchange") == 0) {
4327                         guint32 opcode;
4328                         gboolean is_ref = fsig->params [0]->type == MONO_TYPE_OBJECT;
4329
4330                         if (fsig->params [0]->type == MONO_TYPE_I4)
4331                                 opcode = OP_ATOMIC_EXCHANGE_I4;
4332 #if SIZEOF_REGISTER == 8
4333                         else if (is_ref || (fsig->params [0]->type == MONO_TYPE_I8) ||
4334                                         (fsig->params [0]->type == MONO_TYPE_I))
4335                                 opcode = OP_ATOMIC_EXCHANGE_I8;
4336 #else
4337                         else if (is_ref || (fsig->params [0]->type == MONO_TYPE_I))
4338                                 opcode = OP_ATOMIC_EXCHANGE_I4;
4339 #endif
4340                         else
4341                                 return NULL;
4342
4343                         MONO_INST_NEW (cfg, ins, opcode);
4344                         ins->dreg = mono_alloc_ireg (cfg);
4345                         ins->inst_basereg = args [0]->dreg;
4346                         ins->inst_offset = 0;
4347                         ins->sreg2 = args [1]->dreg;
4348                         MONO_ADD_INS (cfg->cbb, ins);
4349
4350                         switch (fsig->params [0]->type) {
4351                         case MONO_TYPE_I4:
4352                                 ins->type = STACK_I4;
4353                                 break;
4354                         case MONO_TYPE_I8:
4355                         case MONO_TYPE_I:
4356                                 ins->type = STACK_I8;
4357                                 break;
4358                         case MONO_TYPE_OBJECT:
4359                                 ins->type = STACK_OBJ;
4360                                 break;
4361                         default:
4362                                 g_assert_not_reached ();
4363                         }
4364
4365                         if (cfg->gen_write_barriers && is_ref) {
4366                                 MonoInst *dummy_use;
4367                                 MonoMethod *write_barrier = mono_gc_get_write_barrier ();
4368                                 mono_emit_method_call (cfg, write_barrier, &args [0], NULL);
4369                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, args [1]);
4370                         }
4371                 }
4372 #endif /* MONO_ARCH_HAVE_ATOMIC_EXCHANGE */
4373  
4374 #ifdef MONO_ARCH_HAVE_ATOMIC_CAS
4375                 if ((strcmp (cmethod->name, "CompareExchange") == 0)) {
4376                         int size = 0;
4377                         gboolean is_ref = MONO_TYPE_IS_REFERENCE (fsig->params [1]);
4378                         if (fsig->params [1]->type == MONO_TYPE_I4)
4379                                 size = 4;
4380                         else if (is_ref || fsig->params [1]->type == MONO_TYPE_I)
4381                                 size = sizeof (gpointer);
4382                         else if (sizeof (gpointer) == 8 && fsig->params [1]->type == MONO_TYPE_I8)
4383                                 size = 8;
4384                         if (size == 4) {
4385                                 MONO_INST_NEW (cfg, ins, OP_ATOMIC_CAS_I4);
4386                                 ins->dreg = alloc_ireg (cfg);
4387                                 ins->sreg1 = args [0]->dreg;
4388                                 ins->sreg2 = args [1]->dreg;
4389                                 ins->sreg3 = args [2]->dreg;
4390                                 ins->type = STACK_I4;
4391                                 MONO_ADD_INS (cfg->cbb, ins);
4392                         } else if (size == 8) {
4393                                 MONO_INST_NEW (cfg, ins, OP_ATOMIC_CAS_I8);
4394                                 ins->dreg = alloc_ireg (cfg);
4395                                 ins->sreg1 = args [0]->dreg;
4396                                 ins->sreg2 = args [1]->dreg;
4397                                 ins->sreg3 = args [2]->dreg;
4398                                 ins->type = STACK_I8;
4399                                 MONO_ADD_INS (cfg->cbb, ins);
4400                         } else {
4401                                 /* g_assert_not_reached (); */
4402                         }
4403                         if (cfg->gen_write_barriers && is_ref) {
4404                                 MonoInst *dummy_use;
4405                                 MonoMethod *write_barrier = mono_gc_get_write_barrier ();
4406                                 mono_emit_method_call (cfg, write_barrier, &args [0], NULL);
4407                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, args [1]);
4408                         }
4409                 }
4410 #endif /* MONO_ARCH_HAVE_ATOMIC_CAS */
4411
4412                 if (ins)
4413                         return ins;
4414         } else if (cmethod->klass->image == mono_defaults.corlib) {
4415                 if (cmethod->name [0] == 'B' && strcmp (cmethod->name, "Break") == 0
4416                                 && strcmp (cmethod->klass->name, "Debugger") == 0) {
4417                         if (should_insert_brekpoint (cfg->method))
4418                                 MONO_INST_NEW (cfg, ins, OP_BREAK);
4419                         else
4420                                 MONO_INST_NEW (cfg, ins, OP_NOP);
4421                         MONO_ADD_INS (cfg->cbb, ins);
4422                         return ins;
4423                 }
4424                 if (cmethod->name [0] == 'g' && strcmp (cmethod->name, "get_IsRunningOnWindows") == 0
4425                                 && strcmp (cmethod->klass->name, "Environment") == 0) {
4426 #ifdef TARGET_WIN32
4427                         EMIT_NEW_ICONST (cfg, ins, 1);
4428 #else
4429                         EMIT_NEW_ICONST (cfg, ins, 0);
4430 #endif
4431                         return ins;
4432                 }
4433         } else if (cmethod->klass == mono_defaults.math_class) {
4434                 /* 
4435                  * There is general branches code for Min/Max, but it does not work for 
4436                  * all inputs:
4437                  * http://everything2.com/?node_id=1051618
4438                  */
4439         }
4440
4441 #ifdef MONO_ARCH_SIMD_INTRINSICS
4442         if (cfg->opt & MONO_OPT_SIMD) {
4443                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
4444                 if (ins)
4445                         return ins;
4446         }
4447 #endif
4448
4449         return mono_arch_emit_inst_for_method (cfg, cmethod, fsig, args);
4450 }
4451
4452 /*
4453  * This entry point could be used later for arbitrary method
4454  * redirection.
4455  */
4456 inline static MonoInst*
4457 mini_redirect_call (MonoCompile *cfg, MonoMethod *method,  
4458                                         MonoMethodSignature *signature, MonoInst **args, MonoInst *this)
4459 {
4460         if (method->klass == mono_defaults.string_class) {
4461                 /* managed string allocation support */
4462                 if (strcmp (method->name, "InternalAllocateStr") == 0 && !(mono_profiler_events & MONO_PROFILE_ALLOCATIONS)) {
4463                         MonoInst *iargs [2];
4464                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
4465                         MonoMethod *managed_alloc = NULL;
4466
4467                         g_assert (vtable); /*Should not fail since it System.String*/
4468 #ifndef MONO_CROSS_COMPILE
4469                         managed_alloc = mono_gc_get_managed_allocator (vtable, FALSE);
4470 #endif
4471                         if (!managed_alloc)
4472                                 return NULL;
4473                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
4474                         iargs [1] = args [0];
4475                         return mono_emit_method_call (cfg, managed_alloc, iargs, this);
4476                 }
4477         }
4478         return NULL;
4479 }
4480
4481 static void
4482 mono_save_args (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **sp)
4483 {
4484         MonoInst *store, *temp;
4485         int i;
4486
4487         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
4488                 MonoType *argtype = (sig->hasthis && (i == 0)) ? type_from_stack_type (*sp) : sig->params [i - sig->hasthis];
4489
4490                 /*
4491                  * FIXME: We should use *args++ = sp [0], but that would mean the arg
4492                  * would be different than the MonoInst's used to represent arguments, and
4493                  * the ldelema implementation can't deal with that.
4494                  * Solution: When ldelema is used on an inline argument, create a var for 
4495                  * it, emit ldelema on that var, and emit the saving code below in
4496                  * inline_method () if needed.
4497                  */
4498                 temp = mono_compile_create_var (cfg, argtype, OP_LOCAL);
4499                 cfg->args [i] = temp;
4500                 /* This uses cfg->args [i] which is set by the preceeding line */
4501                 EMIT_NEW_ARGSTORE (cfg, store, i, *sp);
4502                 store->cil_code = sp [0]->cil_code;
4503                 sp++;
4504         }
4505 }
4506
4507 #define MONO_INLINE_CALLED_LIMITED_METHODS 1
4508 #define MONO_INLINE_CALLER_LIMITED_METHODS 1
4509
4510 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
4511 static gboolean
4512 check_inline_called_method_name_limit (MonoMethod *called_method)
4513 {
4514         int strncmp_result;
4515         static char *limit = NULL;
4516         
4517         if (limit == NULL) {
4518                 char *limit_string = getenv ("MONO_INLINE_CALLED_METHOD_NAME_LIMIT");
4519
4520                 if (limit_string != NULL)
4521                         limit = limit_string;
4522                 else
4523                         limit = (char *) "";
4524         }
4525
4526         if (limit [0] != '\0') {
4527                 char *called_method_name = mono_method_full_name (called_method, TRUE);
4528
4529                 strncmp_result = strncmp (called_method_name, limit, strlen (limit));
4530                 g_free (called_method_name);
4531         
4532                 //return (strncmp_result <= 0);
4533                 return (strncmp_result == 0);
4534         } else {
4535                 return TRUE;
4536         }
4537 }
4538 #endif
4539
4540 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
4541 static gboolean
4542 check_inline_caller_method_name_limit (MonoMethod *caller_method)
4543 {
4544         int strncmp_result;
4545         static char *limit = NULL;
4546         
4547         if (limit == NULL) {
4548                 char *limit_string = getenv ("MONO_INLINE_CALLER_METHOD_NAME_LIMIT");
4549                 if (limit_string != NULL) {
4550                         limit = limit_string;
4551                 } else {
4552                         limit = (char *) "";
4553                 }
4554         }
4555
4556         if (limit [0] != '\0') {
4557                 char *caller_method_name = mono_method_full_name (caller_method, TRUE);
4558
4559                 strncmp_result = strncmp (caller_method_name, limit, strlen (limit));
4560                 g_free (caller_method_name);
4561         
4562                 //return (strncmp_result <= 0);
4563                 return (strncmp_result == 0);
4564         } else {
4565                 return TRUE;
4566         }
4567 }
4568 #endif
4569
4570 static int
4571 inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp,
4572                 guchar *ip, guint real_offset, GList *dont_inline, gboolean inline_allways)
4573 {
4574         MonoInst *ins, *rvar = NULL;
4575         MonoMethodHeader *cheader;
4576         MonoBasicBlock *ebblock, *sbblock;
4577         int i, costs;
4578         MonoMethod *prev_inlined_method;
4579         MonoInst **prev_locals, **prev_args;
4580         MonoType **prev_arg_types;
4581         guint prev_real_offset;
4582         GHashTable *prev_cbb_hash;
4583         MonoBasicBlock **prev_cil_offset_to_bb;
4584         MonoBasicBlock *prev_cbb;
4585         unsigned char* prev_cil_start;
4586         guint32 prev_cil_offset_to_bb_len;
4587         MonoMethod *prev_current_method;
4588         MonoGenericContext *prev_generic_context;
4589         gboolean ret_var_set, prev_ret_var_set;
4590
4591         g_assert (cfg->exception_type == MONO_EXCEPTION_NONE);
4592
4593 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
4594         if ((! inline_allways) && ! check_inline_called_method_name_limit (cmethod))
4595                 return 0;
4596 #endif
4597 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
4598         if ((! inline_allways) && ! check_inline_caller_method_name_limit (cfg->method))
4599                 return 0;
4600 #endif
4601
4602         if (cfg->verbose_level > 2)
4603                 printf ("INLINE START %p %s -> %s\n", cmethod,  mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
4604
4605         if (!cmethod->inline_info) {
4606                 mono_jit_stats.inlineable_methods++;
4607                 cmethod->inline_info = 1;
4608         }
4609
4610         /* allocate local variables */
4611         cheader = mono_method_get_header (cmethod);
4612
4613         if (cheader == NULL || mono_loader_get_last_error ()) {
4614                 if (cheader)
4615                         mono_metadata_free_mh (cheader);
4616                 mono_loader_clear_error ();
4617                 return 0;
4618         }
4619
4620         /* allocate space to store the return value */
4621         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
4622                 rvar = mono_compile_create_var (cfg, fsig->ret, OP_LOCAL);
4623         }
4624
4625
4626         prev_locals = cfg->locals;
4627         cfg->locals = mono_mempool_alloc0 (cfg->mempool, cheader->num_locals * sizeof (MonoInst*));     
4628         for (i = 0; i < cheader->num_locals; ++i)
4629                 cfg->locals [i] = mono_compile_create_var (cfg, cheader->locals [i], OP_LOCAL);
4630
4631         /* allocate start and end blocks */
4632         /* This is needed so if the inline is aborted, we can clean up */
4633         NEW_BBLOCK (cfg, sbblock);
4634         sbblock->real_offset = real_offset;
4635
4636         NEW_BBLOCK (cfg, ebblock);
4637         ebblock->block_num = cfg->num_bblocks++;
4638         ebblock->real_offset = real_offset;
4639
4640         prev_args = cfg->args;
4641         prev_arg_types = cfg->arg_types;
4642         prev_inlined_method = cfg->inlined_method;
4643         cfg->inlined_method = cmethod;
4644         cfg->ret_var_set = FALSE;
4645         cfg->inline_depth ++;
4646         prev_real_offset = cfg->real_offset;
4647         prev_cbb_hash = cfg->cbb_hash;
4648         prev_cil_offset_to_bb = cfg->cil_offset_to_bb;
4649         prev_cil_offset_to_bb_len = cfg->cil_offset_to_bb_len;
4650         prev_cil_start = cfg->cil_start;
4651         prev_cbb = cfg->cbb;
4652         prev_current_method = cfg->current_method;
4653         prev_generic_context = cfg->generic_context;
4654         prev_ret_var_set = cfg->ret_var_set;
4655
4656         costs = mono_method_to_ir (cfg, cmethod, sbblock, ebblock, rvar, dont_inline, sp, real_offset, *ip == CEE_CALLVIRT);
4657
4658         ret_var_set = cfg->ret_var_set;
4659
4660         cfg->inlined_method = prev_inlined_method;
4661         cfg->real_offset = prev_real_offset;
4662         cfg->cbb_hash = prev_cbb_hash;
4663         cfg->cil_offset_to_bb = prev_cil_offset_to_bb;
4664         cfg->cil_offset_to_bb_len = prev_cil_offset_to_bb_len;
4665         cfg->cil_start = prev_cil_start;
4666         cfg->locals = prev_locals;
4667         cfg->args = prev_args;
4668         cfg->arg_types = prev_arg_types;
4669         cfg->current_method = prev_current_method;
4670         cfg->generic_context = prev_generic_context;
4671         cfg->ret_var_set = prev_ret_var_set;
4672         cfg->inline_depth --;
4673
4674         if ((costs >= 0 && costs < 60) || inline_allways) {
4675                 if (cfg->verbose_level > 2)
4676                         printf ("INLINE END %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
4677                 
4678                 mono_jit_stats.inlined_methods++;
4679
4680                 /* always add some code to avoid block split failures */
4681                 MONO_INST_NEW (cfg, ins, OP_NOP);
4682                 MONO_ADD_INS (prev_cbb, ins);
4683
4684                 prev_cbb->next_bb = sbblock;
4685                 link_bblock (cfg, prev_cbb, sbblock);
4686
4687                 /* 
4688                  * Get rid of the begin and end bblocks if possible to aid local
4689                  * optimizations.
4690                  */
4691                 mono_merge_basic_blocks (cfg, prev_cbb, sbblock);
4692
4693                 if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] != ebblock))
4694                         mono_merge_basic_blocks (cfg, prev_cbb, prev_cbb->out_bb [0]);
4695
4696                 if ((ebblock->in_count == 1) && ebblock->in_bb [0]->out_count == 1) {
4697                         MonoBasicBlock *prev = ebblock->in_bb [0];
4698                         mono_merge_basic_blocks (cfg, prev, ebblock);
4699                         cfg->cbb = prev;
4700                         if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] == prev)) {
4701                                 mono_merge_basic_blocks (cfg, prev_cbb, prev);
4702                                 cfg->cbb = prev_cbb;
4703                         }
4704                 } else {
4705                         cfg->cbb = ebblock;
4706                 }
4707
4708                 if (rvar) {
4709                         /*
4710                          * If the inlined method contains only a throw, then the ret var is not 
4711                          * set, so set it to a dummy value.
4712                          */
4713                         if (!ret_var_set) {
4714                                 static double r8_0 = 0.0;
4715
4716                                 switch (rvar->type) {
4717                                 case STACK_I4:
4718                                         MONO_EMIT_NEW_ICONST (cfg, rvar->dreg, 0);
4719                                         break;
4720                                 case STACK_I8:
4721                                         MONO_EMIT_NEW_I8CONST (cfg, rvar->dreg, 0);
4722                                         break;
4723                                 case STACK_PTR:
4724                                 case STACK_MP:
4725                                 case STACK_OBJ:
4726                                         MONO_EMIT_NEW_PCONST (cfg, rvar->dreg, 0);
4727                                         break;
4728                                 case STACK_R8:
4729                                         MONO_INST_NEW (cfg, ins, OP_R8CONST);
4730                                         ins->type = STACK_R8;
4731                                         ins->inst_p0 = (void*)&r8_0;
4732                                         ins->dreg = rvar->dreg;
4733                                         MONO_ADD_INS (cfg->cbb, ins);
4734                                         break;
4735                                 case STACK_VTYPE:
4736                                         MONO_EMIT_NEW_VZERO (cfg, rvar->dreg, mono_class_from_mono_type (fsig->ret));
4737                                         break;
4738                                 default:
4739                                         g_assert_not_reached ();
4740                                 }
4741                         }
4742
4743                         EMIT_NEW_TEMPLOAD (cfg, ins, rvar->inst_c0);
4744                         *sp++ = ins;
4745                 }
4746                 cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
4747                 return costs + 1;
4748         } else {
4749                 if (cfg->verbose_level > 2)
4750                         printf ("INLINE ABORTED %s\n", mono_method_full_name (cmethod, TRUE));
4751                 cfg->exception_type = MONO_EXCEPTION_NONE;
4752                 mono_loader_clear_error ();
4753
4754                 /* This gets rid of the newly added bblocks */
4755                 cfg->cbb = prev_cbb;
4756         }
4757         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
4758         return 0;
4759 }
4760
4761 /*
4762  * Some of these comments may well be out-of-date.
4763  * Design decisions: we do a single pass over the IL code (and we do bblock 
4764  * splitting/merging in the few cases when it's required: a back jump to an IL
4765  * address that was not already seen as bblock starting point).
4766  * Code is validated as we go (full verification is still better left to metadata/verify.c).
4767  * Complex operations are decomposed in simpler ones right away. We need to let the 
4768  * arch-specific code peek and poke inside this process somehow (except when the 
4769  * optimizations can take advantage of the full semantic info of coarse opcodes).
4770  * All the opcodes of the form opcode.s are 'normalized' to opcode.
4771  * MonoInst->opcode initially is the IL opcode or some simplification of that 
4772  * (OP_LOAD, OP_STORE). The arch-specific code may rearrange it to an arch-specific 
4773  * opcode with value bigger than OP_LAST.
4774  * At this point the IR can be handed over to an interpreter, a dumb code generator
4775  * or to the optimizing code generator that will translate it to SSA form.
4776  *
4777  * Profiling directed optimizations.
4778  * We may compile by default with few or no optimizations and instrument the code
4779  * or the user may indicate what methods to optimize the most either in a config file
4780  * or through repeated runs where the compiler applies offline the optimizations to 
4781  * each method and then decides if it was worth it.
4782  */
4783
4784 #define CHECK_TYPE(ins) if (!(ins)->type) UNVERIFIED
4785 #define CHECK_STACK(num) if ((sp - stack_start) < (num)) UNVERIFIED
4786 #define CHECK_STACK_OVF(num) if (((sp - stack_start) + (num)) > header->max_stack) UNVERIFIED
4787 #define CHECK_ARG(num) if ((unsigned)(num) >= (unsigned)num_args) UNVERIFIED
4788 #define CHECK_LOCAL(num) if ((unsigned)(num) >= (unsigned)header->num_locals) UNVERIFIED
4789 #define CHECK_OPSIZE(size) if (ip + size > end) UNVERIFIED
4790 #define CHECK_UNVERIFIABLE(cfg) if (cfg->unverifiable) UNVERIFIED
4791 #define CHECK_TYPELOAD(klass) if (!(klass) || (klass)->exception_type) {cfg->exception_ptr = klass; goto load_error;}
4792
4793 /* offset from br.s -> br like opcodes */
4794 #define BIG_BRANCH_OFFSET 13
4795
4796 static gboolean
4797 ip_in_bb (MonoCompile *cfg, MonoBasicBlock *bb, const guint8* ip)
4798 {
4799         MonoBasicBlock *b = cfg->cil_offset_to_bb [ip - cfg->cil_start];
4800
4801         return b == NULL || b == bb;
4802 }
4803
4804 static int
4805 get_basic_blocks (MonoCompile *cfg, MonoMethodHeader* header, guint real_offset, unsigned char *start, unsigned char *end, unsigned char **pos)
4806 {
4807         unsigned char *ip = start;
4808         unsigned char *target;
4809         int i;
4810         guint cli_addr;
4811         MonoBasicBlock *bblock;
4812         const MonoOpcode *opcode;
4813
4814         while (ip < end) {
4815                 cli_addr = ip - start;
4816                 i = mono_opcode_value ((const guint8 **)&ip, end);
4817                 if (i < 0)
4818                         UNVERIFIED;
4819                 opcode = &mono_opcodes [i];
4820                 switch (opcode->argument) {
4821                 case MonoInlineNone:
4822                         ip++; 
4823                         break;
4824                 case MonoInlineString:
4825                 case MonoInlineType:
4826                 case MonoInlineField:
4827                 case MonoInlineMethod:
4828                 case MonoInlineTok:
4829                 case MonoInlineSig:
4830                 case MonoShortInlineR:
4831                 case MonoInlineI:
4832                         ip += 5;
4833                         break;
4834                 case MonoInlineVar:
4835                         ip += 3;
4836                         break;
4837                 case MonoShortInlineVar:
4838                 case MonoShortInlineI:
4839                         ip += 2;
4840                         break;
4841                 case MonoShortInlineBrTarget:
4842                         target = start + cli_addr + 2 + (signed char)ip [1];
4843                         GET_BBLOCK (cfg, bblock, target);
4844                         ip += 2;
4845                         if (ip < end)
4846                                 GET_BBLOCK (cfg, bblock, ip);
4847                         break;
4848                 case MonoInlineBrTarget:
4849                         target = start + cli_addr + 5 + (gint32)read32 (ip + 1);
4850                         GET_BBLOCK (cfg, bblock, target);
4851                         ip += 5;
4852                         if (ip < end)
4853                                 GET_BBLOCK (cfg, bblock, ip);
4854                         break;
4855                 case MonoInlineSwitch: {
4856                         guint32 n = read32 (ip + 1);
4857                         guint32 j;
4858                         ip += 5;
4859                         cli_addr += 5 + 4 * n;
4860                         target = start + cli_addr;
4861                         GET_BBLOCK (cfg, bblock, target);
4862                         
4863                         for (j = 0; j < n; ++j) {
4864                                 target = start + cli_addr + (gint32)read32 (ip);
4865                                 GET_BBLOCK (cfg, bblock, target);
4866                                 ip += 4;
4867                         }
4868                         break;
4869                 }
4870                 case MonoInlineR:
4871                 case MonoInlineI8:
4872                         ip += 9;
4873                         break;
4874                 default:
4875                         g_assert_not_reached ();
4876                 }
4877
4878                 if (i == CEE_THROW) {
4879                         unsigned char *bb_start = ip - 1;
4880                         
4881                         /* Find the start of the bblock containing the throw */
4882                         bblock = NULL;
4883                         while ((bb_start >= start) && !bblock) {
4884                                 bblock = cfg->cil_offset_to_bb [(bb_start) - start];
4885                                 bb_start --;
4886                         }
4887                         if (bblock)
4888                                 bblock->out_of_line = 1;
4889                 }
4890         }
4891         return 0;
4892 unverified:
4893         *pos = ip;
4894         return 1;
4895 }
4896
4897 static inline MonoMethod *
4898 mini_get_method_allow_open (MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
4899 {
4900         MonoMethod *method;
4901
4902         if (m->wrapper_type != MONO_WRAPPER_NONE)
4903                 return mono_method_get_wrapper_data (m, token);
4904
4905         method = mono_get_method_full (m->klass->image, token, klass, context);
4906
4907         return method;
4908 }
4909
4910 static inline MonoMethod *
4911 mini_get_method (MonoCompile *cfg, MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
4912 {
4913         MonoMethod *method = mini_get_method_allow_open (m, token, klass, context);
4914
4915         if (method && cfg && !cfg->generic_sharing_context && mono_class_is_open_constructed_type (&method->klass->byval_arg))
4916                 return NULL;
4917
4918         return method;
4919 }
4920
4921 static inline MonoClass*
4922 mini_get_class (MonoMethod *method, guint32 token, MonoGenericContext *context)
4923 {
4924         MonoClass *klass;
4925
4926         if (method->wrapper_type != MONO_WRAPPER_NONE)
4927                 klass = mono_method_get_wrapper_data (method, token);
4928         else
4929                 klass = mono_class_get_full (method->klass->image, token, context);
4930         if (klass)
4931                 mono_class_init (klass);
4932         return klass;
4933 }
4934
4935 /*
4936  * Returns TRUE if the JIT should abort inlining because "callee"
4937  * is influenced by security attributes.
4938  */
4939 static
4940 gboolean check_linkdemand (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee)
4941 {
4942         guint32 result;
4943         
4944         if ((cfg->method != caller) && mono_method_has_declsec (callee)) {
4945                 return TRUE;
4946         }
4947         
4948         result = mono_declsec_linkdemand (cfg->domain, caller, callee);
4949         if (result == MONO_JIT_SECURITY_OK)
4950                 return FALSE;
4951
4952         if (result == MONO_JIT_LINKDEMAND_ECMA) {
4953                 /* Generate code to throw a SecurityException before the actual call/link */
4954                 MonoSecurityManager *secman = mono_security_manager_get_methods ();
4955                 MonoInst *args [2];
4956
4957                 NEW_ICONST (cfg, args [0], 4);
4958                 NEW_METHODCONST (cfg, args [1], caller);
4959                 mono_emit_method_call (cfg, secman->linkdemandsecurityexception, args, NULL);
4960         } else if (cfg->exception_type == MONO_EXCEPTION_NONE) {
4961                  /* don't hide previous results */
4962                 cfg->exception_type = MONO_EXCEPTION_SECURITY_LINKDEMAND;
4963                 cfg->exception_data = result;
4964                 return TRUE;
4965         }
4966         
4967         return FALSE;
4968 }
4969
4970 static MonoMethod*
4971 throw_exception (void)
4972 {
4973         static MonoMethod *method = NULL;
4974
4975         if (!method) {
4976                 MonoSecurityManager *secman = mono_security_manager_get_methods ();
4977                 method = mono_class_get_method_from_name (secman->securitymanager, "ThrowException", 1);
4978         }
4979         g_assert (method);
4980         return method;
4981 }
4982
4983 static void
4984 emit_throw_exception (MonoCompile *cfg, MonoException *ex)
4985 {
4986         MonoMethod *thrower = throw_exception ();
4987         MonoInst *args [1];
4988
4989         EMIT_NEW_PCONST (cfg, args [0], ex);
4990         mono_emit_method_call (cfg, thrower, args, NULL);
4991 }
4992
4993 /*
4994  * Return the original method is a wrapper is specified. We can only access 
4995  * the custom attributes from the original method.
4996  */
4997 static MonoMethod*
4998 get_original_method (MonoMethod *method)
4999 {
5000         if (method->wrapper_type == MONO_WRAPPER_NONE)
5001                 return method;
5002
5003         /* native code (which is like Critical) can call any managed method XXX FIXME XXX to validate all usages */
5004         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED)
5005                 return NULL;
5006
5007         /* in other cases we need to find the original method */
5008         return mono_marshal_method_from_wrapper (method);
5009 }
5010
5011 static void
5012 ensure_method_is_allowed_to_access_field (MonoCompile *cfg, MonoMethod *caller, MonoClassField *field,
5013                                           MonoBasicBlock *bblock, unsigned char *ip)
5014 {
5015         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
5016         MonoException *ex = mono_security_core_clr_is_field_access_allowed (get_original_method (caller), field);
5017         if (ex)
5018                 emit_throw_exception (cfg, ex);
5019 }
5020
5021 static void
5022 ensure_method_is_allowed_to_call_method (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee,
5023                                          MonoBasicBlock *bblock, unsigned char *ip)
5024 {
5025         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
5026         MonoException *ex = mono_security_core_clr_is_call_allowed (get_original_method (caller), callee);
5027         if (ex)
5028                 emit_throw_exception (cfg, ex);
5029 }
5030
5031 /*
5032  * Check that the IL instructions at ip are the array initialization
5033  * sequence and return the pointer to the data and the size.
5034  */
5035 static const char*
5036 initialize_array_data (MonoMethod *method, gboolean aot, unsigned char *ip, MonoClass *klass, guint32 len, int *out_size, guint32 *out_field_token)
5037 {
5038         /*
5039          * newarr[System.Int32]
5040          * dup
5041          * ldtoken field valuetype ...
5042          * call void class [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype [mscorlib]System.RuntimeFieldHandle)
5043          */
5044         if (ip [0] == CEE_DUP && ip [1] == CEE_LDTOKEN && ip [5] == 0x4 && ip [6] == CEE_CALL) {
5045                 guint32 token = read32 (ip + 7);
5046                 guint32 field_token = read32 (ip + 2);
5047                 guint32 field_index = field_token & 0xffffff;
5048                 guint32 rva;
5049                 const char *data_ptr;
5050                 int size = 0;
5051                 MonoMethod *cmethod;
5052                 MonoClass *dummy_class;
5053                 MonoClassField *field = mono_field_from_token (method->klass->image, field_token, &dummy_class, NULL);
5054                 int dummy_align;
5055
5056                 if (!field)
5057                         return NULL;
5058
5059                 *out_field_token = field_token;
5060
5061                 cmethod = mini_get_method (NULL, method, token, NULL, NULL);
5062                 if (!cmethod)
5063                         return NULL;
5064                 if (strcmp (cmethod->name, "InitializeArray") || strcmp (cmethod->klass->name, "RuntimeHelpers") || cmethod->klass->image != mono_defaults.corlib)
5065                         return NULL;
5066                 switch (mono_type_get_underlying_type (&klass->byval_arg)->type) {
5067                 case MONO_TYPE_BOOLEAN:
5068                 case MONO_TYPE_I1:
5069                 case MONO_TYPE_U1:
5070                         size = 1; break;
5071                 /* we need to swap on big endian, so punt. Should we handle R4 and R8 as well? */
5072 #if TARGET_BYTE_ORDER == G_LITTLE_ENDIAN
5073                 case MONO_TYPE_CHAR:
5074                 case MONO_TYPE_I2:
5075                 case MONO_TYPE_U2:
5076                         size = 2; break;
5077                 case MONO_TYPE_I4:
5078                 case MONO_TYPE_U4:
5079                 case MONO_TYPE_R4:
5080                         size = 4; break;
5081                 case MONO_TYPE_R8:
5082 #ifdef ARM_FPU_FPA
5083                         return NULL; /* stupid ARM FP swapped format */
5084 #endif
5085                 case MONO_TYPE_I8:
5086                 case MONO_TYPE_U8:
5087                         size = 8; break;
5088 #endif
5089                 default:
5090                         return NULL;
5091                 }
5092                 size *= len;
5093                 if (size > mono_type_size (field->type, &dummy_align))
5094                     return NULL;
5095                 *out_size = size;
5096                 /*g_print ("optimized in %s: size: %d, numelems: %d\n", method->name, size, newarr->inst_newa_len->inst_c0);*/
5097                 if (!method->klass->image->dynamic) {
5098                         field_index = read32 (ip + 2) & 0xffffff;
5099                         mono_metadata_field_info (method->klass->image, field_index - 1, NULL, &rva, NULL);
5100                         data_ptr = mono_image_rva_map (method->klass->image, rva);
5101                         /*g_print ("field: 0x%08x, rva: %d, rva_ptr: %p\n", read32 (ip + 2), rva, data_ptr);*/
5102                         /* for aot code we do the lookup on load */
5103                         if (aot && data_ptr)
5104                                 return GUINT_TO_POINTER (rva);
5105                 } else {
5106                         /*FIXME is it possible to AOT a SRE assembly not meant to be saved? */ 
5107                         g_assert (!aot);
5108                         data_ptr = mono_field_get_data (field);
5109                 }
5110                 return data_ptr;
5111         }
5112         return NULL;
5113 }
5114
5115 static void
5116 set_exception_type_from_invalid_il (MonoCompile *cfg, MonoMethod *method, unsigned char *ip)
5117 {
5118         char *method_fname = mono_method_full_name (method, TRUE);
5119         char *method_code;
5120         MonoMethodHeader *header = mono_method_get_header (method);
5121
5122         if (header->code_size == 0)
5123                 method_code = g_strdup ("method body is empty.");
5124         else
5125                 method_code = mono_disasm_code_one (NULL, method, ip, NULL);
5126         cfg->exception_type = MONO_EXCEPTION_INVALID_PROGRAM;
5127         cfg->exception_message = g_strdup_printf ("Invalid IL code in %s: %s\n", method_fname, method_code);
5128         g_free (method_fname);
5129         g_free (method_code);
5130         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
5131 }
5132
5133 static void
5134 set_exception_object (MonoCompile *cfg, MonoException *exception)
5135 {
5136         cfg->exception_type = MONO_EXCEPTION_OBJECT_SUPPLIED;
5137         MONO_GC_REGISTER_ROOT (cfg->exception_ptr);
5138         cfg->exception_ptr = exception;
5139 }
5140
5141 static gboolean
5142 generic_class_is_reference_type (MonoCompile *cfg, MonoClass *klass)
5143 {
5144         MonoType *type;
5145
5146         if (cfg->generic_sharing_context)
5147                 type = mini_get_basic_type_from_generic (cfg->generic_sharing_context, &klass->byval_arg);
5148         else
5149                 type = &klass->byval_arg;
5150         return MONO_TYPE_IS_REFERENCE (type);
5151 }
5152
5153 static void
5154 emit_stloc_ir (MonoCompile *cfg, MonoInst **sp, MonoMethodHeader *header, int n)
5155 {
5156         MonoInst *ins;
5157         guint32 opcode = mono_type_to_regmove (cfg, header->locals [n]);
5158         if ((opcode == OP_MOVE) && cfg->cbb->last_ins == sp [0]  &&
5159                         ((sp [0]->opcode == OP_ICONST) || (sp [0]->opcode == OP_I8CONST))) {
5160                 /* Optimize reg-reg moves away */
5161                 /* 
5162                  * Can't optimize other opcodes, since sp[0] might point to
5163                  * the last ins of a decomposed opcode.
5164                  */
5165                 sp [0]->dreg = (cfg)->locals [n]->dreg;
5166         } else {
5167                 EMIT_NEW_LOCSTORE (cfg, ins, n, *sp);
5168         }
5169 }
5170
5171 /*
5172  * ldloca inhibits many optimizations so try to get rid of it in common
5173  * cases.
5174  */
5175 static inline unsigned char *
5176 emit_optimized_ldloca_ir (MonoCompile *cfg, unsigned char *ip, unsigned char *end, int size)
5177 {
5178         int local, token;
5179         MonoClass *klass;
5180
5181         if (size == 1) {
5182                 local = ip [1];
5183                 ip += 2;
5184         } else {
5185                 local = read16 (ip + 2);
5186                 ip += 4;
5187         }
5188         
5189         if (ip + 6 < end && (ip [0] == CEE_PREFIX1) && (ip [1] == CEE_INITOBJ) && ip_in_bb (cfg, cfg->cbb, ip + 1)) {
5190                 gboolean skip = FALSE;
5191
5192                 /* From the INITOBJ case */
5193                 token = read32 (ip + 2);
5194                 klass = mini_get_class (cfg->current_method, token, cfg->generic_context);
5195                 CHECK_TYPELOAD (klass);
5196                 if (generic_class_is_reference_type (cfg, klass)) {
5197                         MONO_EMIT_NEW_PCONST (cfg, cfg->locals [local]->dreg, NULL);
5198                 } else if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
5199                         MONO_EMIT_NEW_PCONST (cfg, cfg->locals [local]->dreg, NULL);
5200                 } else if (MONO_TYPE_ISSTRUCT (&klass->byval_arg)) {
5201                         MONO_EMIT_NEW_VZERO (cfg, cfg->locals [local]->dreg, klass);
5202                 } else {
5203                         skip = TRUE;
5204                 }
5205                         
5206                 if (!skip)
5207                         return ip + 6;
5208         }
5209 load_error:
5210         return NULL;
5211 }
5212
5213 static gboolean
5214 is_exception_class (MonoClass *class)
5215 {
5216         while (class) {
5217                 if (class == mono_defaults.exception_class)
5218                         return TRUE;
5219                 class = class->parent;
5220         }
5221         return FALSE;
5222 }
5223
5224 /*
5225  * mono_method_to_ir:
5226  *
5227  *   Translate the .net IL into linear IR.
5228  */
5229 int
5230 mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock, 
5231                    MonoInst *return_var, GList *dont_inline, MonoInst **inline_args, 
5232                    guint inline_offset, gboolean is_virtual_call)
5233 {
5234         MonoError error;
5235         MonoInst *ins, **sp, **stack_start;
5236         MonoBasicBlock *bblock, *tblock = NULL, *init_localsbb = NULL;
5237         MonoSimpleBasicBlock *bb = NULL, *original_bb = NULL;
5238         MonoMethod *cmethod, *method_definition;
5239         MonoInst **arg_array;
5240         MonoMethodHeader *header;
5241         MonoImage *image;
5242         guint32 token, ins_flag;
5243         MonoClass *klass;
5244         MonoClass *constrained_call = NULL;
5245         unsigned char *ip, *end, *target, *err_pos;
5246         static double r8_0 = 0.0;
5247         MonoMethodSignature *sig;
5248         MonoGenericContext *generic_context = NULL;
5249         MonoGenericContainer *generic_container = NULL;
5250         MonoType **param_types;
5251         int i, n, start_new_bblock, dreg;
5252         int num_calls = 0, inline_costs = 0;
5253         int breakpoint_id = 0;
5254         guint num_args;
5255         MonoBoolean security, pinvoke;
5256         MonoSecurityManager* secman = NULL;
5257         MonoDeclSecurityActions actions;
5258         GSList *class_inits = NULL;
5259         gboolean dont_verify, dont_verify_stloc, readonly = FALSE;
5260         int context_used;
5261         gboolean init_locals, seq_points, skip_dead_blocks;
5262
5263         /* serialization and xdomain stuff may need access to private fields and methods */
5264         dont_verify = method->klass->image->assembly->corlib_internal? TRUE: FALSE;
5265         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE;
5266         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH;
5267         dont_verify |= method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE; /* bug #77896 */
5268         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP;
5269         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP_INVOKE;
5270
5271         dont_verify |= mono_security_get_mode () == MONO_SECURITY_MODE_SMCS_HACK;
5272
5273         /* still some type unsafety issues in marshal wrappers... (unknown is PtrToStructure) */
5274         dont_verify_stloc = method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE;
5275         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_UNKNOWN;
5276         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED;
5277
5278         image = method->klass->image;
5279         header = mono_method_get_header (method);
5280         if (!header) {
5281                 MonoLoaderError *error;
5282
5283                 if ((error = mono_loader_get_last_error ())) {
5284                         cfg->exception_type = error->exception_type;
5285                 } else {
5286                         cfg->exception_type = MONO_EXCEPTION_INVALID_PROGRAM;
5287                         cfg->exception_message = g_strdup_printf ("Missing or incorrect header for method %s", cfg->method->name);
5288                 }
5289                 goto exception_exit;
5290         }
5291         generic_container = mono_method_get_generic_container (method);
5292         sig = mono_method_signature (method);
5293         num_args = sig->hasthis + sig->param_count;
5294         ip = (unsigned char*)header->code;
5295         cfg->cil_start = ip;
5296         end = ip + header->code_size;
5297         mono_jit_stats.cil_code_size += header->code_size;
5298         init_locals = header->init_locals;
5299
5300         seq_points = cfg->gen_seq_points && cfg->method == method;
5301
5302         /* 
5303          * Methods without init_locals set could cause asserts in various passes
5304          * (#497220).
5305          */
5306         init_locals = TRUE;
5307
5308         method_definition = method;
5309         while (method_definition->is_inflated) {
5310                 MonoMethodInflated *imethod = (MonoMethodInflated *) method_definition;
5311                 method_definition = imethod->declaring;
5312         }
5313
5314         /* SkipVerification is not allowed if core-clr is enabled */
5315         if (!dont_verify && mini_assembly_can_skip_verification (cfg->domain, method)) {
5316                 dont_verify = TRUE;
5317                 dont_verify_stloc = TRUE;
5318         }
5319
5320         if (!dont_verify && mini_method_verify (cfg, method_definition))
5321                 goto exception_exit;
5322
5323         if (mono_debug_using_mono_debugger ())
5324                 cfg->keep_cil_nops = TRUE;
5325
5326         if (sig->is_inflated)
5327                 generic_context = mono_method_get_context (method);
5328         else if (generic_container)
5329                 generic_context = &generic_container->context;
5330         cfg->generic_context = generic_context;
5331
5332         if (!cfg->generic_sharing_context)
5333                 g_assert (!sig->has_type_parameters);
5334
5335         if (sig->generic_param_count && method->wrapper_type == MONO_WRAPPER_NONE) {
5336                 g_assert (method->is_inflated);
5337                 g_assert (mono_method_get_context (method)->method_inst);
5338         }
5339         if (method->is_inflated && mono_method_get_context (method)->method_inst)
5340                 g_assert (sig->generic_param_count);
5341
5342         if (cfg->method == method) {
5343                 cfg->real_offset = 0;
5344         } else {
5345                 cfg->real_offset = inline_offset;
5346         }
5347
5348         cfg->cil_offset_to_bb = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoBasicBlock*) * header->code_size);
5349         cfg->cil_offset_to_bb_len = header->code_size;
5350
5351         cfg->current_method = method;
5352
5353         if (cfg->verbose_level > 2)
5354                 printf ("method to IR %s\n", mono_method_full_name (method, TRUE));
5355
5356         param_types = mono_mempool_alloc (cfg->mempool, sizeof (MonoType*) * num_args);
5357         if (sig->hasthis)
5358                 param_types [0] = method->klass->valuetype?&method->klass->this_arg:&method->klass->byval_arg;
5359         for (n = 0; n < sig->param_count; ++n)
5360                 param_types [n + sig->hasthis] = sig->params [n];
5361         cfg->arg_types = param_types;
5362
5363         dont_inline = g_list_prepend (dont_inline, method);
5364         if (cfg->method == method) {
5365
5366                 if (cfg->prof_options & MONO_PROFILE_INS_COVERAGE)
5367                         cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, header->code_size);
5368
5369                 /* ENTRY BLOCK */
5370                 NEW_BBLOCK (cfg, start_bblock);
5371                 cfg->bb_entry = start_bblock;
5372                 start_bblock->cil_code = NULL;
5373                 start_bblock->cil_length = 0;
5374
5375                 /* EXIT BLOCK */
5376                 NEW_BBLOCK (cfg, end_bblock);
5377                 cfg->bb_exit = end_bblock;
5378                 end_bblock->cil_code = NULL;
5379                 end_bblock->cil_length = 0;
5380                 g_assert (cfg->num_bblocks == 2);
5381
5382                 arg_array = cfg->args;
5383
5384                 if (header->num_clauses) {
5385                         cfg->spvars = g_hash_table_new (NULL, NULL);
5386                         cfg->exvars = g_hash_table_new (NULL, NULL);
5387                 }
5388                 /* handle exception clauses */
5389                 for (i = 0; i < header->num_clauses; ++i) {
5390                         MonoBasicBlock *try_bb;
5391                         MonoExceptionClause *clause = &header->clauses [i];
5392                         GET_BBLOCK (cfg, try_bb, ip + clause->try_offset);
5393                         try_bb->real_offset = clause->try_offset;
5394                         GET_BBLOCK (cfg, tblock, ip + clause->handler_offset);
5395                         tblock->real_offset = clause->handler_offset;
5396                         tblock->flags |= BB_EXCEPTION_HANDLER;
5397
5398                         link_bblock (cfg, try_bb, tblock);
5399
5400                         if (*(ip + clause->handler_offset) == CEE_POP)
5401                                 tblock->flags |= BB_EXCEPTION_DEAD_OBJ;
5402
5403                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY ||
5404                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER ||
5405                             clause->flags == MONO_EXCEPTION_CLAUSE_FAULT) {
5406                                 MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
5407                                 MONO_ADD_INS (tblock, ins);
5408
5409                                 /* todo: is a fault block unsafe to optimize? */
5410                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
5411                                         tblock->flags |= BB_EXCEPTION_UNSAFE;
5412                         }
5413
5414
5415                         /*printf ("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);
5416                           while (p < end) {
5417                           printf ("%s", mono_disasm_code_one (NULL, method, p, &p));
5418                           }*/
5419                         /* catch and filter blocks get the exception object on the stack */
5420                         if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE ||
5421                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
5422                                 MonoInst *dummy_use;
5423
5424                                 /* mostly like handle_stack_args (), but just sets the input args */
5425                                 /* printf ("handling clause at IL_%04x\n", clause->handler_offset); */
5426                                 tblock->in_scount = 1;
5427                                 tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
5428                                 tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
5429
5430                                 /* 
5431                                  * Add a dummy use for the exvar so its liveness info will be
5432                                  * correct.
5433                                  */
5434                                 cfg->cbb = tblock;
5435                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, tblock->in_stack [0]);
5436                                 
5437                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
5438                                         GET_BBLOCK (cfg, tblock, ip + clause->data.filter_offset);
5439                                         tblock->flags |= BB_EXCEPTION_HANDLER;
5440                                         tblock->real_offset = clause->data.filter_offset;
5441                                         tblock->in_scount = 1;
5442                                         tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
5443                                         /* The filter block shares the exvar with the handler block */
5444                                         tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
5445                                         MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
5446                                         MONO_ADD_INS (tblock, ins);
5447                                 }
5448                         }
5449
5450                         if (clause->flags != MONO_EXCEPTION_CLAUSE_FILTER &&
5451                                         clause->data.catch_class &&
5452                                         cfg->generic_sharing_context &&
5453                                         mono_class_check_context_used (clause->data.catch_class)) {
5454                                 /*
5455                                  * In shared generic code with catch
5456                                  * clauses containing type variables
5457                                  * the exception handling code has to
5458                                  * be able to get to the rgctx.
5459                                  * Therefore we have to make sure that
5460                                  * the vtable/mrgctx argument (for
5461                                  * static or generic methods) or the
5462                                  * "this" argument (for non-static
5463                                  * methods) are live.
5464                                  */
5465                                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
5466                                                 mini_method_get_context (method)->method_inst ||
5467                                                 method->klass->valuetype) {
5468                                         mono_get_vtable_var (cfg);
5469                                 } else {
5470                                         MonoInst *dummy_use;
5471
5472                                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, arg_array [0]);
5473                                 }
5474                         }
5475                 }
5476         } else {
5477                 arg_array = (MonoInst **) alloca (sizeof (MonoInst *) * num_args);
5478                 cfg->cbb = start_bblock;
5479                 cfg->args = arg_array;
5480                 mono_save_args (cfg, sig, inline_args);
5481         }
5482
5483         /* FIRST CODE BLOCK */
5484         NEW_BBLOCK (cfg, bblock);
5485         bblock->cil_code = ip;
5486         cfg->cbb = bblock;
5487         cfg->ip = ip;
5488
5489         ADD_BBLOCK (cfg, bblock);
5490
5491         if (cfg->method == method) {
5492                 breakpoint_id = mono_debugger_method_has_breakpoint (method);
5493                 if (breakpoint_id && (mono_debug_format != MONO_DEBUG_FORMAT_DEBUGGER)) {
5494                         MONO_INST_NEW (cfg, ins, OP_BREAK);
5495                         MONO_ADD_INS (bblock, ins);
5496                 }
5497         }
5498
5499         if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS)
5500                 secman = mono_security_manager_get_methods ();
5501
5502         security = (secman && mono_method_has_declsec (method));
5503         /* at this point having security doesn't mean we have any code to generate */
5504         if (security && (cfg->method == method)) {
5505                 /* Only Demand, NonCasDemand and DemandChoice requires code generation.
5506                  * And we do not want to enter the next section (with allocation) if we
5507                  * have nothing to generate */
5508                 security = mono_declsec_get_demands (method, &actions);
5509         }
5510
5511         /* we must Demand SecurityPermission.Unmanaged before P/Invoking */
5512         pinvoke = (secman && (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE));
5513         if (pinvoke) {
5514                 MonoMethod *wrapped = mono_marshal_method_from_wrapper (method);
5515                 if (wrapped && (wrapped->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
5516                         MonoCustomAttrInfo* custom = mono_custom_attrs_from_method (wrapped);
5517
5518                         /* unless the method or it's class has the [SuppressUnmanagedCodeSecurity] attribute */
5519                         if (custom && mono_custom_attrs_has_attr (custom, secman->suppressunmanagedcodesecurity)) {
5520                                 pinvoke = FALSE;
5521                         }
5522                         if (custom)
5523                                 mono_custom_attrs_free (custom);
5524
5525                         if (pinvoke) {
5526                                 custom = mono_custom_attrs_from_class (wrapped->klass);
5527                                 if (custom && mono_custom_attrs_has_attr (custom, secman->suppressunmanagedcodesecurity)) {
5528                                         pinvoke = FALSE;
5529                                 }
5530                                 if (custom)
5531                                         mono_custom_attrs_free (custom);
5532                         }
5533                 } else {
5534                         /* not a P/Invoke after all */
5535                         pinvoke = FALSE;
5536                 }
5537         }
5538         
5539         if ((init_locals || (cfg->method == method && (cfg->opt & MONO_OPT_SHARED))) || cfg->compile_aot || security || pinvoke) {
5540                 /* we use a separate basic block for the initialization code */
5541                 NEW_BBLOCK (cfg, init_localsbb);
5542                 cfg->bb_init = init_localsbb;
5543                 init_localsbb->real_offset = cfg->real_offset;
5544                 start_bblock->next_bb = init_localsbb;
5545                 init_localsbb->next_bb = bblock;
5546                 link_bblock (cfg, start_bblock, init_localsbb);
5547                 link_bblock (cfg, init_localsbb, bblock);
5548                 
5549                 cfg->cbb = init_localsbb;
5550         } else {
5551                 start_bblock->next_bb = bblock;
5552                 link_bblock (cfg, start_bblock, bblock);
5553         }
5554
5555         /* at this point we know, if security is TRUE, that some code needs to be generated */
5556         if (security && (cfg->method == method)) {
5557                 MonoInst *args [2];
5558
5559                 mono_jit_stats.cas_demand_generation++;
5560
5561                 if (actions.demand.blob) {
5562                         /* Add code for SecurityAction.Demand */
5563                         EMIT_NEW_DECLSECCONST (cfg, args[0], image, actions.demand);
5564                         EMIT_NEW_ICONST (cfg, args [1], actions.demand.size);
5565                         /* Calls static void SecurityManager.InternalDemand (byte* permissions, int size); */
5566                         mono_emit_method_call (cfg, secman->demand, args, NULL);
5567                 }
5568                 if (actions.noncasdemand.blob) {
5569                         /* CLR 1.x uses a .noncasdemand (but 2.x doesn't) */
5570                         /* For Mono we re-route non-CAS Demand to Demand (as the managed code must deal with it anyway) */
5571                         EMIT_NEW_DECLSECCONST (cfg, args[0], image, actions.noncasdemand);
5572                         EMIT_NEW_ICONST (cfg, args [1], actions.noncasdemand.size);
5573                         /* Calls static void SecurityManager.InternalDemand (byte* permissions, int size); */
5574                         mono_emit_method_call (cfg, secman->demand, args, NULL);
5575                 }
5576                 if (actions.demandchoice.blob) {
5577                         /* New in 2.0, Demand must succeed for one of the permissions (i.e. not all) */
5578                         EMIT_NEW_DECLSECCONST (cfg, args[0], image, actions.demandchoice);
5579                         EMIT_NEW_ICONST (cfg, args [1], actions.demandchoice.size);
5580                         /* Calls static void SecurityManager.InternalDemandChoice (byte* permissions, int size); */
5581                         mono_emit_method_call (cfg, secman->demandchoice, args, NULL);
5582                 }
5583         }
5584
5585         /* we must Demand SecurityPermission.Unmanaged before p/invoking */
5586         if (pinvoke) {
5587                 mono_emit_method_call (cfg, secman->demandunmanaged, NULL, NULL);
5588         }
5589
5590         if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR) {
5591                 /* check if this is native code, e.g. an icall or a p/invoke */
5592                 if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
5593                         MonoMethod *wrapped = mono_marshal_method_from_wrapper (method);
5594                         if (wrapped) {
5595                                 gboolean pinvk = (wrapped->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL);
5596                                 gboolean icall = (wrapped->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL);
5597
5598                                 /* if this ia a native call then it can only be JITted from platform code */
5599                                 if ((icall || pinvk) && method->klass && method->klass->image) {
5600                                         if (!mono_security_core_clr_is_platform_image (method->klass->image)) {
5601                                                 MonoException *ex = icall ? mono_get_exception_security () : 
5602                                                         mono_get_exception_method_access ();
5603                                                 emit_throw_exception (cfg, ex);
5604                                         }
5605                                 }
5606                         }
5607                 }
5608         }
5609
5610         if (header->code_size == 0)
5611                 UNVERIFIED;
5612
5613         if (get_basic_blocks (cfg, header, cfg->real_offset, ip, end, &err_pos)) {
5614                 ip = err_pos;
5615                 UNVERIFIED;
5616         }
5617
5618         if (cfg->method == method)
5619                 mono_debug_init_method (cfg, bblock, breakpoint_id);
5620
5621         for (n = 0; n < header->num_locals; ++n) {
5622                 if (header->locals [n]->type == MONO_TYPE_VOID && !header->locals [n]->byref)
5623                         UNVERIFIED;
5624         }
5625         class_inits = NULL;
5626
5627         /* We force the vtable variable here for all shared methods
5628            for the possibility that they might show up in a stack
5629            trace where their exact instantiation is needed. */
5630         if (cfg->generic_sharing_context && method == cfg->method) {
5631                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
5632                                 mini_method_get_context (method)->method_inst ||
5633                                 method->klass->valuetype) {
5634                         mono_get_vtable_var (cfg);
5635                 } else {
5636                         /* FIXME: Is there a better way to do this?
5637                            We need the variable live for the duration
5638                            of the whole method. */
5639                         cfg->args [0]->flags |= MONO_INST_INDIRECT;
5640                 }
5641         }
5642
5643         /* add a check for this != NULL to inlined methods */
5644         if (is_virtual_call) {
5645                 MonoInst *arg_ins;
5646
5647                 NEW_ARGLOAD (cfg, arg_ins, 0);
5648                 MONO_ADD_INS (cfg->cbb, arg_ins);
5649                 MONO_EMIT_NEW_CHECK_THIS (cfg, arg_ins->dreg);
5650         }
5651
5652         skip_dead_blocks = !dont_verify;
5653         if (skip_dead_blocks) {
5654                 original_bb = bb = mono_basic_block_split (method, &error);
5655                 if (!mono_error_ok (&error)) {
5656                         mono_error_cleanup (&error);
5657                         UNVERIFIED;
5658                 }
5659                 g_assert (bb);
5660         }
5661
5662         /* we use a spare stack slot in SWITCH and NEWOBJ and others */
5663         stack_start = sp = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (header->max_stack + 1));
5664
5665         ins_flag = 0;
5666         start_new_bblock = 0;
5667         cfg->cbb = bblock;
5668         while (ip < end) {
5669                 if (cfg->method == method)
5670                         cfg->real_offset = ip - header->code;
5671                 else
5672                         cfg->real_offset = inline_offset;
5673                 cfg->ip = ip;
5674
5675                 context_used = 0;
5676                 
5677                 if (start_new_bblock) {
5678                         bblock->cil_length = ip - bblock->cil_code;
5679                         if (start_new_bblock == 2) {
5680                                 g_assert (ip == tblock->cil_code);
5681                         } else {
5682                                 GET_BBLOCK (cfg, tblock, ip);
5683                         }
5684                         bblock->next_bb = tblock;
5685                         bblock = tblock;
5686                         cfg->cbb = bblock;
5687                         start_new_bblock = 0;
5688                         for (i = 0; i < bblock->in_scount; ++i) {
5689                                 if (cfg->verbose_level > 3)
5690                                         printf ("loading %d from temp %d\n", i, (int)bblock->in_stack [i]->inst_c0);                                            
5691                                 EMIT_NEW_TEMPLOAD (cfg, ins, bblock->in_stack [i]->inst_c0);
5692                                 *sp++ = ins;
5693                         }
5694                         if (class_inits)
5695                                 g_slist_free (class_inits);
5696                         class_inits = NULL;
5697                 } else {
5698                         if ((tblock = cfg->cil_offset_to_bb [ip - cfg->cil_start]) && (tblock != bblock)) {
5699                                 link_bblock (cfg, bblock, tblock);
5700                                 if (sp != stack_start) {
5701                                         handle_stack_args (cfg, stack_start, sp - stack_start);
5702                                         sp = stack_start;
5703                                         CHECK_UNVERIFIABLE (cfg);
5704                                 }
5705                                 bblock->next_bb = tblock;
5706                                 bblock = tblock;
5707                                 cfg->cbb = bblock;
5708                                 for (i = 0; i < bblock->in_scount; ++i) {
5709                                         if (cfg->verbose_level > 3)
5710                                                 printf ("loading %d from temp %d\n", i, (int)bblock->in_stack [i]->inst_c0);                                            
5711                                         EMIT_NEW_TEMPLOAD (cfg, ins, bblock->in_stack [i]->inst_c0);
5712                                         *sp++ = ins;
5713                                 }
5714                                 g_slist_free (class_inits);
5715                                 class_inits = NULL;
5716                         }
5717                 }
5718
5719                 if (skip_dead_blocks) {
5720                         int ip_offset = ip - header->code;
5721
5722                         if (ip_offset == bb->end)
5723                                 bb = bb->next;
5724
5725                         if (bb->dead) {
5726                                 int op_size = mono_opcode_size (ip, end);
5727                                 g_assert (op_size > 0); /*The BB formation pass must catch all bad ops*/
5728
5729                                 if (cfg->verbose_level > 3) printf ("SKIPPING DEAD OP at %x\n", ip_offset);
5730
5731                                 if (ip_offset + op_size == bb->end) {
5732                                         MONO_INST_NEW (cfg, ins, OP_NOP);
5733                                         MONO_ADD_INS (bblock, ins);
5734                                         start_new_bblock = 1;
5735                                 }
5736
5737                                 ip += op_size;
5738                                 continue;
5739                         }
5740                 }
5741                 /*
5742                  * Sequence points are points where the debugger can place a breakpoint.
5743                  * Currently, we generate these automatically at points where the IL
5744                  * stack is empty.
5745                  */
5746                 if (seq_points && sp == stack_start) {
5747                         NEW_SEQ_POINT (cfg, ins, ip - header->code, TRUE);
5748                         MONO_ADD_INS (cfg->cbb, ins);
5749                 }
5750
5751                 bblock->real_offset = cfg->real_offset;
5752
5753                 if ((cfg->method == method) && cfg->coverage_info) {
5754                         guint32 cil_offset = ip - header->code;
5755                         cfg->coverage_info->data [cil_offset].cil_code = ip;
5756
5757                         /* TODO: Use an increment here */
5758 #if defined(TARGET_X86)
5759                         MONO_INST_NEW (cfg, ins, OP_STORE_MEM_IMM);
5760                         ins->inst_p0 = &(cfg->coverage_info->data [cil_offset].count);
5761                         ins->inst_imm = 1;
5762                         MONO_ADD_INS (cfg->cbb, ins);
5763 #else
5764                         EMIT_NEW_PCONST (cfg, ins, &(cfg->coverage_info->data [cil_offset].count));
5765                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, ins->dreg, 0, 1);
5766 #endif
5767                 }
5768
5769                 if (cfg->verbose_level > 3)
5770                         printf ("converting (in B%d: stack: %d) %s", bblock->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
5771
5772                 switch (*ip) {
5773                 case CEE_NOP:
5774                         if (cfg->keep_cil_nops)
5775                                 MONO_INST_NEW (cfg, ins, OP_HARD_NOP);
5776                         else
5777                                 MONO_INST_NEW (cfg, ins, OP_NOP);
5778                         ip++;
5779                         MONO_ADD_INS (bblock, ins);
5780                         break;
5781                 case CEE_BREAK:
5782                         if (should_insert_brekpoint (cfg->method))
5783                                 MONO_INST_NEW (cfg, ins, OP_BREAK);
5784                         else
5785                                 MONO_INST_NEW (cfg, ins, OP_NOP);
5786                         ip++;
5787                         MONO_ADD_INS (bblock, ins);
5788                         break;
5789                 case CEE_LDARG_0:
5790                 case CEE_LDARG_1:
5791                 case CEE_LDARG_2:
5792                 case CEE_LDARG_3:
5793                         CHECK_STACK_OVF (1);
5794                         n = (*ip)-CEE_LDARG_0;
5795                         CHECK_ARG (n);
5796                         EMIT_NEW_ARGLOAD (cfg, ins, n);
5797                         ip++;
5798                         *sp++ = ins;
5799                         break;
5800                 case CEE_LDLOC_0:
5801                 case CEE_LDLOC_1:
5802                 case CEE_LDLOC_2:
5803                 case CEE_LDLOC_3:
5804                         CHECK_STACK_OVF (1);
5805                         n = (*ip)-CEE_LDLOC_0;
5806                         CHECK_LOCAL (n);
5807                         EMIT_NEW_LOCLOAD (cfg, ins, n);
5808                         ip++;
5809                         *sp++ = ins;
5810                         break;
5811                 case CEE_STLOC_0:
5812                 case CEE_STLOC_1:
5813                 case CEE_STLOC_2:
5814                 case CEE_STLOC_3: {
5815                         CHECK_STACK (1);
5816                         n = (*ip)-CEE_STLOC_0;
5817                         CHECK_LOCAL (n);
5818                         --sp;
5819                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
5820                                 UNVERIFIED;
5821                         emit_stloc_ir (cfg, sp, header, n);
5822                         ++ip;
5823                         inline_costs += 1;
5824                         break;
5825                         }
5826                 case CEE_LDARG_S:
5827                         CHECK_OPSIZE (2);
5828                         CHECK_STACK_OVF (1);
5829                         n = ip [1];
5830                         CHECK_ARG (n);
5831                         EMIT_NEW_ARGLOAD (cfg, ins, n);
5832                         *sp++ = ins;
5833                         ip += 2;
5834                         break;
5835                 case CEE_LDARGA_S:
5836                         CHECK_OPSIZE (2);
5837                         CHECK_STACK_OVF (1);
5838                         n = ip [1];
5839                         CHECK_ARG (n);
5840                         NEW_ARGLOADA (cfg, ins, n);
5841                         MONO_ADD_INS (cfg->cbb, ins);
5842                         *sp++ = ins;
5843                         ip += 2;
5844                         break;
5845                 case CEE_STARG_S:
5846                         CHECK_OPSIZE (2);
5847                         CHECK_STACK (1);
5848                         --sp;
5849                         n = ip [1];
5850                         CHECK_ARG (n);
5851                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [ip [1]], *sp))
5852                                 UNVERIFIED;
5853                         EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
5854                         ip += 2;
5855                         break;
5856                 case CEE_LDLOC_S:
5857                         CHECK_OPSIZE (2);
5858                         CHECK_STACK_OVF (1);
5859                         n = ip [1];
5860                         CHECK_LOCAL (n);
5861                         EMIT_NEW_LOCLOAD (cfg, ins, n);
5862                         *sp++ = ins;
5863                         ip += 2;
5864                         break;
5865                 case CEE_LDLOCA_S: {
5866                         unsigned char *tmp_ip;
5867                         CHECK_OPSIZE (2);
5868                         CHECK_STACK_OVF (1);
5869                         CHECK_LOCAL (ip [1]);
5870
5871                         if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 1))) {
5872                                 ip = tmp_ip;
5873                                 inline_costs += 1;
5874                                 break;
5875                         }
5876
5877                         EMIT_NEW_LOCLOADA (cfg, ins, ip [1]);
5878                         *sp++ = ins;
5879                         ip += 2;
5880                         break;
5881                 }
5882                 case CEE_STLOC_S:
5883                         CHECK_OPSIZE (2);
5884                         CHECK_STACK (1);
5885                         --sp;
5886                         CHECK_LOCAL (ip [1]);
5887                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [ip [1]], *sp))
5888                                 UNVERIFIED;
5889                         emit_stloc_ir (cfg, sp, header, ip [1]);
5890                         ip += 2;
5891                         inline_costs += 1;
5892                         break;
5893                 case CEE_LDNULL:
5894                         CHECK_STACK_OVF (1);
5895                         EMIT_NEW_PCONST (cfg, ins, NULL);
5896                         ins->type = STACK_OBJ;
5897                         ++ip;
5898                         *sp++ = ins;
5899                         break;
5900                 case CEE_LDC_I4_M1:
5901                         CHECK_STACK_OVF (1);
5902                         EMIT_NEW_ICONST (cfg, ins, -1);
5903                         ++ip;
5904                         *sp++ = ins;
5905                         break;
5906                 case CEE_LDC_I4_0:
5907                 case CEE_LDC_I4_1:
5908                 case CEE_LDC_I4_2:
5909                 case CEE_LDC_I4_3:
5910                 case CEE_LDC_I4_4:
5911                 case CEE_LDC_I4_5:
5912                 case CEE_LDC_I4_6:
5913                 case CEE_LDC_I4_7:
5914                 case CEE_LDC_I4_8:
5915                         CHECK_STACK_OVF (1);
5916                         EMIT_NEW_ICONST (cfg, ins, (*ip) - CEE_LDC_I4_0);
5917                         ++ip;
5918                         *sp++ = ins;
5919                         break;
5920                 case CEE_LDC_I4_S:
5921                         CHECK_OPSIZE (2);
5922                         CHECK_STACK_OVF (1);
5923                         ++ip;
5924                         EMIT_NEW_ICONST (cfg, ins, *((signed char*)ip));
5925                         ++ip;
5926                         *sp++ = ins;
5927                         break;
5928                 case CEE_LDC_I4:
5929                         CHECK_OPSIZE (5);
5930                         CHECK_STACK_OVF (1);
5931                         EMIT_NEW_ICONST (cfg, ins, (gint32)read32 (ip + 1));
5932                         ip += 5;
5933                         *sp++ = ins;
5934                         break;
5935                 case CEE_LDC_I8:
5936                         CHECK_OPSIZE (9);
5937                         CHECK_STACK_OVF (1);
5938                         MONO_INST_NEW (cfg, ins, OP_I8CONST);
5939                         ins->type = STACK_I8;
5940                         ins->dreg = alloc_dreg (cfg, STACK_I8);
5941                         ++ip;
5942                         ins->inst_l = (gint64)read64 (ip);
5943                         MONO_ADD_INS (bblock, ins);
5944                         ip += 8;
5945                         *sp++ = ins;
5946                         break;
5947                 case CEE_LDC_R4: {
5948                         float *f;
5949                         gboolean use_aotconst = FALSE;
5950
5951 #ifdef TARGET_POWERPC
5952                         /* FIXME: Clean this up */
5953                         if (cfg->compile_aot)
5954                                 use_aotconst = TRUE;
5955 #endif
5956
5957                         /* FIXME: we should really allocate this only late in the compilation process */
5958                         f = mono_domain_alloc (cfg->domain, sizeof (float));
5959                         CHECK_OPSIZE (5);
5960                         CHECK_STACK_OVF (1);
5961
5962                         if (use_aotconst) {
5963                                 MonoInst *cons;
5964                                 int dreg;
5965
5966                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R4, f);
5967
5968                                 dreg = alloc_freg (cfg);
5969                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR4_MEMBASE, dreg, cons->dreg, 0);
5970                                 ins->type = STACK_R8;
5971                         } else {
5972                                 MONO_INST_NEW (cfg, ins, OP_R4CONST);
5973                                 ins->type = STACK_R8;
5974                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
5975                                 ins->inst_p0 = f;
5976                                 MONO_ADD_INS (bblock, ins);
5977                         }
5978                         ++ip;
5979                         readr4 (ip, f);
5980                         ip += 4;
5981                         *sp++ = ins;                    
5982                         break;
5983                 }
5984                 case CEE_LDC_R8: {
5985                         double *d;
5986                         gboolean use_aotconst = FALSE;
5987
5988 #ifdef TARGET_POWERPC
5989                         /* FIXME: Clean this up */
5990                         if (cfg->compile_aot)
5991                                 use_aotconst = TRUE;
5992 #endif
5993
5994                         /* FIXME: we should really allocate this only late in the compilation process */
5995                         d = mono_domain_alloc (cfg->domain, sizeof (double));
5996                         CHECK_OPSIZE (9);
5997                         CHECK_STACK_OVF (1);
5998
5999                         if (use_aotconst) {
6000                                 MonoInst *cons;
6001                                 int dreg;
6002
6003                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R8, d);
6004
6005                                 dreg = alloc_freg (cfg);
6006                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR8_MEMBASE, dreg, cons->dreg, 0);
6007                                 ins->type = STACK_R8;
6008                         } else {
6009                                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
6010                                 ins->type = STACK_R8;
6011                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
6012                                 ins->inst_p0 = d;
6013                                 MONO_ADD_INS (bblock, ins);
6014                         }
6015                         ++ip;
6016                         readr8 (ip, d);
6017                         ip += 8;
6018                         *sp++ = ins;
6019                         break;
6020                 }
6021                 case CEE_DUP: {
6022                         MonoInst *temp, *store;
6023                         CHECK_STACK (1);
6024                         CHECK_STACK_OVF (1);
6025                         sp--;
6026                         ins = *sp;
6027
6028                         temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
6029                         EMIT_NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
6030
6031                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
6032                         *sp++ = ins;
6033
6034                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
6035                         *sp++ = ins;
6036
6037                         ++ip;
6038                         inline_costs += 2;
6039                         break;
6040                 }
6041                 case CEE_POP:
6042                         CHECK_STACK (1);
6043                         ip++;
6044                         --sp;
6045
6046 #ifdef TARGET_X86
6047                         if (sp [0]->type == STACK_R8)
6048                                 /* we need to pop the value from the x86 FP stack */
6049                                 MONO_EMIT_NEW_UNALU (cfg, OP_X86_FPOP, -1, sp [0]->dreg);
6050 #endif
6051                         break;
6052                 case CEE_JMP: {
6053                         MonoCallInst *call;
6054
6055                         INLINE_FAILURE;
6056
6057                         CHECK_OPSIZE (5);
6058                         if (stack_start != sp)
6059                                 UNVERIFIED;
6060                         token = read32 (ip + 1);
6061                         /* FIXME: check the signature matches */
6062                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
6063
6064                         if (!cmethod)
6065                                 goto load_error;
6066  
6067                         if (cfg->generic_sharing_context && mono_method_check_context_used (cmethod))
6068                                 GENERIC_SHARING_FAILURE (CEE_JMP);
6069
6070                         if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS)
6071                                 CHECK_CFG_EXCEPTION;
6072
6073 #ifdef MONO_ARCH_USE_OP_TAIL_CALL
6074                         {
6075                                 MonoMethodSignature *fsig = mono_method_signature (cmethod);
6076                                 int i, n;
6077
6078                                 /* Handle tail calls similarly to calls */
6079                                 n = fsig->param_count + fsig->hasthis;
6080
6081                                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
6082                                 call->method = cmethod;
6083                                 call->tail_call = TRUE;
6084                                 call->signature = mono_method_signature (cmethod);
6085                                 call->args = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * n);
6086                                 call->inst.inst_p0 = cmethod;
6087                                 for (i = 0; i < n; ++i)
6088                                         EMIT_NEW_ARGLOAD (cfg, call->args [i], i);
6089
6090                                 mono_arch_emit_call (cfg, call);
6091                                 MONO_ADD_INS (bblock, (MonoInst*)call);
6092                         }
6093 #else
6094                         for (i = 0; i < num_args; ++i)
6095                                 /* Prevent arguments from being optimized away */
6096                                 arg_array [i]->flags |= MONO_INST_VOLATILE;
6097
6098                         MONO_INST_NEW_CALL (cfg, call, OP_JMP);
6099                         ins = (MonoInst*)call;
6100                         ins->inst_p0 = cmethod;
6101                         MONO_ADD_INS (bblock, ins);
6102 #endif
6103
6104                         ip += 5;
6105                         start_new_bblock = 1;
6106                         break;
6107                 }
6108                 case CEE_CALLI:
6109                 case CEE_CALL:
6110                 case CEE_CALLVIRT: {
6111                         MonoInst *addr = NULL;
6112                         MonoMethodSignature *fsig = NULL;
6113                         int array_rank = 0;
6114                         int virtual = *ip == CEE_CALLVIRT;
6115                         int calli = *ip == CEE_CALLI;
6116                         gboolean pass_imt_from_rgctx = FALSE;
6117                         MonoInst *imt_arg = NULL;
6118                         gboolean pass_vtable = FALSE;
6119                         gboolean pass_mrgctx = FALSE;
6120                         MonoInst *vtable_arg = NULL;
6121                         gboolean check_this = FALSE;
6122                         gboolean supported_tail_call = FALSE;
6123
6124                         CHECK_OPSIZE (5);
6125                         token = read32 (ip + 1);
6126
6127                         if (calli) {
6128                                 cmethod = NULL;
6129                                 CHECK_STACK (1);
6130                                 --sp;
6131                                 addr = *sp;
6132                                 if (method->wrapper_type != MONO_WRAPPER_NONE)
6133                                         fsig = (MonoMethodSignature *)mono_method_get_wrapper_data (method, token);
6134                                 else
6135                                         fsig = mono_metadata_parse_signature (image, token);
6136
6137                                 n = fsig->param_count + fsig->hasthis;
6138
6139                                 if (method->dynamic && fsig->pinvoke) {
6140                                         MonoInst *args [3];
6141
6142                                         /*
6143                                          * This is a call through a function pointer using a pinvoke
6144                                          * signature. Have to create a wrapper and call that instead.
6145                                          * FIXME: This is very slow, need to create a wrapper at JIT time
6146                                          * instead based on the signature.
6147                                          */
6148                                         EMIT_NEW_IMAGECONST (cfg, args [0], method->klass->image);
6149                                         EMIT_NEW_PCONST (cfg, args [1], fsig);
6150                                         args [2] = addr;
6151                                         addr = mono_emit_jit_icall (cfg, mono_get_native_calli_wrapper, args);
6152                                 }
6153                         } else {
6154                                 MonoMethod *cil_method;
6155                                 
6156                                 if (method->wrapper_type != MONO_WRAPPER_NONE) {
6157                                         cmethod =  (MonoMethod *)mono_method_get_wrapper_data (method, token);
6158                                         cil_method = cmethod;
6159                                 } else if (constrained_call) {
6160                                         if ((constrained_call->byval_arg.type == MONO_TYPE_VAR || constrained_call->byval_arg.type == MONO_TYPE_MVAR) && cfg->generic_sharing_context) {
6161                                                 /* 
6162                                                  * This is needed since get_method_constrained can't find 
6163                                                  * the method in klass representing a type var.
6164                                                  * The type var is guaranteed to be a reference type in this
6165                                                  * case.
6166                                                  */
6167                                                 cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
6168                                                 cil_method = cmethod;
6169                                                 g_assert (!cmethod->klass->valuetype);
6170                                         } else {
6171                                                 cmethod = mono_get_method_constrained (image, token, constrained_call, generic_context, &cil_method);
6172                                         }
6173                                 } else {
6174                                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
6175                                         cil_method = cmethod;
6176                                 }
6177
6178                                 if (!cmethod)
6179                                         goto load_error;
6180                                 if (!dont_verify && !cfg->skip_visibility) {
6181                                         MonoMethod *target_method = cil_method;
6182                                         if (method->is_inflated) {
6183                                                 target_method = mini_get_method_allow_open (method, token, NULL, &(mono_method_get_generic_container (method_definition)->context));
6184                                         }
6185                                         if (!mono_method_can_access_method (method_definition, target_method) &&
6186                                                 !mono_method_can_access_method (method, cil_method))
6187                                                 METHOD_ACCESS_FAILURE;
6188                                 }
6189
6190                                 if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR)
6191                                         ensure_method_is_allowed_to_call_method (cfg, method, cil_method, bblock, ip);
6192
6193                                 if (!virtual && (cmethod->flags & METHOD_ATTRIBUTE_ABSTRACT))
6194                                         /* MS.NET seems to silently convert this to a callvirt */
6195                                         virtual = 1;
6196
6197                                 {
6198                                         /*
6199                                          * MS.NET accepts non virtual calls to virtual final methods of transparent proxy classes and
6200                                          * converts to a callvirt.
6201                                          *
6202                                          * tests/bug-515884.il is an example of this behavior
6203                                          */
6204                                         const int test_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_STATIC;
6205                                         const int expected_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL;
6206                                         if (!virtual && cmethod->klass->marshalbyref && (cmethod->flags & test_flags) == expected_flags && cfg->method->wrapper_type == MONO_WRAPPER_NONE)
6207                                                 virtual = 1;
6208                                 }
6209
6210                                 if (!cmethod->klass->inited)
6211                                         if (!mono_class_init (cmethod->klass))
6212                                                 goto load_error;
6213
6214                                 if (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL &&
6215                                     mini_class_is_system_array (cmethod->klass)) {
6216                                         array_rank = cmethod->klass->rank;
6217                                         fsig = mono_method_signature (cmethod);
6218                                 } else {
6219                                         fsig = mono_method_signature (cmethod);
6220
6221                                         if (!fsig)
6222                                                 goto load_error;
6223
6224                                         if (fsig->pinvoke) {
6225                                                 MonoMethod *wrapper = mono_marshal_get_native_wrapper (cmethod,
6226                                                         check_for_pending_exc, FALSE);
6227                                                 fsig = mono_method_signature (wrapper);
6228                                         } else if (constrained_call) {
6229                                                 fsig = mono_method_signature (cmethod);
6230                                         } else {
6231                                                 fsig = mono_method_get_signature_full (cmethod, image, token, generic_context);
6232                                         }
6233                                 }
6234
6235                                 mono_save_token_info (cfg, image, token, cil_method);
6236
6237                                 n = fsig->param_count + fsig->hasthis;
6238
6239                                 if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS) {
6240                                         if (check_linkdemand (cfg, method, cmethod))
6241                                                 INLINE_FAILURE;
6242                                         CHECK_CFG_EXCEPTION;
6243                                 }
6244
6245                                 if (cmethod->string_ctor && method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE)
6246                                         g_assert_not_reached ();
6247                         }
6248
6249                         if (!cfg->generic_sharing_context && cmethod && cmethod->klass->generic_container)
6250                                 UNVERIFIED;
6251
6252                         if (!cfg->generic_sharing_context && cmethod)
6253                                 g_assert (!mono_method_check_context_used (cmethod));
6254
6255                         CHECK_STACK (n);
6256
6257                         //g_assert (!virtual || fsig->hasthis);
6258
6259                         sp -= n;
6260
6261                         if (constrained_call) {
6262                                 /*
6263                                  * We have the `constrained.' prefix opcode.
6264                                  */
6265                                 if (constrained_call->valuetype && !cmethod->klass->valuetype) {
6266                                         /*
6267                                          * The type parameter is instantiated as a valuetype,
6268                                          * but that type doesn't override the method we're
6269                                          * calling, so we need to box `this'.
6270                                          */
6271                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_call->byval_arg, sp [0]->dreg, 0);
6272                                         ins->klass = constrained_call;
6273                                         sp [0] = handle_box (cfg, ins, constrained_call, mono_class_check_context_used (constrained_call));
6274                                         CHECK_CFG_EXCEPTION;
6275                                 } else if (!constrained_call->valuetype) {
6276                                         int dreg = alloc_preg (cfg);
6277
6278                                         /*
6279                                          * The type parameter is instantiated as a reference
6280                                          * type.  We have a managed pointer on the stack, so
6281                                          * we need to dereference it here.
6282                                          */
6283                                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, sp [0]->dreg, 0);
6284                                         ins->type = STACK_OBJ;
6285                                         sp [0] = ins;
6286                                 } else if (cmethod->klass->valuetype)
6287                                         virtual = 0;
6288                                 constrained_call = NULL;
6289                         }
6290
6291                         if (*ip != CEE_CALLI && check_call_signature (cfg, fsig, sp))
6292                                 UNVERIFIED;
6293
6294                         /* 
6295                          * If the callee is a shared method, then its static cctor
6296                          * might not get called after the call was patched.
6297                          */
6298                         if (cfg->generic_sharing_context && cmethod && cmethod->klass != method->klass && cmethod->klass->generic_class && mono_method_is_generic_sharable_impl (cmethod, TRUE) && mono_class_needs_cctor_run (cmethod->klass, method)) {
6299                                 emit_generic_class_init (cfg, cmethod->klass);
6300                                 CHECK_TYPELOAD (cmethod->klass);
6301                         }
6302
6303                         if (cmethod && ((cmethod->flags & METHOD_ATTRIBUTE_STATIC) || cmethod->klass->valuetype) &&
6304                                         (cmethod->klass->generic_class || cmethod->klass->generic_container)) {
6305                                 gboolean sharing_enabled = mono_class_generic_sharing_enabled (cmethod->klass);
6306                                 MonoGenericContext *context = mini_class_get_context (cmethod->klass);
6307                                 gboolean context_sharable = mono_generic_context_is_sharable (context, TRUE);
6308
6309                                 /*
6310                                  * Pass vtable iff target method might
6311                                  * be shared, which means that sharing
6312                                  * is enabled for its class and its
6313                                  * context is sharable (and it's not a
6314                                  * generic method).
6315                                  */
6316                                 if (sharing_enabled && context_sharable &&
6317                                         !(mini_method_get_context (cmethod) && mini_method_get_context (cmethod)->method_inst))
6318                                         pass_vtable = TRUE;
6319                         }
6320
6321                         if (cmethod && mini_method_get_context (cmethod) &&
6322                                         mini_method_get_context (cmethod)->method_inst) {
6323                                 gboolean sharing_enabled = mono_class_generic_sharing_enabled (cmethod->klass);
6324                                 MonoGenericContext *context = mini_method_get_context (cmethod);
6325                                 gboolean context_sharable = mono_generic_context_is_sharable (context, TRUE);
6326
6327                                 g_assert (!pass_vtable);
6328
6329                                 if (sharing_enabled && context_sharable)
6330                                         pass_mrgctx = TRUE;
6331                         }
6332
6333                         if (cfg->generic_sharing_context && cmethod) {
6334                                 MonoGenericContext *cmethod_context = mono_method_get_context (cmethod);
6335
6336                                 context_used = mono_method_check_context_used (cmethod);
6337
6338                                 if (context_used && (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
6339                                         /* Generic method interface
6340                                            calls are resolved via a
6341                                            helper function and don't
6342                                            need an imt. */
6343                                         if (!cmethod_context || !cmethod_context->method_inst)
6344                                                 pass_imt_from_rgctx = TRUE;
6345                                 }
6346
6347                                 /*
6348                                  * If a shared method calls another
6349                                  * shared method then the caller must
6350                                  * have a generic sharing context
6351                                  * because the magic trampoline
6352                                  * requires it.  FIXME: We shouldn't
6353                                  * have to force the vtable/mrgctx
6354                                  * variable here.  Instead there
6355                                  * should be a flag in the cfg to
6356                                  * request a generic sharing context.
6357                                  */
6358                                 if (context_used &&
6359                                                 ((method->flags & METHOD_ATTRIBUTE_STATIC) || method->klass->valuetype))
6360                                         mono_get_vtable_var (cfg);
6361                         }
6362
6363                         if (pass_vtable) {
6364                                 if (context_used) {
6365                                         vtable_arg = emit_get_rgctx_klass (cfg, context_used, cmethod->klass, MONO_RGCTX_INFO_VTABLE);
6366                                 } else {
6367                                         MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
6368
6369                                         CHECK_TYPELOAD (cmethod->klass);
6370                                         EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
6371                                 }
6372                         }
6373
6374                         if (pass_mrgctx) {
6375                                 g_assert (!vtable_arg);
6376
6377                                 if (!cfg->compile_aot) {
6378                                         /* 
6379                                          * emit_get_rgctx_method () calls mono_class_vtable () so check 
6380                                          * for type load errors before.
6381                                          */
6382                                         mono_class_setup_vtable (cmethod->klass);
6383                                         CHECK_TYPELOAD (cmethod->klass);
6384                                 }
6385
6386                                 vtable_arg = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
6387
6388                                 if (!(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
6389                                                 MONO_METHOD_IS_FINAL (cmethod)) {
6390                                         if (virtual)
6391                                                 check_this = TRUE;
6392                                         virtual = 0;
6393                                 }
6394                         }
6395
6396                         if (pass_imt_from_rgctx) {
6397                                 g_assert (!pass_vtable);
6398                                 g_assert (cmethod);
6399
6400                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
6401                                         cmethod, MONO_RGCTX_INFO_METHOD);
6402                         }
6403
6404                         if (check_this)
6405                                 MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
6406
6407                         /* Calling virtual generic methods */
6408                         if (cmethod && virtual && 
6409                             (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) && 
6410                             !(MONO_METHOD_IS_FINAL (cmethod) && 
6411                               cmethod->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK) &&
6412                             mono_method_signature (cmethod)->generic_param_count) {
6413                                 MonoInst *this_temp, *this_arg_temp, *store;
6414                                 MonoInst *iargs [4];
6415
6416                                 g_assert (mono_method_signature (cmethod)->is_inflated);
6417
6418                                 /* Prevent inlining of methods that contain indirect calls */
6419                                 INLINE_FAILURE;
6420
6421 #if MONO_ARCH_HAVE_GENERALIZED_IMT_THUNK && defined(MONO_ARCH_GSHARED_SUPPORTED)
6422                                 if (cmethod->wrapper_type == MONO_WRAPPER_NONE && mono_use_imt) {
6423                                         g_assert (!imt_arg);
6424                                         if (!context_used)
6425                                                 g_assert (cmethod->is_inflated);
6426                                         imt_arg = emit_get_rgctx_method (cfg, context_used,
6427                                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
6428                                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, sp, sp [0], imt_arg);
6429                                 } else
6430 #endif
6431                                 {
6432                                         this_temp = mono_compile_create_var (cfg, type_from_stack_type (sp [0]), OP_LOCAL);
6433                                         NEW_TEMPSTORE (cfg, store, this_temp->inst_c0, sp [0]);
6434                                         MONO_ADD_INS (bblock, store);
6435
6436                                         /* FIXME: This should be a managed pointer */
6437                                         this_arg_temp = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
6438
6439                                         EMIT_NEW_TEMPLOAD (cfg, iargs [0], this_temp->inst_c0);
6440                                         iargs [1] = emit_get_rgctx_method (cfg, context_used,
6441                                                                                                            cmethod, MONO_RGCTX_INFO_METHOD);
6442                                         EMIT_NEW_TEMPLOADA (cfg, iargs [2], this_arg_temp->inst_c0);
6443                                         addr = mono_emit_jit_icall (cfg,
6444                                                                                                 mono_helper_compile_generic_method, iargs);
6445
6446                                         EMIT_NEW_TEMPLOAD (cfg, sp [0], this_arg_temp->inst_c0);
6447
6448                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr);
6449                                 }
6450
6451                                 if (!MONO_TYPE_IS_VOID (fsig->ret))
6452                                         *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
6453
6454                                 CHECK_CFG_EXCEPTION;
6455
6456                                 ip += 5;
6457                                 ins_flag = 0;
6458                                 break;
6459                         }
6460
6461 #ifdef MONO_ARCH_USE_OP_TAIL_CALL
6462                         supported_tail_call = cmethod && MONO_ARCH_USE_OP_TAIL_CALL (mono_method_signature (method), mono_method_signature (cmethod));
6463 #else
6464                         supported_tail_call = cmethod && mono_metadata_signature_equal (mono_method_signature (method), mono_method_signature (cmethod)) && !MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->ret);
6465 #endif
6466
6467                         /* Tail prefix */
6468                         /* FIXME: runtime generic context pointer for jumps? */
6469                         /* FIXME: handle this for generic sharing eventually */
6470                         if ((ins_flag & MONO_INST_TAILCALL) && !cfg->generic_sharing_context && !vtable_arg && cmethod && (*ip == CEE_CALL) && supported_tail_call) {
6471                                 MonoCallInst *call;
6472
6473                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
6474                                 INLINE_FAILURE;
6475
6476 #ifdef MONO_ARCH_USE_OP_TAIL_CALL
6477                                 /* Handle tail calls similarly to calls */
6478                                 call = mono_emit_call_args (cfg, mono_method_signature (cmethod), sp, FALSE, FALSE, TRUE);
6479 #else
6480                                 MONO_INST_NEW_CALL (cfg, call, OP_JMP);
6481                                 call->tail_call = TRUE;
6482                                 call->method = cmethod;
6483                                 call->signature = mono_method_signature (cmethod);
6484
6485                                 /*
6486                                  * We implement tail calls by storing the actual arguments into the 
6487                                  * argument variables, then emitting a CEE_JMP.
6488                                  */
6489                                 for (i = 0; i < n; ++i) {
6490                                         /* Prevent argument from being register allocated */
6491                                         arg_array [i]->flags |= MONO_INST_VOLATILE;
6492                                         EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
6493                                 }
6494 #endif
6495
6496                                 ins = (MonoInst*)call;
6497                                 ins->inst_p0 = cmethod;
6498                                 ins->inst_p1 = arg_array [0];
6499                                 MONO_ADD_INS (bblock, ins);
6500                                 link_bblock (cfg, bblock, end_bblock);                  
6501                                 start_new_bblock = 1;
6502
6503                                 CHECK_CFG_EXCEPTION;
6504
6505                                 /* skip CEE_RET as well */
6506                                 ip += 6;
6507                                 ins_flag = 0;
6508                                 break;
6509                         }
6510
6511                         /* Conversion to a JIT intrinsic */
6512                         if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_method (cfg, cmethod, fsig, sp))) {
6513                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
6514                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
6515                                         *sp = ins;
6516                                         sp++;
6517                                 }
6518
6519                                 CHECK_CFG_EXCEPTION;
6520
6521                                 ip += 5;
6522                                 ins_flag = 0;
6523                                 break;
6524                         }
6525
6526                         /* Inlining */
6527                         if ((cfg->opt & MONO_OPT_INLINE) && cmethod &&
6528                                 (!virtual || !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) || MONO_METHOD_IS_FINAL (cmethod)) &&
6529                             mono_method_check_inlining (cfg, cmethod) &&
6530                                  !g_list_find (dont_inline, cmethod)) {
6531                                 int costs;
6532                                 gboolean allways = FALSE;
6533
6534                                 if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
6535                                         (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
6536                                         /* Prevent inlining of methods that call wrappers */
6537                                         INLINE_FAILURE;
6538                                         cmethod = mono_marshal_get_native_wrapper (cmethod, check_for_pending_exc, FALSE);
6539                                         allways = TRUE;
6540                                 }
6541
6542                                 if ((costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, dont_inline, allways))) {
6543                                         ip += 5;
6544                                         cfg->real_offset += 5;
6545                                         bblock = cfg->cbb;
6546
6547                                         if (!MONO_TYPE_IS_VOID (fsig->ret))
6548                                                 /* *sp is already set by inline_method */
6549                                                 sp++;
6550
6551                                         inline_costs += costs;
6552                                         ins_flag = 0;
6553                                         break;
6554                                 }
6555                         }
6556                         
6557                         inline_costs += 10 * num_calls++;
6558
6559                         /* Tail recursion elimination */
6560                         if ((cfg->opt & MONO_OPT_TAILC) && *ip == CEE_CALL && cmethod == method && ip [5] == CEE_RET && !vtable_arg) {
6561                                 gboolean has_vtargs = FALSE;
6562                                 int i;
6563
6564                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
6565                                 INLINE_FAILURE;
6566
6567                                 /* keep it simple */
6568                                 for (i =  fsig->param_count - 1; i >= 0; i--) {
6569                                         if (MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->params [i])) 
6570                                                 has_vtargs = TRUE;
6571                                 }
6572
6573                                 if (!has_vtargs) {
6574                                         for (i = 0; i < n; ++i)
6575                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
6576                                         MONO_INST_NEW (cfg, ins, OP_BR);
6577                                         MONO_ADD_INS (bblock, ins);
6578                                         tblock = start_bblock->out_bb [0];
6579                                         link_bblock (cfg, bblock, tblock);
6580                                         ins->inst_target_bb = tblock;
6581                                         start_new_bblock = 1;
6582
6583                                         /* skip the CEE_RET, too */
6584                                         if (ip_in_bb (cfg, bblock, ip + 5))
6585                                                 ip += 6;
6586                                         else
6587                                                 ip += 5;
6588
6589                                         ins_flag = 0;
6590                                         break;
6591                                 }
6592                         }
6593
6594                         /* Generic sharing */
6595                         /* FIXME: only do this for generic methods if
6596                            they are not shared! */
6597                         if (context_used && !imt_arg && !array_rank &&
6598                                         (!mono_method_is_generic_sharable_impl (cmethod, TRUE) ||
6599                                                 !mono_class_generic_sharing_enabled (cmethod->klass)) &&
6600                                         (!virtual || MONO_METHOD_IS_FINAL (cmethod) ||
6601                                                 !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))) {
6602                                 INLINE_FAILURE;
6603
6604                                 g_assert (cfg->generic_sharing_context && cmethod);
6605                                 g_assert (!addr);
6606
6607                                 /*
6608                                  * We are compiling a call to a
6609                                  * generic method from shared code,
6610                                  * which means that we have to look up
6611                                  * the method in the rgctx and do an
6612                                  * indirect call.
6613                                  */
6614                                 addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
6615                         }
6616
6617                         /* Indirect calls */
6618                         if (addr) {
6619                                 g_assert (!imt_arg);
6620
6621                                 if (*ip == CEE_CALL)
6622                                         g_assert (context_used);
6623                                 else if (*ip == CEE_CALLI)
6624                                         g_assert (!vtable_arg);
6625                                 else
6626                                         /* FIXME: what the hell is this??? */
6627                                         g_assert (cmethod->flags & METHOD_ATTRIBUTE_FINAL ||
6628                                                         !(cmethod->flags & METHOD_ATTRIBUTE_FINAL));
6629
6630                                 /* Prevent inlining of methods with indirect calls */
6631                                 INLINE_FAILURE;
6632
6633                                 if (vtable_arg) {
6634                                         MonoCallInst *call;
6635                                         int rgctx_reg = mono_alloc_preg (cfg);
6636
6637                                         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, vtable_arg->dreg);
6638                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr);
6639                                         call = (MonoCallInst*)ins;
6640                                         set_rgctx_arg (cfg, call, rgctx_reg, vtable_arg);
6641                                 } else {
6642                                         if (addr->opcode == OP_AOTCONST && addr->inst_c1 == MONO_PATCH_INFO_ICALL_ADDR) {
6643                                                 /* 
6644                                                  * Instead of emitting an indirect call, emit a direct call
6645                                                  * with the contents of the aotconst as the patch info.
6646                                                  */
6647                                                 ins = (MonoInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_ICALL_ADDR, addr->inst_p0, fsig, sp);
6648                                                 NULLIFY_INS (addr);
6649                                         } else if (addr->opcode == OP_GOT_ENTRY && addr->inst_right->inst_c1 == MONO_PATCH_INFO_ICALL_ADDR) {
6650                                                 ins = (MonoInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_ICALL_ADDR, addr->inst_right->inst_left, fsig, sp);
6651                                                 NULLIFY_INS (addr);
6652                                         } else {
6653                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr);
6654                                         }
6655                                 }
6656                                 if (!MONO_TYPE_IS_VOID (fsig->ret))
6657                                         *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
6658
6659                                 CHECK_CFG_EXCEPTION;
6660
6661                                 ip += 5;
6662                                 ins_flag = 0;
6663                                 break;
6664                         }
6665                                         
6666                         /* Array methods */
6667                         if (array_rank) {
6668                                 MonoInst *addr;
6669
6670                                 if (strcmp (cmethod->name, "Set") == 0) { /* array Set */ 
6671                                         if (sp [fsig->param_count]->type == STACK_OBJ) {
6672                                                 MonoInst *iargs [2];
6673
6674                                                 iargs [0] = sp [0];
6675                                                 iargs [1] = sp [fsig->param_count];
6676                                                 
6677                                                 mono_emit_jit_icall (cfg, mono_helper_stelem_ref_check, iargs);
6678                                         }
6679                                         
6680                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, TRUE);
6681                                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, fsig->params [fsig->param_count - 1], addr->dreg, 0, sp [fsig->param_count]->dreg);
6682                                 } else if (strcmp (cmethod->name, "Get") == 0) { /* array Get */
6683                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
6684
6685                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, addr->dreg, 0);
6686
6687                                         *sp++ = ins;
6688                                 } else if (strcmp (cmethod->name, "Address") == 0) { /* array Address */
6689                                         if (!cmethod->klass->element_class->valuetype && !readonly)
6690                                                 mini_emit_check_array_type (cfg, sp [0], cmethod->klass);
6691                                         CHECK_TYPELOAD (cmethod->klass);
6692                                         
6693                                         readonly = FALSE;
6694                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
6695                                         *sp++ = addr;
6696                                 } else {
6697                                         g_assert_not_reached ();
6698                                 }
6699
6700                                 CHECK_CFG_EXCEPTION;
6701
6702                                 ip += 5;
6703                                 ins_flag = 0;
6704                                 break;
6705                         }
6706
6707                         ins = mini_redirect_call (cfg, cmethod, fsig, sp, virtual ? sp [0] : NULL);
6708                         if (ins) {
6709                                 if (!MONO_TYPE_IS_VOID (fsig->ret))
6710                                         *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
6711
6712                                 CHECK_CFG_EXCEPTION;
6713
6714                                 ip += 5;
6715                                 ins_flag = 0;
6716                                 break;
6717                         }
6718
6719                         /* Common call */
6720                         INLINE_FAILURE;
6721                         if (vtable_arg) {
6722                                 ins = mono_emit_rgctx_method_call_full (cfg, cmethod, fsig, sp, virtual ? sp [0] : NULL,
6723                                         NULL, vtable_arg);
6724                         } else if (imt_arg) {
6725                                 ins = (MonoInst*)mono_emit_method_call_full (cfg, cmethod, fsig, sp, virtual ? sp [0] : NULL, imt_arg);
6726                         } else {
6727                                 ins = (MonoInst*)mono_emit_method_call_full (cfg, cmethod, fsig, sp, virtual ? sp [0] : NULL, NULL);
6728                         }
6729
6730                         if (!MONO_TYPE_IS_VOID (fsig->ret))
6731                                 *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
6732
6733                         CHECK_CFG_EXCEPTION;
6734
6735                         ip += 5;
6736                         ins_flag = 0;
6737                         break;
6738                 }
6739                 case CEE_RET:
6740                         if (cfg->method != method) {
6741                                 /* return from inlined method */
6742                                 /* 
6743                                  * If in_count == 0, that means the ret is unreachable due to
6744                                  * being preceeded by a throw. In that case, inline_method () will
6745                                  * handle setting the return value 
6746                                  * (test case: test_0_inline_throw ()).
6747                                  */
6748                                 if (return_var && cfg->cbb->in_count) {
6749                                         MonoInst *store;
6750                                         CHECK_STACK (1);
6751                                         --sp;
6752                                         //g_assert (returnvar != -1);
6753                                         EMIT_NEW_TEMPSTORE (cfg, store, return_var->inst_c0, *sp);
6754                                         cfg->ret_var_set = TRUE;
6755                                 } 
6756                         } else {
6757                                 if (cfg->ret) {
6758                                         MonoType *ret_type = mono_method_signature (method)->ret;
6759
6760                                         if (seq_points) {
6761                                                 /* 
6762                                                  * Place a seq point here too even through the IL stack is not
6763                                                  * empty, so a step over on
6764                                                  * call <FOO>
6765                                                  * ret
6766                                                  * will work correctly.
6767                                                  */
6768                                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, TRUE);
6769                                                 MONO_ADD_INS (cfg->cbb, ins);
6770                                         }
6771
6772                                         g_assert (!return_var);
6773                                         CHECK_STACK (1);
6774                                         --sp;
6775                                         if (mini_type_to_stind (cfg, ret_type) == CEE_STOBJ) {
6776                                                 MonoInst *ret_addr;
6777
6778                                                 if (!cfg->vret_addr) {
6779                                                         MonoInst *ins;
6780
6781                                                         EMIT_NEW_VARSTORE (cfg, ins, cfg->ret, ret_type, (*sp));
6782                                                 } else {
6783                                                         EMIT_NEW_RETLOADA (cfg, ret_addr);
6784
6785                                                         EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STOREV_MEMBASE, ret_addr->dreg, 0, (*sp)->dreg);
6786                                                         ins->klass = mono_class_from_mono_type (ret_type);
6787                                                 }
6788                                         } else {
6789 #ifdef MONO_ARCH_SOFT_FLOAT
6790                                                 if (COMPILE_SOFT_FLOAT (cfg) && !ret_type->byref && ret_type->type == MONO_TYPE_R4) {
6791                                                         MonoInst *iargs [1];
6792                                                         MonoInst *conv;
6793
6794                                                         iargs [0] = *sp;
6795                                                         conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
6796                                                         mono_arch_emit_setret (cfg, method, conv);
6797                                                 } else {
6798                                                         mono_arch_emit_setret (cfg, method, *sp);
6799                                                 }
6800 #else
6801                                                 mono_arch_emit_setret (cfg, method, *sp);
6802 #endif
6803                                         }
6804                                 }
6805                         }
6806                         if (sp != stack_start)
6807                                 UNVERIFIED;
6808                         MONO_INST_NEW (cfg, ins, OP_BR);
6809                         ip++;
6810                         ins->inst_target_bb = end_bblock;
6811                         MONO_ADD_INS (bblock, ins);
6812                         link_bblock (cfg, bblock, end_bblock);
6813                         start_new_bblock = 1;
6814                         break;
6815                 case CEE_BR_S:
6816                         CHECK_OPSIZE (2);
6817                         MONO_INST_NEW (cfg, ins, OP_BR);
6818                         ip++;
6819                         target = ip + 1 + (signed char)(*ip);
6820                         ++ip;
6821                         GET_BBLOCK (cfg, tblock, target);
6822                         link_bblock (cfg, bblock, tblock);
6823                         ins->inst_target_bb = tblock;
6824                         if (sp != stack_start) {
6825                                 handle_stack_args (cfg, stack_start, sp - stack_start);
6826                                 sp = stack_start;
6827                                 CHECK_UNVERIFIABLE (cfg);
6828                         }
6829                         MONO_ADD_INS (bblock, ins);
6830                         start_new_bblock = 1;
6831                         inline_costs += BRANCH_COST;
6832                         break;
6833                 case CEE_BEQ_S:
6834                 case CEE_BGE_S:
6835                 case CEE_BGT_S:
6836                 case CEE_BLE_S:
6837                 case CEE_BLT_S:
6838                 case CEE_BNE_UN_S:
6839                 case CEE_BGE_UN_S:
6840                 case CEE_BGT_UN_S:
6841                 case CEE_BLE_UN_S:
6842                 case CEE_BLT_UN_S:
6843                         CHECK_OPSIZE (2);
6844                         CHECK_STACK (2);
6845                         MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
6846                         ip++;
6847                         target = ip + 1 + *(signed char*)ip;
6848                         ip++;
6849
6850                         ADD_BINCOND (NULL);
6851
6852                         sp = stack_start;
6853                         inline_costs += BRANCH_COST;
6854                         break;
6855                 case CEE_BR:
6856                         CHECK_OPSIZE (5);
6857                         MONO_INST_NEW (cfg, ins, OP_BR);
6858                         ip++;
6859
6860                         target = ip + 4 + (gint32)read32(ip);
6861                         ip += 4;
6862                         GET_BBLOCK (cfg, tblock, target);
6863                         link_bblock (cfg, bblock, tblock);
6864                         ins->inst_target_bb = tblock;
6865                         if (sp != stack_start) {
6866                                 handle_stack_args (cfg, stack_start, sp - stack_start);
6867                                 sp = stack_start;
6868                                 CHECK_UNVERIFIABLE (cfg);
6869                         }
6870
6871                         MONO_ADD_INS (bblock, ins);
6872
6873                         start_new_bblock = 1;
6874                         inline_costs += BRANCH_COST;
6875                         break;
6876                 case CEE_BRFALSE_S:
6877                 case CEE_BRTRUE_S:
6878                 case CEE_BRFALSE:
6879                 case CEE_BRTRUE: {
6880                         MonoInst *cmp;
6881                         gboolean is_short = ((*ip) == CEE_BRFALSE_S) || ((*ip) == CEE_BRTRUE_S);
6882                         gboolean is_true = ((*ip) == CEE_BRTRUE_S) || ((*ip) == CEE_BRTRUE);
6883                         guint32 opsize = is_short ? 1 : 4;
6884
6885                         CHECK_OPSIZE (opsize);
6886                         CHECK_STACK (1);
6887                         if (sp [-1]->type == STACK_VTYPE || sp [-1]->type == STACK_R8)
6888                                 UNVERIFIED;
6889                         ip ++;
6890                         target = ip + opsize + (is_short ? *(signed char*)ip : (gint32)read32(ip));
6891                         ip += opsize;
6892
6893                         sp--;
6894
6895                         GET_BBLOCK (cfg, tblock, target);
6896                         link_bblock (cfg, bblock, tblock);
6897                         GET_BBLOCK (cfg, tblock, ip);
6898                         link_bblock (cfg, bblock, tblock);
6899
6900                         if (sp != stack_start) {
6901                                 handle_stack_args (cfg, stack_start, sp - stack_start);
6902                                 CHECK_UNVERIFIABLE (cfg);
6903                         }
6904
6905                         MONO_INST_NEW(cfg, cmp, OP_ICOMPARE_IMM);
6906                         cmp->sreg1 = sp [0]->dreg;
6907                         type_from_op (cmp, sp [0], NULL);
6908                         CHECK_TYPE (cmp);
6909
6910 #if SIZEOF_REGISTER == 4
6911                         if (cmp->opcode == OP_LCOMPARE_IMM) {
6912                                 /* Convert it to OP_LCOMPARE */
6913                                 MONO_INST_NEW (cfg, ins, OP_I8CONST);
6914                                 ins->type = STACK_I8;
6915                                 ins->dreg = alloc_dreg (cfg, STACK_I8);
6916                                 ins->inst_l = 0;
6917                                 MONO_ADD_INS (bblock, ins);
6918                                 cmp->opcode = OP_LCOMPARE;
6919                                 cmp->sreg2 = ins->dreg;
6920                         }
6921 #endif
6922                         MONO_ADD_INS (bblock, cmp);
6923
6924                         MONO_INST_NEW (cfg, ins, is_true ? CEE_BNE_UN : CEE_BEQ);
6925                         type_from_op (ins, sp [0], NULL);
6926                         MONO_ADD_INS (bblock, ins);
6927                         ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);
6928                         GET_BBLOCK (cfg, tblock, target);
6929                         ins->inst_true_bb = tblock;
6930                         GET_BBLOCK (cfg, tblock, ip);
6931                         ins->inst_false_bb = tblock;
6932                         start_new_bblock = 2;
6933
6934                         sp = stack_start;
6935                         inline_costs += BRANCH_COST;
6936                         break;
6937                 }
6938                 case CEE_BEQ:
6939                 case CEE_BGE:
6940                 case CEE_BGT:
6941                 case CEE_BLE:
6942                 case CEE_BLT:
6943                 case CEE_BNE_UN:
6944                 case CEE_BGE_UN:
6945                 case CEE_BGT_UN:
6946                 case CEE_BLE_UN:
6947                 case CEE_BLT_UN:
6948                         CHECK_OPSIZE (5);
6949                         CHECK_STACK (2);
6950                         MONO_INST_NEW (cfg, ins, *ip);
6951                         ip++;
6952                         target = ip + 4 + (gint32)read32(ip);
6953                         ip += 4;
6954
6955                         ADD_BINCOND (NULL);
6956
6957                         sp = stack_start;
6958                         inline_costs += BRANCH_COST;
6959                         break;
6960                 case CEE_SWITCH: {
6961                         MonoInst *src1;
6962                         MonoBasicBlock **targets;
6963                         MonoBasicBlock *default_bblock;
6964                         MonoJumpInfoBBTable *table;
6965                         int offset_reg = alloc_preg (cfg);
6966                         int target_reg = alloc_preg (cfg);
6967                         int table_reg = alloc_preg (cfg);
6968                         int sum_reg = alloc_preg (cfg);
6969                         gboolean use_op_switch;
6970
6971                         CHECK_OPSIZE (5);
6972                         CHECK_STACK (1);
6973                         n = read32 (ip + 1);
6974                         --sp;
6975                         src1 = sp [0];
6976                         if ((src1->type != STACK_I4) && (src1->type != STACK_PTR)) 
6977                                 UNVERIFIED;
6978
6979                         ip += 5;
6980                         CHECK_OPSIZE (n * sizeof (guint32));
6981                         target = ip + n * sizeof (guint32);
6982
6983                         GET_BBLOCK (cfg, default_bblock, target);
6984
6985                         targets = mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * n);
6986                         for (i = 0; i < n; ++i) {
6987                                 GET_BBLOCK (cfg, tblock, target + (gint32)read32(ip));
6988                                 targets [i] = tblock;
6989                                 ip += 4;
6990                         }
6991
6992                         if (sp != stack_start) {
6993                                 /* 
6994                                  * Link the current bb with the targets as well, so handle_stack_args
6995                                  * will set their in_stack correctly.
6996                                  */
6997                                 link_bblock (cfg, bblock, default_bblock);
6998                                 for (i = 0; i < n; ++i)
6999                                         link_bblock (cfg, bblock, targets [i]);
7000
7001                                 handle_stack_args (cfg, stack_start, sp - stack_start);
7002                                 sp = stack_start;
7003                                 CHECK_UNVERIFIABLE (cfg);
7004                         }
7005
7006                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, src1->dreg, n);
7007                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBGE_UN, default_bblock);
7008                         bblock = cfg->cbb;
7009
7010                         for (i = 0; i < n; ++i)
7011                                 link_bblock (cfg, bblock, targets [i]);
7012
7013                         table = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfoBBTable));
7014                         table->table = targets;
7015                         table->table_size = n;
7016
7017                         use_op_switch = FALSE;
7018 #ifdef TARGET_ARM
7019                         /* ARM implements SWITCH statements differently */
7020                         /* FIXME: Make it use the generic implementation */
7021                         if (!cfg->compile_aot)
7022                                 use_op_switch = TRUE;
7023 #endif
7024
7025                         if (COMPILE_LLVM (cfg))
7026                                 use_op_switch = TRUE;
7027
7028                         cfg->cbb->has_jump_table = 1;
7029
7030                         if (use_op_switch) {
7031                                 MONO_INST_NEW (cfg, ins, OP_SWITCH);
7032                                 ins->sreg1 = src1->dreg;
7033                                 ins->inst_p0 = table;
7034                                 ins->inst_many_bb = targets;
7035                                 ins->klass = GUINT_TO_POINTER (n);
7036                                 MONO_ADD_INS (cfg->cbb, ins);
7037                         } else {
7038                                 if (sizeof (gpointer) == 8)
7039                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 3);
7040                                 else
7041                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 2);
7042
7043 #if SIZEOF_REGISTER == 8
7044                                 /* The upper word might not be zero, and we add it to a 64 bit address later */
7045                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, offset_reg, offset_reg);
7046 #endif
7047
7048                                 if (cfg->compile_aot) {
7049                                         MONO_EMIT_NEW_AOTCONST (cfg, table_reg, table, MONO_PATCH_INFO_SWITCH);
7050                                 } else {
7051                                         MONO_INST_NEW (cfg, ins, OP_JUMP_TABLE);
7052                                         ins->inst_c1 = MONO_PATCH_INFO_SWITCH;
7053                                         ins->inst_p0 = table;
7054                                         ins->dreg = table_reg;
7055                                         MONO_ADD_INS (cfg->cbb, ins);
7056                                 }
7057
7058                                 /* FIXME: Use load_memindex */
7059                                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, table_reg, offset_reg);
7060                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, target_reg, sum_reg, 0);
7061                                 MONO_EMIT_NEW_UNALU (cfg, OP_BR_REG, -1, target_reg);
7062                         }
7063                         start_new_bblock = 1;
7064                         inline_costs += (BRANCH_COST * 2);
7065                         break;
7066                 }
7067                 case CEE_LDIND_I1:
7068                 case CEE_LDIND_U1:
7069                 case CEE_LDIND_I2:
7070                 case CEE_LDIND_U2:
7071                 case CEE_LDIND_I4:
7072                 case CEE_LDIND_U4:
7073                 case CEE_LDIND_I8:
7074                 case CEE_LDIND_I:
7075                 case CEE_LDIND_R4:
7076                 case CEE_LDIND_R8:
7077                 case CEE_LDIND_REF:
7078                         CHECK_STACK (1);
7079                         --sp;
7080
7081                         switch (*ip) {
7082                         case CEE_LDIND_R4:
7083                         case CEE_LDIND_R8:
7084                                 dreg = alloc_freg (cfg);
7085                                 break;
7086                         case CEE_LDIND_I8:
7087                                 dreg = alloc_lreg (cfg);
7088                                 break;
7089                         default:
7090                                 dreg = alloc_preg (cfg);
7091                         }
7092
7093                         NEW_LOAD_MEMBASE (cfg, ins, ldind_to_load_membase (*ip), dreg, sp [0]->dreg, 0);
7094                         ins->type = ldind_type [*ip - CEE_LDIND_I1];
7095                         ins->flags |= ins_flag;
7096                         ins_flag = 0;
7097                         MONO_ADD_INS (bblock, ins);
7098                         *sp++ = ins;
7099                         ++ip;
7100                         break;
7101                 case CEE_STIND_REF:
7102                 case CEE_STIND_I1:
7103                 case CEE_STIND_I2:
7104                 case CEE_STIND_I4:
7105                 case CEE_STIND_I8:
7106                 case CEE_STIND_R4:
7107                 case CEE_STIND_R8:
7108                 case CEE_STIND_I:
7109                         CHECK_STACK (2);
7110                         sp -= 2;
7111
7112                         NEW_STORE_MEMBASE (cfg, ins, stind_to_store_membase (*ip), sp [0]->dreg, 0, sp [1]->dreg);
7113                         ins->flags |= ins_flag;
7114                         ins_flag = 0;
7115                         MONO_ADD_INS (bblock, ins);
7116
7117                         if (cfg->gen_write_barriers && *ip == CEE_STIND_REF && method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER && !((sp [1]->opcode == OP_PCONST) && (sp [1]->inst_p0 == 0))) {
7118                                 MonoInst *dummy_use;
7119                                 /* insert call to write barrier */
7120                                 MonoMethod *write_barrier = mono_gc_get_write_barrier ();
7121                                 mono_emit_method_call (cfg, write_barrier, sp, NULL);
7122                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, sp [1]);
7123                         }
7124
7125                         inline_costs += 1;
7126                         ++ip;
7127                         break;
7128
7129                 case CEE_MUL:
7130                         CHECK_STACK (2);
7131
7132                         MONO_INST_NEW (cfg, ins, (*ip));
7133                         sp -= 2;
7134                         ins->sreg1 = sp [0]->dreg;
7135                         ins->sreg2 = sp [1]->dreg;
7136                         type_from_op (ins, sp [0], sp [1]);
7137                         CHECK_TYPE (ins);
7138                         ins->dreg = alloc_dreg ((cfg), (ins)->type);
7139
7140                         /* Use the immediate opcodes if possible */
7141                         if ((sp [1]->opcode == OP_ICONST) && mono_arch_is_inst_imm (sp [1]->inst_c0)) {
7142                                 int imm_opcode = mono_op_to_op_imm (ins->opcode);
7143                                 if (imm_opcode != -1) {
7144                                         ins->opcode = imm_opcode;
7145                                         ins->inst_p1 = (gpointer)(gssize)(sp [1]->inst_c0);
7146                                         ins->sreg2 = -1;
7147
7148                                         sp [1]->opcode = OP_NOP;
7149                                 }
7150                         }
7151
7152                         MONO_ADD_INS ((cfg)->cbb, (ins));
7153
7154                         *sp++ = mono_decompose_opcode (cfg, ins);
7155                         ip++;
7156                         break;
7157                 case CEE_ADD:
7158                 case CEE_SUB:
7159                 case CEE_DIV:
7160                 case CEE_DIV_UN:
7161                 case CEE_REM:
7162                 case CEE_REM_UN:
7163                 case CEE_AND:
7164                 case CEE_OR:
7165                 case CEE_XOR:
7166                 case CEE_SHL:
7167                 case CEE_SHR:
7168                 case CEE_SHR_UN:
7169                         CHECK_STACK (2);
7170
7171                         MONO_INST_NEW (cfg, ins, (*ip));
7172                         sp -= 2;
7173                         ins->sreg1 = sp [0]->dreg;
7174                         ins->sreg2 = sp [1]->dreg;
7175                         type_from_op (ins, sp [0], sp [1]);
7176                         CHECK_TYPE (ins);
7177                         ADD_WIDEN_OP (ins, sp [0], sp [1]);
7178                         ins->dreg = alloc_dreg ((cfg), (ins)->type);
7179
7180                         /* FIXME: Pass opcode to is_inst_imm */
7181
7182                         /* Use the immediate opcodes if possible */
7183                         if (((sp [1]->opcode == OP_ICONST) || (sp [1]->opcode == OP_I8CONST)) && mono_arch_is_inst_imm (sp [1]->opcode == OP_ICONST ? sp [1]->inst_c0 : sp [1]->inst_l)) {
7184                                 int imm_opcode;
7185
7186                                 imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
7187                                 if (imm_opcode != -1) {
7188                                         ins->opcode = imm_opcode;
7189                                         if (sp [1]->opcode == OP_I8CONST) {
7190 #if SIZEOF_REGISTER == 8
7191                                                 ins->inst_imm = sp [1]->inst_l;
7192 #else
7193                                                 ins->inst_ls_word = sp [1]->inst_ls_word;
7194                                                 ins->inst_ms_word = sp [1]->inst_ms_word;
7195 #endif
7196                                         }
7197                                         else
7198                                                 ins->inst_imm = (gssize)(sp [1]->inst_c0);
7199                                         ins->sreg2 = -1;
7200
7201                                         /* Might be followed by an instruction added by ADD_WIDEN_OP */
7202                                         if (sp [1]->next == NULL)
7203                                                 sp [1]->opcode = OP_NOP;
7204                                 }
7205                         }
7206                         MONO_ADD_INS ((cfg)->cbb, (ins));
7207
7208                         *sp++ = mono_decompose_opcode (cfg, ins);
7209                         ip++;
7210                         break;
7211                 case CEE_NEG:
7212                 case CEE_NOT:
7213                 case CEE_CONV_I1:
7214                 case CEE_CONV_I2:
7215                 case CEE_CONV_I4:
7216                 case CEE_CONV_R4:
7217                 case CEE_CONV_R8:
7218                 case CEE_CONV_U4:
7219                 case CEE_CONV_I8:
7220                 case CEE_CONV_U8:
7221                 case CEE_CONV_OVF_I8:
7222                 case CEE_CONV_OVF_U8:
7223                 case CEE_CONV_R_UN:
7224                         CHECK_STACK (1);
7225
7226                         /* Special case this earlier so we have long constants in the IR */
7227                         if ((((*ip) == CEE_CONV_I8) || ((*ip) == CEE_CONV_U8)) && (sp [-1]->opcode == OP_ICONST)) {
7228                                 int data = sp [-1]->inst_c0;
7229                                 sp [-1]->opcode = OP_I8CONST;
7230                                 sp [-1]->type = STACK_I8;
7231 #if SIZEOF_REGISTER == 8
7232                                 if ((*ip) == CEE_CONV_U8)
7233                                         sp [-1]->inst_c0 = (guint32)data;
7234                                 else
7235                                         sp [-1]->inst_c0 = data;
7236 #else
7237                                 sp [-1]->inst_ls_word = data;
7238                                 if ((*ip) == CEE_CONV_U8)
7239                                         sp [-1]->inst_ms_word = 0;
7240                                 else
7241                                         sp [-1]->inst_ms_word = (data < 0) ? -1 : 0;
7242 #endif
7243                                 sp [-1]->dreg = alloc_dreg (cfg, STACK_I8);
7244                         }
7245                         else {
7246                                 ADD_UNOP (*ip);
7247                         }
7248                         ip++;
7249                         break;
7250                 case CEE_CONV_OVF_I4:
7251                 case CEE_CONV_OVF_I1:
7252                 case CEE_CONV_OVF_I2:
7253                 case CEE_CONV_OVF_I:
7254                 case CEE_CONV_OVF_U:
7255                         CHECK_STACK (1);
7256
7257                         if (sp [-1]->type == STACK_R8) {
7258                                 ADD_UNOP (CEE_CONV_OVF_I8);
7259                                 ADD_UNOP (*ip);
7260                         } else {
7261                                 ADD_UNOP (*ip);
7262                         }
7263                         ip++;
7264                         break;
7265                 case CEE_CONV_OVF_U1:
7266                 case CEE_CONV_OVF_U2:
7267                 case CEE_CONV_OVF_U4:
7268                         CHECK_STACK (1);
7269
7270                         if (sp [-1]->type == STACK_R8) {
7271                                 ADD_UNOP (CEE_CONV_OVF_U8);
7272                                 ADD_UNOP (*ip);
7273                         } else {
7274                                 ADD_UNOP (*ip);
7275                         }
7276                         ip++;
7277                         break;
7278                 case CEE_CONV_OVF_I1_UN:
7279                 case CEE_CONV_OVF_I2_UN:
7280                 case CEE_CONV_OVF_I4_UN:
7281                 case CEE_CONV_OVF_I8_UN:
7282                 case CEE_CONV_OVF_U1_UN:
7283                 case CEE_CONV_OVF_U2_UN:
7284                 case CEE_CONV_OVF_U4_UN:
7285                 case CEE_CONV_OVF_U8_UN:
7286                 case CEE_CONV_OVF_I_UN:
7287                 case CEE_CONV_OVF_U_UN:
7288                 case CEE_CONV_U2:
7289                 case CEE_CONV_U1:
7290                 case CEE_CONV_I:
7291                 case CEE_CONV_U:
7292                         CHECK_STACK (1);
7293                         ADD_UNOP (*ip);
7294                         CHECK_CFG_EXCEPTION;
7295                         ip++;
7296                         break;
7297                 case CEE_ADD_OVF:
7298                 case CEE_ADD_OVF_UN:
7299                 case CEE_MUL_OVF:
7300                 case CEE_MUL_OVF_UN:
7301                 case CEE_SUB_OVF:
7302                 case CEE_SUB_OVF_UN:
7303                         CHECK_STACK (2);
7304                         ADD_BINOP (*ip);
7305                         ip++;
7306                         break;
7307                 case CEE_CPOBJ:
7308                         CHECK_OPSIZE (5);
7309                         CHECK_STACK (2);
7310                         token = read32 (ip + 1);
7311                         klass = mini_get_class (method, token, generic_context);
7312                         CHECK_TYPELOAD (klass);
7313                         sp -= 2;
7314                         if (generic_class_is_reference_type (cfg, klass)) {
7315                                 MonoInst *store, *load;
7316                                 int dreg = alloc_preg (cfg);
7317
7318                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, dreg, sp [1]->dreg, 0);
7319                                 load->flags |= ins_flag;
7320                                 MONO_ADD_INS (cfg->cbb, load);
7321
7322                                 NEW_STORE_MEMBASE (cfg, store, OP_STORE_MEMBASE_REG, sp [0]->dreg, 0, dreg);
7323                                 store->flags |= ins_flag;
7324                                 MONO_ADD_INS (cfg->cbb, store);
7325
7326                                 if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER) {
7327                                         MonoInst *dummy_use;
7328                                         MonoMethod *write_barrier = mono_gc_get_write_barrier ();
7329                                         mono_emit_method_call (cfg, write_barrier, sp, NULL);
7330                                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, sp [1]);
7331                                 }
7332                         } else {
7333                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
7334                         }
7335                         ins_flag = 0;
7336                         ip += 5;
7337                         break;
7338                 case CEE_LDOBJ: {
7339                         int loc_index = -1;
7340                         int stloc_len = 0;
7341
7342                         CHECK_OPSIZE (5);
7343                         CHECK_STACK (1);
7344                         --sp;
7345                         token = read32 (ip + 1);
7346                         klass = mini_get_class (method, token, generic_context);
7347                         CHECK_TYPELOAD (klass);
7348
7349                         /* Optimize the common ldobj+stloc combination */
7350                         switch (ip [5]) {
7351                         case CEE_STLOC_S:
7352                                 loc_index = ip [6];
7353                                 stloc_len = 2;
7354                                 break;
7355                         case CEE_STLOC_0:
7356                         case CEE_STLOC_1:
7357                         case CEE_STLOC_2:
7358                         case CEE_STLOC_3:
7359                                 loc_index = ip [5] - CEE_STLOC_0;
7360                                 stloc_len = 1;
7361                                 break;
7362                         default:
7363                                 break;
7364                         }
7365
7366                         if ((loc_index != -1) && ip_in_bb (cfg, bblock, ip + 5)) {
7367                                 CHECK_LOCAL (loc_index);
7368
7369                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
7370                                 ins->dreg = cfg->locals [loc_index]->dreg;
7371                                 ip += 5;
7372                                 ip += stloc_len;
7373                                 break;
7374                         }
7375
7376                         /* Optimize the ldobj+stobj combination */
7377                         /* The reference case ends up being a load+store anyway */
7378                         if (((ip [5] == CEE_STOBJ) && ip_in_bb (cfg, bblock, ip + 5) && read32 (ip + 6) == token) && !generic_class_is_reference_type (cfg, klass)) {
7379                                 CHECK_STACK (1);
7380
7381                                 sp --;
7382
7383                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
7384
7385                                 ip += 5 + 5;
7386                                 ins_flag = 0;
7387                                 break;
7388                         }
7389
7390                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
7391                         *sp++ = ins;
7392
7393                         ip += 5;
7394                         ins_flag = 0;
7395                         inline_costs += 1;
7396                         break;
7397                 }
7398                 case CEE_LDSTR:
7399                         CHECK_STACK_OVF (1);
7400                         CHECK_OPSIZE (5);
7401                         n = read32 (ip + 1);
7402
7403                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
7404                                 EMIT_NEW_PCONST (cfg, ins, mono_method_get_wrapper_data (method, n));
7405                                 ins->type = STACK_OBJ;
7406                                 *sp = ins;
7407                         }
7408                         else if (method->wrapper_type != MONO_WRAPPER_NONE) {
7409                                 MonoInst *iargs [1];
7410
7411                                 EMIT_NEW_PCONST (cfg, iargs [0], mono_method_get_wrapper_data (method, n));                             
7412                                 *sp = mono_emit_jit_icall (cfg, mono_string_new_wrapper, iargs);
7413                         } else {
7414                                 if (cfg->opt & MONO_OPT_SHARED) {
7415                                         MonoInst *iargs [3];
7416
7417                                         if (cfg->compile_aot) {
7418                                                 cfg->ldstr_list = g_list_prepend (cfg->ldstr_list, GINT_TO_POINTER (n));
7419                                         }
7420                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
7421                                         EMIT_NEW_IMAGECONST (cfg, iargs [1], image);
7422                                         EMIT_NEW_ICONST (cfg, iargs [2], mono_metadata_token_index (n));
7423                                         *sp = mono_emit_jit_icall (cfg, mono_ldstr, iargs);
7424                                         mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
7425                                 } else {
7426                                         if (bblock->out_of_line) {
7427                                                 MonoInst *iargs [2];
7428
7429                                                 if (image == mono_defaults.corlib) {
7430                                                         /* 
7431                                                          * Avoid relocations in AOT and save some space by using a 
7432                                                          * version of helper_ldstr specialized to mscorlib.
7433                                                          */
7434                                                         EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (n));
7435                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr_mscorlib, iargs);
7436                                                 } else {
7437                                                         /* Avoid creating the string object */
7438                                                         EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
7439                                                         EMIT_NEW_ICONST (cfg, iargs [1], mono_metadata_token_index (n));
7440                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr, iargs);
7441                                                 }
7442                                         } 
7443                                         else
7444                                         if (cfg->compile_aot) {
7445                                                 NEW_LDSTRCONST (cfg, ins, image, n);
7446                                                 *sp = ins;
7447                                                 MONO_ADD_INS (bblock, ins);
7448                                         } 
7449                                         else {
7450                                                 NEW_PCONST (cfg, ins, NULL);
7451                                                 ins->type = STACK_OBJ;
7452                                                 ins->inst_p0 = mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
7453                                                 *sp = ins;
7454                                                 MONO_ADD_INS (bblock, ins);
7455                                         }
7456                                 }
7457                         }
7458
7459                         sp++;
7460                         ip += 5;
7461                         break;
7462                 case CEE_NEWOBJ: {
7463                         MonoInst *iargs [2];
7464                         MonoMethodSignature *fsig;
7465                         MonoInst this_ins;
7466                         MonoInst *alloc;
7467                         MonoInst *vtable_arg = NULL;
7468
7469                         CHECK_OPSIZE (5);
7470                         token = read32 (ip + 1);
7471                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
7472                         if (!cmethod)
7473                                 goto load_error;
7474                         fsig = mono_method_get_signature (cmethod, image, token);
7475                         if (!fsig)
7476                                 goto load_error;
7477
7478                         mono_save_token_info (cfg, image, token, cmethod);
7479
7480                         if (!mono_class_init (cmethod->klass))
7481                                 goto load_error;
7482
7483                         if (cfg->generic_sharing_context)
7484                                 context_used = mono_method_check_context_used (cmethod);
7485
7486                         if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS) {
7487                                 if (check_linkdemand (cfg, method, cmethod))
7488                                         INLINE_FAILURE;
7489                                 CHECK_CFG_EXCEPTION;
7490                         } else if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR) {
7491                                 ensure_method_is_allowed_to_call_method (cfg, method, cmethod, bblock, ip);
7492                         }
7493
7494                         if (cmethod->klass->valuetype && mono_class_generic_sharing_enabled (cmethod->klass) &&
7495                                         mono_method_is_generic_sharable_impl (cmethod, TRUE)) {
7496                                 if (cmethod->is_inflated && mono_method_get_context (cmethod)->method_inst) {
7497                                         mono_class_vtable (cfg->domain, cmethod->klass);
7498                                         CHECK_TYPELOAD (cmethod->klass);
7499
7500                                         vtable_arg = emit_get_rgctx_method (cfg, context_used,
7501                                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
7502                                 } else {
7503                                         if (context_used) {
7504                                                 vtable_arg = emit_get_rgctx_klass (cfg, context_used,
7505                                                         cmethod->klass, MONO_RGCTX_INFO_VTABLE);
7506                                         } else {
7507                                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
7508
7509                                                 CHECK_TYPELOAD (cmethod->klass);
7510                                                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
7511                                         }
7512                                 }
7513                         }
7514
7515                         n = fsig->param_count;
7516                         CHECK_STACK (n);
7517
7518                         /* 
7519                          * Generate smaller code for the common newobj <exception> instruction in
7520                          * argument checking code.
7521                          */
7522                         if (bblock->out_of_line && cmethod->klass->image == mono_defaults.corlib &&
7523                                 is_exception_class (cmethod->klass) && n <= 2 &&
7524                                 ((n < 1) || (!fsig->params [0]->byref && fsig->params [0]->type == MONO_TYPE_STRING)) && 
7525                                 ((n < 2) || (!fsig->params [1]->byref && fsig->params [1]->type == MONO_TYPE_STRING))) {
7526                                 MonoInst *iargs [3];
7527
7528                                 g_assert (!vtable_arg);
7529
7530                                 sp -= n;
7531
7532                                 EMIT_NEW_ICONST (cfg, iargs [0], cmethod->klass->type_token);
7533                                 switch (n) {
7534                                 case 0:
7535                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_0, iargs);
7536                                         break;
7537                                 case 1:
7538                                         iargs [1] = sp [0];
7539                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_1, iargs);
7540                                         break;
7541                                 case 2:
7542                                         iargs [1] = sp [0];
7543                                         iargs [2] = sp [1];
7544                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_2, iargs);
7545                                         break;
7546                                 default:
7547                                         g_assert_not_reached ();
7548                                 }
7549
7550                                 ip += 5;
7551                                 inline_costs += 5;
7552                                 break;
7553                         }
7554
7555                         /* move the args to allow room for 'this' in the first position */
7556                         while (n--) {
7557                                 --sp;
7558                                 sp [1] = sp [0];
7559                         }
7560
7561                         /* check_call_signature () requires sp[0] to be set */
7562                         this_ins.type = STACK_OBJ;
7563                         sp [0] = &this_ins;
7564                         if (check_call_signature (cfg, fsig, sp))
7565                                 UNVERIFIED;
7566
7567                         iargs [0] = NULL;
7568
7569                         if (mini_class_is_system_array (cmethod->klass)) {
7570                                 g_assert (!vtable_arg);
7571
7572                                 *sp = emit_get_rgctx_method (cfg, context_used,
7573                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
7574
7575                                 /* Avoid varargs in the common case */
7576                                 if (fsig->param_count == 1)
7577                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_1, sp);
7578                                 else if (fsig->param_count == 2)
7579                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_2, sp);
7580                                 else if (fsig->param_count == 3)
7581                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_3, sp);
7582                                 else
7583                                         alloc = handle_array_new (cfg, fsig->param_count, sp, ip);
7584                         } else if (cmethod->string_ctor) {
7585                                 g_assert (!context_used);
7586                                 g_assert (!vtable_arg);
7587                                 /* we simply pass a null pointer */
7588                                 EMIT_NEW_PCONST (cfg, *sp, NULL); 
7589                                 /* now call the string ctor */
7590                                 alloc = mono_emit_method_call_full (cfg, cmethod, fsig, sp, NULL, NULL);
7591                         } else {
7592                                 MonoInst* callvirt_this_arg = NULL;
7593                                 
7594                                 if (cmethod->klass->valuetype) {
7595                                         iargs [0] = mono_compile_create_var (cfg, &cmethod->klass->byval_arg, OP_LOCAL);
7596                                         MONO_EMIT_NEW_VZERO (cfg, iargs [0]->dreg, cmethod->klass);
7597                                         EMIT_NEW_TEMPLOADA (cfg, *sp, iargs [0]->inst_c0);
7598
7599                                         alloc = NULL;
7600
7601                                         /* 
7602                                          * The code generated by mini_emit_virtual_call () expects
7603                                          * iargs [0] to be a boxed instance, but luckily the vcall
7604                                          * will be transformed into a normal call there.
7605                                          */
7606                                 } else if (context_used) {
7607                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, context_used);
7608                                         *sp = alloc;
7609                                 } else {
7610                                         MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
7611
7612                                         CHECK_TYPELOAD (cmethod->klass);
7613
7614                                         /*
7615                                          * TypeInitializationExceptions thrown from the mono_runtime_class_init
7616                                          * call in mono_jit_runtime_invoke () can abort the finalizer thread.
7617                                          * As a workaround, we call class cctors before allocating objects.
7618                                          */
7619                                         if (mini_field_access_needs_cctor_run (cfg, method, vtable) && !(g_slist_find (class_inits, vtable))) {
7620                                                 mono_emit_abs_call (cfg, MONO_PATCH_INFO_CLASS_INIT, vtable->klass, helper_sig_class_init_trampoline, NULL);
7621                                                 if (cfg->verbose_level > 2)
7622                                                         printf ("class %s.%s needs init call for ctor\n", cmethod->klass->name_space, cmethod->klass->name);
7623                                                 class_inits = g_slist_prepend (class_inits, vtable);
7624                                         }
7625
7626                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, 0);
7627                                         *sp = alloc;
7628                                 }
7629                                 CHECK_CFG_EXCEPTION; /*for handle_alloc*/
7630
7631                                 if (alloc)
7632                                         MONO_EMIT_NEW_UNALU (cfg, OP_NOT_NULL, -1, alloc->dreg);
7633
7634                                 /* Now call the actual ctor */
7635                                 /* Avoid virtual calls to ctors if possible */
7636                                 if (cmethod->klass->marshalbyref)
7637                                         callvirt_this_arg = sp [0];
7638
7639
7640                                 if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_ctor (cfg, cmethod, fsig, sp))) {
7641                                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
7642                                                 type_to_eval_stack_type ((cfg), fsig->ret, ins);
7643                                                 *sp = ins;
7644                                                 sp++;
7645                                         }
7646
7647                                         CHECK_CFG_EXCEPTION;
7648                                 } else
7649
7650
7651
7652                                 if ((cfg->opt & MONO_OPT_INLINE) && cmethod && !context_used && !vtable_arg &&
7653                                     mono_method_check_inlining (cfg, cmethod) &&
7654                                     !mono_class_is_subclass_of (cmethod->klass, mono_defaults.exception_class, FALSE) &&
7655                                     !g_list_find (dont_inline, cmethod)) {
7656                                         int costs;
7657
7658                                         if ((costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, dont_inline, FALSE))) {
7659                                                 cfg->real_offset += 5;
7660                                                 bblock = cfg->cbb;
7661
7662                                                 inline_costs += costs - 5;
7663                                         } else {
7664                                                 INLINE_FAILURE;
7665                                                 mono_emit_method_call_full (cfg, cmethod, fsig, sp, callvirt_this_arg, NULL);
7666                                         }
7667                                 } else if (context_used &&
7668                                                 (!mono_method_is_generic_sharable_impl (cmethod, TRUE) ||
7669                                                         !mono_class_generic_sharing_enabled (cmethod->klass))) {
7670                                         MonoInst *cmethod_addr;
7671
7672                                         cmethod_addr = emit_get_rgctx_method (cfg, context_used,
7673                                                 cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
7674
7675                                         mono_emit_rgctx_calli (cfg, fsig, sp, cmethod_addr, vtable_arg);
7676                                 } else {
7677                                         INLINE_FAILURE;
7678                                         ins = mono_emit_rgctx_method_call_full (cfg, cmethod, fsig, sp,
7679                                                                                                                         callvirt_this_arg, NULL, vtable_arg);
7680                                 }
7681                         }
7682
7683                         if (alloc == NULL) {
7684                                 /* Valuetype */
7685                                 EMIT_NEW_TEMPLOAD (cfg, ins, iargs [0]->inst_c0);
7686                                 type_to_eval_stack_type (cfg, &ins->klass->byval_arg, ins);
7687                                 *sp++= ins;
7688                         }
7689                         else
7690                                 *sp++ = alloc;
7691                         
7692                         ip += 5;
7693                         inline_costs += 5;
7694                         break;
7695                 }
7696                 case CEE_CASTCLASS:
7697                         CHECK_STACK (1);
7698                         --sp;
7699                         CHECK_OPSIZE (5);
7700                         token = read32 (ip + 1);
7701                         klass = mini_get_class (method, token, generic_context);
7702                         CHECK_TYPELOAD (klass);
7703                         if (sp [0]->type != STACK_OBJ)
7704                                 UNVERIFIED;
7705
7706                         if (cfg->generic_sharing_context)
7707                                 context_used = mono_class_check_context_used (klass);
7708
7709                         if (!context_used && mono_class_has_variant_generic_params (klass)) {
7710                                 MonoInst *args [2];
7711
7712                                 /* obj */
7713                                 args [0] = *sp;
7714
7715                                 /* klass */
7716                                 EMIT_NEW_CLASSCONST (cfg, args [1], klass);
7717
7718                                 ins = mono_emit_jit_icall (cfg, mono_object_castclass, args);
7719                                 *sp ++ = ins;
7720                                 ip += 5;
7721                                 inline_costs += 2;
7722                         } else if (!context_used && (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
7723                                 MonoMethod *mono_castclass;
7724                                 MonoInst *iargs [1];
7725                                 int costs;
7726
7727                                 mono_castclass = mono_marshal_get_castclass (klass); 
7728                                 iargs [0] = sp [0];
7729                                 
7730                                 costs = inline_method (cfg, mono_castclass, mono_method_signature (mono_castclass), 
7731                                                            iargs, ip, cfg->real_offset, dont_inline, TRUE);                     
7732                                 g_assert (costs > 0);
7733                                 
7734                                 ip += 5;
7735                                 cfg->real_offset += 5;
7736                                 bblock = cfg->cbb;
7737
7738                                 *sp++ = iargs [0];
7739
7740                                 inline_costs += costs;
7741                         }
7742                         else {
7743                                 ins = handle_castclass (cfg, klass, *sp, context_used);
7744                                 CHECK_CFG_EXCEPTION;
7745                                 bblock = cfg->cbb;
7746                                 *sp ++ = ins;
7747                                 ip += 5;
7748                         }
7749                         break;
7750                 case CEE_ISINST: {
7751                         CHECK_STACK (1);
7752                         --sp;
7753                         CHECK_OPSIZE (5);
7754                         token = read32 (ip + 1);
7755                         klass = mini_get_class (method, token, generic_context);
7756                         CHECK_TYPELOAD (klass);
7757                         if (sp [0]->type != STACK_OBJ)
7758                                 UNVERIFIED;
7759  
7760                         if (cfg->generic_sharing_context)
7761                                 context_used = mono_class_check_context_used (klass);
7762
7763                         if (!context_used && mono_class_has_variant_generic_params (klass)) {
7764                                 MonoInst *args [2];
7765
7766                                 /* obj */
7767                                 args [0] = *sp;
7768
7769                                 /* klass */
7770                                 EMIT_NEW_CLASSCONST (cfg, args [1], klass);
7771
7772                                 *sp = mono_emit_jit_icall (cfg, mono_object_isinst, args);
7773                                 sp++;
7774                                 ip += 5;
7775                                 inline_costs += 2;
7776                         } else if (!context_used && (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
7777                                 MonoMethod *mono_isinst;
7778                                 MonoInst *iargs [1];
7779                                 int costs;
7780
7781                                 mono_isinst = mono_marshal_get_isinst (klass); 
7782                                 iargs [0] = sp [0];
7783
7784                                 costs = inline_method (cfg, mono_isinst, mono_method_signature (mono_isinst), 
7785                                                            iargs, ip, cfg->real_offset, dont_inline, TRUE);                     
7786                                 g_assert (costs > 0);
7787                                 
7788                                 ip += 5;
7789                                 cfg->real_offset += 5;
7790                                 bblock = cfg->cbb;
7791
7792                                 *sp++= iargs [0];
7793
7794                                 inline_costs += costs;
7795                         }
7796                         else {
7797                                 ins = handle_isinst (cfg, klass, *sp, context_used);
7798                                 CHECK_CFG_EXCEPTION;
7799                                 bblock = cfg->cbb;
7800                                 *sp ++ = ins;
7801                                 ip += 5;
7802                         }
7803                         break;
7804                 }
7805                 case CEE_UNBOX_ANY: {
7806                         CHECK_STACK (1);
7807                         --sp;
7808                         CHECK_OPSIZE (5);
7809                         token = read32 (ip + 1);
7810                         klass = mini_get_class (method, token, generic_context);
7811                         CHECK_TYPELOAD (klass);
7812  
7813                         mono_save_token_info (cfg, image, token, klass);
7814
7815                         if (cfg->generic_sharing_context)
7816                                 context_used = mono_class_check_context_used (klass);
7817
7818                         if (generic_class_is_reference_type (cfg, klass)) {
7819                                 /* CASTCLASS FIXME kill this huge slice of duplicated code*/
7820                                 if (context_used) {
7821                                         MonoInst *iargs [2];
7822
7823                                         /* obj */
7824                                         iargs [0] = *sp;
7825                                         /* klass */
7826                                         iargs [1] = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
7827                                         ins = mono_emit_jit_icall (cfg, mono_object_castclass, iargs);
7828                                         *sp ++ = ins;
7829                                         ip += 5;
7830                                         inline_costs += 2;
7831                                 } else if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE) {                            
7832                                         MonoMethod *mono_castclass;
7833                                         MonoInst *iargs [1];
7834                                         int costs;
7835
7836                                         mono_castclass = mono_marshal_get_castclass (klass); 
7837                                         iargs [0] = sp [0];
7838
7839                                         costs = inline_method (cfg, mono_castclass, mono_method_signature (mono_castclass), 
7840                                                                                    iargs, ip, cfg->real_offset, dont_inline, TRUE);
7841                         
7842                                         g_assert (costs > 0);
7843                                 
7844                                         ip += 5;
7845                                         cfg->real_offset += 5;
7846                                         bblock = cfg->cbb;
7847
7848                                         *sp++ = iargs [0];
7849                                         inline_costs += costs;
7850                                 } else {
7851                                         ins = handle_castclass (cfg, klass, *sp, 0);
7852                                         CHECK_CFG_EXCEPTION;
7853                                         bblock = cfg->cbb;
7854                                         *sp ++ = ins;
7855                                         ip += 5;
7856                                 }
7857                                 break;
7858                         }
7859
7860                         if (mono_class_is_nullable (klass)) {
7861                                 ins = handle_unbox_nullable (cfg, *sp, klass, context_used);
7862                                 *sp++= ins;
7863                                 ip += 5;
7864                                 break;
7865                         }
7866
7867                         /* UNBOX */
7868                         ins = handle_unbox (cfg, klass, sp, context_used);
7869                         *sp = ins;
7870
7871                         ip += 5;
7872
7873                         /* LDOBJ */
7874                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
7875                         *sp++ = ins;
7876
7877                         inline_costs += 2;
7878                         break;
7879                 }
7880                 case CEE_BOX: {
7881                         MonoInst *val;
7882
7883                         CHECK_STACK (1);
7884                         --sp;
7885                         val = *sp;
7886                         CHECK_OPSIZE (5);
7887                         token = read32 (ip + 1);
7888                         klass = mini_get_class (method, token, generic_context);
7889                         CHECK_TYPELOAD (klass);
7890
7891                         mono_save_token_info (cfg, image, token, klass);
7892
7893                         if (cfg->generic_sharing_context)
7894                                 context_used = mono_class_check_context_used (klass);
7895
7896                         if (generic_class_is_reference_type (cfg, klass)) {
7897                                 *sp++ = val;
7898                                 ip += 5;
7899                                 break;
7900                         }
7901
7902                         if (klass == mono_defaults.void_class)
7903                                 UNVERIFIED;
7904                         if (target_type_is_incompatible (cfg, &klass->byval_arg, *sp))
7905                                 UNVERIFIED;
7906                         /* frequent check in generic code: box (struct), brtrue */
7907                         if (!mono_class_is_nullable (klass) &&
7908                                 ip + 5 < end && ip_in_bb (cfg, bblock, ip + 5) && (ip [5] == CEE_BRTRUE || ip [5] == CEE_BRTRUE_S)) {
7909                                 /*printf ("box-brtrue opt at 0x%04x in %s\n", real_offset, method->name);*/
7910                                 ip += 5;
7911                                 MONO_INST_NEW (cfg, ins, OP_BR);
7912                                 if (*ip == CEE_BRTRUE_S) {
7913                                         CHECK_OPSIZE (2);
7914                                         ip++;
7915                                         target = ip + 1 + (signed char)(*ip);
7916                                         ip++;
7917                                 } else {
7918                                         CHECK_OPSIZE (5);
7919                                         ip++;
7920                                         target = ip + 4 + (gint)(read32 (ip));
7921                                         ip += 4;
7922                                 }
7923                                 GET_BBLOCK (cfg, tblock, target);
7924                                 link_bblock (cfg, bblock, tblock);
7925                                 ins->inst_target_bb = tblock;
7926                                 GET_BBLOCK (cfg, tblock, ip);
7927                                 /* 
7928                                  * This leads to some inconsistency, since the two bblocks are 
7929                                  * not really connected, but it is needed for handling stack 
7930                                  * arguments correctly (See test_0_box_brtrue_opt_regress_81102).
7931                                  * FIXME: This should only be needed if sp != stack_start, but that
7932                                  * doesn't work for some reason (test failure in mcs/tests on x86).
7933                                  */
7934                                 link_bblock (cfg, bblock, tblock);
7935                                 if (sp != stack_start) {
7936                                         handle_stack_args (cfg, stack_start, sp - stack_start);
7937                                         sp = stack_start;
7938                                         CHECK_UNVERIFIABLE (cfg);
7939                                 }
7940                                 MONO_ADD_INS (bblock, ins);
7941                                 start_new_bblock = 1;
7942                                 break;
7943                         }
7944
7945                         *sp++ = handle_box (cfg, val, klass, context_used);
7946
7947                         CHECK_CFG_EXCEPTION;
7948                         ip += 5;
7949                         inline_costs += 1;
7950                         break;
7951                 }
7952                 case CEE_UNBOX: {
7953                         CHECK_STACK (1);
7954                         --sp;
7955                         CHECK_OPSIZE (5);
7956                         token = read32 (ip + 1);
7957                         klass = mini_get_class (method, token, generic_context);
7958                         CHECK_TYPELOAD (klass);
7959
7960                         mono_save_token_info (cfg, image, token, klass);
7961
7962                         if (cfg->generic_sharing_context)
7963                                 context_used = mono_class_check_context_used (klass);
7964
7965                         if (mono_class_is_nullable (klass)) {
7966                                 MonoInst *val;
7967
7968                                 val = handle_unbox_nullable (cfg, *sp, klass, context_used);
7969                                 EMIT_NEW_VARLOADA (cfg, ins, get_vreg_to_inst (cfg, val->dreg), &val->klass->byval_arg);
7970
7971                                 *sp++= ins;
7972                         } else {
7973                                 ins = handle_unbox (cfg, klass, sp, context_used);
7974                                 *sp++ = ins;
7975                         }
7976                         ip += 5;
7977                         inline_costs += 2;
7978                         break;
7979                 }
7980                 case CEE_LDFLD:
7981                 case CEE_LDFLDA:
7982                 case CEE_STFLD: {
7983                         MonoClassField *field;
7984                         int costs;
7985                         guint foffset;
7986
7987                         if (*ip == CEE_STFLD) {
7988                                 CHECK_STACK (2);
7989                                 sp -= 2;
7990                         } else {
7991                                 CHECK_STACK (1);
7992                                 --sp;
7993                         }
7994                         if (sp [0]->type == STACK_I4 || sp [0]->type == STACK_I8 || sp [0]->type == STACK_R8)
7995                                 UNVERIFIED;
7996                         if (*ip != CEE_LDFLD && sp [0]->type == STACK_VTYPE)
7997                                 UNVERIFIED;
7998                         CHECK_OPSIZE (5);
7999                         token = read32 (ip + 1);
8000                         if (method->wrapper_type != MONO_WRAPPER_NONE) {
8001                                 field = mono_method_get_wrapper_data (method, token);
8002                                 klass = field->parent;
8003                         }
8004                         else {
8005                                 field = mono_field_from_token (image, token, &klass, generic_context);
8006                         }
8007                         if (!field)
8008                                 goto load_error;
8009                         if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_field (method, field))
8010                                 FIELD_ACCESS_FAILURE;
8011                         mono_class_init (klass);
8012
8013                         /* XXX this is technically required but, so far (SL2), no [SecurityCritical] types (not many exists) have
8014                            any visible *instance* field  (in fact there's a single case for a static field in Marshal) XXX
8015                         if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR)
8016                                 ensure_method_is_allowed_to_access_field (cfg, method, field, bblock, ip);
8017                         */
8018
8019                         foffset = klass->valuetype? field->offset - sizeof (MonoObject): field->offset;
8020                         if (*ip == CEE_STFLD) {
8021                                 if (target_type_is_incompatible (cfg, field->type, sp [1]))
8022                                         UNVERIFIED;
8023                                 if ((klass->marshalbyref && !MONO_CHECK_THIS (sp [0])) || klass->contextbound || klass == mono_defaults.marshalbyrefobject_class) {
8024                                         MonoMethod *stfld_wrapper = mono_marshal_get_stfld_wrapper (field->type); 
8025                                         MonoInst *iargs [5];
8026
8027                                         iargs [0] = sp [0];
8028                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
8029                                         EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
8030                                         EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : 
8031                                                     field->offset);
8032                                         iargs [4] = sp [1];
8033
8034                                         if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
8035                                                 costs = inline_method (cfg, stfld_wrapper, mono_method_signature (stfld_wrapper), 
8036                                                                        iargs, ip, cfg->real_offset, dont_inline, TRUE);
8037                                                 g_assert (costs > 0);
8038                                                       
8039                                                 cfg->real_offset += 5;
8040                                                 bblock = cfg->cbb;
8041
8042                                                 inline_costs += costs;
8043                                         } else {
8044                                                 mono_emit_method_call (cfg, stfld_wrapper, iargs, NULL);
8045                                         }
8046                                 } else {
8047                                         MonoInst *store;
8048
8049                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
8050
8051                                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, sp [0]->dreg, foffset, sp [1]->dreg);
8052                                         if (sp [0]->opcode != OP_LDADDR)
8053                                                 store->flags |= MONO_INST_FAULT;
8054
8055                                 if (cfg->gen_write_barriers && mini_type_to_stind (cfg, field->type) == CEE_STIND_REF && !(sp [1]->opcode == OP_PCONST && sp [1]->inst_c0 == 0)) {
8056                                         /* insert call to write barrier */
8057                                         MonoMethod *write_barrier = mono_gc_get_write_barrier ();
8058                                         MonoInst *iargs [2], *dummy_use;
8059                                         int dreg;
8060
8061                                         dreg = alloc_preg (cfg);
8062                                         EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
8063                                         iargs [1] = sp [1];
8064                                         mono_emit_method_call (cfg, write_barrier, iargs, NULL);
8065
8066                                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, sp [1]);
8067                                 }
8068
8069                                         store->flags |= ins_flag;
8070                                 }
8071                                 ins_flag = 0;
8072                                 ip += 5;
8073                                 break;
8074                         }
8075
8076                         if ((klass->marshalbyref && !MONO_CHECK_THIS (sp [0])) || klass->contextbound || klass == mono_defaults.marshalbyrefobject_class) {
8077                                 MonoMethod *wrapper = (*ip == CEE_LDFLDA) ? mono_marshal_get_ldflda_wrapper (field->type) : mono_marshal_get_ldfld_wrapper (field->type); 
8078                                 MonoInst *iargs [4];
8079
8080                                 iargs [0] = sp [0];
8081                                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
8082                                 EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
8083                                 EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset);
8084                                 if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
8085                                         costs = inline_method (cfg, wrapper, mono_method_signature (wrapper), 
8086                                                                                    iargs, ip, cfg->real_offset, dont_inline, TRUE);
8087                                         bblock = cfg->cbb;
8088                                         g_assert (costs > 0);
8089                                                       
8090                                         cfg->real_offset += 5;
8091
8092                                         *sp++ = iargs [0];
8093
8094                                         inline_costs += costs;
8095                                 } else {
8096                                         ins = mono_emit_method_call (cfg, wrapper, iargs, NULL);
8097                                         *sp++ = ins;
8098                                 }
8099                         } else {
8100                                 if (sp [0]->type == STACK_VTYPE) {
8101                                         MonoInst *var;
8102
8103                                         /* Have to compute the address of the variable */
8104
8105                                         var = get_vreg_to_inst (cfg, sp [0]->dreg);
8106                                         if (!var)
8107                                                 var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, sp [0]->dreg);
8108                                         else
8109                                                 g_assert (var->klass == klass);
8110                                         
8111                                         EMIT_NEW_VARLOADA (cfg, ins, var, &var->klass->byval_arg);
8112                                         sp [0] = ins;
8113                                 }
8114
8115                                 MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
8116
8117                                 if (*ip == CEE_LDFLDA) {
8118                                         dreg = alloc_preg (cfg);
8119
8120                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
8121                                         ins->klass = mono_class_from_mono_type (field->type);
8122                                         ins->type = STACK_MP;
8123                                         *sp++ = ins;
8124                                 } else {
8125                                         MonoInst *load;
8126
8127                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, sp [0]->dreg, foffset);
8128                                         load->flags |= ins_flag;
8129                                         if (sp [0]->opcode != OP_LDADDR)
8130                                                 load->flags |= MONO_INST_FAULT;
8131                                         *sp++ = load;
8132                                 }
8133                         }
8134                         ins_flag = 0;
8135                         ip += 5;
8136                         break;
8137                 }
8138                 case CEE_LDSFLD:
8139                 case CEE_LDSFLDA:
8140                 case CEE_STSFLD: {
8141                         MonoClassField *field;
8142                         gpointer addr = NULL;
8143                         gboolean is_special_static;
8144
8145                         CHECK_OPSIZE (5);
8146                         token = read32 (ip + 1);
8147
8148                         if (method->wrapper_type != MONO_WRAPPER_NONE) {
8149                                 field = mono_method_get_wrapper_data (method, token);
8150                                 klass = field->parent;
8151                         }
8152                         else
8153                                 field = mono_field_from_token (image, token, &klass, generic_context);
8154                         if (!field)
8155                                 goto load_error;
8156                         mono_class_init (klass);
8157                         if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_field (method, field))
8158                                 FIELD_ACCESS_FAILURE;
8159
8160                         /* if the class is Critical then transparent code cannot access it's fields */
8161                         if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR)
8162                                 ensure_method_is_allowed_to_access_field (cfg, method, field, bblock, ip);
8163
8164                         /*
8165                          * We can only support shared generic static
8166                          * field access on architectures where the
8167                          * trampoline code has been extended to handle
8168                          * the generic class init.
8169                          */
8170 #ifndef MONO_ARCH_VTABLE_REG
8171                         GENERIC_SHARING_FAILURE (*ip);
8172 #endif
8173
8174                         if (cfg->generic_sharing_context)
8175                                 context_used = mono_class_check_context_used (klass);
8176
8177                         g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
8178
8179                         /* The special_static_fields field is init'd in mono_class_vtable, so it needs
8180                          * to be called here.
8181                          */
8182                         if (!context_used && !(cfg->opt & MONO_OPT_SHARED)) {
8183                                 mono_class_vtable (cfg->domain, klass);
8184                                 CHECK_TYPELOAD (klass);
8185                         }
8186                         mono_domain_lock (cfg->domain);
8187                         if (cfg->domain->special_static_fields)
8188                                 addr = g_hash_table_lookup (cfg->domain->special_static_fields, field);
8189                         mono_domain_unlock (cfg->domain);
8190
8191                         is_special_static = mono_class_field_is_special_static (field);
8192
8193                         /* Generate IR to compute the field address */
8194                         if (is_special_static && ((gsize)addr & 0x80000000) == 0 && mono_get_thread_intrinsic (cfg) && !(cfg->opt & MONO_OPT_SHARED) && !context_used) {
8195                                 /*
8196                                  * Fast access to TLS data
8197                                  * Inline version of get_thread_static_data () in
8198                                  * threads.c.
8199                                  */
8200                                 guint32 offset;
8201                                 int idx, static_data_reg, array_reg, dreg;
8202                                 MonoInst *thread_ins;
8203
8204                                 // offset &= 0x7fffffff;
8205                                 // idx = (offset >> 24) - 1;
8206                                 //      return ((char*) thread->static_data [idx]) + (offset & 0xffffff);
8207
8208                                 thread_ins = mono_get_thread_intrinsic (cfg);
8209                                 MONO_ADD_INS (cfg->cbb, thread_ins);
8210                                 static_data_reg = alloc_ireg (cfg);
8211                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, static_data_reg, thread_ins->dreg, G_STRUCT_OFFSET (MonoInternalThread, static_data));
8212
8213                                 if (cfg->compile_aot) {
8214                                         int offset_reg, offset2_reg, idx_reg;
8215
8216                                         /* For TLS variables, this will return the TLS offset */
8217                                         EMIT_NEW_SFLDACONST (cfg, ins, field);
8218                                         offset_reg = ins->dreg;
8219                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset_reg, offset_reg, 0x7fffffff);
8220                                         idx_reg = alloc_ireg (cfg);
8221                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_IMM, idx_reg, offset_reg, 24);
8222                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, idx_reg, idx_reg, 1);
8223                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHL_IMM, idx_reg, idx_reg, sizeof (gpointer) == 8 ? 3 : 2);
8224                                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, static_data_reg, static_data_reg, idx_reg);
8225                                         array_reg = alloc_ireg (cfg);
8226                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, 0);
8227                                         offset2_reg = alloc_ireg (cfg);
8228                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset2_reg, offset_reg, 0xffffff);
8229                                         dreg = alloc_ireg (cfg);
8230                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, array_reg, offset2_reg);
8231                                 } else {
8232                                         offset = (gsize)addr & 0x7fffffff;
8233                                         idx = (offset >> 24) - 1;
8234
8235                                         array_reg = alloc_ireg (cfg);
8236                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, idx * sizeof (gpointer));
8237                                         dreg = alloc_ireg (cfg);
8238                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_ADD_IMM, dreg, array_reg, (offset & 0xffffff));
8239                                 }
8240                         } else if ((cfg->opt & MONO_OPT_SHARED) ||
8241                                         (cfg->compile_aot && is_special_static) ||
8242                                         (context_used && is_special_static)) {
8243                                 MonoInst *iargs [2];
8244
8245                                 g_assert (field->parent);
8246                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
8247                                 if (context_used) {
8248                                         iargs [1] = emit_get_rgctx_field (cfg, context_used,
8249                                                 field, MONO_RGCTX_INFO_CLASS_FIELD);
8250                                 } else {
8251                                         EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
8252                                 }
8253                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
8254                         } else if (context_used) {
8255                                 MonoInst *static_data;
8256
8257                                 /*
8258                                 g_print ("sharing static field access in %s.%s.%s - depth %d offset %d\n",
8259                                         method->klass->name_space, method->klass->name, method->name,
8260                                         depth, field->offset);
8261                                 */
8262
8263                                 if (mono_class_needs_cctor_run (klass, method))
8264                                         emit_generic_class_init (cfg, klass);
8265
8266                                 /*
8267                                  * The pointer we're computing here is
8268                                  *
8269                                  *   super_info.static_data + field->offset
8270                                  */
8271                                 static_data = emit_get_rgctx_klass (cfg, context_used,
8272                                         klass, MONO_RGCTX_INFO_STATIC_DATA);
8273
8274                                 if (field->offset == 0) {
8275                                         ins = static_data;
8276                                 } else {
8277                                         int addr_reg = mono_alloc_preg (cfg);
8278                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, addr_reg, static_data->dreg, field->offset);
8279                                 }
8280                                 } else if ((cfg->opt & MONO_OPT_SHARED) || (cfg->compile_aot && addr)) {
8281                                 MonoInst *iargs [2];
8282
8283                                 g_assert (field->parent);
8284                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
8285                                 EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
8286                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
8287                         } else {
8288                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
8289
8290                                 CHECK_TYPELOAD (klass);
8291                                 if (!addr) {
8292                                         if (mini_field_access_needs_cctor_run (cfg, method, vtable) && !(g_slist_find (class_inits, vtable))) {
8293                                                 mono_emit_abs_call (cfg, MONO_PATCH_INFO_CLASS_INIT, vtable->klass, helper_sig_class_init_trampoline, NULL);
8294                                                 if (cfg->verbose_level > 2)
8295                                                         printf ("class %s.%s needs init call for %s\n", klass->name_space, klass->name, mono_field_get_name (field));
8296                                                 class_inits = g_slist_prepend (class_inits, vtable);
8297                                         } else {
8298                                                 if (cfg->run_cctors) {
8299                                                         MonoException *ex;
8300                                                         /* This makes so that inline cannot trigger */
8301                                                         /* .cctors: too many apps depend on them */
8302                                                         /* running with a specific order... */
8303                                                         if (! vtable->initialized)
8304                                                                 INLINE_FAILURE;
8305                                                         ex = mono_runtime_class_init_full (vtable, FALSE);
8306                                                         if (ex) {
8307                                                                 set_exception_object (cfg, ex);
8308                                                                 goto exception_exit;
8309                                                         }
8310                                                 }
8311                                         }
8312                                         addr = (char*)vtable->data + field->offset;
8313
8314                                         if (cfg->compile_aot)
8315                                                 EMIT_NEW_SFLDACONST (cfg, ins, field);
8316                                         else
8317                                                 EMIT_NEW_PCONST (cfg, ins, addr);
8318                                 } else {
8319                                         MonoInst *iargs [1];
8320                                         EMIT_NEW_ICONST (cfg, iargs [0], GPOINTER_TO_UINT (addr));
8321                                         ins = mono_emit_jit_icall (cfg, mono_get_special_static_data, iargs);
8322                                 }
8323                         }
8324
8325                         /* Generate IR to do the actual load/store operation */
8326
8327                         if (*ip == CEE_LDSFLDA) {
8328                                 ins->klass = mono_class_from_mono_type (field->type);
8329                                 ins->type = STACK_PTR;
8330                                 *sp++ = ins;
8331                         } else if (*ip == CEE_STSFLD) {
8332                                 MonoInst *store;
8333                                 CHECK_STACK (1);
8334                                 sp--;
8335
8336                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, ins->dreg, 0, sp [0]->dreg);
8337                                 store->flags |= ins_flag;
8338                         } else {
8339                                 gboolean is_const = FALSE;
8340                                 MonoVTable *vtable = NULL;
8341
8342                                 if (!context_used) {
8343                                         vtable = mono_class_vtable (cfg->domain, klass);
8344                                         CHECK_TYPELOAD (klass);
8345                                 }
8346                                 if (!context_used && !((cfg->opt & MONO_OPT_SHARED) || cfg->compile_aot) && 
8347                                     vtable->initialized && (field->type->attrs & FIELD_ATTRIBUTE_INIT_ONLY)) {
8348                                         gpointer addr = (char*)vtable->data + field->offset;
8349                                         int ro_type = field->type->type;
8350                                         if (ro_type == MONO_TYPE_VALUETYPE && field->type->data.klass->enumtype) {
8351                                                 ro_type = mono_class_enum_basetype (field->type->data.klass)->type;
8352                                         }
8353                                         /* printf ("RO-FIELD %s.%s:%s\n", klass->name_space, klass->name, mono_field_get_name (field));*/
8354                                         is_const = TRUE;
8355                                         switch (ro_type) {
8356                                         case MONO_TYPE_BOOLEAN:
8357                                         case MONO_TYPE_U1:
8358                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint8 *)addr));
8359                                                 sp++;
8360                                                 break;
8361                                         case MONO_TYPE_I1:
8362                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint8 *)addr));
8363                                                 sp++;
8364                                                 break;                                          
8365                                         case MONO_TYPE_CHAR:
8366                                         case MONO_TYPE_U2:
8367                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint16 *)addr));
8368                                                 sp++;
8369                                                 break;
8370                                         case MONO_TYPE_I2:
8371                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint16 *)addr));
8372                                                 sp++;
8373                                                 break;
8374                                                 break;
8375                                         case MONO_TYPE_I4:
8376                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint32 *)addr));
8377                                                 sp++;
8378                                                 break;                                          
8379                                         case MONO_TYPE_U4:
8380                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint32 *)addr));
8381                                                 sp++;
8382                                                 break;
8383                                         case MONO_TYPE_I:
8384                                         case MONO_TYPE_U:
8385                                         case MONO_TYPE_PTR:
8386                                         case MONO_TYPE_FNPTR:
8387 #ifndef HAVE_MOVING_COLLECTOR
8388                                         case MONO_TYPE_STRING:
8389                                         case MONO_TYPE_OBJECT:
8390                                         case MONO_TYPE_CLASS:
8391                                         case MONO_TYPE_SZARRAY:
8392                                         case MONO_TYPE_ARRAY:
8393 #endif
8394                                                 EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
8395                                                 type_to_eval_stack_type ((cfg), field->type, *sp);
8396                                                 sp++;
8397                                                 break;
8398                                         case MONO_TYPE_I8:
8399                                         case MONO_TYPE_U8:
8400                                                 EMIT_NEW_I8CONST (cfg, *sp, *((gint64 *)addr));
8401                                                 sp++;
8402                                                 break;
8403                                         case MONO_TYPE_R4:
8404                                         case MONO_TYPE_R8:
8405                                         case MONO_TYPE_VALUETYPE:
8406                                         default:
8407                                                 is_const = FALSE;
8408                                                 break;
8409                                         }
8410                                 }
8411
8412                                 if (!is_const) {
8413                                         MonoInst *load;
8414
8415                                         CHECK_STACK_OVF (1);
8416
8417                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, ins->dreg, 0);
8418                                         load->flags |= ins_flag;
8419                                         ins_flag = 0;
8420                                         *sp++ = load;
8421                                 }
8422                         }
8423                         ins_flag = 0;
8424                         ip += 5;
8425                         break;
8426                 }
8427                 case CEE_STOBJ:
8428                         CHECK_STACK (2);
8429                         sp -= 2;
8430                         CHECK_OPSIZE (5);
8431                         token = read32 (ip + 1);
8432                         klass = mini_get_class (method, token, generic_context);
8433                         CHECK_TYPELOAD (klass);
8434                         /* FIXME: should check item at sp [1] is compatible with the type of the store. */
8435                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0, sp [1]->dreg);
8436                         if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER &&
8437                                         generic_class_is_reference_type (cfg, klass)) {
8438                                 MonoInst *dummy_use;
8439                                 /* insert call to write barrier */
8440                                 MonoMethod *write_barrier = mono_gc_get_write_barrier ();
8441                                 mono_emit_method_call (cfg, write_barrier, sp, NULL);
8442                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, sp [1]);
8443                         }
8444                         ins_flag = 0;
8445                         ip += 5;
8446                         inline_costs += 1;
8447                         break;
8448
8449                         /*
8450                          * Array opcodes
8451                          */
8452                 case CEE_NEWARR: {
8453                         MonoInst *len_ins;
8454                         const char *data_ptr;
8455                         int data_size = 0;
8456                         guint32 field_token;
8457
8458                         CHECK_STACK (1);
8459                         --sp;
8460
8461                         CHECK_OPSIZE (5);
8462                         token = read32 (ip + 1);
8463
8464                         klass = mini_get_class (method, token, generic_context);
8465                         CHECK_TYPELOAD (klass);
8466
8467                         if (cfg->generic_sharing_context)
8468                                 context_used = mono_class_check_context_used (klass);
8469
8470                         if (sp [0]->type == STACK_I8 || (SIZEOF_VOID_P == 8 && sp [0]->type == STACK_PTR)) {
8471                                 MONO_INST_NEW (cfg, ins, OP_LCONV_TO_I4);
8472                                 ins->sreg1 = sp [0]->dreg;
8473                                 ins->type = STACK_I4;
8474                                 ins->dreg = alloc_ireg (cfg);
8475                                 MONO_ADD_INS (cfg->cbb, ins);
8476                                 *sp = mono_decompose_opcode (cfg, ins);
8477                         }
8478
8479                         if (context_used) {
8480                                 MonoInst *args [3];
8481                                 MonoClass *array_class = mono_array_class_get (klass, 1);
8482                                 /* FIXME: we cannot get a managed
8483                                    allocator because we can't get the
8484                                    open generic class's vtable.  We
8485                                    have the same problem in
8486                                    handle_alloc().  This
8487                                    needs to be solved so that we can
8488                                    have managed allocs of shared
8489                                    generic classes. */
8490                                 /*
8491                                 MonoVTable *array_class_vtable = mono_class_vtable (cfg->domain, array_class);
8492                                 MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (array_class_vtable, 1);
8493                                 */
8494                                 MonoMethod *managed_alloc = NULL;
8495
8496                                 /* FIXME: Decompose later to help abcrem */
8497
8498                                 /* vtable */
8499                                 args [0] = emit_get_rgctx_klass (cfg, context_used,
8500                                         array_class, MONO_RGCTX_INFO_VTABLE);
8501                                 /* array len */
8502                                 args [1] = sp [0];
8503
8504                                 if (managed_alloc)
8505                                         ins = mono_emit_method_call (cfg, managed_alloc, args, NULL);
8506                                 else
8507                                         ins = mono_emit_jit_icall (cfg, mono_array_new_specific, args);
8508                         } else {
8509                                 if (cfg->opt & MONO_OPT_SHARED) {
8510                                         /* Decompose now to avoid problems with references to the domainvar */
8511                                         MonoInst *iargs [3];
8512
8513                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
8514                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
8515                                         iargs [2] = sp [0];
8516
8517                                         ins = mono_emit_jit_icall (cfg, mono_array_new, iargs);
8518                                 } else {
8519                                         /* Decompose later since it is needed by abcrem */
8520                                         MonoClass *array_type = mono_array_class_get (klass, 1);
8521                                         mono_class_vtable (cfg->domain, array_type);
8522                                         CHECK_TYPELOAD (array_type);
8523
8524                                         MONO_INST_NEW (cfg, ins, OP_NEWARR);
8525                                         ins->dreg = alloc_preg (cfg);
8526                                         ins->sreg1 = sp [0]->dreg;
8527                                         ins->inst_newa_class = klass;
8528                                         ins->type = STACK_OBJ;
8529                                         ins->klass = klass;
8530                                         MONO_ADD_INS (cfg->cbb, ins);
8531                                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
8532                                         cfg->cbb->has_array_access = TRUE;
8533
8534                                         /* Needed so mono_emit_load_get_addr () gets called */
8535                                         mono_get_got_var (cfg);
8536                                 }
8537                         }
8538
8539                         len_ins = sp [0];
8540                         ip += 5;
8541                         *sp++ = ins;
8542                         inline_costs += 1;
8543
8544                         /* 
8545                          * we inline/optimize the initialization sequence if possible.
8546                          * we should also allocate the array as not cleared, since we spend as much time clearing to 0 as initializing
8547                          * for small sizes open code the memcpy
8548                          * ensure the rva field is big enough
8549                          */
8550                         if ((cfg->opt & MONO_OPT_INTRINS) && ip + 6 < end && ip_in_bb (cfg, bblock, ip + 6) && (len_ins->opcode == OP_ICONST) && (data_ptr = initialize_array_data (method, cfg->compile_aot, ip, klass, len_ins->inst_c0, &data_size, &field_token))) {
8551                                 MonoMethod *memcpy_method = get_memcpy_method ();
8552                                 MonoInst *iargs [3];
8553                                 int add_reg = alloc_preg (cfg);
8554
8555                                 EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, add_reg, ins->dreg, G_STRUCT_OFFSET (MonoArray, vector));
8556                                 if (cfg->compile_aot) {
8557                                         EMIT_NEW_AOTCONST_TOKEN (cfg, iargs [1], MONO_PATCH_INFO_RVA, method->klass->image, GPOINTER_TO_UINT(field_token), STACK_PTR, NULL);
8558                                 } else {
8559                                         EMIT_NEW_PCONST (cfg, iargs [1], (char*)data_ptr);
8560                                 }
8561                                 EMIT_NEW_ICONST (cfg, iargs [2], data_size);
8562                                 mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
8563                                 ip += 11;
8564                         }
8565
8566                         break;
8567                 }
8568                 case CEE_LDLEN:
8569                         CHECK_STACK (1);
8570                         --sp;
8571                         if (sp [0]->type != STACK_OBJ)
8572                                 UNVERIFIED;
8573
8574                         dreg = alloc_preg (cfg);
8575                         MONO_INST_NEW (cfg, ins, OP_LDLEN);
8576                         ins->dreg = alloc_preg (cfg);
8577                         ins->sreg1 = sp [0]->dreg;
8578                         ins->type = STACK_I4;
8579                         MONO_ADD_INS (cfg->cbb, ins);
8580                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
8581                         cfg->cbb->has_array_access = TRUE;
8582                         ip ++;
8583                         *sp++ = ins;
8584                         break;
8585                 case CEE_LDELEMA:
8586                         CHECK_STACK (2);
8587                         sp -= 2;
8588                         CHECK_OPSIZE (5);
8589                         if (sp [0]->type != STACK_OBJ)
8590                                 UNVERIFIED;
8591
8592                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
8593
8594                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
8595                         CHECK_TYPELOAD (klass);
8596                         /* we need to make sure that this array is exactly the type it needs
8597                          * to be for correctness. the wrappers are lax with their usage
8598                          * so we need to ignore them here
8599                          */
8600                         if (!klass->valuetype && method->wrapper_type == MONO_WRAPPER_NONE && !readonly) {
8601                                 MonoClass *array_class = mono_array_class_get (klass, 1);
8602                                 mini_emit_check_array_type (cfg, sp [0], array_class);
8603                                 CHECK_TYPELOAD (array_class);
8604                         }
8605
8606                         readonly = FALSE;
8607                         ins = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
8608                         *sp++ = ins;
8609                         ip += 5;
8610                         break;
8611                 case CEE_LDELEM:
8612                 case CEE_LDELEM_I1:
8613                 case CEE_LDELEM_U1:
8614                 case CEE_LDELEM_I2:
8615                 case CEE_LDELEM_U2:
8616                 case CEE_LDELEM_I4:
8617                 case CEE_LDELEM_U4:
8618                 case CEE_LDELEM_I8:
8619                 case CEE_LDELEM_I:
8620                 case CEE_LDELEM_R4:
8621                 case CEE_LDELEM_R8:
8622                 case CEE_LDELEM_REF: {
8623                         MonoInst *addr;
8624
8625                         CHECK_STACK (2);
8626                         sp -= 2;
8627
8628                         if (*ip == CEE_LDELEM) {
8629                                 CHECK_OPSIZE (5);
8630                                 token = read32 (ip + 1);
8631                                 klass = mini_get_class (method, token, generic_context);
8632                                 CHECK_TYPELOAD (klass);
8633                                 mono_class_init (klass);
8634                         }
8635                         else
8636                                 klass = array_access_to_klass (*ip);
8637
8638                         if (sp [0]->type != STACK_OBJ)
8639                                 UNVERIFIED;
8640
8641                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
8642
8643                         if (sp [1]->opcode == OP_ICONST) {
8644                                 int array_reg = sp [0]->dreg;
8645                                 int index_reg = sp [1]->dreg;
8646                                 int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + G_STRUCT_OFFSET (MonoArray, vector);
8647
8648                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
8649                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset);
8650                         } else {
8651                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
8652                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
8653                         }
8654                         *sp++ = ins;
8655                         if (*ip == CEE_LDELEM)
8656                                 ip += 5;
8657                         else
8658                                 ++ip;
8659                         break;
8660                 }
8661                 case CEE_STELEM_I:
8662                 case CEE_STELEM_I1:
8663                 case CEE_STELEM_I2:
8664                 case CEE_STELEM_I4:
8665                 case CEE_STELEM_I8:
8666                 case CEE_STELEM_R4:
8667                 case CEE_STELEM_R8:
8668                 case CEE_STELEM_REF:
8669                 case CEE_STELEM: {
8670                         MonoInst *addr;
8671
8672                         CHECK_STACK (3);
8673                         sp -= 3;
8674
8675                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
8676
8677                         if (*ip == CEE_STELEM) {
8678                                 CHECK_OPSIZE (5);
8679                                 token = read32 (ip + 1);
8680                                 klass = mini_get_class (method, token, generic_context);
8681                                 CHECK_TYPELOAD (klass);
8682                                 mono_class_init (klass);
8683                         }
8684                         else
8685                                 klass = array_access_to_klass (*ip);
8686
8687                         if (sp [0]->type != STACK_OBJ)
8688                                 UNVERIFIED;
8689
8690                         /* storing a NULL doesn't need any of the complex checks in stelemref */
8691                         if (generic_class_is_reference_type (cfg, klass) &&
8692                                 !(sp [2]->opcode == OP_PCONST && sp [2]->inst_p0 == NULL)) {
8693                                 MonoMethod* helper = mono_marshal_get_stelemref ();
8694                                 MonoInst *iargs [3];
8695
8696                                 if (sp [0]->type != STACK_OBJ)
8697                                         UNVERIFIED;
8698                                 if (sp [2]->type != STACK_OBJ)
8699                                         UNVERIFIED;
8700
8701                                 iargs [2] = sp [2];
8702                                 iargs [1] = sp [1];
8703                                 iargs [0] = sp [0];
8704                                 
8705                                 mono_emit_method_call (cfg, helper, iargs, NULL);
8706                         } else {
8707                                 if (sp [1]->opcode == OP_ICONST) {
8708                                         int array_reg = sp [0]->dreg;
8709                                         int index_reg = sp [1]->dreg;
8710                                         int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + G_STRUCT_OFFSET (MonoArray, vector);
8711
8712                                         MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
8713                                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset, sp [2]->dreg);
8714                                 } else {
8715                                         addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
8716                                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
8717                                 }
8718                         }
8719
8720                         if (*ip == CEE_STELEM)
8721                                 ip += 5;
8722                         else
8723                                 ++ip;
8724                         inline_costs += 1;
8725                         break;
8726                 }
8727                 case CEE_CKFINITE: {
8728                         CHECK_STACK (1);
8729                         --sp;
8730
8731                         MONO_INST_NEW (cfg, ins, OP_CKFINITE);
8732                         ins->sreg1 = sp [0]->dreg;
8733                         ins->dreg = alloc_freg (cfg);
8734                         ins->type = STACK_R8;
8735                         MONO_ADD_INS (bblock, ins);
8736
8737                         *sp++ = mono_decompose_opcode (cfg, ins);
8738
8739                         ++ip;
8740                         break;
8741                 }
8742                 case CEE_REFANYVAL: {
8743                         MonoInst *src_var, *src;
8744
8745                         int klass_reg = alloc_preg (cfg);
8746                         int dreg = alloc_preg (cfg);
8747
8748                         CHECK_STACK (1);
8749                         MONO_INST_NEW (cfg, ins, *ip);
8750                         --sp;
8751                         CHECK_OPSIZE (5);
8752                         klass = mono_class_get_full (image, read32 (ip + 1), generic_context);
8753                         CHECK_TYPELOAD (klass);
8754                         mono_class_init (klass);
8755
8756                         if (cfg->generic_sharing_context)
8757                                 context_used = mono_class_check_context_used (klass);
8758
8759                         // FIXME:
8760                         src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
8761                         if (!src_var)
8762                                 src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
8763                         EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
8764                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, src->dreg, G_STRUCT_OFFSET (MonoTypedRef, klass));
8765
8766                         if (context_used) {
8767                                 MonoInst *klass_ins;
8768
8769                                 klass_ins = emit_get_rgctx_klass (cfg, context_used,
8770                                                 klass, MONO_RGCTX_INFO_KLASS);
8771
8772                                 // FIXME:
8773                                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_ins->dreg);
8774                                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
8775                         } else {
8776                                 mini_emit_class_check (cfg, klass_reg, klass);
8777                         }
8778                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, src->dreg, G_STRUCT_OFFSET (MonoTypedRef, value));
8779                         ins->type = STACK_MP;
8780                         *sp++ = ins;
8781                         ip += 5;
8782                         break;
8783                 }
8784                 case CEE_MKREFANY: {
8785                         MonoInst *loc, *addr;
8786
8787                         CHECK_STACK (1);
8788                         MONO_INST_NEW (cfg, ins, *ip);
8789                         --sp;
8790                         CHECK_OPSIZE (5);
8791                         klass = mono_class_get_full (image, read32 (ip + 1), generic_context);
8792                         CHECK_TYPELOAD (klass);
8793                         mono_class_init (klass);
8794
8795                         if (cfg->generic_sharing_context)
8796                                 context_used = mono_class_check_context_used (klass);
8797
8798                         loc = mono_compile_create_var (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL);
8799                         EMIT_NEW_TEMPLOADA (cfg, addr, loc->inst_c0);
8800
8801                         if (context_used) {
8802                                 MonoInst *const_ins;
8803                                 int type_reg = alloc_preg (cfg);
8804
8805                                 const_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
8806                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, G_STRUCT_OFFSET (MonoTypedRef, klass), const_ins->dreg);
8807                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_ins->dreg, G_STRUCT_OFFSET (MonoClass, byval_arg));
8808                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, G_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
8809                         } else if (cfg->compile_aot) {
8810                                 int const_reg = alloc_preg (cfg);
8811                                 int type_reg = alloc_preg (cfg);
8812
8813                                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
8814                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, G_STRUCT_OFFSET (MonoTypedRef, klass), const_reg);
8815                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_reg, G_STRUCT_OFFSET (MonoClass, byval_arg));
8816                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, G_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
8817                         } else {
8818                                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, G_STRUCT_OFFSET (MonoTypedRef, type), &klass->byval_arg);
8819                                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, G_STRUCT_OFFSET (MonoTypedRef, klass), klass);
8820                         }
8821                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, G_STRUCT_OFFSET (MonoTypedRef, value), sp [0]->dreg);
8822
8823                         EMIT_NEW_TEMPLOAD (cfg, ins, loc->inst_c0);
8824                         ins->type = STACK_VTYPE;
8825                         ins->klass = mono_defaults.typed_reference_class;
8826                         *sp++ = ins;
8827                         ip += 5;
8828                         break;
8829                 }
8830                 case CEE_LDTOKEN: {
8831                         gpointer handle;
8832                         MonoClass *handle_class;
8833
8834                         CHECK_STACK_OVF (1);
8835
8836                         CHECK_OPSIZE (5);
8837                         n = read32 (ip + 1);
8838
8839                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD ||
8840                                         method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
8841                                 handle = mono_method_get_wrapper_data (method, n);
8842                                 handle_class = mono_method_get_wrapper_data (method, n + 1);
8843                                 if (handle_class == mono_defaults.typehandle_class)
8844                                         handle = &((MonoClass*)handle)->byval_arg;
8845                         }
8846                         else {
8847                                 handle = mono_ldtoken (image, n, &handle_class, generic_context);
8848                         }
8849                         if (!handle)
8850                                 goto load_error;
8851                         mono_class_init (handle_class);
8852                         if (cfg->generic_sharing_context) {
8853                                 if (mono_metadata_token_table (n) == MONO_TABLE_TYPEDEF ||
8854                                                 mono_metadata_token_table (n) == MONO_TABLE_TYPEREF) {
8855                                         /* This case handles ldtoken
8856                                            of an open type, like for
8857                                            typeof(Gen<>). */
8858                                         context_used = 0;
8859                                 } else if (handle_class == mono_defaults.typehandle_class) {
8860                                         /* If we get a MONO_TYPE_CLASS
8861                                            then we need to provide the
8862                                            open type, not an
8863                                            instantiation of it. */
8864                                         if (mono_type_get_type (handle) == MONO_TYPE_CLASS)
8865                                                 context_used = 0;
8866                                         else
8867                                                 context_used = mono_class_check_context_used (mono_class_from_mono_type (handle));
8868                                 } else if (handle_class == mono_defaults.fieldhandle_class)
8869                                         context_used = mono_class_check_context_used (((MonoClassField*)handle)->parent);
8870                                 else if (handle_class == mono_defaults.methodhandle_class)
8871                                         context_used = mono_method_check_context_used (handle);
8872                                 else
8873                                         g_assert_not_reached ();
8874                         }
8875
8876                         if ((cfg->opt & MONO_OPT_SHARED) &&
8877                                         method->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD &&
8878                                         method->wrapper_type != MONO_WRAPPER_SYNCHRONIZED) {
8879                                 MonoInst *addr, *vtvar, *iargs [3];
8880                                 int method_context_used;
8881
8882                                 if (cfg->generic_sharing_context)
8883                                         method_context_used = mono_method_check_context_used (method);
8884                                 else
8885                                         method_context_used = 0;
8886
8887                                 vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL); 
8888
8889                                 EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
8890                                 EMIT_NEW_ICONST (cfg, iargs [1], n);
8891                                 if (method_context_used) {
8892                                         iargs [2] = emit_get_rgctx_method (cfg, method_context_used,
8893                                                 method, MONO_RGCTX_INFO_METHOD);
8894                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper_generic_shared, iargs);
8895                                 } else {
8896                                         EMIT_NEW_PCONST (cfg, iargs [2], generic_context);
8897                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper, iargs);
8898                                 }
8899                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
8900
8901                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
8902
8903                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
8904                         } else {
8905                                 if ((ip + 5 < end) && ip_in_bb (cfg, bblock, ip + 5) && 
8906                                         ((ip [5] == CEE_CALL) || (ip [5] == CEE_CALLVIRT)) && 
8907                                         (cmethod = mini_get_method (cfg, method, read32 (ip + 6), NULL, generic_context)) &&
8908                                         (cmethod->klass == mono_defaults.monotype_class->parent) &&
8909                                         (strcmp (cmethod->name, "GetTypeFromHandle") == 0)) {
8910                                         MonoClass *tclass = mono_class_from_mono_type (handle);
8911
8912                                         mono_class_init (tclass);
8913                                         if (context_used) {
8914                                                 ins = emit_get_rgctx_klass (cfg, context_used,
8915                                                         tclass, MONO_RGCTX_INFO_REFLECTION_TYPE);
8916                                         } else if (cfg->compile_aot) {
8917                                                 if (method->wrapper_type) {
8918                                                         if (mono_class_get (tclass->image, tclass->type_token) == tclass && !generic_context) {
8919                                                                 /* Special case for static synchronized wrappers */
8920                                                                 EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, tclass->image, tclass->type_token, generic_context);
8921                                                         } else {
8922                                                                 /* FIXME: n is not a normal token */
8923                                                                 cfg->disable_aot = TRUE;
8924                                                                 EMIT_NEW_PCONST (cfg, ins, NULL);
8925                                                         }
8926                                                 } else {
8927                                                         EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, image, n, generic_context);
8928                                                 }
8929                                         } else {
8930                                                 EMIT_NEW_PCONST (cfg, ins, mono_type_get_object (cfg->domain, handle));
8931                                         }
8932                                         ins->type = STACK_OBJ;
8933                                         ins->klass = cmethod->klass;
8934                                         ip += 5;
8935                                 } else {
8936                                         MonoInst *addr, *vtvar;
8937
8938                                         vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL);
8939
8940                                         if (context_used) {
8941                                                 if (handle_class == mono_defaults.typehandle_class) {
8942                                                         ins = emit_get_rgctx_klass (cfg, context_used,
8943                                                                         mono_class_from_mono_type (handle),
8944                                                                         MONO_RGCTX_INFO_TYPE);
8945                                                 } else if (handle_class == mono_defaults.methodhandle_class) {
8946                                                         ins = emit_get_rgctx_method (cfg, context_used,
8947                                                                         handle, MONO_RGCTX_INFO_METHOD);
8948                                                 } else if (handle_class == mono_defaults.fieldhandle_class) {
8949                                                         ins = emit_get_rgctx_field (cfg, context_used,
8950                                                                         handle, MONO_RGCTX_INFO_CLASS_FIELD);
8951                                                 } else {
8952                                                         g_assert_not_reached ();
8953                                                 }
8954                                         } else if (cfg->compile_aot) {
8955                                                 EMIT_NEW_LDTOKENCONST (cfg, ins, image, n);
8956                                         } else {
8957                                                 EMIT_NEW_PCONST (cfg, ins, handle);
8958                                         }
8959                                         EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
8960                                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
8961                                         EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
8962                                 }
8963                         }
8964
8965                         *sp++ = ins;
8966                         ip += 5;
8967                         break;
8968                 }
8969                 case CEE_THROW:
8970                         CHECK_STACK (1);
8971                         MONO_INST_NEW (cfg, ins, OP_THROW);
8972                         --sp;
8973                         ins->sreg1 = sp [0]->dreg;
8974                         ip++;
8975                         bblock->out_of_line = TRUE;
8976                         MONO_ADD_INS (bblock, ins);
8977                         MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
8978                         MONO_ADD_INS (bblock, ins);
8979                         sp = stack_start;
8980                         
8981                         link_bblock (cfg, bblock, end_bblock);
8982                         start_new_bblock = 1;
8983                         break;
8984                 case CEE_ENDFINALLY:
8985                         MONO_INST_NEW (cfg, ins, OP_ENDFINALLY);
8986                         MONO_ADD_INS (bblock, ins);
8987                         ip++;
8988                         start_new_bblock = 1;
8989
8990                         /*
8991                          * Control will leave the method so empty the stack, otherwise
8992                          * the next basic block will start with a nonempty stack.
8993                          */
8994                         while (sp != stack_start) {
8995                                 sp--;
8996                         }
8997                         break;
8998                 case CEE_LEAVE:
8999                 case CEE_LEAVE_S: {
9000                         GList *handlers;
9001
9002                         if (*ip == CEE_LEAVE) {
9003                                 CHECK_OPSIZE (5);
9004                                 target = ip + 5 + (gint32)read32(ip + 1);
9005                         } else {
9006                                 CHECK_OPSIZE (2);
9007                                 target = ip + 2 + (signed char)(ip [1]);
9008                         }
9009
9010                         /* empty the stack */
9011                         while (sp != stack_start) {
9012                                 sp--;
9013                         }
9014
9015                         /* 
9016                          * If this leave statement is in a catch block, check for a
9017                          * pending exception, and rethrow it if necessary.
9018                          * We avoid doing this in runtime invoke wrappers, since those are called
9019                          * by native code which excepts the wrapper to catch all exceptions.
9020                          */
9021                         for (i = 0; i < header->num_clauses; ++i) {
9022                                 MonoExceptionClause *clause = &header->clauses [i];
9023
9024                                 /* 
9025                                  * Use <= in the final comparison to handle clauses with multiple
9026                                  * leave statements, like in bug #78024.
9027                                  * The ordering of the exception clauses guarantees that we find the
9028                                  * innermost clause.
9029                                  */
9030                                 if (MONO_OFFSET_IN_HANDLER (clause, ip - header->code) && (clause->flags == MONO_EXCEPTION_CLAUSE_NONE) && (ip - header->code + ((*ip == CEE_LEAVE) ? 5 : 2)) <= (clause->handler_offset + clause->handler_len) && method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE) {
9031                                         MonoInst *exc_ins;
9032                                         MonoBasicBlock *dont_throw;
9033
9034                                         /*
9035                                           MonoInst *load;
9036
9037                                           NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, clause->handler_offset)->inst_c0);
9038                                         */
9039
9040                                         exc_ins = mono_emit_jit_icall (cfg, mono_thread_get_undeniable_exception, NULL);
9041
9042                                         NEW_BBLOCK (cfg, dont_throw);
9043
9044                                         /*
9045                                          * Currently, we allways rethrow the abort exception, despite the 
9046                                          * fact that this is not correct. See thread6.cs for an example. 
9047                                          * But propagating the abort exception is more important than 
9048                                          * getting the sematics right.
9049                                          */
9050                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, exc_ins->dreg, 0);
9051                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, dont_throw);
9052                                         MONO_EMIT_NEW_UNALU (cfg, OP_THROW, -1, exc_ins->dreg);
9053
9054                                         MONO_START_BB (cfg, dont_throw);
9055                                         bblock = cfg->cbb;
9056                                 }
9057                         }
9058
9059                         if ((handlers = mono_find_final_block (cfg, ip, target, MONO_EXCEPTION_CLAUSE_FINALLY))) {
9060                                 GList *tmp;
9061                                 MonoExceptionClause *clause;
9062
9063                                 for (tmp = handlers; tmp; tmp = tmp->next) {
9064                                         clause = tmp->data;
9065                                         tblock = cfg->cil_offset_to_bb [clause->handler_offset];
9066                                         g_assert (tblock);
9067                                         link_bblock (cfg, bblock, tblock);
9068                                         MONO_INST_NEW (cfg, ins, OP_CALL_HANDLER);
9069                                         ins->inst_target_bb = tblock;
9070                                         ins->inst_eh_block = clause;
9071                                         MONO_ADD_INS (bblock, ins);
9072                                         bblock->has_call_handler = 1;
9073                                         if (COMPILE_LLVM (cfg)) {
9074                                                 MonoBasicBlock *target_bb;
9075
9076                                                 /* 
9077                                                  * Link the finally bblock with the target, since it will
9078                                                  * conceptually branch there.
9079                                                  * FIXME: Have to link the bblock containing the endfinally.
9080                                                  */
9081                                                 GET_BBLOCK (cfg, target_bb, target);
9082                                                 link_bblock (cfg, tblock, target_bb);
9083                                         }
9084                                 }
9085                                 g_list_free (handlers);
9086                         } 
9087
9088                         MONO_INST_NEW (cfg, ins, OP_BR);
9089                         MONO_ADD_INS (bblock, ins);
9090                         GET_BBLOCK (cfg, tblock, target);
9091                         link_bblock (cfg, bblock, tblock);
9092                         ins->inst_target_bb = tblock;
9093                         start_new_bblock = 1;
9094
9095                         if (*ip == CEE_LEAVE)
9096                                 ip += 5;
9097                         else
9098                                 ip += 2;
9099
9100                         break;
9101                 }
9102
9103                         /*
9104                          * Mono specific opcodes
9105                          */
9106                 case MONO_CUSTOM_PREFIX: {
9107
9108                         g_assert (method->wrapper_type != MONO_WRAPPER_NONE);
9109
9110                         CHECK_OPSIZE (2);
9111                         switch (ip [1]) {
9112                         case CEE_MONO_ICALL: {
9113                                 gpointer func;
9114                                 MonoJitICallInfo *info;
9115
9116                                 token = read32 (ip + 2);
9117                                 func = mono_method_get_wrapper_data (method, token);
9118                                 info = mono_find_jit_icall_by_addr (func);
9119                                 g_assert (info);
9120
9121                                 CHECK_STACK (info->sig->param_count);
9122                                 sp -= info->sig->param_count;
9123
9124                                 ins = mono_emit_jit_icall (cfg, info->func, sp);
9125                                 if (!MONO_TYPE_IS_VOID (info->sig->ret))
9126                                         *sp++ = ins;
9127
9128                                 ip += 6;
9129                                 inline_costs += 10 * num_calls++;
9130
9131                                 break;
9132                         }
9133                         case CEE_MONO_LDPTR: {
9134                                 gpointer ptr;
9135
9136                                 CHECK_STACK_OVF (1);
9137                                 CHECK_OPSIZE (6);
9138                                 token = read32 (ip + 2);
9139
9140                                 ptr = mono_method_get_wrapper_data (method, token);
9141                                 if (cfg->compile_aot && (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) && (strstr (method->name, "__icall_wrapper_") == method->name)) {
9142                                         MonoJitICallInfo *callinfo;
9143                                         const char *icall_name;
9144
9145                                         icall_name = method->name + strlen ("__icall_wrapper_");
9146                                         g_assert (icall_name);
9147                                         callinfo = mono_find_jit_icall_by_name (icall_name);
9148                                         g_assert (callinfo);
9149                                                 
9150                                         if (ptr == callinfo->func) {
9151                                                 /* Will be transformed into an AOTCONST later */
9152                                                 EMIT_NEW_PCONST (cfg, ins, ptr);
9153                                                 *sp++ = ins;
9154                                                 ip += 6;
9155                                                 break;
9156                                         }
9157                                 }
9158                                 /* FIXME: Generalize this */
9159                                 if (cfg->compile_aot && ptr == mono_thread_interruption_request_flag ()) {
9160                                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG, NULL);
9161                                         *sp++ = ins;
9162                                         ip += 6;
9163                                         break;
9164                                 }
9165                                 EMIT_NEW_PCONST (cfg, ins, ptr);
9166                                 *sp++ = ins;
9167                                 ip += 6;
9168                                 inline_costs += 10 * num_calls++;
9169                                 /* Can't embed random pointers into AOT code */
9170                                 cfg->disable_aot = 1;
9171                                 break;
9172                         }
9173                         case CEE_MONO_ICALL_ADDR: {
9174                                 MonoMethod *cmethod;
9175                                 gpointer ptr;
9176
9177                                 CHECK_STACK_OVF (1);
9178                                 CHECK_OPSIZE (6);
9179                                 token = read32 (ip + 2);
9180
9181                                 cmethod = mono_method_get_wrapper_data (method, token);
9182
9183                                 if (cfg->compile_aot) {
9184                                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_ICALL_ADDR, cmethod);
9185                                 } else {
9186                                         ptr = mono_lookup_internal_call (cmethod);
9187                                         g_assert (ptr);
9188                                         EMIT_NEW_PCONST (cfg, ins, ptr);
9189                                 }
9190                                 *sp++ = ins;
9191                                 ip += 6;
9192                                 break;
9193                         }
9194                         case CEE_MONO_VTADDR: {
9195                                 MonoInst *src_var, *src;
9196
9197                                 CHECK_STACK (1);
9198                                 --sp;
9199
9200                                 // FIXME:
9201                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
9202                                 EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
9203                                 *sp++ = src;
9204                                 ip += 2;
9205                                 break;
9206                         }
9207                         case CEE_MONO_NEWOBJ: {
9208                                 MonoInst *iargs [2];
9209
9210                                 CHECK_STACK_OVF (1);
9211                                 CHECK_OPSIZE (6);
9212                                 token = read32 (ip + 2);
9213                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
9214                                 mono_class_init (klass);
9215                                 NEW_DOMAINCONST (cfg, iargs [0]);
9216                                 MONO_ADD_INS (cfg->cbb, iargs [0]);
9217                                 NEW_CLASSCONST (cfg, iargs [1], klass);
9218                                 MONO_ADD_INS (cfg->cbb, iargs [1]);
9219                                 *sp++ = mono_emit_jit_icall (cfg, mono_object_new, iargs);
9220                                 ip += 6;
9221                                 inline_costs += 10 * num_calls++;
9222                                 break;
9223                         }
9224                         case CEE_MONO_OBJADDR:
9225                                 CHECK_STACK (1);
9226                                 --sp;
9227                                 MONO_INST_NEW (cfg, ins, OP_MOVE);
9228                                 ins->dreg = alloc_preg (cfg);
9229                                 ins->sreg1 = sp [0]->dreg;
9230                                 ins->type = STACK_MP;
9231                                 MONO_ADD_INS (cfg->cbb, ins);
9232                                 *sp++ = ins;
9233                                 ip += 2;
9234                                 break;
9235                         case CEE_MONO_LDNATIVEOBJ:
9236                                 /*
9237                                  * Similar to LDOBJ, but instead load the unmanaged 
9238                                  * representation of the vtype to the stack.
9239                                  */
9240                                 CHECK_STACK (1);
9241                                 CHECK_OPSIZE (6);
9242                                 --sp;
9243                                 token = read32 (ip + 2);
9244                                 klass = mono_method_get_wrapper_data (method, token);
9245                                 g_assert (klass->valuetype);
9246                                 mono_class_init (klass);
9247
9248                                 {
9249                                         MonoInst *src, *dest, *temp;
9250
9251                                         src = sp [0];
9252                                         temp = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
9253                                         temp->backend.is_pinvoke = 1;
9254                                         EMIT_NEW_TEMPLOADA (cfg, dest, temp->inst_c0);
9255                                         mini_emit_stobj (cfg, dest, src, klass, TRUE);
9256
9257                                         EMIT_NEW_TEMPLOAD (cfg, dest, temp->inst_c0);
9258                                         dest->type = STACK_VTYPE;
9259                                         dest->klass = klass;
9260
9261                                         *sp ++ = dest;
9262                                         ip += 6;
9263                                 }
9264                                 break;
9265                         case CEE_MONO_RETOBJ: {
9266                                 /*
9267                                  * Same as RET, but return the native representation of a vtype
9268                                  * to the caller.
9269                                  */
9270                                 g_assert (cfg->ret);
9271                                 g_assert (mono_method_signature (method)->pinvoke); 
9272                                 CHECK_STACK (1);
9273                                 --sp;
9274                                 
9275                                 CHECK_OPSIZE (6);
9276                                 token = read32 (ip + 2);    
9277                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
9278
9279                                 if (!cfg->vret_addr) {
9280                                         g_assert (cfg->ret_var_is_local);
9281
9282                                         EMIT_NEW_VARLOADA (cfg, ins, cfg->ret, cfg->ret->inst_vtype);
9283                                 } else {
9284                                         EMIT_NEW_RETLOADA (cfg, ins);
9285                                 }
9286                                 mini_emit_stobj (cfg, ins, sp [0], klass, TRUE);
9287                                 
9288                                 if (sp != stack_start)
9289                                         UNVERIFIED;
9290                                 
9291                                 MONO_INST_NEW (cfg, ins, OP_BR);
9292                                 ins->inst_target_bb = end_bblock;
9293                                 MONO_ADD_INS (bblock, ins);
9294                                 link_bblock (cfg, bblock, end_bblock);
9295                                 start_new_bblock = 1;
9296                                 ip += 6;
9297                                 break;
9298                         }
9299                         case CEE_MONO_CISINST:
9300                         case CEE_MONO_CCASTCLASS: {
9301                                 int token;
9302                                 CHECK_STACK (1);
9303                                 --sp;
9304                                 CHECK_OPSIZE (6);
9305                                 token = read32 (ip + 2);
9306                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
9307                                 if (ip [1] == CEE_MONO_CISINST)
9308                                         ins = handle_cisinst (cfg, klass, sp [0]);
9309                                 else
9310                                         ins = handle_ccastclass (cfg, klass, sp [0]);
9311                                 bblock = cfg->cbb;
9312                                 *sp++ = ins;
9313                                 ip += 6;
9314                                 break;
9315                         }
9316                         case CEE_MONO_SAVE_LMF:
9317                         case CEE_MONO_RESTORE_LMF:
9318 #ifdef MONO_ARCH_HAVE_LMF_OPS
9319                                 MONO_INST_NEW (cfg, ins, (ip [1] == CEE_MONO_SAVE_LMF) ? OP_SAVE_LMF : OP_RESTORE_LMF);
9320                                 MONO_ADD_INS (bblock, ins);
9321                                 cfg->need_lmf_area = TRUE;
9322 #endif
9323                                 ip += 2;
9324                                 break;
9325                         case CEE_MONO_CLASSCONST:
9326                                 CHECK_STACK_OVF (1);
9327                                 CHECK_OPSIZE (6);
9328                                 token = read32 (ip + 2);
9329                                 EMIT_NEW_CLASSCONST (cfg, ins, mono_method_get_wrapper_data (method, token));
9330                                 *sp++ = ins;
9331                                 ip += 6;
9332                                 inline_costs += 10 * num_calls++;
9333                                 break;
9334                         case CEE_MONO_NOT_TAKEN:
9335                                 bblock->out_of_line = TRUE;
9336                                 ip += 2;
9337                                 break;
9338                         case CEE_MONO_TLS:
9339                                 CHECK_STACK_OVF (1);
9340                                 CHECK_OPSIZE (6);
9341                                 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
9342                                 ins->dreg = alloc_preg (cfg);
9343                                 ins->inst_offset = (gint32)read32 (ip + 2);
9344                                 ins->type = STACK_PTR;
9345                                 MONO_ADD_INS (bblock, ins);
9346                                 *sp++ = ins;
9347                                 ip += 6;
9348                                 break;
9349                         case CEE_MONO_DYN_CALL: {
9350                                 MonoCallInst *call;
9351
9352                                 /* It would be easier to call a trampoline, but that would put an
9353                                  * extra frame on the stack, confusing exception handling. So
9354                                  * implement it inline using an opcode for now.
9355                                  */
9356
9357                                 if (!cfg->dyn_call_var) {
9358                                         cfg->dyn_call_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
9359                                         /* prevent it from being register allocated */
9360                                         cfg->dyn_call_var->flags |= MONO_INST_INDIRECT;
9361                                 }
9362
9363                                 /* Has to use a call inst since it local regalloc expects it */
9364                                 MONO_INST_NEW_CALL (cfg, call, OP_DYN_CALL);
9365                                 ins = (MonoInst*)call;
9366                                 sp -= 2;
9367                                 ins->sreg1 = sp [0]->dreg;
9368                                 ins->sreg2 = sp [1]->dreg;
9369                                 MONO_ADD_INS (bblock, ins);
9370
9371 #ifdef MONO_ARCH_DYN_CALL_PARAM_AREA
9372                                 cfg->param_area = MAX (cfg->param_area, MONO_ARCH_DYN_CALL_PARAM_AREA);
9373 #endif
9374
9375                                 ip += 2;
9376                                 inline_costs += 10 * num_calls++;
9377
9378                                 break;
9379                         }
9380                         default:
9381                                 g_error ("opcode 0x%02x 0x%02x not handled", MONO_CUSTOM_PREFIX, ip [1]);
9382                                 break;
9383                         }
9384                         break;
9385                 }
9386
9387                 case CEE_PREFIX1: {
9388                         CHECK_OPSIZE (2);
9389                         switch (ip [1]) {
9390                         case CEE_ARGLIST: {
9391                                 /* somewhat similar to LDTOKEN */
9392                                 MonoInst *addr, *vtvar;
9393                                 CHECK_STACK_OVF (1);
9394                                 vtvar = mono_compile_create_var (cfg, &mono_defaults.argumenthandle_class->byval_arg, OP_LOCAL); 
9395
9396                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
9397                                 EMIT_NEW_UNALU (cfg, ins, OP_ARGLIST, -1, addr->dreg);
9398
9399                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
9400                                 ins->type = STACK_VTYPE;
9401                                 ins->klass = mono_defaults.argumenthandle_class;
9402                                 *sp++ = ins;
9403                                 ip += 2;
9404                                 break;
9405                         }
9406                         case CEE_CEQ:
9407                         case CEE_CGT:
9408                         case CEE_CGT_UN:
9409                         case CEE_CLT:
9410                         case CEE_CLT_UN: {
9411                                 MonoInst *cmp;
9412                                 CHECK_STACK (2);
9413                                 /*
9414                                  * The following transforms:
9415                                  *    CEE_CEQ    into OP_CEQ
9416                                  *    CEE_CGT    into OP_CGT
9417                                  *    CEE_CGT_UN into OP_CGT_UN
9418                                  *    CEE_CLT    into OP_CLT
9419                                  *    CEE_CLT_UN into OP_CLT_UN
9420                                  */
9421                                 MONO_INST_NEW (cfg, cmp, (OP_CEQ - CEE_CEQ) + ip [1]);
9422                                 
9423                                 MONO_INST_NEW (cfg, ins, cmp->opcode);
9424                                 sp -= 2;
9425                                 cmp->sreg1 = sp [0]->dreg;
9426                                 cmp->sreg2 = sp [1]->dreg;
9427                                 type_from_op (cmp, sp [0], sp [1]);
9428                                 CHECK_TYPE (cmp);
9429                                 if ((sp [0]->type == STACK_I8) || ((SIZEOF_REGISTER == 8) && ((sp [0]->type == STACK_PTR) || (sp [0]->type == STACK_OBJ) || (sp [0]->type == STACK_MP))))
9430                                         cmp->opcode = OP_LCOMPARE;
9431                                 else if (sp [0]->type == STACK_R8)
9432                                         cmp->opcode = OP_FCOMPARE;
9433                                 else
9434                                         cmp->opcode = OP_ICOMPARE;
9435                                 MONO_ADD_INS (bblock, cmp);
9436                                 ins->type = STACK_I4;
9437                                 ins->dreg = alloc_dreg (cfg, ins->type);
9438                                 type_from_op (ins, sp [0], sp [1]);
9439
9440                                 if (cmp->opcode == OP_FCOMPARE) {
9441                                         /*
9442                                          * The backends expect the fceq opcodes to do the
9443                                          * comparison too.
9444                                          */
9445                                         cmp->opcode = OP_NOP;
9446                                         ins->sreg1 = cmp->sreg1;
9447                                         ins->sreg2 = cmp->sreg2;
9448                                 }
9449                                 MONO_ADD_INS (bblock, ins);
9450                                 *sp++ = ins;
9451                                 ip += 2;
9452                                 break;
9453                         }
9454                         case CEE_LDFTN: {
9455                                 MonoInst *argconst;
9456                                 MonoMethod *cil_method;
9457                                 gboolean needs_static_rgctx_invoke;
9458
9459                                 CHECK_STACK_OVF (1);
9460                                 CHECK_OPSIZE (6);
9461                                 n = read32 (ip + 2);
9462                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
9463                                 if (!cmethod)
9464                                         goto load_error;
9465                                 mono_class_init (cmethod->klass);
9466
9467                                 mono_save_token_info (cfg, image, n, cmethod);
9468
9469                                 if (cfg->generic_sharing_context)
9470                                         context_used = mono_method_check_context_used (cmethod);
9471
9472                                 needs_static_rgctx_invoke = mono_method_needs_static_rgctx_invoke (cmethod, TRUE);
9473  
9474                                 cil_method = cmethod;
9475                                 if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_method (method, cmethod))
9476                                         METHOD_ACCESS_FAILURE;
9477
9478                                 if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS) {
9479                                         if (check_linkdemand (cfg, method, cmethod))
9480                                                 INLINE_FAILURE;
9481                                         CHECK_CFG_EXCEPTION;
9482                                 } else if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR) {
9483                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod, bblock, ip);
9484                                 }
9485
9486                                 /* 
9487                                  * Optimize the common case of ldftn+delegate creation
9488                                  */
9489                                 if ((sp > stack_start) && (ip + 6 + 5 < end) && ip_in_bb (cfg, bblock, ip + 6) && (ip [6] == CEE_NEWOBJ)) {
9490                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
9491                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
9492                                                 MonoMethod *invoke;
9493                                                 int invoke_context_used = 0;
9494
9495                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
9496                                                 if (!invoke || !mono_method_signature (invoke))
9497                                                         goto load_error;
9498
9499                                                 if (cfg->generic_sharing_context)
9500                                                         invoke_context_used = mono_method_check_context_used (invoke);
9501
9502 #if defined(MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE)
9503                                                 /* FIXME: SGEN support */
9504                                                 if (!cfg->gen_write_barriers && invoke_context_used == 0) {
9505                                                         MonoInst *target_ins;
9506
9507                                                         ip += 6;
9508                                                         if (cfg->verbose_level > 3)
9509                                                                 g_print ("converting (in B%d: stack: %d) %s", bblock->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
9510                                                         target_ins = sp [-1];
9511                                                         sp --;
9512                                                         *sp = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used);
9513                                                         CHECK_CFG_EXCEPTION;
9514                                                         ip += 5;                        
9515                                                         sp ++;
9516                                                         break;
9517                                                 }
9518 #endif
9519                                         }
9520                                 }
9521
9522                                 argconst = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD);
9523                                 ins = mono_emit_jit_icall (cfg, mono_ldftn, &argconst);
9524                                 *sp++ = ins;
9525                                 
9526                                 ip += 6;
9527                                 inline_costs += 10 * num_calls++;
9528                                 break;
9529                         }
9530                         case CEE_LDVIRTFTN: {
9531                                 MonoInst *args [2];
9532
9533                                 CHECK_STACK (1);
9534                                 CHECK_OPSIZE (6);
9535                                 n = read32 (ip + 2);
9536                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
9537                                 if (!cmethod)
9538                                         goto load_error;
9539                                 mono_class_init (cmethod->klass);
9540  
9541                                 if (cfg->generic_sharing_context)
9542                                         context_used = mono_method_check_context_used (cmethod);
9543
9544                                 if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS) {
9545                                         if (check_linkdemand (cfg, method, cmethod))
9546                                                 INLINE_FAILURE;
9547                                         CHECK_CFG_EXCEPTION;
9548                                 } else if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR) {
9549                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod, bblock, ip);
9550                                 }
9551
9552                                 --sp;
9553                                 args [0] = *sp;
9554
9555                                 args [1] = emit_get_rgctx_method (cfg, context_used,
9556                                                                                                   cmethod, MONO_RGCTX_INFO_METHOD);
9557
9558                                 if (context_used)
9559                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn_gshared, args);
9560                                 else
9561                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn, args);
9562
9563                                 ip += 6;
9564                                 inline_costs += 10 * num_calls++;
9565                                 break;
9566                         }
9567                         case CEE_LDARG:
9568                                 CHECK_STACK_OVF (1);
9569                                 CHECK_OPSIZE (4);
9570                                 n = read16 (ip + 2);
9571                                 CHECK_ARG (n);
9572                                 EMIT_NEW_ARGLOAD (cfg, ins, n);
9573                                 *sp++ = ins;
9574                                 ip += 4;
9575                                 break;
9576                         case CEE_LDARGA:
9577                                 CHECK_STACK_OVF (1);
9578                                 CHECK_OPSIZE (4);
9579                                 n = read16 (ip + 2);
9580                                 CHECK_ARG (n);
9581                                 NEW_ARGLOADA (cfg, ins, n);
9582                                 MONO_ADD_INS (cfg->cbb, ins);
9583                                 *sp++ = ins;
9584                                 ip += 4;
9585                                 break;
9586                         case CEE_STARG:
9587                                 CHECK_STACK (1);
9588                                 --sp;
9589                                 CHECK_OPSIZE (4);
9590                                 n = read16 (ip + 2);
9591                                 CHECK_ARG (n);
9592                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [n], *sp))
9593                                         UNVERIFIED;
9594                                 EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
9595                                 ip += 4;
9596                                 break;
9597                         case CEE_LDLOC:
9598                                 CHECK_STACK_OVF (1);
9599                                 CHECK_OPSIZE (4);
9600                                 n = read16 (ip + 2);
9601                                 CHECK_LOCAL (n);
9602                                 EMIT_NEW_LOCLOAD (cfg, ins, n);
9603                                 *sp++ = ins;
9604                                 ip += 4;
9605                                 break;
9606                         case CEE_LDLOCA: {
9607                                 unsigned char *tmp_ip;
9608                                 CHECK_STACK_OVF (1);
9609                                 CHECK_OPSIZE (4);
9610                                 n = read16 (ip + 2);
9611                                 CHECK_LOCAL (n);
9612
9613                                 if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 2))) {
9614                                         ip = tmp_ip;
9615                                         inline_costs += 1;
9616                                         break;
9617                                 }                       
9618                                 
9619                                 EMIT_NEW_LOCLOADA (cfg, ins, n);
9620                                 *sp++ = ins;
9621                                 ip += 4;
9622                                 break;
9623                         }
9624                         case CEE_STLOC:
9625                                 CHECK_STACK (1);
9626                                 --sp;
9627                                 CHECK_OPSIZE (4);
9628                                 n = read16 (ip + 2);
9629                                 CHECK_LOCAL (n);
9630                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
9631                                         UNVERIFIED;
9632                                 emit_stloc_ir (cfg, sp, header, n);
9633                                 ip += 4;
9634                                 inline_costs += 1;
9635                                 break;
9636                         case CEE_LOCALLOC:
9637                                 CHECK_STACK (1);
9638                                 --sp;
9639                                 if (sp != stack_start) 
9640                                         UNVERIFIED;
9641                                 if (cfg->method != method) 
9642                                         /* 
9643                                          * Inlining this into a loop in a parent could lead to 
9644                                          * stack overflows which is different behavior than the
9645                                          * non-inlined case, thus disable inlining in this case.
9646                                          */
9647                                         goto inline_failure;
9648
9649                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
9650                                 ins->dreg = alloc_preg (cfg);
9651                                 ins->sreg1 = sp [0]->dreg;
9652                                 ins->type = STACK_PTR;
9653                                 MONO_ADD_INS (cfg->cbb, ins);
9654
9655                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
9656                                 if (init_locals)
9657                                         ins->flags |= MONO_INST_INIT;
9658
9659                                 *sp++ = ins;
9660                                 ip += 2;
9661                                 break;
9662                         case CEE_ENDFILTER: {
9663                                 MonoExceptionClause *clause, *nearest;
9664                                 int cc, nearest_num;
9665
9666                                 CHECK_STACK (1);
9667                                 --sp;
9668                                 if ((sp != stack_start) || (sp [0]->type != STACK_I4)) 
9669                                         UNVERIFIED;
9670                                 MONO_INST_NEW (cfg, ins, OP_ENDFILTER);
9671                                 ins->sreg1 = (*sp)->dreg;
9672                                 MONO_ADD_INS (bblock, ins);
9673                                 start_new_bblock = 1;
9674                                 ip += 2;
9675
9676                                 nearest = NULL;
9677                                 nearest_num = 0;
9678                                 for (cc = 0; cc < header->num_clauses; ++cc) {
9679                                         clause = &header->clauses [cc];
9680                                         if ((clause->flags & MONO_EXCEPTION_CLAUSE_FILTER) &&
9681                                                 ((ip - header->code) > clause->data.filter_offset && (ip - header->code) <= clause->handler_offset) &&
9682                                             (!nearest || (clause->data.filter_offset < nearest->data.filter_offset))) {
9683                                                 nearest = clause;
9684                                                 nearest_num = cc;
9685                                         }
9686                                 }
9687                                 g_assert (nearest);
9688                                 if ((ip - header->code) != nearest->handler_offset)
9689                                         UNVERIFIED;
9690
9691                                 break;
9692                         }
9693                         case CEE_UNALIGNED_:
9694                                 ins_flag |= MONO_INST_UNALIGNED;
9695                                 /* FIXME: record alignment? we can assume 1 for now */
9696                                 CHECK_OPSIZE (3);
9697                                 ip += 3;
9698                                 break;
9699                         case CEE_VOLATILE_:
9700                                 ins_flag |= MONO_INST_VOLATILE;
9701                                 ip += 2;
9702                                 break;
9703                         case CEE_TAIL_:
9704                                 ins_flag   |= MONO_INST_TAILCALL;
9705                                 cfg->flags |= MONO_CFG_HAS_TAIL;
9706                                 /* Can't inline tail calls at this time */
9707                                 inline_costs += 100000;
9708                                 ip += 2;
9709                                 break;
9710                         case CEE_INITOBJ:
9711                                 CHECK_STACK (1);
9712                                 --sp;
9713                                 CHECK_OPSIZE (6);
9714                                 token = read32 (ip + 2);
9715                                 klass = mini_get_class (method, token, generic_context);
9716                                 CHECK_TYPELOAD (klass);
9717                                 if (generic_class_is_reference_type (cfg, klass))
9718                                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, sp [0]->dreg, 0, 0);
9719                                 else
9720                                         mini_emit_initobj (cfg, *sp, NULL, klass);
9721                                 ip += 6;
9722                                 inline_costs += 1;
9723                                 break;
9724                         case CEE_CONSTRAINED_:
9725                                 CHECK_OPSIZE (6);
9726                                 token = read32 (ip + 2);
9727                                 if (method->wrapper_type != MONO_WRAPPER_NONE)
9728                                         constrained_call =  (MonoClass *)mono_method_get_wrapper_data (method, token);
9729                                 else
9730                                         constrained_call = mono_class_get_full (image, token, generic_context);
9731                                 CHECK_TYPELOAD (constrained_call);
9732                                 ip += 6;
9733                                 break;
9734                         case CEE_CPBLK:
9735                         case CEE_INITBLK: {
9736                                 MonoInst *iargs [3];
9737                                 CHECK_STACK (3);
9738                                 sp -= 3;
9739
9740                                 if ((ip [1] == CEE_CPBLK) && (cfg->opt & MONO_OPT_INTRINS) && (sp [2]->opcode == OP_ICONST) && ((n = sp [2]->inst_c0) <= sizeof (gpointer) * 5)) {
9741                                         mini_emit_memcpy (cfg, sp [0]->dreg, 0, sp [1]->dreg, 0, sp [2]->inst_c0, 0);
9742                                 } else if ((ip [1] == CEE_INITBLK) && (cfg->opt & MONO_OPT_INTRINS) && (sp [2]->opcode == OP_ICONST) && ((n = sp [2]->inst_c0) <= sizeof (gpointer) * 5) && (sp [1]->opcode == OP_ICONST) && (sp [1]->inst_c0 == 0)) {
9743                                         /* emit_memset only works when val == 0 */
9744                                         mini_emit_memset (cfg, sp [0]->dreg, 0, sp [2]->inst_c0, sp [1]->inst_c0, 0);
9745                                 } else {
9746                                         iargs [0] = sp [0];
9747                                         iargs [1] = sp [1];
9748                                         iargs [2] = sp [2];
9749                                         if (ip [1] == CEE_CPBLK) {
9750                                                 MonoMethod *memcpy_method = get_memcpy_method ();
9751                                                 mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
9752                                         } else {
9753                                                 MonoMethod *memset_method = get_memset_method ();
9754                                                 mono_emit_method_call (cfg, memset_method, iargs, NULL);
9755                                         }
9756                                 }
9757                                 ip += 2;
9758                                 inline_costs += 1;
9759                                 break;
9760                         }
9761                         case CEE_NO_:
9762                                 CHECK_OPSIZE (3);
9763                                 if (ip [2] & 0x1)
9764                                         ins_flag |= MONO_INST_NOTYPECHECK;
9765                                 if (ip [2] & 0x2)
9766                                         ins_flag |= MONO_INST_NORANGECHECK;
9767                                 /* we ignore the no-nullcheck for now since we
9768                                  * really do it explicitly only when doing callvirt->call
9769                                  */
9770                                 ip += 3;
9771                                 break;
9772                         case CEE_RETHROW: {
9773                                 MonoInst *load;
9774                                 int handler_offset = -1;
9775
9776                                 for (i = 0; i < header->num_clauses; ++i) {
9777                                         MonoExceptionClause *clause = &header->clauses [i];
9778                                         if (MONO_OFFSET_IN_HANDLER (clause, ip - header->code) && !(clause->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
9779                                                 handler_offset = clause->handler_offset;
9780                                                 break;
9781                                         }
9782                                 }
9783
9784                                 bblock->flags |= BB_EXCEPTION_UNSAFE;
9785
9786                                 g_assert (handler_offset != -1);
9787
9788                                 EMIT_NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, handler_offset)->inst_c0);
9789                                 MONO_INST_NEW (cfg, ins, OP_RETHROW);
9790                                 ins->sreg1 = load->dreg;
9791                                 MONO_ADD_INS (bblock, ins);
9792
9793                                 MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
9794                                 MONO_ADD_INS (bblock, ins);
9795
9796                                 sp = stack_start;
9797                                 link_bblock (cfg, bblock, end_bblock);
9798                                 start_new_bblock = 1;
9799                                 ip += 2;
9800                                 break;
9801                         }
9802                         case CEE_SIZEOF: {
9803                                 guint32 align;
9804                                 int ialign;
9805
9806                                 CHECK_STACK_OVF (1);
9807                                 CHECK_OPSIZE (6);
9808                                 token = read32 (ip + 2);
9809                                 if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC && !method->klass->image->dynamic) {
9810                                         MonoType *type = mono_type_create_from_typespec (image, token);
9811                                         token = mono_type_size (type, &ialign);
9812                                 } else {
9813                                         MonoClass *klass = mono_class_get_full (image, token, generic_context);
9814                                         CHECK_TYPELOAD (klass);
9815                                         mono_class_init (klass);
9816                                         token = mono_class_value_size (klass, &align);
9817                                 }
9818                                 EMIT_NEW_ICONST (cfg, ins, token);
9819                                 *sp++= ins;
9820                                 ip += 6;
9821                                 break;
9822                         }
9823                         case CEE_REFANYTYPE: {
9824                                 MonoInst *src_var, *src;
9825
9826                                 CHECK_STACK (1);
9827                                 --sp;
9828
9829                                 // FIXME:
9830                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
9831                                 if (!src_var)
9832                                         src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
9833                                 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
9834                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &mono_defaults.typehandle_class->byval_arg, src->dreg, G_STRUCT_OFFSET (MonoTypedRef, type));
9835                                 *sp++ = ins;
9836                                 ip += 2;
9837                                 break;
9838                         }
9839                         case CEE_READONLY_:
9840                                 readonly = TRUE;
9841                                 ip += 2;
9842                                 break;
9843
9844                         case CEE_UNUSED56:
9845                         case CEE_UNUSED57:
9846                         case CEE_UNUSED70:
9847                         case CEE_UNUSED:
9848                         case CEE_UNUSED99:
9849                                 UNVERIFIED;
9850                                 
9851                         default:
9852                                 g_warning ("opcode 0xfe 0x%02x not handled", ip [1]);
9853                                 UNVERIFIED;
9854                         }
9855                         break;
9856                 }
9857                 case CEE_UNUSED58:
9858                 case CEE_UNUSED1:
9859                         UNVERIFIED;
9860
9861                 default:
9862                         g_warning ("opcode 0x%02x not handled", *ip);
9863                         UNVERIFIED;
9864                 }
9865         }
9866         if (start_new_bblock != 1)
9867                 UNVERIFIED;
9868
9869         bblock->cil_length = ip - bblock->cil_code;
9870         bblock->next_bb = end_bblock;
9871
9872         if (cfg->method == method && cfg->domainvar) {
9873                 MonoInst *store;
9874                 MonoInst *get_domain;
9875
9876                 cfg->cbb = init_localsbb;
9877
9878                 if (! (get_domain = mono_arch_get_domain_intrinsic (cfg))) {
9879                         get_domain = mono_emit_jit_icall (cfg, mono_domain_get, NULL);
9880                 }
9881                 else {
9882                         get_domain->dreg = alloc_preg (cfg);
9883                         MONO_ADD_INS (cfg->cbb, get_domain);
9884                 }               
9885                 NEW_TEMPSTORE (cfg, store, cfg->domainvar->inst_c0, get_domain);
9886                 MONO_ADD_INS (cfg->cbb, store);
9887         }
9888
9889 #if defined(TARGET_POWERPC) || defined(TARGET_X86)
9890         if (cfg->compile_aot)
9891                 /* FIXME: The plt slots require a GOT var even if the method doesn't use it */
9892                 mono_get_got_var (cfg);
9893 #endif
9894
9895         if (cfg->method == method && cfg->got_var)
9896                 mono_emit_load_got_addr (cfg);
9897
9898         if (init_locals) {
9899                 MonoInst *store;
9900
9901                 cfg->cbb = init_localsbb;
9902                 cfg->ip = NULL;
9903                 for (i = 0; i < header->num_locals; ++i) {
9904                         MonoType *ptype = header->locals [i];
9905                         int t = ptype->type;
9906                         dreg = cfg->locals [i]->dreg;
9907
9908                         if (t == MONO_TYPE_VALUETYPE && ptype->data.klass->enumtype)
9909                                 t = mono_class_enum_basetype (ptype->data.klass)->type;
9910                         if (ptype->byref) {
9911                                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
9912                         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
9913                                 MONO_EMIT_NEW_ICONST (cfg, cfg->locals [i]->dreg, 0);
9914                         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
9915                                 MONO_EMIT_NEW_I8CONST (cfg, cfg->locals [i]->dreg, 0);
9916                         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
9917                                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
9918                                 ins->type = STACK_R8;
9919                                 ins->inst_p0 = (void*)&r8_0;
9920                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
9921                                 MONO_ADD_INS (init_localsbb, ins);
9922                                 EMIT_NEW_LOCSTORE (cfg, store, i, ins);
9923                         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
9924                                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (ptype))) {
9925                                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (ptype));
9926                         } else {
9927                                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
9928                         }
9929                 }
9930         }
9931
9932         if (cfg->init_ref_vars && cfg->method == method) {
9933                 /* Emit initialization for ref vars */
9934                 // FIXME: Avoid duplication initialization for IL locals.
9935                 for (i = 0; i < cfg->num_varinfo; ++i) {
9936                         MonoInst *ins = cfg->varinfo [i];
9937
9938                         if (ins->opcode == OP_LOCAL && ins->type == STACK_OBJ)
9939                                 MONO_EMIT_NEW_PCONST (cfg, ins->dreg, NULL);
9940                 }
9941         }
9942
9943         /* Add a sequence point for method entry/exit events */
9944         if (seq_points) {
9945                 NEW_SEQ_POINT (cfg, ins, METHOD_ENTRY_IL_OFFSET, FALSE);
9946                 MONO_ADD_INS (init_localsbb, ins);
9947                 NEW_SEQ_POINT (cfg, ins, METHOD_EXIT_IL_OFFSET, FALSE);
9948                 MONO_ADD_INS (cfg->bb_exit, ins);
9949         }
9950
9951         cfg->ip = NULL;
9952
9953         if (cfg->method == method) {
9954                 MonoBasicBlock *bb;
9955                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
9956                         bb->region = mono_find_block_region (cfg, bb->real_offset);
9957                         if (cfg->spvars)
9958                                 mono_create_spvar_for_region (cfg, bb->region);
9959                         if (cfg->verbose_level > 2)
9960                                 printf ("REGION BB%d IL_%04x ID_%08X\n", bb->block_num, bb->real_offset, bb->region);
9961                 }
9962         }
9963
9964         g_slist_free (class_inits);
9965         dont_inline = g_list_remove (dont_inline, method);
9966
9967         if (inline_costs < 0) {
9968                 char *mname;
9969
9970                 /* Method is too large */
9971                 mname = mono_method_full_name (method, TRUE);
9972                 cfg->exception_type = MONO_EXCEPTION_INVALID_PROGRAM;
9973                 cfg->exception_message = g_strdup_printf ("Method %s is too complex.", mname);
9974                 g_free (mname);
9975                 cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
9976                 mono_basic_block_free (original_bb);
9977                 return -1;
9978         }
9979
9980         if ((cfg->verbose_level > 2) && (cfg->method == method)) 
9981                 mono_print_code (cfg, "AFTER METHOD-TO-IR");
9982
9983         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
9984         mono_basic_block_free (original_bb);
9985         return inline_costs;
9986  
9987  exception_exit:
9988         g_assert (cfg->exception_type != MONO_EXCEPTION_NONE);
9989         goto cleanup;
9990
9991  inline_failure:
9992         goto cleanup;
9993
9994  load_error:
9995         cfg->exception_type = MONO_EXCEPTION_TYPE_LOAD;
9996         goto cleanup;
9997
9998  unverified:
9999         set_exception_type_from_invalid_il (cfg, method, ip);
10000         goto cleanup;
10001
10002  cleanup:
10003         g_slist_free (class_inits);
10004         mono_basic_block_free (original_bb);
10005         dont_inline = g_list_remove (dont_inline, method);
10006         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
10007         return -1;
10008 }
10009
10010 static int
10011 store_membase_reg_to_store_membase_imm (int opcode)
10012 {
10013         switch (opcode) {
10014         case OP_STORE_MEMBASE_REG:
10015                 return OP_STORE_MEMBASE_IMM;
10016         case OP_STOREI1_MEMBASE_REG:
10017                 return OP_STOREI1_MEMBASE_IMM;
10018         case OP_STOREI2_MEMBASE_REG:
10019                 return OP_STOREI2_MEMBASE_IMM;
10020         case OP_STOREI4_MEMBASE_REG:
10021                 return OP_STOREI4_MEMBASE_IMM;
10022         case OP_STOREI8_MEMBASE_REG:
10023                 return OP_STOREI8_MEMBASE_IMM;
10024         default:
10025                 g_assert_not_reached ();
10026         }
10027
10028         return -1;
10029 }               
10030
10031 #endif /* DISABLE_JIT */
10032
10033 int
10034 mono_op_to_op_imm (int opcode)
10035 {
10036         switch (opcode) {
10037         case OP_IADD:
10038                 return OP_IADD_IMM;
10039         case OP_ISUB:
10040                 return OP_ISUB_IMM;
10041         case OP_IDIV:
10042                 return OP_IDIV_IMM;
10043         case OP_IDIV_UN:
10044                 return OP_IDIV_UN_IMM;
10045         case OP_IREM:
10046                 return OP_IREM_IMM;
10047         case OP_IREM_UN:
10048                 return OP_IREM_UN_IMM;
10049         case OP_IMUL:
10050                 return OP_IMUL_IMM;
10051         case OP_IAND:
10052                 return OP_IAND_IMM;
10053         case OP_IOR:
10054                 return OP_IOR_IMM;
10055         case OP_IXOR:
10056                 return OP_IXOR_IMM;
10057         case OP_ISHL:
10058                 return OP_ISHL_IMM;
10059         case OP_ISHR:
10060                 return OP_ISHR_IMM;
10061         case OP_ISHR_UN:
10062                 return OP_ISHR_UN_IMM;
10063
10064         case OP_LADD:
10065                 return OP_LADD_IMM;
10066         case OP_LSUB:
10067                 return OP_LSUB_IMM;
10068         case OP_LAND:
10069                 return OP_LAND_IMM;
10070         case OP_LOR:
10071                 return OP_LOR_IMM;
10072         case OP_LXOR:
10073                 return OP_LXOR_IMM;
10074         case OP_LSHL:
10075                 return OP_LSHL_IMM;
10076         case OP_LSHR:
10077                 return OP_LSHR_IMM;
10078         case OP_LSHR_UN:
10079                 return OP_LSHR_UN_IMM;          
10080
10081         case OP_COMPARE:
10082                 return OP_COMPARE_IMM;
10083         case OP_ICOMPARE:
10084                 return OP_ICOMPARE_IMM;
10085         case OP_LCOMPARE:
10086                 return OP_LCOMPARE_IMM;
10087
10088         case OP_STORE_MEMBASE_REG:
10089                 return OP_STORE_MEMBASE_IMM;
10090         case OP_STOREI1_MEMBASE_REG:
10091                 return OP_STOREI1_MEMBASE_IMM;
10092         case OP_STOREI2_MEMBASE_REG:
10093                 return OP_STOREI2_MEMBASE_IMM;
10094         case OP_STOREI4_MEMBASE_REG:
10095                 return OP_STOREI4_MEMBASE_IMM;
10096
10097 #if defined(TARGET_X86) || defined (TARGET_AMD64)
10098         case OP_X86_PUSH:
10099                 return OP_X86_PUSH_IMM;
10100         case OP_X86_COMPARE_MEMBASE_REG:
10101                 return OP_X86_COMPARE_MEMBASE_IMM;
10102 #endif
10103 #if defined(TARGET_AMD64)
10104         case OP_AMD64_ICOMPARE_MEMBASE_REG:
10105                 return OP_AMD64_ICOMPARE_MEMBASE_IMM;
10106 #endif
10107         case OP_VOIDCALL_REG:
10108                 return OP_VOIDCALL;
10109         case OP_CALL_REG:
10110                 return OP_CALL;
10111         case OP_LCALL_REG:
10112                 return OP_LCALL;
10113         case OP_FCALL_REG:
10114                 return OP_FCALL;
10115         case OP_LOCALLOC:
10116                 return OP_LOCALLOC_IMM;
10117         }
10118
10119         return -1;
10120 }
10121
10122 static int
10123 ldind_to_load_membase (int opcode)
10124 {
10125         switch (opcode) {
10126         case CEE_LDIND_I1:
10127                 return OP_LOADI1_MEMBASE;
10128         case CEE_LDIND_U1:
10129                 return OP_LOADU1_MEMBASE;
10130         case CEE_LDIND_I2:
10131                 return OP_LOADI2_MEMBASE;
10132         case CEE_LDIND_U2:
10133                 return OP_LOADU2_MEMBASE;
10134         case CEE_LDIND_I4:
10135                 return OP_LOADI4_MEMBASE;
10136         case CEE_LDIND_U4:
10137                 return OP_LOADU4_MEMBASE;
10138         case CEE_LDIND_I:
10139                 return OP_LOAD_MEMBASE;
10140         case CEE_LDIND_REF:
10141                 return OP_LOAD_MEMBASE;
10142         case CEE_LDIND_I8:
10143                 return OP_LOADI8_MEMBASE;
10144         case CEE_LDIND_R4:
10145                 return OP_LOADR4_MEMBASE;
10146         case CEE_LDIND_R8:
10147                 return OP_LOADR8_MEMBASE;
10148         default:
10149                 g_assert_not_reached ();
10150         }
10151
10152         return -1;
10153 }
10154
10155 static int
10156 stind_to_store_membase (int opcode)
10157 {
10158         switch (opcode) {
10159         case CEE_STIND_I1:
10160                 return OP_STOREI1_MEMBASE_REG;
10161         case CEE_STIND_I2:
10162                 return OP_STOREI2_MEMBASE_REG;
10163         case CEE_STIND_I4:
10164                 return OP_STOREI4_MEMBASE_REG;
10165         case CEE_STIND_I:
10166         case CEE_STIND_REF:
10167                 return OP_STORE_MEMBASE_REG;
10168         case CEE_STIND_I8:
10169                 return OP_STOREI8_MEMBASE_REG;
10170         case CEE_STIND_R4:
10171                 return OP_STORER4_MEMBASE_REG;
10172         case CEE_STIND_R8:
10173                 return OP_STORER8_MEMBASE_REG;
10174         default:
10175                 g_assert_not_reached ();
10176         }
10177
10178         return -1;
10179 }
10180
10181 int
10182 mono_load_membase_to_load_mem (int opcode)
10183 {
10184         // FIXME: Add a MONO_ARCH_HAVE_LOAD_MEM macro
10185 #if defined(TARGET_X86) || defined(TARGET_AMD64)
10186         switch (opcode) {
10187         case OP_LOAD_MEMBASE:
10188                 return OP_LOAD_MEM;
10189         case OP_LOADU1_MEMBASE:
10190                 return OP_LOADU1_MEM;
10191         case OP_LOADU2_MEMBASE:
10192                 return OP_LOADU2_MEM;
10193         case OP_LOADI4_MEMBASE:
10194                 return OP_LOADI4_MEM;
10195         case OP_LOADU4_MEMBASE:
10196                 return OP_LOADU4_MEM;
10197 #if SIZEOF_REGISTER == 8
10198         case OP_LOADI8_MEMBASE:
10199                 return OP_LOADI8_MEM;
10200 #endif
10201         }
10202 #endif
10203
10204         return -1;
10205 }
10206
10207 static inline int
10208 op_to_op_dest_membase (int store_opcode, int opcode)
10209 {
10210 #if defined(TARGET_X86)
10211         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG)))
10212                 return -1;
10213
10214         switch (opcode) {
10215         case OP_IADD:
10216                 return OP_X86_ADD_MEMBASE_REG;
10217         case OP_ISUB:
10218                 return OP_X86_SUB_MEMBASE_REG;
10219         case OP_IAND:
10220                 return OP_X86_AND_MEMBASE_REG;
10221         case OP_IOR:
10222                 return OP_X86_OR_MEMBASE_REG;
10223         case OP_IXOR:
10224                 return OP_X86_XOR_MEMBASE_REG;
10225         case OP_ADD_IMM:
10226         case OP_IADD_IMM:
10227                 return OP_X86_ADD_MEMBASE_IMM;
10228         case OP_SUB_IMM:
10229         case OP_ISUB_IMM:
10230                 return OP_X86_SUB_MEMBASE_IMM;
10231         case OP_AND_IMM:
10232         case OP_IAND_IMM:
10233                 return OP_X86_AND_MEMBASE_IMM;
10234         case OP_OR_IMM:
10235         case OP_IOR_IMM:
10236                 return OP_X86_OR_MEMBASE_IMM;
10237         case OP_XOR_IMM:
10238         case OP_IXOR_IMM:
10239                 return OP_X86_XOR_MEMBASE_IMM;
10240         case OP_MOVE:
10241                 return OP_NOP;
10242         }
10243 #endif
10244
10245 #if defined(TARGET_AMD64)
10246         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG) || (store_opcode == OP_STOREI8_MEMBASE_REG)))
10247                 return -1;
10248
10249         switch (opcode) {
10250         case OP_IADD:
10251                 return OP_X86_ADD_MEMBASE_REG;
10252         case OP_ISUB:
10253                 return OP_X86_SUB_MEMBASE_REG;
10254         case OP_IAND:
10255                 return OP_X86_AND_MEMBASE_REG;
10256         case OP_IOR:
10257                 return OP_X86_OR_MEMBASE_REG;
10258         case OP_IXOR:
10259                 return OP_X86_XOR_MEMBASE_REG;
10260         case OP_IADD_IMM:
10261                 return OP_X86_ADD_MEMBASE_IMM;
10262         case OP_ISUB_IMM:
10263                 return OP_X86_SUB_MEMBASE_IMM;
10264         case OP_IAND_IMM:
10265                 return OP_X86_AND_MEMBASE_IMM;
10266         case OP_IOR_IMM:
10267                 return OP_X86_OR_MEMBASE_IMM;
10268         case OP_IXOR_IMM:
10269                 return OP_X86_XOR_MEMBASE_IMM;
10270         case OP_LADD:
10271                 return OP_AMD64_ADD_MEMBASE_REG;
10272         case OP_LSUB:
10273                 return OP_AMD64_SUB_MEMBASE_REG;
10274         case OP_LAND:
10275                 return OP_AMD64_AND_MEMBASE_REG;
10276         case OP_LOR:
10277                 return OP_AMD64_OR_MEMBASE_REG;
10278         case OP_LXOR:
10279                 return OP_AMD64_XOR_MEMBASE_REG;
10280         case OP_ADD_IMM:
10281         case OP_LADD_IMM:
10282                 return OP_AMD64_ADD_MEMBASE_IMM;
10283         case OP_SUB_IMM:
10284         case OP_LSUB_IMM:
10285                 return OP_AMD64_SUB_MEMBASE_IMM;
10286         case OP_AND_IMM:
10287         case OP_LAND_IMM:
10288                 return OP_AMD64_AND_MEMBASE_IMM;
10289         case OP_OR_IMM:
10290         case OP_LOR_IMM:
10291                 return OP_AMD64_OR_MEMBASE_IMM;
10292         case OP_XOR_IMM:
10293         case OP_LXOR_IMM:
10294                 return OP_AMD64_XOR_MEMBASE_IMM;
10295         case OP_MOVE:
10296                 return OP_NOP;
10297         }
10298 #endif
10299
10300         return -1;
10301 }
10302
10303 static inline int
10304 op_to_op_store_membase (int store_opcode, int opcode)
10305 {
10306 #if defined(TARGET_X86) || defined(TARGET_AMD64)
10307         switch (opcode) {
10308         case OP_ICEQ:
10309                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
10310                         return OP_X86_SETEQ_MEMBASE;
10311         case OP_CNE:
10312                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
10313                         return OP_X86_SETNE_MEMBASE;
10314         }
10315 #endif
10316
10317         return -1;
10318 }
10319
10320 static inline int
10321 op_to_op_src1_membase (int load_opcode, int opcode)
10322 {
10323 #ifdef TARGET_X86
10324         /* FIXME: This has sign extension issues */
10325         /*
10326         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
10327                 return OP_X86_COMPARE_MEMBASE8_IMM;
10328         */
10329
10330         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
10331                 return -1;
10332
10333         switch (opcode) {
10334         case OP_X86_PUSH:
10335                 return OP_X86_PUSH_MEMBASE;
10336         case OP_COMPARE_IMM:
10337         case OP_ICOMPARE_IMM:
10338                 return OP_X86_COMPARE_MEMBASE_IMM;
10339         case OP_COMPARE:
10340         case OP_ICOMPARE:
10341                 return OP_X86_COMPARE_MEMBASE_REG;
10342         }
10343 #endif
10344
10345 #ifdef TARGET_AMD64
10346         /* FIXME: This has sign extension issues */
10347         /*
10348         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
10349                 return OP_X86_COMPARE_MEMBASE8_IMM;
10350         */
10351
10352         switch (opcode) {
10353         case OP_X86_PUSH:
10354                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
10355                         return OP_X86_PUSH_MEMBASE;
10356                 break;
10357                 /* FIXME: This only works for 32 bit immediates
10358         case OP_COMPARE_IMM:
10359         case OP_LCOMPARE_IMM:
10360                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
10361                         return OP_AMD64_COMPARE_MEMBASE_IMM;
10362                 */
10363         case OP_ICOMPARE_IMM:
10364                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
10365                         return OP_AMD64_ICOMPARE_MEMBASE_IMM;
10366                 break;
10367         case OP_COMPARE:
10368         case OP_LCOMPARE:
10369                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
10370                         return OP_AMD64_COMPARE_MEMBASE_REG;
10371                 break;
10372         case OP_ICOMPARE:
10373                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
10374                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
10375                 break;
10376         }
10377 #endif
10378
10379         return -1;
10380 }
10381
10382 static inline int
10383 op_to_op_src2_membase (int load_opcode, int opcode)
10384 {
10385 #ifdef TARGET_X86
10386         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
10387                 return -1;
10388         
10389         switch (opcode) {
10390         case OP_COMPARE:
10391         case OP_ICOMPARE:
10392                 return OP_X86_COMPARE_REG_MEMBASE;
10393         case OP_IADD:
10394                 return OP_X86_ADD_REG_MEMBASE;
10395         case OP_ISUB:
10396                 return OP_X86_SUB_REG_MEMBASE;
10397         case OP_IAND:
10398                 return OP_X86_AND_REG_MEMBASE;
10399         case OP_IOR:
10400                 return OP_X86_OR_REG_MEMBASE;
10401         case OP_IXOR:
10402                 return OP_X86_XOR_REG_MEMBASE;
10403         }
10404 #endif
10405
10406 #ifdef TARGET_AMD64
10407         switch (opcode) {
10408         case OP_ICOMPARE:
10409                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
10410                         return OP_AMD64_ICOMPARE_REG_MEMBASE;
10411                 break;
10412         case OP_COMPARE:
10413         case OP_LCOMPARE:
10414                 if ((load_opcode == OP_LOADI8_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE))
10415                         return OP_AMD64_COMPARE_REG_MEMBASE;
10416                 break;
10417         case OP_IADD:
10418                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
10419                         return OP_X86_ADD_REG_MEMBASE;
10420         case OP_ISUB:
10421                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
10422                         return OP_X86_SUB_REG_MEMBASE;
10423         case OP_IAND:
10424                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
10425                         return OP_X86_AND_REG_MEMBASE;
10426         case OP_IOR:
10427                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
10428                         return OP_X86_OR_REG_MEMBASE;
10429         case OP_IXOR:
10430                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
10431                         return OP_X86_XOR_REG_MEMBASE;
10432         case OP_LADD:
10433                 if ((load_opcode == OP_LOADI8_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE))
10434                         return OP_AMD64_ADD_REG_MEMBASE;
10435         case OP_LSUB:
10436                 if ((load_opcode == OP_LOADI8_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE))
10437                         return OP_AMD64_SUB_REG_MEMBASE;
10438         case OP_LAND:
10439                 if ((load_opcode == OP_LOADI8_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE))
10440                         return OP_AMD64_AND_REG_MEMBASE;
10441         case OP_LOR:
10442                 if ((load_opcode == OP_LOADI8_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE))
10443                         return OP_AMD64_OR_REG_MEMBASE;
10444         case OP_LXOR:
10445                 if ((load_opcode == OP_LOADI8_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE))
10446                         return OP_AMD64_XOR_REG_MEMBASE;
10447         }
10448 #endif
10449
10450         return -1;
10451 }
10452
10453 int
10454 mono_op_to_op_imm_noemul (int opcode)
10455 {
10456         switch (opcode) {
10457 #if SIZEOF_REGISTER == 4 && !defined(MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS)
10458         case OP_LSHR:
10459         case OP_LSHL:
10460         case OP_LSHR_UN:
10461                 return -1;
10462 #endif
10463 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
10464         case OP_IDIV:
10465         case OP_IDIV_UN:
10466         case OP_IREM:
10467         case OP_IREM_UN:
10468                 return -1;
10469 #endif
10470         default:
10471                 return mono_op_to_op_imm (opcode);
10472         }
10473 }
10474
10475 #ifndef DISABLE_JIT
10476
10477 /**
10478  * mono_handle_global_vregs:
10479  *
10480  *   Make vregs used in more than one bblock 'global', i.e. allocate a variable
10481  * for them.
10482  */
10483 void
10484 mono_handle_global_vregs (MonoCompile *cfg)
10485 {
10486         gint32 *vreg_to_bb;
10487         MonoBasicBlock *bb;
10488         int i, pos;
10489
10490         vreg_to_bb = mono_mempool_alloc0 (cfg->mempool, sizeof (gint32*) * cfg->next_vreg + 1);
10491
10492 #ifdef MONO_ARCH_SIMD_INTRINSICS
10493         if (cfg->uses_simd_intrinsics)
10494                 mono_simd_simplify_indirection (cfg);
10495 #endif
10496
10497         /* Find local vregs used in more than one bb */
10498         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
10499                 MonoInst *ins = bb->code;       
10500                 int block_num = bb->block_num;
10501
10502                 if (cfg->verbose_level > 2)
10503                         printf ("\nHANDLE-GLOBAL-VREGS BLOCK %d:\n", bb->block_num);
10504
10505                 cfg->cbb = bb;
10506                 for (; ins; ins = ins->next) {
10507                         const char *spec = INS_INFO (ins->opcode);
10508                         int regtype = 0, regindex;
10509                         gint32 prev_bb;
10510
10511                         if (G_UNLIKELY (cfg->verbose_level > 2))
10512                                 mono_print_ins (ins);
10513
10514                         g_assert (ins->opcode >= MONO_CEE_LAST);
10515
10516                         for (regindex = 0; regindex < 4; regindex ++) {
10517                                 int vreg = 0;
10518
10519                                 if (regindex == 0) {
10520                                         regtype = spec [MONO_INST_DEST];
10521                                         if (regtype == ' ')
10522                                                 continue;
10523                                         vreg = ins->dreg;
10524                                 } else if (regindex == 1) {
10525                                         regtype = spec [MONO_INST_SRC1];
10526                                         if (regtype == ' ')
10527                                                 continue;
10528                                         vreg = ins->sreg1;
10529                                 } else if (regindex == 2) {
10530                                         regtype = spec [MONO_INST_SRC2];
10531                                         if (regtype == ' ')
10532                                                 continue;
10533                                         vreg = ins->sreg2;
10534                                 } else if (regindex == 3) {
10535                                         regtype = spec [MONO_INST_SRC3];
10536                                         if (regtype == ' ')
10537                                                 continue;
10538                                         vreg = ins->sreg3;
10539                                 }
10540
10541 #if SIZEOF_REGISTER == 4
10542                                 /* In the LLVM case, the long opcodes are not decomposed */
10543                                 if (regtype == 'l' && !COMPILE_LLVM (cfg)) {
10544                                         /*
10545                                          * Since some instructions reference the original long vreg,
10546                                          * and some reference the two component vregs, it is quite hard
10547                                          * to determine when it needs to be global. So be conservative.
10548                                          */
10549                                         if (!get_vreg_to_inst (cfg, vreg)) {
10550                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
10551
10552                                                 if (cfg->verbose_level > 2)
10553                                                         printf ("LONG VREG R%d made global.\n", vreg);
10554                                         }
10555
10556                                         /*
10557                                          * Make the component vregs volatile since the optimizations can
10558                                          * get confused otherwise.
10559                                          */
10560                                         get_vreg_to_inst (cfg, vreg + 1)->flags |= MONO_INST_VOLATILE;
10561                                         get_vreg_to_inst (cfg, vreg + 2)->flags |= MONO_INST_VOLATILE;
10562                                 }
10563 #endif
10564
10565                                 g_assert (vreg != -1);
10566
10567                                 prev_bb = vreg_to_bb [vreg];
10568                                 if (prev_bb == 0) {
10569                                         /* 0 is a valid block num */
10570                                         vreg_to_bb [vreg] = block_num + 1;
10571                                 } else if ((prev_bb != block_num + 1) && (prev_bb != -1)) {
10572                                         if (((regtype == 'i' && (vreg < MONO_MAX_IREGS))) || (regtype == 'f' && (vreg < MONO_MAX_FREGS)))
10573                                                 continue;
10574
10575                                         if (!get_vreg_to_inst (cfg, vreg)) {
10576                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
10577                                                         printf ("VREG R%d used in BB%d and BB%d made global.\n", vreg, vreg_to_bb [vreg], block_num);
10578
10579                                                 switch (regtype) {
10580                                                 case 'i':
10581                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL, vreg);
10582                                                         break;
10583                                                 case 'l':
10584                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
10585                                                         break;
10586                                                 case 'f':
10587                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.double_class->byval_arg, OP_LOCAL, vreg);
10588                                                         break;
10589                                                 case 'v':
10590                                                         mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, vreg);
10591                                                         break;
10592                                                 default:
10593                                                         g_assert_not_reached ();
10594                                                 }
10595                                         }
10596
10597                                         /* Flag as having been used in more than one bb */
10598                                         vreg_to_bb [vreg] = -1;
10599                                 }
10600                         }
10601                 }
10602         }
10603
10604         /* If a variable is used in only one bblock, convert it into a local vreg */
10605         for (i = 0; i < cfg->num_varinfo; i++) {
10606                 MonoInst *var = cfg->varinfo [i];
10607                 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
10608
10609                 switch (var->type) {
10610                 case STACK_I4:
10611                 case STACK_OBJ:
10612                 case STACK_PTR:
10613                 case STACK_MP:
10614                 case STACK_VTYPE:
10615 #if SIZEOF_REGISTER == 8
10616                 case STACK_I8:
10617 #endif
10618 #if !defined(TARGET_X86) && !defined(MONO_ARCH_SOFT_FLOAT)
10619                 /* Enabling this screws up the fp stack on x86 */
10620                 case STACK_R8:
10621 #endif
10622                         /* Arguments are implicitly global */
10623                         /* Putting R4 vars into registers doesn't work currently */
10624                         if ((var->opcode != OP_ARG) && (var != cfg->ret) && !(var->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT)) && (vreg_to_bb [var->dreg] != -1) && (var->klass->byval_arg.type != MONO_TYPE_R4) && !cfg->disable_vreg_to_lvreg) {
10625                                 /* 
10626                                  * Make that the variable's liveness interval doesn't contain a call, since
10627                                  * that would cause the lvreg to be spilled, making the whole optimization
10628                                  * useless.
10629                                  */
10630                                 /* This is too slow for JIT compilation */
10631 #if 0
10632                                 if (cfg->compile_aot && vreg_to_bb [var->dreg]) {
10633                                         MonoInst *ins;
10634                                         int def_index, call_index, ins_index;
10635                                         gboolean spilled = FALSE;
10636
10637                                         def_index = -1;
10638                                         call_index = -1;
10639                                         ins_index = 0;
10640                                         for (ins = vreg_to_bb [var->dreg]->code; ins; ins = ins->next) {
10641                                                 const char *spec = INS_INFO (ins->opcode);
10642
10643                                                 if ((spec [MONO_INST_DEST] != ' ') && (ins->dreg == var->dreg))
10644                                                         def_index = ins_index;
10645
10646                                                 if (((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg)) ||
10647                                                         ((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg))) {
10648                                                         if (call_index > def_index) {
10649                                                                 spilled = TRUE;
10650                                                                 break;
10651                                                         }
10652                                                 }
10653
10654                                                 if (MONO_IS_CALL (ins))
10655                                                         call_index = ins_index;
10656
10657                                                 ins_index ++;
10658                                         }
10659
10660                                         if (spilled)
10661                                                 break;
10662                                 }
10663 #endif
10664
10665                                 if (G_UNLIKELY (cfg->verbose_level > 2))
10666                                         printf ("CONVERTED R%d(%d) TO VREG.\n", var->dreg, vmv->idx);
10667                                 var->flags |= MONO_INST_IS_DEAD;
10668                                 cfg->vreg_to_inst [var->dreg] = NULL;
10669                         }
10670                         break;
10671                 }
10672         }
10673
10674         /* 
10675          * Compress the varinfo and vars tables so the liveness computation is faster and
10676          * takes up less space.
10677          */
10678         pos = 0;
10679         for (i = 0; i < cfg->num_varinfo; ++i) {
10680                 MonoInst *var = cfg->varinfo [i];
10681                 if (pos < i && cfg->locals_start == i)
10682                         cfg->locals_start = pos;
10683                 if (!(var->flags & MONO_INST_IS_DEAD)) {
10684                         if (pos < i) {
10685                                 cfg->varinfo [pos] = cfg->varinfo [i];
10686                                 cfg->varinfo [pos]->inst_c0 = pos;
10687                                 memcpy (&cfg->vars [pos], &cfg->vars [i], sizeof (MonoMethodVar));
10688                                 cfg->vars [pos].idx = pos;
10689 #if SIZEOF_REGISTER == 4
10690                                 if (cfg->varinfo [pos]->type == STACK_I8) {
10691                                         /* Modify the two component vars too */
10692                                         MonoInst *var1;
10693
10694                                         var1 = get_vreg_to_inst (cfg, cfg->varinfo [pos]->dreg + 1);
10695                                         var1->inst_c0 = pos;
10696                                         var1 = get_vreg_to_inst (cfg, cfg->varinfo [pos]->dreg + 2);
10697                                         var1->inst_c0 = pos;
10698                                 }
10699 #endif
10700                         }
10701                         pos ++;
10702                 }
10703         }
10704         cfg->num_varinfo = pos;
10705         if (cfg->locals_start > cfg->num_varinfo)
10706                 cfg->locals_start = cfg->num_varinfo;
10707 }
10708
10709 /**
10710  * mono_spill_global_vars:
10711  *
10712  *   Generate spill code for variables which are not allocated to registers, 
10713  * and replace vregs with their allocated hregs. *need_local_opts is set to TRUE if
10714  * code is generated which could be optimized by the local optimization passes.
10715  */
10716 void
10717 mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
10718 {
10719         MonoBasicBlock *bb;
10720         char spec2 [16];
10721         int orig_next_vreg;
10722         guint32 *vreg_to_lvreg;
10723         guint32 *lvregs;
10724         guint32 i, lvregs_len;
10725         gboolean dest_has_lvreg = FALSE;
10726         guint32 stacktypes [128];
10727         MonoInst **live_range_start, **live_range_end;
10728         MonoBasicBlock **live_range_start_bb, **live_range_end_bb;
10729
10730         *need_local_opts = FALSE;
10731
10732         memset (spec2, 0, sizeof (spec2));
10733
10734         /* FIXME: Move this function to mini.c */
10735         stacktypes ['i'] = STACK_PTR;
10736         stacktypes ['l'] = STACK_I8;
10737         stacktypes ['f'] = STACK_R8;
10738 #ifdef MONO_ARCH_SIMD_INTRINSICS
10739         stacktypes ['x'] = STACK_VTYPE;
10740 #endif
10741
10742 #if SIZEOF_REGISTER == 4
10743         /* Create MonoInsts for longs */
10744         for (i = 0; i < cfg->num_varinfo; i++) {
10745                 MonoInst *ins = cfg->varinfo [i];
10746
10747                 if ((ins->opcode != OP_REGVAR) && !(ins->flags & MONO_INST_IS_DEAD)) {
10748                         switch (ins->type) {
10749                         case STACK_R8:
10750                         case STACK_I8: {
10751                                 MonoInst *tree;
10752
10753                                 if (ins->type == STACK_R8 && !COMPILE_SOFT_FLOAT (cfg))
10754                                         break;
10755
10756                                 g_assert (ins->opcode == OP_REGOFFSET);
10757
10758                                 tree = get_vreg_to_inst (cfg, ins->dreg + 1);
10759                                 g_assert (tree);
10760                                 tree->opcode = OP_REGOFFSET;
10761                                 tree->inst_basereg = ins->inst_basereg;
10762                                 tree->inst_offset = ins->inst_offset + MINI_LS_WORD_OFFSET;
10763
10764                                 tree = get_vreg_to_inst (cfg, ins->dreg + 2);
10765                                 g_assert (tree);
10766                                 tree->opcode = OP_REGOFFSET;
10767                                 tree->inst_basereg = ins->inst_basereg;
10768                                 tree->inst_offset = ins->inst_offset + MINI_MS_WORD_OFFSET;
10769                                 break;
10770                         }
10771                         default:
10772                                 break;
10773                         }
10774                 }
10775         }
10776 #endif
10777
10778         /* FIXME: widening and truncation */
10779
10780         /*
10781          * As an optimization, when a variable allocated to the stack is first loaded into 
10782          * an lvreg, we will remember the lvreg and use it the next time instead of loading
10783          * the variable again.
10784          */
10785         orig_next_vreg = cfg->next_vreg;
10786         vreg_to_lvreg = mono_mempool_alloc0 (cfg->mempool, sizeof (guint32) * cfg->next_vreg);
10787         lvregs = mono_mempool_alloc (cfg->mempool, sizeof (guint32) * 1024);
10788         lvregs_len = 0;
10789
10790         /* 
10791          * These arrays contain the first and last instructions accessing a given
10792          * variable.
10793          * Since we emit bblocks in the same order we process them here, and we
10794          * don't split live ranges, these will precisely describe the live range of
10795          * the variable, i.e. the instruction range where a valid value can be found
10796          * in the variables location.
10797          * The live range is computed using the liveness info computed by the liveness pass.
10798          * We can't use vmv->range, since that is an abstract live range, and we need
10799          * one which is instruction precise.
10800          * FIXME: Variables used in out-of-line bblocks have a hole in their live range.
10801          */
10802         /* FIXME: Only do this if debugging info is requested */
10803         live_range_start = g_new0 (MonoInst*, cfg->next_vreg);
10804         live_range_end = g_new0 (MonoInst*, cfg->next_vreg);
10805         live_range_start_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
10806         live_range_end_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
10807         
10808         /* Add spill loads/stores */
10809         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
10810                 MonoInst *ins;
10811
10812                 if (cfg->verbose_level > 2)
10813                         printf ("\nSPILL BLOCK %d:\n", bb->block_num);
10814
10815                 /* Clear vreg_to_lvreg array */
10816                 for (i = 0; i < lvregs_len; i++)
10817                         vreg_to_lvreg [lvregs [i]] = 0;
10818                 lvregs_len = 0;
10819
10820                 cfg->cbb = bb;
10821                 MONO_BB_FOR_EACH_INS (bb, ins) {
10822                         const char *spec = INS_INFO (ins->opcode);
10823                         int regtype, srcindex, sreg, tmp_reg, prev_dreg, num_sregs;
10824                         gboolean store, no_lvreg;
10825                         int sregs [MONO_MAX_SRC_REGS];
10826
10827                         if (G_UNLIKELY (cfg->verbose_level > 2))
10828                                 mono_print_ins (ins);
10829
10830                         if (ins->opcode == OP_NOP)
10831                                 continue;
10832
10833                         /* 
10834                          * We handle LDADDR here as well, since it can only be decomposed
10835                          * when variable addresses are known.
10836                          */
10837                         if (ins->opcode == OP_LDADDR) {
10838                                 MonoInst *var = ins->inst_p0;
10839
10840                                 if (var->opcode == OP_VTARG_ADDR) {
10841                                         /* Happens on SPARC/S390 where vtypes are passed by reference */
10842                                         MonoInst *vtaddr = var->inst_left;
10843                                         if (vtaddr->opcode == OP_REGVAR) {
10844                                                 ins->opcode = OP_MOVE;
10845                                                 ins->sreg1 = vtaddr->dreg;
10846                                         }
10847                                         else if (var->inst_left->opcode == OP_REGOFFSET) {
10848                                                 ins->opcode = OP_LOAD_MEMBASE;
10849                                                 ins->inst_basereg = vtaddr->inst_basereg;
10850                                                 ins->inst_offset = vtaddr->inst_offset;
10851                                         } else
10852                                                 NOT_IMPLEMENTED;
10853                                 } else {
10854                                         g_assert (var->opcode == OP_REGOFFSET);
10855
10856                                         ins->opcode = OP_ADD_IMM;
10857                                         ins->sreg1 = var->inst_basereg;
10858                                         ins->inst_imm = var->inst_offset;
10859                                 }
10860
10861                                 *need_local_opts = TRUE;
10862                                 spec = INS_INFO (ins->opcode);
10863                         }
10864
10865                         if (ins->opcode < MONO_CEE_LAST) {
10866                                 mono_print_ins (ins);
10867                                 g_assert_not_reached ();
10868                         }
10869
10870                         /*
10871                          * Store opcodes have destbasereg in the dreg, but in reality, it is an
10872                          * src register.
10873                          * FIXME:
10874                          */
10875                         if (MONO_IS_STORE_MEMBASE (ins)) {
10876                                 tmp_reg = ins->dreg;
10877                                 ins->dreg = ins->sreg2;
10878                                 ins->sreg2 = tmp_reg;
10879                                 store = TRUE;
10880
10881                                 spec2 [MONO_INST_DEST] = ' ';
10882                                 spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
10883                                 spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
10884                                 spec2 [MONO_INST_SRC3] = ' ';
10885                                 spec = spec2;
10886                         } else if (MONO_IS_STORE_MEMINDEX (ins))
10887                                 g_assert_not_reached ();
10888                         else
10889                                 store = FALSE;
10890                         no_lvreg = FALSE;
10891
10892                         if (G_UNLIKELY (cfg->verbose_level > 2)) {
10893                                 printf ("\t %.3s %d", spec, ins->dreg);
10894                                 num_sregs = mono_inst_get_src_registers (ins, sregs);
10895                                 for (srcindex = 0; srcindex < 3; ++srcindex)
10896                                         printf (" %d", sregs [srcindex]);
10897                                 printf ("\n");
10898                         }
10899
10900                         /***************/
10901                         /*    DREG     */
10902                         /***************/
10903                         regtype = spec [MONO_INST_DEST];
10904                         g_assert (((ins->dreg == -1) && (regtype == ' ')) || ((ins->dreg != -1) && (regtype != ' ')));
10905                         prev_dreg = -1;
10906
10907                         if ((ins->dreg != -1) && get_vreg_to_inst (cfg, ins->dreg)) {
10908                                 MonoInst *var = get_vreg_to_inst (cfg, ins->dreg);
10909                                 MonoInst *store_ins;
10910                                 int store_opcode;
10911                                 MonoInst *def_ins = ins;
10912                                 int dreg = ins->dreg; /* The original vreg */
10913
10914                                 store_opcode = mono_type_to_store_membase (cfg, var->inst_vtype);
10915
10916                                 if (var->opcode == OP_REGVAR) {
10917                                         ins->dreg = var->dreg;
10918                                 } else if ((ins->dreg == ins->sreg1) && (spec [MONO_INST_DEST] == 'i') && (spec [MONO_INST_SRC1] == 'i') && !vreg_to_lvreg [ins->dreg] && (op_to_op_dest_membase (store_opcode, ins->opcode) != -1)) {
10919                                         /* 
10920                                          * Instead of emitting a load+store, use a _membase opcode.
10921                                          */
10922                                         g_assert (var->opcode == OP_REGOFFSET);
10923                                         if (ins->opcode == OP_MOVE) {
10924                                                 NULLIFY_INS (ins);
10925                                                 def_ins = NULL;
10926                                         } else {
10927                                                 ins->opcode = op_to_op_dest_membase (store_opcode, ins->opcode);
10928                                                 ins->inst_basereg = var->inst_basereg;
10929                                                 ins->inst_offset = var->inst_offset;
10930                                                 ins->dreg = -1;
10931                                         }
10932                                         spec = INS_INFO (ins->opcode);
10933                                 } else {
10934                                         guint32 lvreg;
10935
10936                                         g_assert (var->opcode == OP_REGOFFSET);
10937
10938                                         prev_dreg = ins->dreg;
10939
10940                                         /* Invalidate any previous lvreg for this vreg */
10941                                         vreg_to_lvreg [ins->dreg] = 0;
10942
10943                                         lvreg = 0;
10944
10945                                         if (COMPILE_SOFT_FLOAT (cfg) && store_opcode == OP_STORER8_MEMBASE_REG) {
10946                                                 regtype = 'l';
10947                                                 store_opcode = OP_STOREI8_MEMBASE_REG;
10948                                         }
10949
10950                                         ins->dreg = alloc_dreg (cfg, stacktypes [regtype]);
10951
10952                                         if (regtype == 'l') {
10953                                                 NEW_STORE_MEMBASE (cfg, store_ins, OP_STOREI4_MEMBASE_REG, var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET, ins->dreg + 1);
10954                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
10955                                                 NEW_STORE_MEMBASE (cfg, store_ins, OP_STOREI4_MEMBASE_REG, var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET, ins->dreg + 2);
10956                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
10957                                                 def_ins = store_ins;
10958                                         }
10959                                         else {
10960                                                 g_assert (store_opcode != OP_STOREV_MEMBASE);
10961
10962                                                 /* Try to fuse the store into the instruction itself */
10963                                                 /* FIXME: Add more instructions */
10964                                                 if (!lvreg && ((ins->opcode == OP_ICONST) || ((ins->opcode == OP_I8CONST) && (ins->inst_c0 == 0)))) {
10965                                                         ins->opcode = store_membase_reg_to_store_membase_imm (store_opcode);
10966                                                         ins->inst_imm = ins->inst_c0;
10967                                                         ins->inst_destbasereg = var->inst_basereg;
10968                                                         ins->inst_offset = var->inst_offset;
10969                                                         spec = INS_INFO (ins->opcode);
10970                                                 } else if (!lvreg && ((ins->opcode == OP_MOVE) || (ins->opcode == OP_FMOVE) || (ins->opcode == OP_LMOVE))) {
10971                                                         ins->opcode = store_opcode;
10972                                                         ins->inst_destbasereg = var->inst_basereg;
10973                                                         ins->inst_offset = var->inst_offset;
10974
10975                                                         no_lvreg = TRUE;
10976
10977                                                         tmp_reg = ins->dreg;
10978                                                         ins->dreg = ins->sreg2;
10979                                                         ins->sreg2 = tmp_reg;
10980                                                         store = TRUE;
10981
10982                                                         spec2 [MONO_INST_DEST] = ' ';
10983                                                         spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
10984                                                         spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
10985                                                         spec2 [MONO_INST_SRC3] = ' ';
10986                                                         spec = spec2;
10987                                                 } else if (!lvreg && (op_to_op_store_membase (store_opcode, ins->opcode) != -1)) {
10988                                                         // FIXME: The backends expect the base reg to be in inst_basereg
10989                                                         ins->opcode = op_to_op_store_membase (store_opcode, ins->opcode);
10990                                                         ins->dreg = -1;
10991                                                         ins->inst_basereg = var->inst_basereg;
10992                                                         ins->inst_offset = var->inst_offset;
10993                                                         spec = INS_INFO (ins->opcode);
10994                                                 } else {
10995                                                         /* printf ("INS: "); mono_print_ins (ins); */
10996                                                         /* Create a store instruction */
10997                                                         NEW_STORE_MEMBASE (cfg, store_ins, store_opcode, var->inst_basereg, var->inst_offset, ins->dreg);
10998
10999                                                         /* Insert it after the instruction */
11000                                                         mono_bblock_insert_after_ins (bb, ins, store_ins);
11001
11002                                                         def_ins = store_ins;
11003
11004                                                         /* 
11005                                                          * We can't assign ins->dreg to var->dreg here, since the
11006                                                          * sregs could use it. So set a flag, and do it after
11007                                                          * the sregs.
11008                                                          */
11009                                                         if ((!MONO_ARCH_USE_FPSTACK || ((store_opcode != OP_STORER8_MEMBASE_REG) && (store_opcode != OP_STORER4_MEMBASE_REG))) && !((var)->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT)))
11010                                                                 dest_has_lvreg = TRUE;
11011                                                 }
11012                                         }
11013                                 }
11014
11015                                 if (def_ins && !live_range_start [dreg]) {
11016                                         live_range_start [dreg] = def_ins;
11017                                         live_range_start_bb [dreg] = bb;
11018                                 }
11019                         }
11020
11021                         /************/
11022                         /*  SREGS   */
11023                         /************/
11024                         num_sregs = mono_inst_get_src_registers (ins, sregs);
11025                         for (srcindex = 0; srcindex < 3; ++srcindex) {
11026                                 regtype = spec [MONO_INST_SRC1 + srcindex];
11027                                 sreg = sregs [srcindex];
11028
11029                                 g_assert (((sreg == -1) && (regtype == ' ')) || ((sreg != -1) && (regtype != ' ')));
11030                                 if ((sreg != -1) && get_vreg_to_inst (cfg, sreg)) {
11031                                         MonoInst *var = get_vreg_to_inst (cfg, sreg);
11032                                         MonoInst *use_ins = ins;
11033                                         MonoInst *load_ins;
11034                                         guint32 load_opcode;
11035
11036                                         if (var->opcode == OP_REGVAR) {
11037                                                 sregs [srcindex] = var->dreg;
11038                                                 //mono_inst_set_src_registers (ins, sregs);
11039                                                 live_range_end [sreg] = use_ins;
11040                                                 live_range_end_bb [sreg] = bb;
11041                                                 continue;
11042                                         }
11043
11044                                         g_assert (var->opcode == OP_REGOFFSET);
11045                                                 
11046                                         load_opcode = mono_type_to_load_membase (cfg, var->inst_vtype);
11047
11048                                         g_assert (load_opcode != OP_LOADV_MEMBASE);
11049
11050                                         if (vreg_to_lvreg [sreg]) {
11051                                                 g_assert (vreg_to_lvreg [sreg] != -1);
11052
11053                                                 /* The variable is already loaded to an lvreg */
11054                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
11055                                                         printf ("\t\tUse lvreg R%d for R%d.\n", vreg_to_lvreg [sreg], sreg);
11056                                                 sregs [srcindex] = vreg_to_lvreg [sreg];
11057                                                 //mono_inst_set_src_registers (ins, sregs);
11058                                                 continue;
11059                                         }
11060
11061                                         /* Try to fuse the load into the instruction */
11062                                         if ((srcindex == 0) && (op_to_op_src1_membase (load_opcode, ins->opcode) != -1)) {
11063                                                 ins->opcode = op_to_op_src1_membase (load_opcode, ins->opcode);
11064                                                 sregs [0] = var->inst_basereg;
11065                                                 //mono_inst_set_src_registers (ins, sregs);
11066                                                 ins->inst_offset = var->inst_offset;
11067                                         } else if ((srcindex == 1) && (op_to_op_src2_membase (load_opcode, ins->opcode) != -1)) {
11068                                                 ins->opcode = op_to_op_src2_membase (load_opcode, ins->opcode);
11069                                                 sregs [1] = var->inst_basereg;
11070                                                 //mono_inst_set_src_registers (ins, sregs);
11071                                                 ins->inst_offset = var->inst_offset;
11072                                         } else {
11073                                                 if (MONO_IS_REAL_MOVE (ins)) {
11074                                                         ins->opcode = OP_NOP;
11075                                                         sreg = ins->dreg;
11076                                                 } else {
11077                                                         //printf ("%d ", srcindex); mono_print_ins (ins);
11078
11079                                                         sreg = alloc_dreg (cfg, stacktypes [regtype]);
11080
11081                                                         if ((!MONO_ARCH_USE_FPSTACK || ((load_opcode != OP_LOADR8_MEMBASE) && (load_opcode != OP_LOADR4_MEMBASE))) && !((var)->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT)) && !no_lvreg) {
11082                                                                 if (var->dreg == prev_dreg) {
11083                                                                         /*
11084                                                                          * sreg refers to the value loaded by the load
11085                                                                          * emitted below, but we need to use ins->dreg
11086                                                                          * since it refers to the store emitted earlier.
11087                                                                          */
11088                                                                         sreg = ins->dreg;
11089                                                                 }
11090                                                                 g_assert (sreg != -1);
11091                                                                 vreg_to_lvreg [var->dreg] = sreg;
11092                                                                 g_assert (lvregs_len < 1024);
11093                                                                 lvregs [lvregs_len ++] = var->dreg;
11094                                                         }
11095                                                 }
11096
11097                                                 sregs [srcindex] = sreg;
11098                                                 //mono_inst_set_src_registers (ins, sregs);
11099
11100                                                 if (regtype == 'l') {
11101                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, sreg + 2, var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET);
11102                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
11103                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, sreg + 1, var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET);
11104                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
11105                                                         use_ins = load_ins;
11106                                                 }
11107                                                 else {
11108 #if SIZEOF_REGISTER == 4
11109                                                         g_assert (load_opcode != OP_LOADI8_MEMBASE);
11110 #endif
11111                                                         NEW_LOAD_MEMBASE (cfg, load_ins, load_opcode, sreg, var->inst_basereg, var->inst_offset);
11112                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
11113                                                         use_ins = load_ins;
11114                                                 }
11115                                         }
11116
11117                                         if (var->dreg < orig_next_vreg) {
11118                                                 live_range_end [var->dreg] = use_ins;
11119                                                 live_range_end_bb [var->dreg] = bb;
11120                                         }
11121                                 }
11122                         }
11123                         mono_inst_set_src_registers (ins, sregs);
11124
11125                         if (dest_has_lvreg) {
11126                                 g_assert (ins->dreg != -1);
11127                                 vreg_to_lvreg [prev_dreg] = ins->dreg;
11128                                 g_assert (lvregs_len < 1024);
11129                                 lvregs [lvregs_len ++] = prev_dreg;
11130                                 dest_has_lvreg = FALSE;
11131                         }
11132
11133                         if (store) {
11134                                 tmp_reg = ins->dreg;
11135                                 ins->dreg = ins->sreg2;
11136                                 ins->sreg2 = tmp_reg;
11137                         }
11138
11139                         if (MONO_IS_CALL (ins)) {
11140                                 /* Clear vreg_to_lvreg array */
11141                                 for (i = 0; i < lvregs_len; i++)
11142                                         vreg_to_lvreg [lvregs [i]] = 0;
11143                                 lvregs_len = 0;
11144                         } else if (ins->opcode == OP_NOP) {
11145                                 ins->dreg = -1;
11146                                 MONO_INST_NULLIFY_SREGS (ins);
11147                         }
11148
11149                         if (cfg->verbose_level > 2)
11150                                 mono_print_ins_index (1, ins);
11151                 }
11152
11153                 /* Extend the live range based on the liveness info */
11154                 if (cfg->compute_precise_live_ranges && bb->live_out_set && bb->code) {
11155                         for (i = 0; i < cfg->num_varinfo; i ++) {
11156                                 MonoMethodVar *vi = MONO_VARINFO (cfg, i);
11157
11158                                 if (vreg_is_volatile (cfg, vi->vreg))
11159                                         /* The liveness info is incomplete */
11160                                         continue;
11161
11162                                 if (mono_bitset_test_fast (bb->live_in_set, i) && !live_range_start [vi->vreg]) {
11163                                         /* Live from at least the first ins of this bb */
11164                                         live_range_start [vi->vreg] = bb->code;
11165                                         live_range_start_bb [vi->vreg] = bb;
11166                                 }
11167
11168                                 if (mono_bitset_test_fast (bb->live_out_set, i)) {
11169                                         /* Live at least until the last ins of this bb */
11170                                         live_range_end [vi->vreg] = bb->last_ins;
11171                                         live_range_end_bb [vi->vreg] = bb;
11172                                 }
11173                         }
11174                 }
11175         }
11176         
11177 #ifdef MONO_ARCH_HAVE_LIVERANGE_OPS
11178         /*
11179          * Emit LIVERANGE_START/LIVERANGE_END opcodes, the backend will implement them
11180          * by storing the current native offset into MonoMethodVar->live_range_start/end.
11181          */
11182         if (cfg->compute_precise_live_ranges && cfg->comp_done & MONO_COMP_LIVENESS) {
11183                 for (i = 0; i < cfg->num_varinfo; ++i) {
11184                         int vreg = MONO_VARINFO (cfg, i)->vreg;
11185                         MonoInst *ins;
11186
11187                         if (live_range_start [vreg]) {
11188                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_START);
11189                                 ins->inst_c0 = i;
11190                                 ins->inst_c1 = vreg;
11191                                 mono_bblock_insert_after_ins (live_range_start_bb [vreg], live_range_start [vreg], ins);
11192                         }
11193                         if (live_range_end [vreg]) {
11194                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_END);
11195                                 ins->inst_c0 = i;
11196                                 ins->inst_c1 = vreg;
11197                                 if (live_range_end [vreg] == live_range_end_bb [vreg]->last_ins)
11198                                         mono_add_ins_to_end (live_range_end_bb [vreg], ins);
11199                                 else
11200                                         mono_bblock_insert_after_ins (live_range_end_bb [vreg], live_range_end [vreg], ins);
11201                         }
11202                 }
11203         }
11204 #endif
11205
11206         g_free (live_range_start);
11207         g_free (live_range_end);
11208         g_free (live_range_start_bb);
11209         g_free (live_range_end_bb);
11210 }
11211
11212 /**
11213  * FIXME:
11214  * - use 'iadd' instead of 'int_add'
11215  * - handling ovf opcodes: decompose in method_to_ir.
11216  * - unify iregs/fregs
11217  *   -> partly done, the missing parts are:
11218  *   - a more complete unification would involve unifying the hregs as well, so
11219  *     code wouldn't need if (fp) all over the place. but that would mean the hregs
11220  *     would no longer map to the machine hregs, so the code generators would need to
11221  *     be modified. Also, on ia64 for example, niregs + nfregs > 256 -> bitmasks
11222  *     wouldn't work any more. Duplicating the code in mono_local_regalloc () into
11223  *     fp/non-fp branches speeds it up by about 15%.
11224  * - use sext/zext opcodes instead of shifts
11225  * - add OP_ICALL
11226  * - get rid of TEMPLOADs if possible and use vregs instead
11227  * - clean up usage of OP_P/OP_ opcodes
11228  * - cleanup usage of DUMMY_USE
11229  * - cleanup the setting of ins->type for MonoInst's which are pushed on the 
11230  *   stack
11231  * - set the stack type and allocate a dreg in the EMIT_NEW macros
11232  * - get rid of all the <foo>2 stuff when the new JIT is ready.
11233  * - make sure handle_stack_args () is called before the branch is emitted
11234  * - when the new IR is done, get rid of all unused stuff
11235  * - COMPARE/BEQ as separate instructions or unify them ?
11236  *   - keeping them separate allows specialized compare instructions like
11237  *     compare_imm, compare_membase
11238  *   - most back ends unify fp compare+branch, fp compare+ceq
11239  * - integrate mono_save_args into inline_method
11240  * - get rid of the empty bblocks created by MONO_EMIT_NEW_BRACH_BLOCK2
11241  * - handle long shift opts on 32 bit platforms somehow: they require 
11242  *   3 sregs (2 for arg1 and 1 for arg2)
11243  * - make byref a 'normal' type.
11244  * - use vregs for bb->out_stacks if possible, handle_global_vreg will make them a
11245  *   variable if needed.
11246  * - do not start a new IL level bblock when cfg->cbb is changed by a function call
11247  *   like inline_method.
11248  * - remove inlining restrictions
11249  * - fix LNEG and enable cfold of INEG
11250  * - generalize x86 optimizations like ldelema as a peephole optimization
11251  * - add store_mem_imm for amd64
11252  * - optimize the loading of the interruption flag in the managed->native wrappers
11253  * - avoid special handling of OP_NOP in passes
11254  * - move code inserting instructions into one function/macro.
11255  * - try a coalescing phase after liveness analysis
11256  * - add float -> vreg conversion + local optimizations on !x86
11257  * - figure out how to handle decomposed branches during optimizations, ie.
11258  *   compare+branch, op_jump_table+op_br etc.
11259  * - promote RuntimeXHandles to vregs
11260  * - vtype cleanups:
11261  *   - add a NEW_VARLOADA_VREG macro
11262  * - the vtype optimizations are blocked by the LDADDR opcodes generated for 
11263  *   accessing vtype fields.
11264  * - get rid of I8CONST on 64 bit platforms
11265  * - dealing with the increase in code size due to branches created during opcode
11266  *   decomposition:
11267  *   - use extended basic blocks
11268  *     - all parts of the JIT
11269  *     - handle_global_vregs () && local regalloc
11270  *   - avoid introducing global vregs during decomposition, like 'vtable' in isinst
11271  * - sources of increase in code size:
11272  *   - vtypes
11273  *   - long compares
11274  *   - isinst and castclass
11275  *   - lvregs not allocated to global registers even if used multiple times
11276  * - call cctors outside the JIT, to make -v output more readable and JIT timings more
11277  *   meaningful.
11278  * - check for fp stack leakage in other opcodes too. (-> 'exceptions' optimization)
11279  * - add all micro optimizations from the old JIT
11280  * - put tree optimizations into the deadce pass
11281  * - decompose op_start_handler/op_endfilter/op_endfinally earlier using an arch
11282  *   specific function.
11283  * - unify the float comparison opcodes with the other comparison opcodes, i.e.
11284  *   fcompare + branchCC.
11285  * - create a helper function for allocating a stack slot, taking into account 
11286  *   MONO_CFG_HAS_SPILLUP.
11287  * - merge r68207.
11288  * - merge the ia64 switch changes.
11289  * - optimize mono_regstate2_alloc_int/float.
11290  * - fix the pessimistic handling of variables accessed in exception handler blocks.
11291  * - need to write a tree optimization pass, but the creation of trees is difficult, i.e.
11292  *   parts of the tree could be separated by other instructions, killing the tree
11293  *   arguments, or stores killing loads etc. Also, should we fold loads into other
11294  *   instructions if the result of the load is used multiple times ?
11295  * - make the REM_IMM optimization in mini-x86.c arch-independent.
11296  * - LAST MERGE: 108395.
11297  * - when returning vtypes in registers, generate IR and append it to the end of the
11298  *   last bb instead of doing it in the epilog.
11299  * - change the store opcodes so they use sreg1 instead of dreg to store the base register.
11300  */
11301
11302 /*
11303
11304 NOTES
11305 -----
11306
11307 - When to decompose opcodes:
11308   - earlier: this makes some optimizations hard to implement, since the low level IR
11309   no longer contains the neccessary information. But it is easier to do.
11310   - later: harder to implement, enables more optimizations.
11311 - Branches inside bblocks:
11312   - created when decomposing complex opcodes. 
11313     - branches to another bblock: harmless, but not tracked by the branch 
11314       optimizations, so need to branch to a label at the start of the bblock.
11315     - branches to inside the same bblock: very problematic, trips up the local
11316       reg allocator. Can be fixed by spitting the current bblock, but that is a
11317       complex operation, since some local vregs can become global vregs etc.
11318 - Local/global vregs:
11319   - local vregs: temporary vregs used inside one bblock. Assigned to hregs by the
11320     local register allocator.
11321   - global vregs: used in more than one bblock. Have an associated MonoMethodVar
11322     structure, created by mono_create_var (). Assigned to hregs or the stack by
11323     the global register allocator.
11324 - When to do optimizations like alu->alu_imm:
11325   - earlier -> saves work later on since the IR will be smaller/simpler
11326   - later -> can work on more instructions
11327 - Handling of valuetypes:
11328   - When a vtype is pushed on the stack, a new temporary is created, an 
11329     instruction computing its address (LDADDR) is emitted and pushed on
11330     the stack. Need to optimize cases when the vtype is used immediately as in
11331     argument passing, stloc etc.
11332 - Instead of the to_end stuff in the old JIT, simply call the function handling
11333   the values on the stack before emitting the last instruction of the bb.
11334 */
11335
11336 #endif /* DISABLE_JIT */