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