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