Merge pull request #1949 from lewurm/fixtype
[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  * Copyright 2003-2010 Novell, Inc (http://www.novell.com)
10  * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
11  */
12
13 #include <config.h>
14
15 #ifndef DISABLE_JIT
16
17 #include <signal.h>
18
19 #ifdef HAVE_UNISTD_H
20 #include <unistd.h>
21 #endif
22
23 #include <math.h>
24 #include <string.h>
25 #include <ctype.h>
26
27 #ifdef HAVE_SYS_TIME_H
28 #include <sys/time.h>
29 #endif
30
31 #ifdef HAVE_ALLOCA_H
32 #include <alloca.h>
33 #endif
34
35 #include <mono/utils/memcheck.h>
36 #include "mini.h"
37 #include <mono/metadata/abi-details.h>
38 #include <mono/metadata/assembly.h>
39 #include <mono/metadata/attrdefs.h>
40 #include <mono/metadata/loader.h>
41 #include <mono/metadata/tabledefs.h>
42 #include <mono/metadata/class.h>
43 #include <mono/metadata/object.h>
44 #include <mono/metadata/exception.h>
45 #include <mono/metadata/opcodes.h>
46 #include <mono/metadata/mono-endian.h>
47 #include <mono/metadata/tokentype.h>
48 #include <mono/metadata/tabledefs.h>
49 #include <mono/metadata/marshal.h>
50 #include <mono/metadata/debug-helpers.h>
51 #include <mono/metadata/mono-debug.h>
52 #include <mono/metadata/mono-debug-debugger.h>
53 #include <mono/metadata/gc-internal.h>
54 #include <mono/metadata/security-manager.h>
55 #include <mono/metadata/threads-types.h>
56 #include <mono/metadata/security-core-clr.h>
57 #include <mono/metadata/profiler-private.h>
58 #include <mono/metadata/profiler.h>
59 #include <mono/metadata/debug-mono-symfile.h>
60 #include <mono/utils/mono-compiler.h>
61 #include <mono/utils/mono-memory-model.h>
62 #include <mono/metadata/mono-basic-block.h>
63
64 #include "trace.h"
65
66 #include "ir-emit.h"
67
68 #include "jit-icalls.h"
69 #include "jit.h"
70 #include "debugger-agent.h"
71 #include "seq-points.h"
72
73 #define BRANCH_COST 10
74 #define INLINE_LENGTH_LIMIT 20
75
76 /* These have 'cfg' as an implicit argument */
77 #define INLINE_FAILURE(msg) do {                                                                        \
78         if ((cfg->method != cfg->current_method) && (cfg->current_method->wrapper_type == MONO_WRAPPER_NONE)) { \
79                 inline_failure (cfg, msg);                                                                              \
80                 goto exception_exit;                                                                                    \
81         } \
82         } while (0)
83 #define CHECK_CFG_EXCEPTION do {\
84                 if (cfg->exception_type != MONO_EXCEPTION_NONE) \
85                         goto exception_exit;                                            \
86         } while (0)
87 #define METHOD_ACCESS_FAILURE(method, cmethod) do {                     \
88                 method_access_failure ((cfg), (method), (cmethod));                     \
89                 goto exception_exit;                                                                            \
90         } while (0)
91 #define FIELD_ACCESS_FAILURE(method, field) do {                                        \
92                 field_access_failure ((cfg), (method), (field));                        \
93                 goto exception_exit;    \
94         } while (0)
95 #define GENERIC_SHARING_FAILURE(opcode) do {            \
96                 if (cfg->gshared) {                                                                     \
97                         gshared_failure (cfg, opcode, __FILE__, __LINE__);      \
98                         goto exception_exit;    \
99                 }                       \
100         } while (0)
101 #define GSHAREDVT_FAILURE(opcode) do {          \
102         if (cfg->gsharedvt) {                                                                                           \
103                 gsharedvt_failure (cfg, opcode, __FILE__, __LINE__);                    \
104                 goto exception_exit;                                                                                    \
105         }                                                                                                                                       \
106         } while (0)
107 #define OUT_OF_MEMORY_FAILURE do {      \
108                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_OUT_OF_MEMORY);             \
109                 goto exception_exit;    \
110         } while (0)
111 #define DISABLE_AOT(cfg) do { \
112                 if ((cfg)->verbose_level >= 2)                                            \
113                         printf ("AOT disabled: %s:%d\n", __FILE__, __LINE__);   \
114                 (cfg)->disable_aot = TRUE;                                                        \
115         } while (0)
116 #define LOAD_ERROR do { \
117                 break_on_unverified ();                                                         \
118                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD); \
119                 goto exception_exit;                                                                    \
120         } while (0)
121
122 #define TYPE_LOAD_ERROR(klass) do { \
123                 cfg->exception_ptr = klass; \
124                 LOAD_ERROR;                                     \
125         } while (0)
126
127 #define CHECK_CFG_ERROR do {\
128                 if (!mono_error_ok (&cfg->error)) { \
129                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);        \
130                         goto mono_error_exit; \
131                 } \
132         } while (0)
133
134 /* Determine whenever 'ins' represents a load of the 'this' argument */
135 #define MONO_CHECK_THIS(ins) (mono_method_signature (cfg->method)->hasthis && ((ins)->opcode == OP_MOVE) && ((ins)->sreg1 == cfg->args [0]->dreg))
136
137 static int ldind_to_load_membase (int opcode);
138 static int stind_to_store_membase (int opcode);
139
140 int mono_op_to_op_imm (int opcode);
141 int mono_op_to_op_imm_noemul (int opcode);
142
143 MONO_API MonoInst* mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig, MonoInst **args);
144
145 static int inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp,
146                                                   guchar *ip, guint real_offset, gboolean inline_always);
147
148 /* helper methods signatures */
149 static MonoMethodSignature *helper_sig_domain_get;
150 static MonoMethodSignature *helper_sig_rgctx_lazy_fetch_trampoline;
151
152 /*
153  * Instruction metadata
154  */
155 #ifdef MINI_OP
156 #undef MINI_OP
157 #endif
158 #ifdef MINI_OP3
159 #undef MINI_OP3
160 #endif
161 #define MINI_OP(a,b,dest,src1,src2) dest, src1, src2, ' ',
162 #define MINI_OP3(a,b,dest,src1,src2,src3) dest, src1, src2, src3,
163 #define NONE ' '
164 #define IREG 'i'
165 #define FREG 'f'
166 #define VREG 'v'
167 #define XREG 'x'
168 #if SIZEOF_REGISTER == 8 && SIZEOF_REGISTER == SIZEOF_VOID_P
169 #define LREG IREG
170 #else
171 #define LREG 'l'
172 #endif
173 /* keep in sync with the enum in mini.h */
174 const char
175 ins_info[] = {
176 #include "mini-ops.h"
177 };
178 #undef MINI_OP
179 #undef MINI_OP3
180
181 #define MINI_OP(a,b,dest,src1,src2) ((src2) != NONE ? 2 : ((src1) != NONE ? 1 : 0)),
182 #define MINI_OP3(a,b,dest,src1,src2,src3) ((src3) != NONE ? 3 : ((src2) != NONE ? 2 : ((src1) != NONE ? 1 : 0))),
183 /* 
184  * This should contain the index of the last sreg + 1. This is not the same
185  * as the number of sregs for opcodes like IA64_CMP_EQ_IMM.
186  */
187 const gint8 ins_sreg_counts[] = {
188 #include "mini-ops.h"
189 };
190 #undef MINI_OP
191 #undef MINI_OP3
192
193 #define MONO_INIT_VARINFO(vi,id) do { \
194         (vi)->range.first_use.pos.bid = 0xffff; \
195         (vi)->reg = -1; \
196         (vi)->idx = (id); \
197 } while (0)
198
199 guint32
200 mono_alloc_ireg (MonoCompile *cfg)
201 {
202         return alloc_ireg (cfg);
203 }
204
205 guint32
206 mono_alloc_lreg (MonoCompile *cfg)
207 {
208         return alloc_lreg (cfg);
209 }
210
211 guint32
212 mono_alloc_freg (MonoCompile *cfg)
213 {
214         return alloc_freg (cfg);
215 }
216
217 guint32
218 mono_alloc_preg (MonoCompile *cfg)
219 {
220         return alloc_preg (cfg);
221 }
222
223 guint32
224 mono_alloc_dreg (MonoCompile *cfg, MonoStackType stack_type)
225 {
226         return alloc_dreg (cfg, stack_type);
227 }
228
229 /*
230  * mono_alloc_ireg_ref:
231  *
232  *   Allocate an IREG, and mark it as holding a GC ref.
233  */
234 guint32
235 mono_alloc_ireg_ref (MonoCompile *cfg)
236 {
237         return alloc_ireg_ref (cfg);
238 }
239
240 /*
241  * mono_alloc_ireg_mp:
242  *
243  *   Allocate an IREG, and mark it as holding a managed pointer.
244  */
245 guint32
246 mono_alloc_ireg_mp (MonoCompile *cfg)
247 {
248         return alloc_ireg_mp (cfg);
249 }
250
251 /*
252  * mono_alloc_ireg_copy:
253  *
254  *   Allocate an IREG with the same GC type as VREG.
255  */
256 guint32
257 mono_alloc_ireg_copy (MonoCompile *cfg, guint32 vreg)
258 {
259         if (vreg_is_ref (cfg, vreg))
260                 return alloc_ireg_ref (cfg);
261         else if (vreg_is_mp (cfg, vreg))
262                 return alloc_ireg_mp (cfg);
263         else
264                 return alloc_ireg (cfg);
265 }
266
267 guint
268 mono_type_to_regmove (MonoCompile *cfg, MonoType *type)
269 {
270         if (type->byref)
271                 return OP_MOVE;
272
273         type = mini_get_underlying_type (type);
274 handle_enum:
275         switch (type->type) {
276         case MONO_TYPE_I1:
277         case MONO_TYPE_U1:
278                 return OP_MOVE;
279         case MONO_TYPE_I2:
280         case MONO_TYPE_U2:
281                 return OP_MOVE;
282         case MONO_TYPE_I4:
283         case MONO_TYPE_U4:
284                 return OP_MOVE;
285         case MONO_TYPE_I:
286         case MONO_TYPE_U:
287         case MONO_TYPE_PTR:
288         case MONO_TYPE_FNPTR:
289                 return OP_MOVE;
290         case MONO_TYPE_CLASS:
291         case MONO_TYPE_STRING:
292         case MONO_TYPE_OBJECT:
293         case MONO_TYPE_SZARRAY:
294         case MONO_TYPE_ARRAY:    
295                 return OP_MOVE;
296         case MONO_TYPE_I8:
297         case MONO_TYPE_U8:
298 #if SIZEOF_REGISTER == 8
299                 return OP_MOVE;
300 #else
301                 return OP_LMOVE;
302 #endif
303         case MONO_TYPE_R4:
304                 return cfg->r4fp ? OP_RMOVE : OP_FMOVE;
305         case MONO_TYPE_R8:
306                 return OP_FMOVE;
307         case MONO_TYPE_VALUETYPE:
308                 if (type->data.klass->enumtype) {
309                         type = mono_class_enum_basetype (type->data.klass);
310                         goto handle_enum;
311                 }
312                 if (MONO_CLASS_IS_SIMD (cfg, mono_class_from_mono_type (type)))
313                         return OP_XMOVE;
314                 return OP_VMOVE;
315         case MONO_TYPE_TYPEDBYREF:
316                 return OP_VMOVE;
317         case MONO_TYPE_GENERICINST:
318                 type = &type->data.generic_class->container_class->byval_arg;
319                 goto handle_enum;
320         case MONO_TYPE_VAR:
321         case MONO_TYPE_MVAR:
322                 g_assert (cfg->gshared);
323                 if (mini_type_var_is_vt (type))
324                         return OP_VMOVE;
325                 else
326                         return mono_type_to_regmove (cfg, mini_get_underlying_type (type));
327         default:
328                 g_error ("unknown type 0x%02x in type_to_regstore", type->type);
329         }
330         return -1;
331 }
332
333 void
334 mono_print_bb (MonoBasicBlock *bb, const char *msg)
335 {
336         int i;
337         MonoInst *tree;
338
339         printf ("\n%s %d: [IN: ", msg, bb->block_num);
340         for (i = 0; i < bb->in_count; ++i)
341                 printf (" BB%d(%d)", bb->in_bb [i]->block_num, bb->in_bb [i]->dfn);
342         printf (", OUT: ");
343         for (i = 0; i < bb->out_count; ++i)
344                 printf (" BB%d(%d)", bb->out_bb [i]->block_num, bb->out_bb [i]->dfn);
345         printf (" ]\n");
346         for (tree = bb->code; tree; tree = tree->next)
347                 mono_print_ins_index (-1, tree);
348 }
349
350 void
351 mono_create_helper_signatures (void)
352 {
353         helper_sig_domain_get = mono_create_icall_signature ("ptr");
354         helper_sig_rgctx_lazy_fetch_trampoline = mono_create_icall_signature ("ptr ptr");
355 }
356
357 static MONO_NEVER_INLINE void
358 break_on_unverified (void)
359 {
360         if (mini_get_debug_options ()->break_on_unverified)
361                 G_BREAKPOINT ();
362 }
363
364 static MONO_NEVER_INLINE void
365 method_access_failure (MonoCompile *cfg, MonoMethod *method, MonoMethod *cil_method)
366 {
367         char *method_fname = mono_method_full_name (method, TRUE);
368         char *cil_method_fname = mono_method_full_name (cil_method, TRUE);
369         mono_cfg_set_exception (cfg, MONO_EXCEPTION_METHOD_ACCESS);
370         cfg->exception_message = g_strdup_printf ("Method `%s' is inaccessible from method `%s'\n", cil_method_fname, method_fname);
371         g_free (method_fname);
372         g_free (cil_method_fname);
373 }
374
375 static MONO_NEVER_INLINE void
376 field_access_failure (MonoCompile *cfg, MonoMethod *method, MonoClassField *field)
377 {
378         char *method_fname = mono_method_full_name (method, TRUE);
379         char *field_fname = mono_field_full_name (field);
380         mono_cfg_set_exception (cfg, MONO_EXCEPTION_FIELD_ACCESS);
381         cfg->exception_message = g_strdup_printf ("Field `%s' is inaccessible from method `%s'\n", field_fname, method_fname);
382         g_free (method_fname);
383         g_free (field_fname);
384 }
385
386 static MONO_NEVER_INLINE void
387 inline_failure (MonoCompile *cfg, const char *msg)
388 {
389         if (cfg->verbose_level >= 2)
390                 printf ("inline failed: %s\n", msg);
391         mono_cfg_set_exception (cfg, MONO_EXCEPTION_INLINE_FAILED);
392 }
393
394 static MONO_NEVER_INLINE void
395 gshared_failure (MonoCompile *cfg, int opcode, const char *file, int line)
396 {
397         if (cfg->verbose_level > 2)                                                                                     \
398                 printf ("sharing failed for method %s.%s.%s/%d opcode %s line %d\n", cfg->current_method->klass->name_space, cfg->current_method->klass->name, cfg->current_method->name, cfg->current_method->signature->param_count, mono_opcode_name ((opcode)), line);
399         mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED);
400 }
401
402 static MONO_NEVER_INLINE void
403 gsharedvt_failure (MonoCompile *cfg, int opcode, const char *file, int line)
404 {
405         cfg->exception_message = g_strdup_printf ("gsharedvt failed for method %s.%s.%s/%d opcode %s %s:%d", cfg->current_method->klass->name_space, cfg->current_method->klass->name, cfg->current_method->name, cfg->current_method->signature->param_count, mono_opcode_name ((opcode)), file, line);
406         if (cfg->verbose_level >= 2)
407                 printf ("%s\n", cfg->exception_message);
408         mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED);
409 }
410
411 /*
412  * When using gsharedvt, some instatiations might be verifiable, and some might be not. i.e. 
413  * foo<T> (int i) { ldarg.0; box T; }
414  */
415 #define UNVERIFIED do { \
416         if (cfg->gsharedvt) { \
417                 if (cfg->verbose_level > 2)                                                                     \
418                         printf ("gsharedvt method failed to verify, falling back to instantiation.\n"); \
419                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED); \
420                 goto exception_exit;                                                                                    \
421         }                                                                                                                                       \
422         break_on_unverified ();                                                                                         \
423         goto unverified;                                                                                                        \
424 } while (0)
425
426 #define GET_BBLOCK(cfg,tblock,ip) do {  \
427                 (tblock) = cfg->cil_offset_to_bb [(ip) - cfg->cil_start]; \
428                 if (!(tblock)) {        \
429                         if ((ip) >= end || (ip) < header->code) UNVERIFIED; \
430             NEW_BBLOCK (cfg, (tblock)); \
431                         (tblock)->cil_code = (ip);      \
432                         ADD_BBLOCK (cfg, (tblock));     \
433                 } \
434         } while (0)
435
436 #if defined(TARGET_X86) || defined(TARGET_AMD64)
437 #define EMIT_NEW_X86_LEA(cfg,dest,sr1,sr2,shift,imm) do { \
438                 MONO_INST_NEW (cfg, dest, OP_X86_LEA); \
439                 (dest)->dreg = alloc_ireg_mp ((cfg)); \
440                 (dest)->sreg1 = (sr1); \
441                 (dest)->sreg2 = (sr2); \
442                 (dest)->inst_imm = (imm); \
443                 (dest)->backend.shift_amount = (shift); \
444                 MONO_ADD_INS ((cfg)->cbb, (dest)); \
445         } while (0)
446 #endif
447
448 /* Emit conversions so both operands of a binary opcode are of the same type */
449 static void
450 add_widen_op (MonoCompile *cfg, MonoInst *ins, MonoInst **arg1_ref, MonoInst **arg2_ref)
451 {
452         MonoInst *arg1 = *arg1_ref;
453         MonoInst *arg2 = *arg2_ref;
454
455         if (cfg->r4fp &&
456                 ((arg1->type == STACK_R4 && arg2->type == STACK_R8) ||
457                  (arg1->type == STACK_R8 && arg2->type == STACK_R4))) {
458                 MonoInst *conv;
459
460                 /* Mixing r4/r8 is allowed by the spec */
461                 if (arg1->type == STACK_R4) {
462                         int dreg = alloc_freg (cfg);
463
464                         EMIT_NEW_UNALU (cfg, conv, OP_RCONV_TO_R8, dreg, arg1->dreg);
465                         conv->type = STACK_R8;
466                         ins->sreg1 = dreg;
467                         *arg1_ref = conv;
468                 }
469                 if (arg2->type == STACK_R4) {
470                         int dreg = alloc_freg (cfg);
471
472                         EMIT_NEW_UNALU (cfg, conv, OP_RCONV_TO_R8, dreg, arg2->dreg);
473                         conv->type = STACK_R8;
474                         ins->sreg2 = dreg;
475                         *arg2_ref = conv;
476                 }
477         }
478
479 #if SIZEOF_REGISTER == 8
480         /* FIXME: Need to add many more cases */
481         if ((arg1)->type == STACK_PTR && (arg2)->type == STACK_I4) {
482                 MonoInst *widen;
483
484                 int dr = alloc_preg (cfg);
485                 EMIT_NEW_UNALU (cfg, widen, OP_SEXT_I4, dr, (arg2)->dreg);
486                 (ins)->sreg2 = widen->dreg;
487         }
488 #endif
489 }
490
491 #define ADD_BINOP(op) do {      \
492                 MONO_INST_NEW (cfg, ins, (op)); \
493                 sp -= 2;        \
494                 ins->sreg1 = sp [0]->dreg;      \
495                 ins->sreg2 = sp [1]->dreg;      \
496                 type_from_op (cfg, ins, sp [0], sp [1]);        \
497                 CHECK_TYPE (ins);       \
498                 /* Have to insert a widening op */               \
499         add_widen_op (cfg, ins, &sp [0], &sp [1]);               \
500         ins->dreg = alloc_dreg ((cfg), (ins)->type); \
501         MONO_ADD_INS ((cfg)->cbb, (ins)); \
502         *sp++ = mono_decompose_opcode ((cfg), (ins));   \
503         } while (0)
504
505 #define ADD_UNOP(op) do {       \
506                 MONO_INST_NEW (cfg, ins, (op)); \
507                 sp--;   \
508                 ins->sreg1 = sp [0]->dreg;      \
509                 type_from_op (cfg, ins, sp [0], NULL);  \
510                 CHECK_TYPE (ins);       \
511         (ins)->dreg = alloc_dreg ((cfg), (ins)->type); \
512         MONO_ADD_INS ((cfg)->cbb, (ins)); \
513                 *sp++ = mono_decompose_opcode (cfg, ins);       \
514         } while (0)
515
516 #define ADD_BINCOND(next_block) do {    \
517                 MonoInst *cmp;  \
518                 sp -= 2; \
519                 MONO_INST_NEW(cfg, cmp, OP_COMPARE);    \
520                 cmp->sreg1 = sp [0]->dreg;      \
521                 cmp->sreg2 = sp [1]->dreg;      \
522                 type_from_op (cfg, cmp, sp [0], sp [1]);        \
523                 CHECK_TYPE (cmp);       \
524                 add_widen_op (cfg, cmp, &sp [0], &sp [1]);                                              \
525                 type_from_op (cfg, ins, sp [0], sp [1]);                                                        \
526                 ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);      \
527                 GET_BBLOCK (cfg, tblock, target);               \
528                 link_bblock (cfg, cfg->cbb, tblock);    \
529                 ins->inst_true_bb = tblock;     \
530                 if ((next_block)) {     \
531                         link_bblock (cfg, cfg->cbb, (next_block));      \
532                         ins->inst_false_bb = (next_block);      \
533                         start_new_bblock = 1;   \
534                 } else {        \
535                         GET_BBLOCK (cfg, tblock, ip);           \
536                         link_bblock (cfg, cfg->cbb, tblock);    \
537                         ins->inst_false_bb = tblock;    \
538                         start_new_bblock = 2;   \
539                 }       \
540                 if (sp != stack_start) {                                                                        \
541                     handle_stack_args (cfg, stack_start, sp - stack_start); \
542                         CHECK_UNVERIFIABLE (cfg); \
543                 } \
544         MONO_ADD_INS (cfg->cbb, cmp); \
545                 MONO_ADD_INS (cfg->cbb, ins);   \
546         } while (0)
547
548 /* *
549  * link_bblock: Links two basic blocks
550  *
551  * links two basic blocks in the control flow graph, the 'from'
552  * argument is the starting block and the 'to' argument is the block
553  * the control flow ends to after 'from'.
554  */
555 static void
556 link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
557 {
558         MonoBasicBlock **newa;
559         int i, found;
560
561 #if 0
562         if (from->cil_code) {
563                 if (to->cil_code)
564                         printf ("edge from IL%04x to IL_%04x\n", from->cil_code - cfg->cil_code, to->cil_code - cfg->cil_code);
565                 else
566                         printf ("edge from IL%04x to exit\n", from->cil_code - cfg->cil_code);
567         } else {
568                 if (to->cil_code)
569                         printf ("edge from entry to IL_%04x\n", to->cil_code - cfg->cil_code);
570                 else
571                         printf ("edge from entry to exit\n");
572         }
573 #endif
574
575         found = FALSE;
576         for (i = 0; i < from->out_count; ++i) {
577                 if (to == from->out_bb [i]) {
578                         found = TRUE;
579                         break;
580                 }
581         }
582         if (!found) {
583                 newa = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (from->out_count + 1));
584                 for (i = 0; i < from->out_count; ++i) {
585                         newa [i] = from->out_bb [i];
586                 }
587                 newa [i] = to;
588                 from->out_count++;
589                 from->out_bb = newa;
590         }
591
592         found = FALSE;
593         for (i = 0; i < to->in_count; ++i) {
594                 if (from == to->in_bb [i]) {
595                         found = TRUE;
596                         break;
597                 }
598         }
599         if (!found) {
600                 newa = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (to->in_count + 1));
601                 for (i = 0; i < to->in_count; ++i) {
602                         newa [i] = to->in_bb [i];
603                 }
604                 newa [i] = from;
605                 to->in_count++;
606                 to->in_bb = newa;
607         }
608 }
609
610 void
611 mono_link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
612 {
613         link_bblock (cfg, from, to);
614 }
615
616 /**
617  * mono_find_block_region:
618  *
619  *   We mark each basic block with a region ID. We use that to avoid BB
620  *   optimizations when blocks are in different regions.
621  *
622  * Returns:
623  *   A region token that encodes where this region is, and information
624  *   about the clause owner for this block.
625  *
626  *   The region encodes the try/catch/filter clause that owns this block
627  *   as well as the type.  -1 is a special value that represents a block
628  *   that is in none of try/catch/filter.
629  */
630 static int
631 mono_find_block_region (MonoCompile *cfg, int offset)
632 {
633         MonoMethodHeader *header = cfg->header;
634         MonoExceptionClause *clause;
635         int i;
636
637         for (i = 0; i < header->num_clauses; ++i) {
638                 clause = &header->clauses [i];
639                 if ((clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) && (offset >= clause->data.filter_offset) &&
640                     (offset < (clause->handler_offset)))
641                         return ((i + 1) << 8) | MONO_REGION_FILTER | clause->flags;
642                            
643                 if (MONO_OFFSET_IN_HANDLER (clause, offset)) {
644                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY)
645                                 return ((i + 1) << 8) | MONO_REGION_FINALLY | clause->flags;
646                         else if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
647                                 return ((i + 1) << 8) | MONO_REGION_FAULT | clause->flags;
648                         else
649                                 return ((i + 1) << 8) | MONO_REGION_CATCH | clause->flags;
650                 }
651         }
652         for (i = 0; i < header->num_clauses; ++i) {
653                 clause = &header->clauses [i];
654
655                 if (MONO_OFFSET_IN_CLAUSE (clause, offset))
656                         return ((i + 1) << 8) | clause->flags;
657         }
658
659         return -1;
660 }
661
662 static GList*
663 mono_find_final_block (MonoCompile *cfg, unsigned char *ip, unsigned char *target, int type)
664 {
665         MonoMethodHeader *header = cfg->header;
666         MonoExceptionClause *clause;
667         int i;
668         GList *res = NULL;
669
670         for (i = 0; i < header->num_clauses; ++i) {
671                 clause = &header->clauses [i];
672                 if (MONO_OFFSET_IN_CLAUSE (clause, (ip - header->code)) && 
673                     (!MONO_OFFSET_IN_CLAUSE (clause, (target - header->code)))) {
674                         if (clause->flags == type)
675                                 res = g_list_append (res, clause);
676                 }
677         }
678         return res;
679 }
680
681 static void
682 mono_create_spvar_for_region (MonoCompile *cfg, int region)
683 {
684         MonoInst *var;
685
686         var = g_hash_table_lookup (cfg->spvars, GINT_TO_POINTER (region));
687         if (var)
688                 return;
689
690         var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
691         /* prevent it from being register allocated */
692         var->flags |= MONO_INST_VOLATILE;
693
694         g_hash_table_insert (cfg->spvars, GINT_TO_POINTER (region), var);
695 }
696
697 MonoInst *
698 mono_find_exvar_for_offset (MonoCompile *cfg, int offset)
699 {
700         return g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
701 }
702
703 static MonoInst*
704 mono_create_exvar_for_offset (MonoCompile *cfg, int offset)
705 {
706         MonoInst *var;
707
708         var = g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
709         if (var)
710                 return var;
711
712         var = mono_compile_create_var (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL);
713         /* prevent it from being register allocated */
714         var->flags |= MONO_INST_VOLATILE;
715
716         g_hash_table_insert (cfg->exvars, GINT_TO_POINTER (offset), var);
717
718         return var;
719 }
720
721 /*
722  * Returns the type used in the eval stack when @type is loaded.
723  * FIXME: return a MonoType/MonoClass for the byref and VALUETYPE cases.
724  */
725 void
726 type_to_eval_stack_type (MonoCompile *cfg, MonoType *type, MonoInst *inst)
727 {
728         MonoClass *klass;
729
730         type = mini_get_underlying_type (type);
731         inst->klass = klass = mono_class_from_mono_type (type);
732         if (type->byref) {
733                 inst->type = STACK_MP;
734                 return;
735         }
736
737 handle_enum:
738         switch (type->type) {
739         case MONO_TYPE_VOID:
740                 inst->type = STACK_INV;
741                 return;
742         case MONO_TYPE_I1:
743         case MONO_TYPE_U1:
744         case MONO_TYPE_I2:
745         case MONO_TYPE_U2:
746         case MONO_TYPE_I4:
747         case MONO_TYPE_U4:
748                 inst->type = STACK_I4;
749                 return;
750         case MONO_TYPE_I:
751         case MONO_TYPE_U:
752         case MONO_TYPE_PTR:
753         case MONO_TYPE_FNPTR:
754                 inst->type = STACK_PTR;
755                 return;
756         case MONO_TYPE_CLASS:
757         case MONO_TYPE_STRING:
758         case MONO_TYPE_OBJECT:
759         case MONO_TYPE_SZARRAY:
760         case MONO_TYPE_ARRAY:    
761                 inst->type = STACK_OBJ;
762                 return;
763         case MONO_TYPE_I8:
764         case MONO_TYPE_U8:
765                 inst->type = STACK_I8;
766                 return;
767         case MONO_TYPE_R4:
768                 inst->type = cfg->r4_stack_type;
769                 break;
770         case MONO_TYPE_R8:
771                 inst->type = STACK_R8;
772                 return;
773         case MONO_TYPE_VALUETYPE:
774                 if (type->data.klass->enumtype) {
775                         type = mono_class_enum_basetype (type->data.klass);
776                         goto handle_enum;
777                 } else {
778                         inst->klass = klass;
779                         inst->type = STACK_VTYPE;
780                         return;
781                 }
782         case MONO_TYPE_TYPEDBYREF:
783                 inst->klass = mono_defaults.typed_reference_class;
784                 inst->type = STACK_VTYPE;
785                 return;
786         case MONO_TYPE_GENERICINST:
787                 type = &type->data.generic_class->container_class->byval_arg;
788                 goto handle_enum;
789         case MONO_TYPE_VAR:
790         case MONO_TYPE_MVAR:
791                 g_assert (cfg->gshared);
792                 if (mini_is_gsharedvt_type (type)) {
793                         g_assert (cfg->gsharedvt);
794                         inst->type = STACK_VTYPE;
795                 } else {
796                         type_to_eval_stack_type (cfg, mini_get_underlying_type (type), inst);
797                 }
798                 return;
799         default:
800                 g_error ("unknown type 0x%02x in eval stack type", type->type);
801         }
802 }
803
804 /*
805  * The following tables are used to quickly validate the IL code in type_from_op ().
806  */
807 static const char
808 bin_num_table [STACK_MAX] [STACK_MAX] = {
809         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
810         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
811         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
812         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
813         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_R8,  STACK_INV, STACK_INV, STACK_INV, STACK_R8},
814         {STACK_INV, STACK_MP,  STACK_INV, STACK_MP,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV},
815         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
816         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
817         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_R8, STACK_INV, STACK_INV, STACK_INV, STACK_R4}
818 };
819
820 static const char 
821 neg_table [] = {
822         STACK_INV, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_INV, STACK_INV, STACK_INV, STACK_R4
823 };
824
825 /* reduce the size of this table */
826 static const char
827 bin_int_table [STACK_MAX] [STACK_MAX] = {
828         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
829         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
830         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
831         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
832         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
833         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
834         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
835         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
836 };
837
838 static const char
839 bin_comp_table [STACK_MAX] [STACK_MAX] = {
840 /*      Inv i  L  p  F  &  O  vt r4 */
841         {0},
842         {0, 1, 0, 1, 0, 0, 0, 0}, /* i, int32 */
843         {0, 0, 1, 0, 0, 0, 0, 0}, /* L, int64 */
844         {0, 1, 0, 1, 0, 2, 4, 0}, /* p, ptr */
845         {0, 0, 0, 0, 1, 0, 0, 0, 1}, /* F, R8 */
846         {0, 0, 0, 2, 0, 1, 0, 0}, /* &, managed pointer */
847         {0, 0, 0, 4, 0, 0, 3, 0}, /* O, reference */
848         {0, 0, 0, 0, 0, 0, 0, 0}, /* vt value type */
849         {0, 0, 0, 0, 1, 0, 0, 0, 1}, /* r, r4 */
850 };
851
852 /* reduce the size of this table */
853 static const char
854 shift_table [STACK_MAX] [STACK_MAX] = {
855         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
856         {STACK_INV, STACK_I4,  STACK_INV, STACK_I4,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
857         {STACK_INV, STACK_I8,  STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
858         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
859         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
860         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
861         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
862         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
863 };
864
865 /*
866  * Tables to map from the non-specific opcode to the matching
867  * type-specific opcode.
868  */
869 /* handles from CEE_ADD to CEE_SHR_UN (CEE_REM_UN for floats) */
870 static const guint16
871 binops_op_map [STACK_MAX] = {
872         0, OP_IADD-CEE_ADD, OP_LADD-CEE_ADD, OP_PADD-CEE_ADD, OP_FADD-CEE_ADD, OP_PADD-CEE_ADD, 0, 0, OP_RADD-CEE_ADD
873 };
874
875 /* handles from CEE_NEG to CEE_CONV_U8 */
876 static const guint16
877 unops_op_map [STACK_MAX] = {
878         0, OP_INEG-CEE_NEG, OP_LNEG-CEE_NEG, OP_PNEG-CEE_NEG, OP_FNEG-CEE_NEG, OP_PNEG-CEE_NEG, 0, 0, OP_RNEG-CEE_NEG
879 };
880
881 /* handles from CEE_CONV_U2 to CEE_SUB_OVF_UN */
882 static const guint16
883 ovfops_op_map [STACK_MAX] = {
884         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, 0, OP_RCONV_TO_U2-CEE_CONV_U2
885 };
886
887 /* handles from CEE_CONV_OVF_I1_UN to CEE_CONV_OVF_U_UN */
888 static const guint16
889 ovf2ops_op_map [STACK_MAX] = {
890         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, 0, 0, OP_RCONV_TO_OVF_I1_UN-CEE_CONV_OVF_I1_UN
891 };
892
893 /* handles from CEE_CONV_OVF_I1 to CEE_CONV_OVF_U8 */
894 static const guint16
895 ovf3ops_op_map [STACK_MAX] = {
896         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, 0, 0, OP_RCONV_TO_OVF_I1-CEE_CONV_OVF_I1
897 };
898
899 /* handles from CEE_BEQ to CEE_BLT_UN */
900 static const guint16
901 beqops_op_map [STACK_MAX] = {
902         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, 0, OP_FBEQ-CEE_BEQ
903 };
904
905 /* handles from CEE_CEQ to CEE_CLT_UN */
906 static const guint16
907 ceqops_op_map [STACK_MAX] = {
908         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, 0, OP_RCEQ-OP_CEQ
909 };
910
911 /*
912  * Sets ins->type (the type on the eval stack) according to the
913  * type of the opcode and the arguments to it.
914  * Invalid IL code is marked by setting ins->type to the invalid value STACK_INV.
915  *
916  * FIXME: this function sets ins->type unconditionally in some cases, but
917  * it should set it to invalid for some types (a conv.x on an object)
918  */
919 static void
920 type_from_op (MonoCompile *cfg, MonoInst *ins, MonoInst *src1, MonoInst *src2)
921 {
922         switch (ins->opcode) {
923         /* binops */
924         case CEE_ADD:
925         case CEE_SUB:
926         case CEE_MUL:
927         case CEE_DIV:
928         case CEE_REM:
929                 /* FIXME: check unverifiable args for STACK_MP */
930                 ins->type = bin_num_table [src1->type] [src2->type];
931                 ins->opcode += binops_op_map [ins->type];
932                 break;
933         case CEE_DIV_UN:
934         case CEE_REM_UN:
935         case CEE_AND:
936         case CEE_OR:
937         case CEE_XOR:
938                 ins->type = bin_int_table [src1->type] [src2->type];
939                 ins->opcode += binops_op_map [ins->type];
940                 break;
941         case CEE_SHL:
942         case CEE_SHR:
943         case CEE_SHR_UN:
944                 ins->type = shift_table [src1->type] [src2->type];
945                 ins->opcode += binops_op_map [ins->type];
946                 break;
947         case OP_COMPARE:
948         case OP_LCOMPARE:
949         case OP_ICOMPARE:
950                 ins->type = bin_comp_table [src1->type] [src2->type] ? STACK_I4: STACK_INV;
951                 if ((src1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((src1->type == STACK_PTR) || (src1->type == STACK_OBJ) || (src1->type == STACK_MP))))
952                         ins->opcode = OP_LCOMPARE;
953                 else if (src1->type == STACK_R4)
954                         ins->opcode = OP_RCOMPARE;
955                 else if (src1->type == STACK_R8)
956                         ins->opcode = OP_FCOMPARE;
957                 else
958                         ins->opcode = OP_ICOMPARE;
959                 break;
960         case OP_ICOMPARE_IMM:
961                 ins->type = bin_comp_table [src1->type] [src1->type] ? STACK_I4 : STACK_INV;
962                 if ((src1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((src1->type == STACK_PTR) || (src1->type == STACK_OBJ) || (src1->type == STACK_MP))))
963                         ins->opcode = OP_LCOMPARE_IMM;          
964                 break;
965         case CEE_BEQ:
966         case CEE_BGE:
967         case CEE_BGT:
968         case CEE_BLE:
969         case CEE_BLT:
970         case CEE_BNE_UN:
971         case CEE_BGE_UN:
972         case CEE_BGT_UN:
973         case CEE_BLE_UN:
974         case CEE_BLT_UN:
975                 ins->opcode += beqops_op_map [src1->type];
976                 break;
977         case OP_CEQ:
978                 ins->type = bin_comp_table [src1->type] [src2->type] ? STACK_I4: STACK_INV;
979                 ins->opcode += ceqops_op_map [src1->type];
980                 break;
981         case OP_CGT:
982         case OP_CGT_UN:
983         case OP_CLT:
984         case OP_CLT_UN:
985                 ins->type = (bin_comp_table [src1->type] [src2->type] & 1) ? STACK_I4: STACK_INV;
986                 ins->opcode += ceqops_op_map [src1->type];
987                 break;
988         /* unops */
989         case CEE_NEG:
990                 ins->type = neg_table [src1->type];
991                 ins->opcode += unops_op_map [ins->type];
992                 break;
993         case CEE_NOT:
994                 if (src1->type >= STACK_I4 && src1->type <= STACK_PTR)
995                         ins->type = src1->type;
996                 else
997                         ins->type = STACK_INV;
998                 ins->opcode += unops_op_map [ins->type];
999                 break;
1000         case CEE_CONV_I1:
1001         case CEE_CONV_I2:
1002         case CEE_CONV_I4:
1003         case CEE_CONV_U4:
1004                 ins->type = STACK_I4;
1005                 ins->opcode += unops_op_map [src1->type];
1006                 break;
1007         case CEE_CONV_R_UN:
1008                 ins->type = STACK_R8;
1009                 switch (src1->type) {
1010                 case STACK_I4:
1011                 case STACK_PTR:
1012                         ins->opcode = OP_ICONV_TO_R_UN;
1013                         break;
1014                 case STACK_I8:
1015                         ins->opcode = OP_LCONV_TO_R_UN; 
1016                         break;
1017                 }
1018                 break;
1019         case CEE_CONV_OVF_I1:
1020         case CEE_CONV_OVF_U1:
1021         case CEE_CONV_OVF_I2:
1022         case CEE_CONV_OVF_U2:
1023         case CEE_CONV_OVF_I4:
1024         case CEE_CONV_OVF_U4:
1025                 ins->type = STACK_I4;
1026                 ins->opcode += ovf3ops_op_map [src1->type];
1027                 break;
1028         case CEE_CONV_OVF_I_UN:
1029         case CEE_CONV_OVF_U_UN:
1030                 ins->type = STACK_PTR;
1031                 ins->opcode += ovf2ops_op_map [src1->type];
1032                 break;
1033         case CEE_CONV_OVF_I1_UN:
1034         case CEE_CONV_OVF_I2_UN:
1035         case CEE_CONV_OVF_I4_UN:
1036         case CEE_CONV_OVF_U1_UN:
1037         case CEE_CONV_OVF_U2_UN:
1038         case CEE_CONV_OVF_U4_UN:
1039                 ins->type = STACK_I4;
1040                 ins->opcode += ovf2ops_op_map [src1->type];
1041                 break;
1042         case CEE_CONV_U:
1043                 ins->type = STACK_PTR;
1044                 switch (src1->type) {
1045                 case STACK_I4:
1046                         ins->opcode = OP_ICONV_TO_U;
1047                         break;
1048                 case STACK_PTR:
1049                 case STACK_MP:
1050 #if SIZEOF_VOID_P == 8
1051                         ins->opcode = OP_LCONV_TO_U;
1052 #else
1053                         ins->opcode = OP_MOVE;
1054 #endif
1055                         break;
1056                 case STACK_I8:
1057                         ins->opcode = OP_LCONV_TO_U;
1058                         break;
1059                 case STACK_R8:
1060                         ins->opcode = OP_FCONV_TO_U;
1061                         break;
1062                 }
1063                 break;
1064         case CEE_CONV_I8:
1065         case CEE_CONV_U8:
1066                 ins->type = STACK_I8;
1067                 ins->opcode += unops_op_map [src1->type];
1068                 break;
1069         case CEE_CONV_OVF_I8:
1070         case CEE_CONV_OVF_U8:
1071                 ins->type = STACK_I8;
1072                 ins->opcode += ovf3ops_op_map [src1->type];
1073                 break;
1074         case CEE_CONV_OVF_U8_UN:
1075         case CEE_CONV_OVF_I8_UN:
1076                 ins->type = STACK_I8;
1077                 ins->opcode += ovf2ops_op_map [src1->type];
1078                 break;
1079         case CEE_CONV_R4:
1080                 ins->type = cfg->r4_stack_type;
1081                 ins->opcode += unops_op_map [src1->type];
1082                 break;
1083         case CEE_CONV_R8:
1084                 ins->type = STACK_R8;
1085                 ins->opcode += unops_op_map [src1->type];
1086                 break;
1087         case OP_CKFINITE:
1088                 ins->type = STACK_R8;           
1089                 break;
1090         case CEE_CONV_U2:
1091         case CEE_CONV_U1:
1092                 ins->type = STACK_I4;
1093                 ins->opcode += ovfops_op_map [src1->type];
1094                 break;
1095         case CEE_CONV_I:
1096         case CEE_CONV_OVF_I:
1097         case CEE_CONV_OVF_U:
1098                 ins->type = STACK_PTR;
1099                 ins->opcode += ovfops_op_map [src1->type];
1100                 break;
1101         case CEE_ADD_OVF:
1102         case CEE_ADD_OVF_UN:
1103         case CEE_MUL_OVF:
1104         case CEE_MUL_OVF_UN:
1105         case CEE_SUB_OVF:
1106         case CEE_SUB_OVF_UN:
1107                 ins->type = bin_num_table [src1->type] [src2->type];
1108                 ins->opcode += ovfops_op_map [src1->type];
1109                 if (ins->type == STACK_R8)
1110                         ins->type = STACK_INV;
1111                 break;
1112         case OP_LOAD_MEMBASE:
1113                 ins->type = STACK_PTR;
1114                 break;
1115         case OP_LOADI1_MEMBASE:
1116         case OP_LOADU1_MEMBASE:
1117         case OP_LOADI2_MEMBASE:
1118         case OP_LOADU2_MEMBASE:
1119         case OP_LOADI4_MEMBASE:
1120         case OP_LOADU4_MEMBASE:
1121                 ins->type = STACK_PTR;
1122                 break;
1123         case OP_LOADI8_MEMBASE:
1124                 ins->type = STACK_I8;
1125                 break;
1126         case OP_LOADR4_MEMBASE:
1127                 ins->type = cfg->r4_stack_type;
1128                 break;
1129         case OP_LOADR8_MEMBASE:
1130                 ins->type = STACK_R8;
1131                 break;
1132         default:
1133                 g_error ("opcode 0x%04x not handled in type from op", ins->opcode);
1134                 break;
1135         }
1136
1137         if (ins->type == STACK_MP)
1138                 ins->klass = mono_defaults.object_class;
1139 }
1140
1141 static const char 
1142 ldind_type [] = {
1143         STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_R8, STACK_OBJ
1144 };
1145
1146 #if 0
1147
1148 static const char
1149 param_table [STACK_MAX] [STACK_MAX] = {
1150         {0},
1151 };
1152
1153 static int
1154 check_values_to_signature (MonoInst *args, MonoType *this_ins, MonoMethodSignature *sig)
1155 {
1156         int i;
1157
1158         if (sig->hasthis) {
1159                 switch (args->type) {
1160                 case STACK_I4:
1161                 case STACK_I8:
1162                 case STACK_R8:
1163                 case STACK_VTYPE:
1164                 case STACK_INV:
1165                         return 0;
1166                 }
1167                 args++;
1168         }
1169         for (i = 0; i < sig->param_count; ++i) {
1170                 switch (args [i].type) {
1171                 case STACK_INV:
1172                         return 0;
1173                 case STACK_MP:
1174                         if (!sig->params [i]->byref)
1175                                 return 0;
1176                         continue;
1177                 case STACK_OBJ:
1178                         if (sig->params [i]->byref)
1179                                 return 0;
1180                         switch (sig->params [i]->type) {
1181                         case MONO_TYPE_CLASS:
1182                         case MONO_TYPE_STRING:
1183                         case MONO_TYPE_OBJECT:
1184                         case MONO_TYPE_SZARRAY:
1185                         case MONO_TYPE_ARRAY:
1186                                 break;
1187                         default:
1188                                 return 0;
1189                         }
1190                         continue;
1191                 case STACK_R8:
1192                         if (sig->params [i]->byref)
1193                                 return 0;
1194                         if (sig->params [i]->type != MONO_TYPE_R4 && sig->params [i]->type != MONO_TYPE_R8)
1195                                 return 0;
1196                         continue;
1197                 case STACK_PTR:
1198                 case STACK_I4:
1199                 case STACK_I8:
1200                 case STACK_VTYPE:
1201                         break;
1202                 }
1203                 /*if (!param_table [args [i].type] [sig->params [i]->type])
1204                         return 0;*/
1205         }
1206         return 1;
1207 }
1208 #endif
1209
1210 /*
1211  * When we need a pointer to the current domain many times in a method, we
1212  * call mono_domain_get() once and we store the result in a local variable.
1213  * This function returns the variable that represents the MonoDomain*.
1214  */
1215 inline static MonoInst *
1216 mono_get_domainvar (MonoCompile *cfg)
1217 {
1218         if (!cfg->domainvar)
1219                 cfg->domainvar = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1220         return cfg->domainvar;
1221 }
1222
1223 /*
1224  * The got_var contains the address of the Global Offset Table when AOT 
1225  * compiling.
1226  */
1227 MonoInst *
1228 mono_get_got_var (MonoCompile *cfg)
1229 {
1230 #ifdef MONO_ARCH_NEED_GOT_VAR
1231         if (!cfg->compile_aot)
1232                 return NULL;
1233         if (!cfg->got_var) {
1234                 cfg->got_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1235         }
1236         return cfg->got_var;
1237 #else
1238         return NULL;
1239 #endif
1240 }
1241
1242 static MonoInst *
1243 mono_get_vtable_var (MonoCompile *cfg)
1244 {
1245         g_assert (cfg->gshared);
1246
1247         if (!cfg->rgctx_var) {
1248                 cfg->rgctx_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1249                 /* force the var to be stack allocated */
1250                 cfg->rgctx_var->flags |= MONO_INST_VOLATILE;
1251         }
1252
1253         return cfg->rgctx_var;
1254 }
1255
1256 static MonoType*
1257 type_from_stack_type (MonoInst *ins) {
1258         switch (ins->type) {
1259         case STACK_I4: return &mono_defaults.int32_class->byval_arg;
1260         case STACK_I8: return &mono_defaults.int64_class->byval_arg;
1261         case STACK_PTR: return &mono_defaults.int_class->byval_arg;
1262         case STACK_R4: return &mono_defaults.single_class->byval_arg;
1263         case STACK_R8: return &mono_defaults.double_class->byval_arg;
1264         case STACK_MP:
1265                 return &ins->klass->this_arg;
1266         case STACK_OBJ: return &mono_defaults.object_class->byval_arg;
1267         case STACK_VTYPE: return &ins->klass->byval_arg;
1268         default:
1269                 g_error ("stack type %d to monotype not handled\n", ins->type);
1270         }
1271         return NULL;
1272 }
1273
1274 static G_GNUC_UNUSED int
1275 type_to_stack_type (MonoCompile *cfg, MonoType *t)
1276 {
1277         t = mono_type_get_underlying_type (t);
1278         switch (t->type) {
1279         case MONO_TYPE_I1:
1280         case MONO_TYPE_U1:
1281         case MONO_TYPE_I2:
1282         case MONO_TYPE_U2:
1283         case MONO_TYPE_I4:
1284         case MONO_TYPE_U4:
1285                 return STACK_I4;
1286         case MONO_TYPE_I:
1287         case MONO_TYPE_U:
1288         case MONO_TYPE_PTR:
1289         case MONO_TYPE_FNPTR:
1290                 return STACK_PTR;
1291         case MONO_TYPE_CLASS:
1292         case MONO_TYPE_STRING:
1293         case MONO_TYPE_OBJECT:
1294         case MONO_TYPE_SZARRAY:
1295         case MONO_TYPE_ARRAY:    
1296                 return STACK_OBJ;
1297         case MONO_TYPE_I8:
1298         case MONO_TYPE_U8:
1299                 return STACK_I8;
1300         case MONO_TYPE_R4:
1301                 return cfg->r4_stack_type;
1302         case MONO_TYPE_R8:
1303                 return STACK_R8;
1304         case MONO_TYPE_VALUETYPE:
1305         case MONO_TYPE_TYPEDBYREF:
1306                 return STACK_VTYPE;
1307         case MONO_TYPE_GENERICINST:
1308                 if (mono_type_generic_inst_is_valuetype (t))
1309                         return STACK_VTYPE;
1310                 else
1311                         return STACK_OBJ;
1312                 break;
1313         default:
1314                 g_assert_not_reached ();
1315         }
1316
1317         return -1;
1318 }
1319
1320 static MonoClass*
1321 array_access_to_klass (int opcode)
1322 {
1323         switch (opcode) {
1324         case CEE_LDELEM_U1:
1325                 return mono_defaults.byte_class;
1326         case CEE_LDELEM_U2:
1327                 return mono_defaults.uint16_class;
1328         case CEE_LDELEM_I:
1329         case CEE_STELEM_I:
1330                 return mono_defaults.int_class;
1331         case CEE_LDELEM_I1:
1332         case CEE_STELEM_I1:
1333                 return mono_defaults.sbyte_class;
1334         case CEE_LDELEM_I2:
1335         case CEE_STELEM_I2:
1336                 return mono_defaults.int16_class;
1337         case CEE_LDELEM_I4:
1338         case CEE_STELEM_I4:
1339                 return mono_defaults.int32_class;
1340         case CEE_LDELEM_U4:
1341                 return mono_defaults.uint32_class;
1342         case CEE_LDELEM_I8:
1343         case CEE_STELEM_I8:
1344                 return mono_defaults.int64_class;
1345         case CEE_LDELEM_R4:
1346         case CEE_STELEM_R4:
1347                 return mono_defaults.single_class;
1348         case CEE_LDELEM_R8:
1349         case CEE_STELEM_R8:
1350                 return mono_defaults.double_class;
1351         case CEE_LDELEM_REF:
1352         case CEE_STELEM_REF:
1353                 return mono_defaults.object_class;
1354         default:
1355                 g_assert_not_reached ();
1356         }
1357         return NULL;
1358 }
1359
1360 /*
1361  * We try to share variables when possible
1362  */
1363 static MonoInst *
1364 mono_compile_get_interface_var (MonoCompile *cfg, int slot, MonoInst *ins)
1365 {
1366         MonoInst *res;
1367         int pos, vnum;
1368
1369         /* inlining can result in deeper stacks */ 
1370         if (slot >= cfg->header->max_stack)
1371                 return mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1372
1373         pos = ins->type - 1 + slot * STACK_MAX;
1374
1375         switch (ins->type) {
1376         case STACK_I4:
1377         case STACK_I8:
1378         case STACK_R8:
1379         case STACK_PTR:
1380         case STACK_MP:
1381         case STACK_OBJ:
1382                 if ((vnum = cfg->intvars [pos]))
1383                         return cfg->varinfo [vnum];
1384                 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1385                 cfg->intvars [pos] = res->inst_c0;
1386                 break;
1387         default:
1388                 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1389         }
1390         return res;
1391 }
1392
1393 static void
1394 mono_save_token_info (MonoCompile *cfg, MonoImage *image, guint32 token, gpointer key)
1395 {
1396         /* 
1397          * Don't use this if a generic_context is set, since that means AOT can't
1398          * look up the method using just the image+token.
1399          * table == 0 means this is a reference made from a wrapper.
1400          */
1401         if (cfg->compile_aot && !cfg->generic_context && (mono_metadata_token_table (token) > 0)) {
1402                 MonoJumpInfoToken *jump_info_token = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoToken));
1403                 jump_info_token->image = image;
1404                 jump_info_token->token = token;
1405                 g_hash_table_insert (cfg->token_info_hash, key, jump_info_token);
1406         }
1407 }
1408
1409 /*
1410  * This function is called to handle items that are left on the evaluation stack
1411  * at basic block boundaries. What happens is that we save the values to local variables
1412  * and we reload them later when first entering the target basic block (with the
1413  * handle_loaded_temps () function).
1414  * A single joint point will use the same variables (stored in the array bb->out_stack or
1415  * bb->in_stack, if the basic block is before or after the joint point).
1416  *
1417  * This function needs to be called _before_ emitting the last instruction of
1418  * the bb (i.e. before emitting a branch).
1419  * If the stack merge fails at a join point, cfg->unverifiable is set.
1420  */
1421 static void
1422 handle_stack_args (MonoCompile *cfg, MonoInst **sp, int count)
1423 {
1424         int i, bindex;
1425         MonoBasicBlock *bb = cfg->cbb;
1426         MonoBasicBlock *outb;
1427         MonoInst *inst, **locals;
1428         gboolean found;
1429
1430         if (!count)
1431                 return;
1432         if (cfg->verbose_level > 3)
1433                 printf ("%d item(s) on exit from B%d\n", count, bb->block_num);
1434         if (!bb->out_scount) {
1435                 bb->out_scount = count;
1436                 //printf ("bblock %d has out:", bb->block_num);
1437                 found = FALSE;
1438                 for (i = 0; i < bb->out_count; ++i) {
1439                         outb = bb->out_bb [i];
1440                         /* exception handlers are linked, but they should not be considered for stack args */
1441                         if (outb->flags & BB_EXCEPTION_HANDLER)
1442                                 continue;
1443                         //printf (" %d", outb->block_num);
1444                         if (outb->in_stack) {
1445                                 found = TRUE;
1446                                 bb->out_stack = outb->in_stack;
1447                                 break;
1448                         }
1449                 }
1450                 //printf ("\n");
1451                 if (!found) {
1452                         bb->out_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * count);
1453                         for (i = 0; i < count; ++i) {
1454                                 /* 
1455                                  * try to reuse temps already allocated for this purpouse, if they occupy the same
1456                                  * stack slot and if they are of the same type.
1457                                  * This won't cause conflicts since if 'local' is used to 
1458                                  * store one of the values in the in_stack of a bblock, then
1459                                  * the same variable will be used for the same outgoing stack 
1460                                  * slot as well. 
1461                                  * This doesn't work when inlining methods, since the bblocks
1462                                  * in the inlined methods do not inherit their in_stack from
1463                                  * the bblock they are inlined to. See bug #58863 for an
1464                                  * example.
1465                                  */
1466                                 if (cfg->inlined_method)
1467                                         bb->out_stack [i] = mono_compile_create_var (cfg, type_from_stack_type (sp [i]), OP_LOCAL);
1468                                 else
1469                                         bb->out_stack [i] = mono_compile_get_interface_var (cfg, i, sp [i]);
1470                         }
1471                 }
1472         }
1473
1474         for (i = 0; i < bb->out_count; ++i) {
1475                 outb = bb->out_bb [i];
1476                 /* exception handlers are linked, but they should not be considered for stack args */
1477                 if (outb->flags & BB_EXCEPTION_HANDLER)
1478                         continue;
1479                 if (outb->in_scount) {
1480                         if (outb->in_scount != bb->out_scount) {
1481                                 cfg->unverifiable = TRUE;
1482                                 return;
1483                         }
1484                         continue; /* check they are the same locals */
1485                 }
1486                 outb->in_scount = count;
1487                 outb->in_stack = bb->out_stack;
1488         }
1489
1490         locals = bb->out_stack;
1491         cfg->cbb = bb;
1492         for (i = 0; i < count; ++i) {
1493                 EMIT_NEW_TEMPSTORE (cfg, inst, locals [i]->inst_c0, sp [i]);
1494                 inst->cil_code = sp [i]->cil_code;
1495                 sp [i] = locals [i];
1496                 if (cfg->verbose_level > 3)
1497                         printf ("storing %d to temp %d\n", i, (int)locals [i]->inst_c0);
1498         }
1499
1500         /*
1501          * It is possible that the out bblocks already have in_stack assigned, and
1502          * the in_stacks differ. In this case, we will store to all the different 
1503          * in_stacks.
1504          */
1505
1506         found = TRUE;
1507         bindex = 0;
1508         while (found) {
1509                 /* Find a bblock which has a different in_stack */
1510                 found = FALSE;
1511                 while (bindex < bb->out_count) {
1512                         outb = bb->out_bb [bindex];
1513                         /* exception handlers are linked, but they should not be considered for stack args */
1514                         if (outb->flags & BB_EXCEPTION_HANDLER) {
1515                                 bindex++;
1516                                 continue;
1517                         }
1518                         if (outb->in_stack != locals) {
1519                                 for (i = 0; i < count; ++i) {
1520                                         EMIT_NEW_TEMPSTORE (cfg, inst, outb->in_stack [i]->inst_c0, sp [i]);
1521                                         inst->cil_code = sp [i]->cil_code;
1522                                         sp [i] = locals [i];
1523                                         if (cfg->verbose_level > 3)
1524                                                 printf ("storing %d to temp %d\n", i, (int)outb->in_stack [i]->inst_c0);
1525                                 }
1526                                 locals = outb->in_stack;
1527                                 found = TRUE;
1528                                 break;
1529                         }
1530                         bindex ++;
1531                 }
1532         }
1533 }
1534
1535 static void
1536 mini_emit_interface_bitmap_check (MonoCompile *cfg, int intf_bit_reg, int base_reg, int offset, MonoClass *klass)
1537 {
1538         int ibitmap_reg = alloc_preg (cfg);
1539 #ifdef COMPRESSED_INTERFACE_BITMAP
1540         MonoInst *args [2];
1541         MonoInst *res, *ins;
1542         NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, ibitmap_reg, base_reg, offset);
1543         MONO_ADD_INS (cfg->cbb, ins);
1544         args [0] = ins;
1545         if (cfg->compile_aot)
1546                 EMIT_NEW_AOTCONST (cfg, args [1], MONO_PATCH_INFO_IID, klass);
1547         else
1548                 EMIT_NEW_ICONST (cfg, args [1], klass->interface_id);
1549         res = mono_emit_jit_icall (cfg, mono_class_interface_match, args);
1550         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, intf_bit_reg, res->dreg);
1551 #else
1552         int ibitmap_byte_reg = alloc_preg (cfg);
1553
1554         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, ibitmap_reg, base_reg, offset);
1555
1556         if (cfg->compile_aot) {
1557                 int iid_reg = alloc_preg (cfg);
1558                 int shifted_iid_reg = alloc_preg (cfg);
1559                 int ibitmap_byte_address_reg = alloc_preg (cfg);
1560                 int masked_iid_reg = alloc_preg (cfg);
1561                 int iid_one_bit_reg = alloc_preg (cfg);
1562                 int iid_bit_reg = alloc_preg (cfg);
1563                 MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_IID);
1564                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, shifted_iid_reg, iid_reg, 3);
1565                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, ibitmap_byte_address_reg, ibitmap_reg, shifted_iid_reg);
1566                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, ibitmap_byte_reg, ibitmap_byte_address_reg, 0);
1567                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, masked_iid_reg, iid_reg, 7);
1568                 MONO_EMIT_NEW_ICONST (cfg, iid_one_bit_reg, 1);
1569                 MONO_EMIT_NEW_BIALU (cfg, OP_ISHL, iid_bit_reg, iid_one_bit_reg, masked_iid_reg);
1570                 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, intf_bit_reg, ibitmap_byte_reg, iid_bit_reg);
1571         } else {
1572                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, ibitmap_byte_reg, ibitmap_reg, klass->interface_id >> 3);
1573                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, intf_bit_reg, ibitmap_byte_reg, 1 << (klass->interface_id & 7));
1574         }
1575 #endif
1576 }
1577
1578 /* 
1579  * Emit code which loads into "intf_bit_reg" a nonzero value if the MonoClass
1580  * stored in "klass_reg" implements the interface "klass".
1581  */
1582 static void
1583 mini_emit_load_intf_bit_reg_class (MonoCompile *cfg, int intf_bit_reg, int klass_reg, MonoClass *klass)
1584 {
1585         mini_emit_interface_bitmap_check (cfg, intf_bit_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, interface_bitmap), klass);
1586 }
1587
1588 /* 
1589  * Emit code which loads into "intf_bit_reg" a nonzero value if the MonoVTable
1590  * stored in "vtable_reg" implements the interface "klass".
1591  */
1592 static void
1593 mini_emit_load_intf_bit_reg_vtable (MonoCompile *cfg, int intf_bit_reg, int vtable_reg, MonoClass *klass)
1594 {
1595         mini_emit_interface_bitmap_check (cfg, intf_bit_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, interface_bitmap), klass);
1596 }
1597
1598 /* 
1599  * Emit code which checks whenever the interface id of @klass is smaller than
1600  * than the value given by max_iid_reg.
1601 */
1602 static void
1603 mini_emit_max_iid_check (MonoCompile *cfg, int max_iid_reg, MonoClass *klass,
1604                                                  MonoBasicBlock *false_target)
1605 {
1606         if (cfg->compile_aot) {
1607                 int iid_reg = alloc_preg (cfg);
1608                 MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_IID);
1609                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, max_iid_reg, iid_reg);
1610         }
1611         else
1612                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, max_iid_reg, klass->interface_id);
1613         if (false_target)
1614                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBLT_UN, false_target);
1615         else
1616                 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "InvalidCastException");
1617 }
1618
1619 /* Same as above, but obtains max_iid from a vtable */
1620 static void
1621 mini_emit_max_iid_check_vtable (MonoCompile *cfg, int vtable_reg, MonoClass *klass,
1622                                                                  MonoBasicBlock *false_target)
1623 {
1624         int max_iid_reg = alloc_preg (cfg);
1625                 
1626         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, max_iid_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, max_interface_id));
1627         mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target);
1628 }
1629
1630 /* Same as above, but obtains max_iid from a klass */
1631 static void
1632 mini_emit_max_iid_check_class (MonoCompile *cfg, int klass_reg, MonoClass *klass,
1633                                                                  MonoBasicBlock *false_target)
1634 {
1635         int max_iid_reg = alloc_preg (cfg);
1636
1637         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, max_iid_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, max_interface_id));
1638         mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target);
1639 }
1640
1641 static void
1642 mini_emit_isninst_cast_inst (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoInst *klass_ins, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1643 {
1644         int idepth_reg = alloc_preg (cfg);
1645         int stypes_reg = alloc_preg (cfg);
1646         int stype = alloc_preg (cfg);
1647
1648         mono_class_setup_supertypes (klass);
1649
1650         if (klass->idepth > MONO_DEFAULT_SUPERTABLE_SIZE) {
1651                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, idepth_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, idepth));
1652                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, idepth_reg, klass->idepth);
1653                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBLT_UN, false_target);
1654         }
1655         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stypes_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, supertypes));
1656         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stype, stypes_reg, ((klass->idepth - 1) * SIZEOF_VOID_P));
1657         if (klass_ins) {
1658                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, stype, klass_ins->dreg);
1659         } else if (cfg->compile_aot) {
1660                 int const_reg = alloc_preg (cfg);
1661                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
1662                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, stype, const_reg);
1663         } else {
1664                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, stype, klass);
1665         }
1666         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, true_target);
1667 }
1668
1669 static void
1670 mini_emit_isninst_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1671 {
1672         mini_emit_isninst_cast_inst (cfg, klass_reg, klass, NULL, false_target, true_target);
1673 }
1674
1675 static void
1676 mini_emit_iface_cast (MonoCompile *cfg, int vtable_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1677 {
1678         int intf_reg = alloc_preg (cfg);
1679
1680         mini_emit_max_iid_check_vtable (cfg, vtable_reg, klass, false_target);
1681         mini_emit_load_intf_bit_reg_vtable (cfg, intf_reg, vtable_reg, klass);
1682         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, intf_reg, 0);
1683         if (true_target)
1684                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, true_target);
1685         else
1686                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");               
1687 }
1688
1689 /*
1690  * Variant of the above that takes a register to the class, not the vtable.
1691  */
1692 static void
1693 mini_emit_iface_class_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1694 {
1695         int intf_bit_reg = alloc_preg (cfg);
1696
1697         mini_emit_max_iid_check_class (cfg, klass_reg, klass, false_target);
1698         mini_emit_load_intf_bit_reg_class (cfg, intf_bit_reg, klass_reg, klass);
1699         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, intf_bit_reg, 0);
1700         if (true_target)
1701                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, true_target);
1702         else
1703                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
1704 }
1705
1706 static inline void
1707 mini_emit_class_check_inst (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoInst *klass_inst)
1708 {
1709         if (klass_inst) {
1710                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_inst->dreg);
1711         } else if (cfg->compile_aot) {
1712                 int const_reg = alloc_preg (cfg);
1713                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
1714                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, const_reg);
1715         } else {
1716                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
1717         }
1718         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1719 }
1720
1721 static inline void
1722 mini_emit_class_check (MonoCompile *cfg, int klass_reg, MonoClass *klass)
1723 {
1724         mini_emit_class_check_inst (cfg, klass_reg, klass, NULL);
1725 }
1726
1727 static inline void
1728 mini_emit_class_check_branch (MonoCompile *cfg, int klass_reg, MonoClass *klass, int branch_op, MonoBasicBlock *target)
1729 {
1730         if (cfg->compile_aot) {
1731                 int const_reg = alloc_preg (cfg);
1732                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
1733                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, const_reg);
1734         } else {
1735                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
1736         }
1737         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, branch_op, target);
1738 }
1739
1740 static void
1741 mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoBasicBlock *object_is_null);
1742         
1743 static void
1744 mini_emit_castclass_inst (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoInst *klass_inst, MonoBasicBlock *object_is_null)
1745 {
1746         if (klass->rank) {
1747                 int rank_reg = alloc_preg (cfg);
1748                 int eclass_reg = alloc_preg (cfg);
1749
1750                 g_assert (!klass_inst);
1751                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, rank));
1752                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank);
1753                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1754                 //              MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
1755                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, cast_class));
1756                 if (klass->cast_class == mono_defaults.object_class) {
1757                         int parent_reg = alloc_preg (cfg);
1758                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, parent_reg, eclass_reg, MONO_STRUCT_OFFSET (MonoClass, parent));
1759                         mini_emit_class_check_branch (cfg, parent_reg, mono_defaults.enum_class->parent, OP_PBNE_UN, object_is_null);
1760                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1761                 } else if (klass->cast_class == mono_defaults.enum_class->parent) {
1762                         mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class->parent, OP_PBEQ, object_is_null);
1763                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1764                 } else if (klass->cast_class == mono_defaults.enum_class) {
1765                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1766                 } else if (klass->cast_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1767                         mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, NULL, NULL);
1768                 } else {
1769                         // Pass -1 as obj_reg to skip the check below for arrays of arrays
1770                         mini_emit_castclass (cfg, -1, eclass_reg, klass->cast_class, object_is_null);
1771                 }
1772
1773                 if ((klass->rank == 1) && (klass->byval_arg.type == MONO_TYPE_SZARRAY) && (obj_reg != -1)) {
1774                         /* Check that the object is a vector too */
1775                         int bounds_reg = alloc_preg (cfg);
1776                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, obj_reg, MONO_STRUCT_OFFSET (MonoArray, bounds));
1777                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
1778                         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1779                 }
1780         } else {
1781                 int idepth_reg = alloc_preg (cfg);
1782                 int stypes_reg = alloc_preg (cfg);
1783                 int stype = alloc_preg (cfg);
1784
1785                 mono_class_setup_supertypes (klass);
1786
1787                 if (klass->idepth > MONO_DEFAULT_SUPERTABLE_SIZE) {
1788                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, idepth_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, idepth));
1789                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, idepth_reg, klass->idepth);
1790                         MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "InvalidCastException");
1791                 }
1792                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stypes_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, supertypes));
1793                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stype, stypes_reg, ((klass->idepth - 1) * SIZEOF_VOID_P));
1794                 mini_emit_class_check_inst (cfg, stype, klass, klass_inst);
1795         }
1796 }
1797
1798 static void
1799 mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoBasicBlock *object_is_null)
1800 {
1801         mini_emit_castclass_inst (cfg, obj_reg, klass_reg, klass, NULL, object_is_null);
1802 }
1803
1804 static void 
1805 mini_emit_memset (MonoCompile *cfg, int destreg, int offset, int size, int val, int align)
1806 {
1807         int val_reg;
1808
1809         g_assert (val == 0);
1810
1811         if (align == 0)
1812                 align = 4;
1813
1814         if ((size <= SIZEOF_REGISTER) && (size <= align)) {
1815                 switch (size) {
1816                 case 1:
1817                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, destreg, offset, val);
1818                         return;
1819                 case 2:
1820                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI2_MEMBASE_IMM, destreg, offset, val);
1821                         return;
1822                 case 4:
1823                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI4_MEMBASE_IMM, destreg, offset, val);
1824                         return;
1825 #if SIZEOF_REGISTER == 8
1826                 case 8:
1827                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI8_MEMBASE_IMM, destreg, offset, val);
1828                         return;
1829 #endif
1830                 }
1831         }
1832
1833         val_reg = alloc_preg (cfg);
1834
1835         if (SIZEOF_REGISTER == 8)
1836                 MONO_EMIT_NEW_I8CONST (cfg, val_reg, val);
1837         else
1838                 MONO_EMIT_NEW_ICONST (cfg, val_reg, val);
1839
1840         if (align < 4) {
1841                 /* This could be optimized further if neccesary */
1842                 while (size >= 1) {
1843                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
1844                         offset += 1;
1845                         size -= 1;
1846                 }
1847                 return;
1848         }       
1849
1850 #if !NO_UNALIGNED_ACCESS
1851         if (SIZEOF_REGISTER == 8) {
1852                 if (offset % 8) {
1853                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
1854                         offset += 4;
1855                         size -= 4;
1856                 }
1857                 while (size >= 8) {
1858                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, destreg, offset, val_reg);
1859                         offset += 8;
1860                         size -= 8;
1861                 }
1862         }       
1863 #endif
1864
1865         while (size >= 4) {
1866                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
1867                 offset += 4;
1868                 size -= 4;
1869         }
1870         while (size >= 2) {
1871                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, offset, val_reg);
1872                 offset += 2;
1873                 size -= 2;
1874         }
1875         while (size >= 1) {
1876                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
1877                 offset += 1;
1878                 size -= 1;
1879         }
1880 }
1881
1882 void 
1883 mini_emit_memcpy (MonoCompile *cfg, int destreg, int doffset, int srcreg, int soffset, int size, int align)
1884 {
1885         int cur_reg;
1886
1887         if (align == 0)
1888                 align = 4;
1889
1890         /*FIXME arbitrary hack to avoid unbound code expansion.*/
1891         g_assert (size < 10000);
1892
1893         if (align < 4) {
1894                 /* This could be optimized further if neccesary */
1895                 while (size >= 1) {
1896                         cur_reg = alloc_preg (cfg);
1897                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, cur_reg, srcreg, soffset);
1898                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, doffset, cur_reg);
1899                         doffset += 1;
1900                         soffset += 1;
1901                         size -= 1;
1902                 }
1903         }
1904
1905 #if !NO_UNALIGNED_ACCESS
1906         if (SIZEOF_REGISTER == 8) {
1907                 while (size >= 8) {
1908                         cur_reg = alloc_preg (cfg);
1909                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI8_MEMBASE, cur_reg, srcreg, soffset);
1910                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, destreg, doffset, cur_reg);
1911                         doffset += 8;
1912                         soffset += 8;
1913                         size -= 8;
1914                 }
1915         }       
1916 #endif
1917
1918         while (size >= 4) {
1919                 cur_reg = alloc_preg (cfg);
1920                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, cur_reg, srcreg, soffset);
1921                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, doffset, cur_reg);
1922                 doffset += 4;
1923                 soffset += 4;
1924                 size -= 4;
1925         }
1926         while (size >= 2) {
1927                 cur_reg = alloc_preg (cfg);
1928                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, cur_reg, srcreg, soffset);
1929                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, doffset, cur_reg);
1930                 doffset += 2;
1931                 soffset += 2;
1932                 size -= 2;
1933         }
1934         while (size >= 1) {
1935                 cur_reg = alloc_preg (cfg);
1936                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, cur_reg, srcreg, soffset);
1937                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, doffset, cur_reg);
1938                 doffset += 1;
1939                 soffset += 1;
1940                 size -= 1;
1941         }
1942 }
1943
1944 static void
1945 emit_tls_set (MonoCompile *cfg, int sreg1, int tls_key)
1946 {
1947         MonoInst *ins, *c;
1948
1949         if (cfg->compile_aot) {
1950                 EMIT_NEW_TLS_OFFSETCONST (cfg, c, tls_key);
1951                 MONO_INST_NEW (cfg, ins, OP_TLS_SET_REG);
1952                 ins->sreg1 = sreg1;
1953                 ins->sreg2 = c->dreg;
1954                 MONO_ADD_INS (cfg->cbb, ins);
1955         } else {
1956                 MONO_INST_NEW (cfg, ins, OP_TLS_SET);
1957                 ins->sreg1 = sreg1;
1958                 ins->inst_offset = mini_get_tls_offset (tls_key);
1959                 MONO_ADD_INS (cfg->cbb, ins);
1960         }
1961 }
1962
1963 /*
1964  * emit_push_lmf:
1965  *
1966  *   Emit IR to push the current LMF onto the LMF stack.
1967  */
1968 static void
1969 emit_push_lmf (MonoCompile *cfg)
1970 {
1971         /*
1972          * Emit IR to push the LMF:
1973          * lmf_addr = <lmf_addr from tls>
1974          * lmf->lmf_addr = lmf_addr
1975          * lmf->prev_lmf = *lmf_addr
1976          * *lmf_addr = lmf
1977          */
1978         int lmf_reg, prev_lmf_reg;
1979         MonoInst *ins, *lmf_ins;
1980
1981         if (!cfg->lmf_ir)
1982                 return;
1983
1984         if (cfg->lmf_ir_mono_lmf && mini_tls_get_supported (cfg, TLS_KEY_LMF)) {
1985                 /* Load current lmf */
1986                 lmf_ins = mono_get_lmf_intrinsic (cfg);
1987                 g_assert (lmf_ins);
1988                 MONO_ADD_INS (cfg->cbb, lmf_ins);
1989                 EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
1990                 lmf_reg = ins->dreg;
1991                 /* Save previous_lmf */
1992                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf), lmf_ins->dreg);
1993                 /* Set new LMF */
1994                 emit_tls_set (cfg, lmf_reg, TLS_KEY_LMF);
1995         } else {
1996                 /*
1997                  * Store lmf_addr in a variable, so it can be allocated to a global register.
1998                  */
1999                 if (!cfg->lmf_addr_var)
2000                         cfg->lmf_addr_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2001
2002 #ifdef HOST_WIN32
2003                 ins = mono_get_jit_tls_intrinsic (cfg);
2004                 if (ins) {
2005                         int jit_tls_dreg = ins->dreg;
2006
2007                         MONO_ADD_INS (cfg->cbb, ins);
2008                         lmf_reg = alloc_preg (cfg);
2009                         EMIT_NEW_BIALU_IMM (cfg, lmf_ins, OP_PADD_IMM, lmf_reg, jit_tls_dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, lmf));
2010                 } else {
2011                         lmf_ins = mono_emit_jit_icall (cfg, mono_get_lmf_addr, NULL);
2012                 }
2013 #else
2014                 lmf_ins = mono_get_lmf_addr_intrinsic (cfg);
2015                 if (lmf_ins) {
2016                         MONO_ADD_INS (cfg->cbb, lmf_ins);
2017                 } else {
2018 #ifdef TARGET_IOS
2019                         MonoInst *args [16], *jit_tls_ins, *ins;
2020
2021                         /* Inline mono_get_lmf_addr () */
2022                         /* jit_tls = pthread_getspecific (mono_jit_tls_id); lmf_addr = &jit_tls->lmf; */
2023
2024                         /* Load mono_jit_tls_id */
2025                         if (cfg->compile_aot)
2026                                 EMIT_NEW_AOTCONST (cfg, args [0], MONO_PATCH_INFO_JIT_TLS_ID, NULL);
2027                         else
2028                                 EMIT_NEW_ICONST (cfg, args [0], mono_jit_tls_id);
2029                         /* call pthread_getspecific () */
2030                         jit_tls_ins = mono_emit_jit_icall (cfg, pthread_getspecific, args);
2031                         /* lmf_addr = &jit_tls->lmf */
2032                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, cfg->lmf_addr_var->dreg, jit_tls_ins->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, lmf));
2033                         lmf_ins = ins;
2034 #else
2035                         lmf_ins = mono_emit_jit_icall (cfg, mono_get_lmf_addr, NULL);
2036 #endif
2037                 }
2038 #endif
2039                 lmf_ins->dreg = cfg->lmf_addr_var->dreg;
2040
2041                 EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
2042                 lmf_reg = ins->dreg;
2043
2044                 prev_lmf_reg = alloc_preg (cfg);
2045                 /* Save previous_lmf */
2046                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, cfg->lmf_addr_var->dreg, 0);
2047                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf), prev_lmf_reg);
2048                 /* Set new lmf */
2049                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, cfg->lmf_addr_var->dreg, 0, lmf_reg);
2050         }
2051 }
2052
2053 /*
2054  * emit_pop_lmf:
2055  *
2056  *   Emit IR to pop the current LMF from the LMF stack.
2057  */
2058 static void
2059 emit_pop_lmf (MonoCompile *cfg)
2060 {
2061         int lmf_reg, lmf_addr_reg, prev_lmf_reg;
2062         MonoInst *ins;
2063
2064         if (!cfg->lmf_ir)
2065                 return;
2066
2067         EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
2068         lmf_reg = ins->dreg;
2069
2070         if (cfg->lmf_ir_mono_lmf && mini_tls_get_supported (cfg, TLS_KEY_LMF)) {
2071                 /* Load previous_lmf */
2072                 prev_lmf_reg = alloc_preg (cfg);
2073                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf));
2074                 /* Set new LMF */
2075                 emit_tls_set (cfg, prev_lmf_reg, TLS_KEY_LMF);
2076         } else {
2077                 /*
2078                  * Emit IR to pop the LMF:
2079                  * *(lmf->lmf_addr) = lmf->prev_lmf
2080                  */
2081                 /* This could be called before emit_push_lmf () */
2082                 if (!cfg->lmf_addr_var)
2083                         cfg->lmf_addr_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2084                 lmf_addr_reg = cfg->lmf_addr_var->dreg;
2085
2086                 prev_lmf_reg = alloc_preg (cfg);
2087                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf));
2088                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_addr_reg, 0, prev_lmf_reg);
2089         }
2090 }
2091
2092 static void
2093 emit_instrumentation_call (MonoCompile *cfg, void *func)
2094 {
2095         MonoInst *iargs [1];
2096
2097         /*
2098          * Avoid instrumenting inlined methods since it can
2099          * distort profiling results.
2100          */
2101         if (cfg->method != cfg->current_method)
2102                 return;
2103
2104         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE) {
2105                 EMIT_NEW_METHODCONST (cfg, iargs [0], cfg->method);
2106                 mono_emit_jit_icall (cfg, func, iargs);
2107         }
2108 }
2109
2110 static int
2111 ret_type_to_call_opcode (MonoCompile *cfg, MonoType *type, int calli, int virt)
2112 {
2113 handle_enum:
2114         type = mini_get_underlying_type (type);
2115         switch (type->type) {
2116         case MONO_TYPE_VOID:
2117                 return calli? OP_VOIDCALL_REG: virt? OP_VOIDCALL_MEMBASE: OP_VOIDCALL;
2118         case MONO_TYPE_I1:
2119         case MONO_TYPE_U1:
2120         case MONO_TYPE_I2:
2121         case MONO_TYPE_U2:
2122         case MONO_TYPE_I4:
2123         case MONO_TYPE_U4:
2124                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2125         case MONO_TYPE_I:
2126         case MONO_TYPE_U:
2127         case MONO_TYPE_PTR:
2128         case MONO_TYPE_FNPTR:
2129                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2130         case MONO_TYPE_CLASS:
2131         case MONO_TYPE_STRING:
2132         case MONO_TYPE_OBJECT:
2133         case MONO_TYPE_SZARRAY:
2134         case MONO_TYPE_ARRAY:    
2135                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2136         case MONO_TYPE_I8:
2137         case MONO_TYPE_U8:
2138                 return calli? OP_LCALL_REG: virt? OP_LCALL_MEMBASE: OP_LCALL;
2139         case MONO_TYPE_R4:
2140                 if (cfg->r4fp)
2141                         return calli? OP_RCALL_REG: virt? OP_RCALL_MEMBASE: OP_RCALL;
2142                 else
2143                         return calli? OP_FCALL_REG: virt? OP_FCALL_MEMBASE: OP_FCALL;
2144         case MONO_TYPE_R8:
2145                 return calli? OP_FCALL_REG: virt? OP_FCALL_MEMBASE: OP_FCALL;
2146         case MONO_TYPE_VALUETYPE:
2147                 if (type->data.klass->enumtype) {
2148                         type = mono_class_enum_basetype (type->data.klass);
2149                         goto handle_enum;
2150                 } else
2151                         return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2152         case MONO_TYPE_TYPEDBYREF:
2153                 return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2154         case MONO_TYPE_GENERICINST:
2155                 type = &type->data.generic_class->container_class->byval_arg;
2156                 goto handle_enum;
2157         case MONO_TYPE_VAR:
2158         case MONO_TYPE_MVAR:
2159                 /* gsharedvt */
2160                 return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2161         default:
2162                 g_error ("unknown type 0x%02x in ret_type_to_call_opcode", type->type);
2163         }
2164         return -1;
2165 }
2166
2167 /*
2168  * target_type_is_incompatible:
2169  * @cfg: MonoCompile context
2170  *
2171  * Check that the item @arg on the evaluation stack can be stored
2172  * in the target type (can be a local, or field, etc).
2173  * The cfg arg can be used to check if we need verification or just
2174  * validity checks.
2175  *
2176  * Returns: non-0 value if arg can't be stored on a target.
2177  */
2178 static int
2179 target_type_is_incompatible (MonoCompile *cfg, MonoType *target, MonoInst *arg)
2180 {
2181         MonoType *simple_type;
2182         MonoClass *klass;
2183
2184         if (target->byref) {
2185                 /* FIXME: check that the pointed to types match */
2186                 if (arg->type == STACK_MP)
2187                         return arg->klass != mono_class_from_mono_type (target);
2188                 if (arg->type == STACK_PTR)
2189                         return 0;
2190                 return 1;
2191         }
2192
2193         simple_type = mini_get_underlying_type (target);
2194         switch (simple_type->type) {
2195         case MONO_TYPE_VOID:
2196                 return 1;
2197         case MONO_TYPE_I1:
2198         case MONO_TYPE_U1:
2199         case MONO_TYPE_I2:
2200         case MONO_TYPE_U2:
2201         case MONO_TYPE_I4:
2202         case MONO_TYPE_U4:
2203                 if (arg->type != STACK_I4 && arg->type != STACK_PTR)
2204                         return 1;
2205                 return 0;
2206         case MONO_TYPE_PTR:
2207                 /* STACK_MP is needed when setting pinned locals */
2208                 if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
2209                         return 1;
2210                 return 0;
2211         case MONO_TYPE_I:
2212         case MONO_TYPE_U:
2213         case MONO_TYPE_FNPTR:
2214                 /* 
2215                  * Some opcodes like ldloca returns 'transient pointers' which can be stored in
2216                  * in native int. (#688008).
2217                  */
2218                 if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
2219                         return 1;
2220                 return 0;
2221         case MONO_TYPE_CLASS:
2222         case MONO_TYPE_STRING:
2223         case MONO_TYPE_OBJECT:
2224         case MONO_TYPE_SZARRAY:
2225         case MONO_TYPE_ARRAY:    
2226                 if (arg->type != STACK_OBJ)
2227                         return 1;
2228                 /* FIXME: check type compatibility */
2229                 return 0;
2230         case MONO_TYPE_I8:
2231         case MONO_TYPE_U8:
2232                 if (arg->type != STACK_I8)
2233                         return 1;
2234                 return 0;
2235         case MONO_TYPE_R4:
2236                 if (arg->type != cfg->r4_stack_type)
2237                         return 1;
2238                 return 0;
2239         case MONO_TYPE_R8:
2240                 if (arg->type != STACK_R8)
2241                         return 1;
2242                 return 0;
2243         case MONO_TYPE_VALUETYPE:
2244                 if (arg->type != STACK_VTYPE)
2245                         return 1;
2246                 klass = mono_class_from_mono_type (simple_type);
2247                 if (klass != arg->klass)
2248                         return 1;
2249                 return 0;
2250         case MONO_TYPE_TYPEDBYREF:
2251                 if (arg->type != STACK_VTYPE)
2252                         return 1;
2253                 klass = mono_class_from_mono_type (simple_type);
2254                 if (klass != arg->klass)
2255                         return 1;
2256                 return 0;
2257         case MONO_TYPE_GENERICINST:
2258                 if (mono_type_generic_inst_is_valuetype (simple_type)) {
2259                         if (arg->type != STACK_VTYPE)
2260                                 return 1;
2261                         klass = mono_class_from_mono_type (simple_type);
2262                         /* The second cases is needed when doing partial sharing */
2263                         if (klass != arg->klass && mono_class_from_mono_type (target) != arg->klass)
2264                                 return 1;
2265                         return 0;
2266                 } else {
2267                         if (arg->type != STACK_OBJ)
2268                                 return 1;
2269                         /* FIXME: check type compatibility */
2270                         return 0;
2271                 }
2272         case MONO_TYPE_VAR:
2273         case MONO_TYPE_MVAR:
2274                 g_assert (cfg->gshared);
2275                 if (mini_type_var_is_vt (simple_type)) {
2276                         if (arg->type != STACK_VTYPE)
2277                                 return 1;
2278                 } else {
2279                         if (arg->type != STACK_OBJ)
2280                                 return 1;
2281                 }
2282                 return 0;
2283         default:
2284                 g_error ("unknown type 0x%02x in target_type_is_incompatible", simple_type->type);
2285         }
2286         return 1;
2287 }
2288
2289 /*
2290  * Prepare arguments for passing to a function call.
2291  * Return a non-zero value if the arguments can't be passed to the given
2292  * signature.
2293  * The type checks are not yet complete and some conversions may need
2294  * casts on 32 or 64 bit architectures.
2295  *
2296  * FIXME: implement this using target_type_is_incompatible ()
2297  */
2298 static int
2299 check_call_signature (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args)
2300 {
2301         MonoType *simple_type;
2302         int i;
2303
2304         if (sig->hasthis) {
2305                 if (args [0]->type != STACK_OBJ && args [0]->type != STACK_MP && args [0]->type != STACK_PTR)
2306                         return 1;
2307                 args++;
2308         }
2309         for (i = 0; i < sig->param_count; ++i) {
2310                 if (sig->params [i]->byref) {
2311                         if (args [i]->type != STACK_MP && args [i]->type != STACK_PTR)
2312                                 return 1;
2313                         continue;
2314                 }
2315                 simple_type = mini_get_underlying_type (sig->params [i]);
2316 handle_enum:
2317                 switch (simple_type->type) {
2318                 case MONO_TYPE_VOID:
2319                         return 1;
2320                         continue;
2321                 case MONO_TYPE_I1:
2322                 case MONO_TYPE_U1:
2323                 case MONO_TYPE_I2:
2324                 case MONO_TYPE_U2:
2325                 case MONO_TYPE_I4:
2326                 case MONO_TYPE_U4:
2327                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR)
2328                                 return 1;
2329                         continue;
2330                 case MONO_TYPE_I:
2331                 case MONO_TYPE_U:
2332                 case MONO_TYPE_PTR:
2333                 case MONO_TYPE_FNPTR:
2334                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR && args [i]->type != STACK_MP && args [i]->type != STACK_OBJ)
2335                                 return 1;
2336                         continue;
2337                 case MONO_TYPE_CLASS:
2338                 case MONO_TYPE_STRING:
2339                 case MONO_TYPE_OBJECT:
2340                 case MONO_TYPE_SZARRAY:
2341                 case MONO_TYPE_ARRAY:    
2342                         if (args [i]->type != STACK_OBJ)
2343                                 return 1;
2344                         continue;
2345                 case MONO_TYPE_I8:
2346                 case MONO_TYPE_U8:
2347                         if (args [i]->type != STACK_I8)
2348                                 return 1;
2349                         continue;
2350                 case MONO_TYPE_R4:
2351                         if (args [i]->type != cfg->r4_stack_type)
2352                                 return 1;
2353                         continue;
2354                 case MONO_TYPE_R8:
2355                         if (args [i]->type != STACK_R8)
2356                                 return 1;
2357                         continue;
2358                 case MONO_TYPE_VALUETYPE:
2359                         if (simple_type->data.klass->enumtype) {
2360                                 simple_type = mono_class_enum_basetype (simple_type->data.klass);
2361                                 goto handle_enum;
2362                         }
2363                         if (args [i]->type != STACK_VTYPE)
2364                                 return 1;
2365                         continue;
2366                 case MONO_TYPE_TYPEDBYREF:
2367                         if (args [i]->type != STACK_VTYPE)
2368                                 return 1;
2369                         continue;
2370                 case MONO_TYPE_GENERICINST:
2371                         simple_type = &simple_type->data.generic_class->container_class->byval_arg;
2372                         goto handle_enum;
2373                 case MONO_TYPE_VAR:
2374                 case MONO_TYPE_MVAR:
2375                         /* gsharedvt */
2376                         if (args [i]->type != STACK_VTYPE)
2377                                 return 1;
2378                         continue;
2379                 default:
2380                         g_error ("unknown type 0x%02x in check_call_signature",
2381                                  simple_type->type);
2382                 }
2383         }
2384         return 0;
2385 }
2386
2387 static int
2388 callvirt_to_call (int opcode)
2389 {
2390         switch (opcode) {
2391         case OP_CALL_MEMBASE:
2392                 return OP_CALL;
2393         case OP_VOIDCALL_MEMBASE:
2394                 return OP_VOIDCALL;
2395         case OP_FCALL_MEMBASE:
2396                 return OP_FCALL;
2397         case OP_RCALL_MEMBASE:
2398                 return OP_RCALL;
2399         case OP_VCALL_MEMBASE:
2400                 return OP_VCALL;
2401         case OP_LCALL_MEMBASE:
2402                 return OP_LCALL;
2403         default:
2404                 g_assert_not_reached ();
2405         }
2406
2407         return -1;
2408 }
2409
2410 /* Either METHOD or IMT_ARG needs to be set */
2411 static void
2412 emit_imt_argument (MonoCompile *cfg, MonoCallInst *call, MonoMethod *method, MonoInst *imt_arg)
2413 {
2414         int method_reg;
2415
2416         if (COMPILE_LLVM (cfg)) {
2417                 method_reg = alloc_preg (cfg);
2418
2419                 if (imt_arg) {
2420                         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
2421                 } else if (cfg->compile_aot) {
2422                         MONO_EMIT_NEW_AOTCONST (cfg, method_reg, method, MONO_PATCH_INFO_METHODCONST);
2423                 } else {
2424                         MonoInst *ins;
2425                         MONO_INST_NEW (cfg, ins, OP_PCONST);
2426                         ins->inst_p0 = method;
2427                         ins->dreg = method_reg;
2428                         MONO_ADD_INS (cfg->cbb, ins);
2429                 }
2430
2431 #ifdef ENABLE_LLVM
2432                 call->imt_arg_reg = method_reg;
2433 #endif
2434         mono_call_inst_add_outarg_reg (cfg, call, method_reg, MONO_ARCH_IMT_REG, FALSE);
2435                 return;
2436         }
2437
2438         method_reg = alloc_preg (cfg);
2439
2440         if (imt_arg) {
2441                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
2442         } else if (cfg->compile_aot) {
2443                 MONO_EMIT_NEW_AOTCONST (cfg, method_reg, method, MONO_PATCH_INFO_METHODCONST);
2444         } else {
2445                 MonoInst *ins;
2446                 MONO_INST_NEW (cfg, ins, OP_PCONST);
2447                 ins->inst_p0 = method;
2448                 ins->dreg = method_reg;
2449                 MONO_ADD_INS (cfg->cbb, ins);
2450         }
2451
2452         mono_call_inst_add_outarg_reg (cfg, call, method_reg, MONO_ARCH_IMT_REG, FALSE);
2453 }
2454
2455 static MonoJumpInfo *
2456 mono_patch_info_new (MonoMemPool *mp, int ip, MonoJumpInfoType type, gconstpointer target)
2457 {
2458         MonoJumpInfo *ji = mono_mempool_alloc (mp, sizeof (MonoJumpInfo));
2459
2460         ji->ip.i = ip;
2461         ji->type = type;
2462         ji->data.target = target;
2463
2464         return ji;
2465 }
2466
2467 static int
2468 mini_class_check_context_used (MonoCompile *cfg, MonoClass *klass)
2469 {
2470         if (cfg->gshared)
2471                 return mono_class_check_context_used (klass);
2472         else
2473                 return 0;
2474 }
2475
2476 static int
2477 mini_method_check_context_used (MonoCompile *cfg, MonoMethod *method)
2478 {
2479         if (cfg->gshared)
2480                 return mono_method_check_context_used (method);
2481         else
2482                 return 0;
2483 }
2484
2485 /*
2486  * check_method_sharing:
2487  *
2488  *   Check whenever the vtable or an mrgctx needs to be passed when calling CMETHOD.
2489  */
2490 static void
2491 check_method_sharing (MonoCompile *cfg, MonoMethod *cmethod, gboolean *out_pass_vtable, gboolean *out_pass_mrgctx)
2492 {
2493         gboolean pass_vtable = FALSE;
2494         gboolean pass_mrgctx = FALSE;
2495
2496         if (((cmethod->flags & METHOD_ATTRIBUTE_STATIC) || cmethod->klass->valuetype) &&
2497                 (cmethod->klass->generic_class || cmethod->klass->generic_container)) {
2498                 gboolean sharable = FALSE;
2499
2500                 if (mono_method_is_generic_sharable_full (cmethod, TRUE, TRUE, TRUE))
2501                         sharable = TRUE;
2502
2503                 /*
2504                  * Pass vtable iff target method might
2505                  * be shared, which means that sharing
2506                  * is enabled for its class and its
2507                  * context is sharable (and it's not a
2508                  * generic method).
2509                  */
2510                 if (sharable && !(mini_method_get_context (cmethod) && mini_method_get_context (cmethod)->method_inst))
2511                         pass_vtable = TRUE;
2512         }
2513
2514         if (mini_method_get_context (cmethod) &&
2515                 mini_method_get_context (cmethod)->method_inst) {
2516                 g_assert (!pass_vtable);
2517
2518                 if (mono_method_is_generic_sharable_full (cmethod, TRUE, TRUE, TRUE)) {
2519                         pass_mrgctx = TRUE;
2520                 } else {
2521                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (mono_method_signature (cmethod)))
2522                                 pass_mrgctx = TRUE;
2523                 }
2524         }
2525
2526         if (out_pass_vtable)
2527                 *out_pass_vtable = pass_vtable;
2528         if (out_pass_mrgctx)
2529                 *out_pass_mrgctx = pass_mrgctx;
2530 }
2531
2532 inline static MonoCallInst *
2533 mono_emit_call_args (MonoCompile *cfg, MonoMethodSignature *sig, 
2534                                          MonoInst **args, int calli, int virtual, int tail, int rgctx, int unbox_trampoline)
2535 {
2536         MonoType *sig_ret;
2537         MonoCallInst *call;
2538 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
2539         int i;
2540 #endif
2541
2542         if (tail) {
2543                 emit_instrumentation_call (cfg, mono_profiler_method_leave);
2544
2545                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
2546         } else
2547                 MONO_INST_NEW_CALL (cfg, call, ret_type_to_call_opcode (cfg, sig->ret, calli, virtual));
2548
2549         call->args = args;
2550         call->signature = sig;
2551         call->rgctx_reg = rgctx;
2552         sig_ret = mini_get_underlying_type (sig->ret);
2553
2554         type_to_eval_stack_type ((cfg), sig_ret, &call->inst);
2555
2556         if (tail) {
2557                 if (mini_type_is_vtype (sig_ret)) {
2558                         call->vret_var = cfg->vret_addr;
2559                         //g_assert_not_reached ();
2560                 }
2561         } else if (mini_type_is_vtype (sig_ret)) {
2562                 MonoInst *temp = mono_compile_create_var (cfg, sig_ret, OP_LOCAL);
2563                 MonoInst *loada;
2564
2565                 temp->backend.is_pinvoke = sig->pinvoke;
2566
2567                 /*
2568                  * We use a new opcode OP_OUTARG_VTRETADDR instead of LDADDR for emitting the
2569                  * address of return value to increase optimization opportunities.
2570                  * Before vtype decomposition, the dreg of the call ins itself represents the
2571                  * fact the call modifies the return value. After decomposition, the call will
2572                  * be transformed into one of the OP_VOIDCALL opcodes, and the VTRETADDR opcode
2573                  * will be transformed into an LDADDR.
2574                  */
2575                 MONO_INST_NEW (cfg, loada, OP_OUTARG_VTRETADDR);
2576                 loada->dreg = alloc_preg (cfg);
2577                 loada->inst_p0 = temp;
2578                 /* We reference the call too since call->dreg could change during optimization */
2579                 loada->inst_p1 = call;
2580                 MONO_ADD_INS (cfg->cbb, loada);
2581
2582                 call->inst.dreg = temp->dreg;
2583
2584                 call->vret_var = loada;
2585         } else if (!MONO_TYPE_IS_VOID (sig_ret))
2586                 call->inst.dreg = alloc_dreg (cfg, call->inst.type);
2587
2588 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
2589         if (COMPILE_SOFT_FLOAT (cfg)) {
2590                 /* 
2591                  * If the call has a float argument, we would need to do an r8->r4 conversion using 
2592                  * an icall, but that cannot be done during the call sequence since it would clobber
2593                  * the call registers + the stack. So we do it before emitting the call.
2594                  */
2595                 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
2596                         MonoType *t;
2597                         MonoInst *in = call->args [i];
2598
2599                         if (i >= sig->hasthis)
2600                                 t = sig->params [i - sig->hasthis];
2601                         else
2602                                 t = &mono_defaults.int_class->byval_arg;
2603                         t = mono_type_get_underlying_type (t);
2604
2605                         if (!t->byref && t->type == MONO_TYPE_R4) {
2606                                 MonoInst *iargs [1];
2607                                 MonoInst *conv;
2608
2609                                 iargs [0] = in;
2610                                 conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
2611
2612                                 /* The result will be in an int vreg */
2613                                 call->args [i] = conv;
2614                         }
2615                 }
2616         }
2617 #endif
2618
2619         call->need_unbox_trampoline = unbox_trampoline;
2620
2621 #ifdef ENABLE_LLVM
2622         if (COMPILE_LLVM (cfg))
2623                 mono_llvm_emit_call (cfg, call);
2624         else
2625                 mono_arch_emit_call (cfg, call);
2626 #else
2627         mono_arch_emit_call (cfg, call);
2628 #endif
2629
2630         cfg->param_area = MAX (cfg->param_area, call->stack_usage);
2631         cfg->flags |= MONO_CFG_HAS_CALLS;
2632         
2633         return call;
2634 }
2635
2636 static void
2637 set_rgctx_arg (MonoCompile *cfg, MonoCallInst *call, int rgctx_reg, MonoInst *rgctx_arg)
2638 {
2639 #ifdef MONO_ARCH_RGCTX_REG
2640         mono_call_inst_add_outarg_reg (cfg, call, rgctx_reg, MONO_ARCH_RGCTX_REG, FALSE);
2641         cfg->uses_rgctx_reg = TRUE;
2642         call->rgctx_reg = TRUE;
2643 #ifdef ENABLE_LLVM
2644         call->rgctx_arg_reg = rgctx_reg;
2645 #endif
2646 #else
2647         NOT_IMPLEMENTED;
2648 #endif
2649 }       
2650
2651 inline static MonoInst*
2652 mono_emit_calli (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args, MonoInst *addr, MonoInst *imt_arg, MonoInst *rgctx_arg)
2653 {
2654         MonoCallInst *call;
2655         MonoInst *ins;
2656         int rgctx_reg = -1;
2657         gboolean check_sp = FALSE;
2658
2659         if (cfg->check_pinvoke_callconv && cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
2660                 WrapperInfo *info = mono_marshal_get_wrapper_info (cfg->method);
2661
2662                 if (info && info->subtype == WRAPPER_SUBTYPE_PINVOKE)
2663                         check_sp = TRUE;
2664         }
2665
2666         if (rgctx_arg) {
2667                 rgctx_reg = mono_alloc_preg (cfg);
2668                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, rgctx_arg->dreg);
2669         }
2670
2671         if (check_sp) {
2672                 if (!cfg->stack_inbalance_var)
2673                         cfg->stack_inbalance_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2674
2675                 MONO_INST_NEW (cfg, ins, OP_GET_SP);
2676                 ins->dreg = cfg->stack_inbalance_var->dreg;
2677                 MONO_ADD_INS (cfg->cbb, ins);
2678         }
2679
2680         call = mono_emit_call_args (cfg, sig, args, TRUE, FALSE, FALSE, rgctx_arg ? TRUE : FALSE, FALSE);
2681
2682         call->inst.sreg1 = addr->dreg;
2683
2684         if (imt_arg)
2685                 emit_imt_argument (cfg, call, NULL, imt_arg);
2686
2687         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2688
2689         if (check_sp) {
2690                 int sp_reg;
2691
2692                 sp_reg = mono_alloc_preg (cfg);
2693
2694                 MONO_INST_NEW (cfg, ins, OP_GET_SP);
2695                 ins->dreg = sp_reg;
2696                 MONO_ADD_INS (cfg->cbb, ins);
2697
2698                 /* Restore the stack so we don't crash when throwing the exception */
2699                 MONO_INST_NEW (cfg, ins, OP_SET_SP);
2700                 ins->sreg1 = cfg->stack_inbalance_var->dreg;
2701                 MONO_ADD_INS (cfg->cbb, ins);
2702
2703                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, cfg->stack_inbalance_var->dreg, sp_reg);
2704                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "ExecutionEngineException");
2705         }
2706
2707         if (rgctx_arg)
2708                 set_rgctx_arg (cfg, call, rgctx_reg, rgctx_arg);
2709
2710         return (MonoInst*)call;
2711 }
2712
2713 static MonoInst*
2714 emit_get_gsharedvt_info_klass (MonoCompile *cfg, MonoClass *klass, MonoRgctxInfoType rgctx_type);
2715
2716 static MonoInst*
2717 emit_get_rgctx_method (MonoCompile *cfg, int context_used, MonoMethod *cmethod, MonoRgctxInfoType rgctx_type);
2718 static MonoInst*
2719 emit_get_rgctx_klass (MonoCompile *cfg, int context_used, MonoClass *klass, MonoRgctxInfoType rgctx_type);
2720
2721 static MonoInst*
2722 mono_emit_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSignature *sig, gboolean tail,
2723                                                         MonoInst **args, MonoInst *this_ins, MonoInst *imt_arg, MonoInst *rgctx_arg)
2724 {
2725 #ifndef DISABLE_REMOTING
2726         gboolean might_be_remote = FALSE;
2727 #endif
2728         gboolean virtual = this_ins != NULL;
2729         gboolean enable_for_aot = TRUE;
2730         int context_used;
2731         MonoCallInst *call;
2732         int rgctx_reg = 0;
2733         gboolean need_unbox_trampoline;
2734
2735         if (!sig)
2736                 sig = mono_method_signature (method);
2737
2738         if (rgctx_arg) {
2739                 rgctx_reg = mono_alloc_preg (cfg);
2740                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, rgctx_arg->dreg);
2741         }
2742
2743         if (method->string_ctor) {
2744                 /* Create the real signature */
2745                 /* FIXME: Cache these */
2746                 MonoMethodSignature *ctor_sig = mono_metadata_signature_dup_mempool (cfg->mempool, sig);
2747                 ctor_sig->ret = &mono_defaults.string_class->byval_arg;
2748
2749                 sig = ctor_sig;
2750         }
2751
2752         context_used = mini_method_check_context_used (cfg, method);
2753
2754 #ifndef DISABLE_REMOTING
2755         might_be_remote = this_ins && sig->hasthis &&
2756                 (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class) &&
2757                 !(method->flags & METHOD_ATTRIBUTE_VIRTUAL) && (!MONO_CHECK_THIS (this_ins) || context_used);
2758
2759         if (might_be_remote && context_used) {
2760                 MonoInst *addr;
2761
2762                 g_assert (cfg->gshared);
2763
2764                 addr = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK);
2765
2766                 return mono_emit_calli (cfg, sig, args, addr, NULL, NULL);
2767         }
2768 #endif
2769
2770         need_unbox_trampoline = method->klass == mono_defaults.object_class || (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE);
2771
2772         call = mono_emit_call_args (cfg, sig, args, FALSE, virtual, tail, rgctx_arg ? TRUE : FALSE, need_unbox_trampoline);
2773
2774 #ifndef DISABLE_REMOTING
2775         if (might_be_remote)
2776                 call->method = mono_marshal_get_remoting_invoke_with_check (method);
2777         else
2778 #endif
2779                 call->method = method;
2780         call->inst.flags |= MONO_INST_HAS_METHOD;
2781         call->inst.inst_left = this_ins;
2782         call->tail_call = tail;
2783
2784         if (virtual) {
2785                 int vtable_reg, slot_reg, this_reg;
2786                 int offset;
2787
2788                 this_reg = this_ins->dreg;
2789
2790                 if ((method->klass->parent == mono_defaults.multicastdelegate_class) && !strcmp (method->name, "Invoke")) {
2791                         MonoInst *dummy_use;
2792
2793                         MONO_EMIT_NULL_CHECK (cfg, this_reg);
2794
2795                         /* Make a call to delegate->invoke_impl */
2796                         call->inst.inst_basereg = this_reg;
2797                         call->inst.inst_offset = MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl);
2798                         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2799
2800                         /* We must emit a dummy use here because the delegate trampoline will
2801                         replace the 'this' argument with the delegate target making this activation
2802                         no longer a root for the delegate.
2803                         This is an issue for delegates that target collectible code such as dynamic
2804                         methods of GC'able assemblies.
2805
2806                         For a test case look into #667921.
2807
2808                         FIXME: a dummy use is not the best way to do it as the local register allocator
2809                         will put it on a caller save register and spil it around the call. 
2810                         Ideally, we would either put it on a callee save register or only do the store part.  
2811                          */
2812                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, args [0]);
2813
2814                         return (MonoInst*)call;
2815                 }
2816
2817                 if ((!cfg->compile_aot || enable_for_aot) && 
2818                         (!(method->flags & METHOD_ATTRIBUTE_VIRTUAL) || 
2819                          (MONO_METHOD_IS_FINAL (method) &&
2820                           method->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK)) &&
2821                         !(mono_class_is_marshalbyref (method->klass) && context_used)) {
2822                         /* 
2823                          * the method is not virtual, we just need to ensure this is not null
2824                          * and then we can call the method directly.
2825                          */
2826 #ifndef DISABLE_REMOTING
2827                         if (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class) {
2828                                 /* 
2829                                  * The check above ensures method is not gshared, this is needed since
2830                                  * gshared methods can't have wrappers.
2831                                  */
2832                                 method = call->method = mono_marshal_get_remoting_invoke_with_check (method);
2833                         }
2834 #endif
2835
2836                         if (!method->string_ctor)
2837                                 MONO_EMIT_NEW_CHECK_THIS (cfg, this_reg);
2838
2839                         call->inst.opcode = callvirt_to_call (call->inst.opcode);
2840                 } else if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) && MONO_METHOD_IS_FINAL (method)) {
2841                         /*
2842                          * the method is virtual, but we can statically dispatch since either
2843                          * it's class or the method itself are sealed.
2844                          * But first we need to ensure it's not a null reference.
2845                          */
2846                         MONO_EMIT_NEW_CHECK_THIS (cfg, this_reg);
2847
2848                         call->inst.opcode = callvirt_to_call (call->inst.opcode);
2849                 } else {
2850                         vtable_reg = alloc_preg (cfg);
2851                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
2852                         if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2853                                 guint32 imt_slot = mono_method_get_imt_slot (method);
2854                                 emit_imt_argument (cfg, call, call->method, imt_arg);
2855                                 slot_reg = vtable_reg;
2856                                 offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
2857                         } else {
2858                                 slot_reg = vtable_reg;
2859                                 offset = MONO_STRUCT_OFFSET (MonoVTable, vtable) +
2860                                         ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
2861                                 if (imt_arg) {
2862                                         g_assert (mono_method_signature (method)->generic_param_count);
2863                                         emit_imt_argument (cfg, call, call->method, imt_arg);
2864                                 }
2865                         }
2866
2867                         call->inst.sreg1 = slot_reg;
2868                         call->inst.inst_offset = offset;
2869                         call->virtual = TRUE;
2870                 }
2871         }
2872
2873         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2874
2875         if (rgctx_arg)
2876                 set_rgctx_arg (cfg, call, rgctx_reg, rgctx_arg);
2877
2878         return (MonoInst*)call;
2879 }
2880
2881 MonoInst*
2882 mono_emit_method_call (MonoCompile *cfg, MonoMethod *method, MonoInst **args, MonoInst *this_ins)
2883 {
2884         return mono_emit_method_call_full (cfg, method, mono_method_signature (method), FALSE, args, this_ins, NULL, NULL);
2885 }
2886
2887 MonoInst*
2888 mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig,
2889                                            MonoInst **args)
2890 {
2891         MonoCallInst *call;
2892
2893         g_assert (sig);
2894
2895         call = mono_emit_call_args (cfg, sig, args, FALSE, FALSE, FALSE, FALSE, FALSE);
2896         call->fptr = func;
2897
2898         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2899
2900         return (MonoInst*)call;
2901 }
2902
2903 MonoInst*
2904 mono_emit_jit_icall (MonoCompile *cfg, gconstpointer func, MonoInst **args)
2905 {
2906         MonoJitICallInfo *info = mono_find_jit_icall_by_addr (func);
2907
2908         g_assert (info);
2909
2910         return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
2911 }
2912
2913 /*
2914  * mono_emit_abs_call:
2915  *
2916  *   Emit a call to the runtime function described by PATCH_TYPE and DATA.
2917  */
2918 inline static MonoInst*
2919 mono_emit_abs_call (MonoCompile *cfg, MonoJumpInfoType patch_type, gconstpointer data, 
2920                                         MonoMethodSignature *sig, MonoInst **args)
2921 {
2922         MonoJumpInfo *ji = mono_patch_info_new (cfg->mempool, 0, patch_type, data);
2923         MonoInst *ins;
2924
2925         /* 
2926          * We pass ji as the call address, the PATCH_INFO_ABS resolving code will
2927          * handle it.
2928          */
2929         if (cfg->abs_patches == NULL)
2930                 cfg->abs_patches = g_hash_table_new (NULL, NULL);
2931         g_hash_table_insert (cfg->abs_patches, ji, ji);
2932         ins = mono_emit_native_call (cfg, ji, sig, args);
2933         ((MonoCallInst*)ins)->fptr_is_patch = TRUE;
2934         return ins;
2935 }
2936
2937 static gboolean
2938 direct_icalls_enabled (MonoCompile *cfg)
2939 {
2940         /* LLVM on amd64 can't handle calls to non-32 bit addresses */
2941 #ifdef TARGET_AMD64
2942         if (cfg->compile_llvm)
2943                 return FALSE;
2944 #endif
2945         if (cfg->gen_sdb_seq_points || cfg->disable_direct_icalls)
2946                 return FALSE;
2947         return TRUE;
2948 }
2949
2950 MonoInst*
2951 mono_emit_jit_icall_by_info (MonoCompile *cfg, MonoJitICallInfo *info, MonoInst **args)
2952 {
2953         /*
2954          * Call the jit icall without a wrapper if possible.
2955          * The wrapper is needed for the following reasons:
2956          * - to handle exceptions thrown using mono_raise_exceptions () from the
2957          *   icall function. The EH code needs the lmf frame pushed by the
2958          *   wrapper to be able to unwind back to managed code.
2959          * - to be able to do stack walks for asynchronously suspended
2960          *   threads when debugging.
2961          */
2962         if (info->no_raise && direct_icalls_enabled (cfg)) {
2963                 char *name;
2964                 int costs;
2965
2966                 if (!info->wrapper_method) {
2967                         name = g_strdup_printf ("__icall_wrapper_%s", info->name);
2968                         info->wrapper_method = mono_marshal_get_icall_wrapper (info->sig, name, info->func, TRUE);
2969                         g_free (name);
2970                         mono_memory_barrier ();
2971                 }
2972
2973                 /*
2974                  * Inline the wrapper method, which is basically a call to the C icall, and
2975                  * an exception check.
2976                  */
2977                 costs = inline_method (cfg, info->wrapper_method, NULL,
2978                                                            args, NULL, cfg->real_offset, TRUE);
2979                 g_assert (costs > 0);
2980                 g_assert (!MONO_TYPE_IS_VOID (info->sig->ret));
2981
2982                 return args [0];
2983         } else {
2984                 return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
2985         }
2986 }
2987  
2988 static MonoInst*
2989 mono_emit_widen_call_res (MonoCompile *cfg, MonoInst *ins, MonoMethodSignature *fsig)
2990 {
2991         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
2992                 if ((fsig->pinvoke || LLVM_ENABLED) && !fsig->ret->byref) {
2993                         int widen_op = -1;
2994
2995                         /* 
2996                          * Native code might return non register sized integers 
2997                          * without initializing the upper bits.
2998                          */
2999                         switch (mono_type_to_load_membase (cfg, fsig->ret)) {
3000                         case OP_LOADI1_MEMBASE:
3001                                 widen_op = OP_ICONV_TO_I1;
3002                                 break;
3003                         case OP_LOADU1_MEMBASE:
3004                                 widen_op = OP_ICONV_TO_U1;
3005                                 break;
3006                         case OP_LOADI2_MEMBASE:
3007                                 widen_op = OP_ICONV_TO_I2;
3008                                 break;
3009                         case OP_LOADU2_MEMBASE:
3010                                 widen_op = OP_ICONV_TO_U2;
3011                                 break;
3012                         default:
3013                                 break;
3014                         }
3015
3016                         if (widen_op != -1) {
3017                                 int dreg = alloc_preg (cfg);
3018                                 MonoInst *widen;
3019
3020                                 EMIT_NEW_UNALU (cfg, widen, widen_op, dreg, ins->dreg);
3021                                 widen->type = ins->type;
3022                                 ins = widen;
3023                         }
3024                 }
3025         }
3026
3027         return ins;
3028 }
3029
3030 static MonoMethod*
3031 get_memcpy_method (void)
3032 {
3033         static MonoMethod *memcpy_method = NULL;
3034         if (!memcpy_method) {
3035                 memcpy_method = mono_class_get_method_from_name (mono_defaults.string_class, "memcpy", 3);
3036                 if (!memcpy_method)
3037                         g_error ("Old corlib found. Install a new one");
3038         }
3039         return memcpy_method;
3040 }
3041
3042 static void
3043 create_write_barrier_bitmap (MonoCompile *cfg, MonoClass *klass, unsigned *wb_bitmap, int offset)
3044 {
3045         MonoClassField *field;
3046         gpointer iter = NULL;
3047
3048         while ((field = mono_class_get_fields (klass, &iter))) {
3049                 int foffset;
3050
3051                 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
3052                         continue;
3053                 foffset = klass->valuetype ? field->offset - sizeof (MonoObject): field->offset;
3054                 if (mini_type_is_reference (mono_field_get_type (field))) {
3055                         g_assert ((foffset % SIZEOF_VOID_P) == 0);
3056                         *wb_bitmap |= 1 << ((offset + foffset) / SIZEOF_VOID_P);
3057                 } else {
3058                         MonoClass *field_class = mono_class_from_mono_type (field->type);
3059                         if (field_class->has_references)
3060                                 create_write_barrier_bitmap (cfg, field_class, wb_bitmap, offset + foffset);
3061                 }
3062         }
3063 }
3064
3065 static void
3066 emit_write_barrier (MonoCompile *cfg, MonoInst *ptr, MonoInst *value)
3067 {
3068         int card_table_shift_bits;
3069         gpointer card_table_mask;
3070         guint8 *card_table;
3071         MonoInst *dummy_use;
3072         int nursery_shift_bits;
3073         size_t nursery_size;
3074         gboolean has_card_table_wb = FALSE;
3075
3076         if (!cfg->gen_write_barriers)
3077                 return;
3078
3079         card_table = mono_gc_get_card_table (&card_table_shift_bits, &card_table_mask);
3080
3081         mono_gc_get_nursery (&nursery_shift_bits, &nursery_size);
3082
3083 #ifdef MONO_ARCH_HAVE_CARD_TABLE_WBARRIER
3084         has_card_table_wb = TRUE;
3085 #endif
3086
3087         if (has_card_table_wb && !cfg->compile_aot && card_table && nursery_shift_bits > 0 && !COMPILE_LLVM (cfg)) {
3088                 MonoInst *wbarrier;
3089
3090                 MONO_INST_NEW (cfg, wbarrier, OP_CARD_TABLE_WBARRIER);
3091                 wbarrier->sreg1 = ptr->dreg;
3092                 wbarrier->sreg2 = value->dreg;
3093                 MONO_ADD_INS (cfg->cbb, wbarrier);
3094         } else if (card_table && !cfg->compile_aot && !mono_gc_card_table_nursery_check ()) {
3095                 int offset_reg = alloc_preg (cfg);
3096                 int card_reg  = alloc_preg (cfg);
3097                 MonoInst *ins;
3098
3099                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_UN_IMM, offset_reg, ptr->dreg, card_table_shift_bits);
3100                 if (card_table_mask)
3101                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, offset_reg, offset_reg, card_table_mask);
3102
3103                 /*We can't use PADD_IMM since the cardtable might end up in high addresses and amd64 doesn't support
3104                  * IMM's larger than 32bits.
3105                  */
3106                 if (cfg->compile_aot) {
3107                         MONO_EMIT_NEW_AOTCONST (cfg, card_reg, NULL, MONO_PATCH_INFO_GC_CARD_TABLE_ADDR);
3108                 } else {
3109                         MONO_INST_NEW (cfg, ins, OP_PCONST);
3110                         ins->inst_p0 = card_table;
3111                         ins->dreg = card_reg;
3112                         MONO_ADD_INS (cfg->cbb, ins);
3113                 }
3114
3115                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, offset_reg, offset_reg, card_reg);
3116                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, offset_reg, 0, 1);
3117         } else {
3118                 MonoMethod *write_barrier = mono_gc_get_write_barrier ();
3119                 mono_emit_method_call (cfg, write_barrier, &ptr, NULL);
3120         }
3121
3122         EMIT_NEW_DUMMY_USE (cfg, dummy_use, value);
3123 }
3124
3125 static gboolean
3126 mono_emit_wb_aware_memcpy (MonoCompile *cfg, MonoClass *klass, MonoInst *iargs[4], int size, int align)
3127 {
3128         int dest_ptr_reg, tmp_reg, destreg, srcreg, offset;
3129         unsigned need_wb = 0;
3130
3131         if (align == 0)
3132                 align = 4;
3133
3134         /*types with references can't have alignment smaller than sizeof(void*) */
3135         if (align < SIZEOF_VOID_P)
3136                 return FALSE;
3137
3138         /*This value cannot be bigger than 32 due to the way we calculate the required wb bitmap.*/
3139         if (size > 32 * SIZEOF_VOID_P)
3140                 return FALSE;
3141
3142         create_write_barrier_bitmap (cfg, klass, &need_wb, 0);
3143
3144         /* We don't unroll more than 5 stores to avoid code bloat. */
3145         if (size > 5 * SIZEOF_VOID_P) {
3146                 /*This is harmless and simplify mono_gc_wbarrier_value_copy_bitmap */
3147                 size += (SIZEOF_VOID_P - 1);
3148                 size &= ~(SIZEOF_VOID_P - 1);
3149
3150                 EMIT_NEW_ICONST (cfg, iargs [2], size);
3151                 EMIT_NEW_ICONST (cfg, iargs [3], need_wb);
3152                 mono_emit_jit_icall (cfg, mono_gc_wbarrier_value_copy_bitmap, iargs);
3153                 return TRUE;
3154         }
3155
3156         destreg = iargs [0]->dreg;
3157         srcreg = iargs [1]->dreg;
3158         offset = 0;
3159
3160         dest_ptr_reg = alloc_preg (cfg);
3161         tmp_reg = alloc_preg (cfg);
3162
3163         /*tmp = dreg*/
3164         EMIT_NEW_UNALU (cfg, iargs [0], OP_MOVE, dest_ptr_reg, destreg);
3165
3166         while (size >= SIZEOF_VOID_P) {
3167                 MonoInst *load_inst;
3168                 MONO_INST_NEW (cfg, load_inst, OP_LOAD_MEMBASE);
3169                 load_inst->dreg = tmp_reg;
3170                 load_inst->inst_basereg = srcreg;
3171                 load_inst->inst_offset = offset;
3172                 MONO_ADD_INS (cfg->cbb, load_inst);
3173
3174                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, dest_ptr_reg, 0, tmp_reg);
3175
3176                 if (need_wb & 0x1)
3177                         emit_write_barrier (cfg, iargs [0], load_inst);
3178
3179                 offset += SIZEOF_VOID_P;
3180                 size -= SIZEOF_VOID_P;
3181                 need_wb >>= 1;
3182
3183                 /*tmp += sizeof (void*)*/
3184                 if (size >= SIZEOF_VOID_P) {
3185                         NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, dest_ptr_reg, dest_ptr_reg, SIZEOF_VOID_P);
3186                         MONO_ADD_INS (cfg->cbb, iargs [0]);
3187                 }
3188         }
3189
3190         /* Those cannot be references since size < sizeof (void*) */
3191         while (size >= 4) {
3192                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, tmp_reg, srcreg, offset);
3193                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, tmp_reg);
3194                 offset += 4;
3195                 size -= 4;
3196         }
3197
3198         while (size >= 2) {
3199                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, tmp_reg, srcreg, offset);
3200                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, offset, tmp_reg);
3201                 offset += 2;
3202                 size -= 2;
3203         }
3204
3205         while (size >= 1) {
3206                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, tmp_reg, srcreg, offset);
3207                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, tmp_reg);
3208                 offset += 1;
3209                 size -= 1;
3210         }
3211
3212         return TRUE;
3213 }
3214
3215 /*
3216  * Emit code to copy a valuetype of type @klass whose address is stored in
3217  * @src->dreg to memory whose address is stored at @dest->dreg.
3218  */
3219 void
3220 mini_emit_stobj (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *klass, gboolean native)
3221 {
3222         MonoInst *iargs [4];
3223         int n;
3224         guint32 align = 0;
3225         MonoMethod *memcpy_method;
3226         MonoInst *size_ins = NULL;
3227         MonoInst *memcpy_ins = NULL;
3228
3229         g_assert (klass);
3230         if (cfg->gshared)
3231                 klass = mono_class_from_mono_type (mini_get_underlying_type (&klass->byval_arg));
3232
3233         /*
3234          * This check breaks with spilled vars... need to handle it during verification anyway.
3235          * g_assert (klass && klass == src->klass && klass == dest->klass);
3236          */
3237
3238         if (mini_is_gsharedvt_klass (klass)) {
3239                 g_assert (!native);
3240                 size_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_VALUE_SIZE);
3241                 memcpy_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_MEMCPY);
3242         }
3243
3244         if (native)
3245                 n = mono_class_native_size (klass, &align);
3246         else
3247                 n = mono_class_value_size (klass, &align);
3248
3249         /* if native is true there should be no references in the struct */
3250         if (cfg->gen_write_barriers && (klass->has_references || size_ins) && !native) {
3251                 /* Avoid barriers when storing to the stack */
3252                 if (!((dest->opcode == OP_ADD_IMM && dest->sreg1 == cfg->frame_reg) ||
3253                           (dest->opcode == OP_LDADDR))) {
3254                         int context_used;
3255
3256                         iargs [0] = dest;
3257                         iargs [1] = src;
3258
3259                         context_used = mini_class_check_context_used (cfg, klass);
3260
3261                         /* It's ok to intrinsify under gsharing since shared code types are layout stable. */
3262                         if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && mono_emit_wb_aware_memcpy (cfg, klass, iargs, n, align)) {
3263                                 return;
3264                         } else if (context_used) {
3265                                 iargs [2] = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
3266                         }  else {
3267                                 if (cfg->compile_aot) {
3268                                         EMIT_NEW_CLASSCONST (cfg, iargs [2], klass);
3269                                 } else {
3270                                         EMIT_NEW_PCONST (cfg, iargs [2], klass);
3271                                         mono_class_compute_gc_descriptor (klass);
3272                                 }
3273                         }
3274
3275                         if (size_ins)
3276                                 mono_emit_jit_icall (cfg, mono_gsharedvt_value_copy, iargs);
3277                         else
3278                                 mono_emit_jit_icall (cfg, mono_value_copy, iargs);
3279                         return;
3280                 }
3281         }
3282
3283         if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 8) {
3284                 /* FIXME: Optimize the case when src/dest is OP_LDADDR */
3285                 mini_emit_memcpy (cfg, dest->dreg, 0, src->dreg, 0, n, align);
3286         } else {
3287                 iargs [0] = dest;
3288                 iargs [1] = src;
3289                 if (size_ins)
3290                         iargs [2] = size_ins;
3291                 else
3292                         EMIT_NEW_ICONST (cfg, iargs [2], n);
3293                 
3294                 memcpy_method = get_memcpy_method ();
3295                 if (memcpy_ins)
3296                         mono_emit_calli (cfg, mono_method_signature (memcpy_method), iargs, memcpy_ins, NULL, NULL);
3297                 else
3298                         mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
3299         }
3300 }
3301
3302 static MonoMethod*
3303 get_memset_method (void)
3304 {
3305         static MonoMethod *memset_method = NULL;
3306         if (!memset_method) {
3307                 memset_method = mono_class_get_method_from_name (mono_defaults.string_class, "memset", 3);
3308                 if (!memset_method)
3309                         g_error ("Old corlib found. Install a new one");
3310         }
3311         return memset_method;
3312 }
3313
3314 void
3315 mini_emit_initobj (MonoCompile *cfg, MonoInst *dest, const guchar *ip, MonoClass *klass)
3316 {
3317         MonoInst *iargs [3];
3318         int n;
3319         guint32 align;
3320         MonoMethod *memset_method;
3321         MonoInst *size_ins = NULL;
3322         MonoInst *bzero_ins = NULL;
3323         static MonoMethod *bzero_method;
3324
3325         /* FIXME: Optimize this for the case when dest is an LDADDR */
3326         mono_class_init (klass);
3327         if (mini_is_gsharedvt_klass (klass)) {
3328                 size_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_VALUE_SIZE);
3329                 bzero_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_BZERO);
3330                 if (!bzero_method)
3331                         bzero_method = mono_class_get_method_from_name (mono_defaults.string_class, "bzero_aligned_1", 2);
3332                 g_assert (bzero_method);
3333                 iargs [0] = dest;
3334                 iargs [1] = size_ins;
3335                 mono_emit_calli (cfg, mono_method_signature (bzero_method), iargs, bzero_ins, NULL, NULL);
3336                 return;
3337         }
3338
3339         n = mono_class_value_size (klass, &align);
3340
3341         if (n <= sizeof (gpointer) * 8) {
3342                 mini_emit_memset (cfg, dest->dreg, 0, n, 0, align);
3343         }
3344         else {
3345                 memset_method = get_memset_method ();
3346                 iargs [0] = dest;
3347                 EMIT_NEW_ICONST (cfg, iargs [1], 0);
3348                 EMIT_NEW_ICONST (cfg, iargs [2], n);
3349                 mono_emit_method_call (cfg, memset_method, iargs, NULL);
3350         }
3351 }
3352
3353 /*
3354  * emit_get_rgctx:
3355  *
3356  *   Emit IR to return either the this pointer for instance method,
3357  * or the mrgctx for static methods.
3358  */
3359 static MonoInst*
3360 emit_get_rgctx (MonoCompile *cfg, MonoMethod *method, int context_used)
3361 {
3362         MonoInst *this_ins = NULL;
3363
3364         g_assert (cfg->gshared);
3365
3366         if (!(method->flags & METHOD_ATTRIBUTE_STATIC) &&
3367                         !(context_used & MONO_GENERIC_CONTEXT_USED_METHOD) &&
3368                         !method->klass->valuetype)
3369                 EMIT_NEW_ARGLOAD (cfg, this_ins, 0);
3370
3371         if (context_used & MONO_GENERIC_CONTEXT_USED_METHOD) {
3372                 MonoInst *mrgctx_loc, *mrgctx_var;
3373
3374                 g_assert (!this_ins);
3375                 g_assert (method->is_inflated && mono_method_get_context (method)->method_inst);
3376
3377                 mrgctx_loc = mono_get_vtable_var (cfg);
3378                 EMIT_NEW_TEMPLOAD (cfg, mrgctx_var, mrgctx_loc->inst_c0);
3379
3380                 return mrgctx_var;
3381         } else if (method->flags & METHOD_ATTRIBUTE_STATIC || method->klass->valuetype) {
3382                 MonoInst *vtable_loc, *vtable_var;
3383
3384                 g_assert (!this_ins);
3385
3386                 vtable_loc = mono_get_vtable_var (cfg);
3387                 EMIT_NEW_TEMPLOAD (cfg, vtable_var, vtable_loc->inst_c0);
3388
3389                 if (method->is_inflated && mono_method_get_context (method)->method_inst) {
3390                         MonoInst *mrgctx_var = vtable_var;
3391                         int vtable_reg;
3392
3393                         vtable_reg = alloc_preg (cfg);
3394                         EMIT_NEW_LOAD_MEMBASE (cfg, vtable_var, OP_LOAD_MEMBASE, vtable_reg, mrgctx_var->dreg, MONO_STRUCT_OFFSET (MonoMethodRuntimeGenericContext, class_vtable));
3395                         vtable_var->type = STACK_PTR;
3396                 }
3397
3398                 return vtable_var;
3399         } else {
3400                 MonoInst *ins;
3401                 int vtable_reg;
3402         
3403                 vtable_reg = alloc_preg (cfg);
3404                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, vtable_reg, this_ins->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3405                 return ins;
3406         }
3407 }
3408
3409 static MonoJumpInfoRgctxEntry *
3410 mono_patch_info_rgctx_entry_new (MonoMemPool *mp, MonoMethod *method, gboolean in_mrgctx, MonoJumpInfoType patch_type, gconstpointer patch_data, MonoRgctxInfoType info_type)
3411 {
3412         MonoJumpInfoRgctxEntry *res = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoRgctxEntry));
3413         res->method = method;
3414         res->in_mrgctx = in_mrgctx;
3415         res->data = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfo));
3416         res->data->type = patch_type;
3417         res->data->data.target = patch_data;
3418         res->info_type = info_type;
3419
3420         return res;
3421 }
3422
3423 /*
3424  * emit_rgctx_fetch:
3425  *
3426  *   Emit IR to load the value of the rgctx entry ENTRY from the rgctx
3427  * given by RGCTX.
3428  */
3429 static inline MonoInst*
3430 emit_rgctx_fetch (MonoCompile *cfg, MonoInst *rgctx, MonoJumpInfoRgctxEntry *entry)
3431 {
3432         /* Inline version, not currently used */
3433         // FIXME: This can be called from mono_decompose_vtype_opts (), which can't create new bblocks
3434 #if 0
3435         int i, slot, depth, index, rgctx_reg, val_reg, res_reg;
3436         gboolean mrgctx;
3437         MonoBasicBlock *is_null_bb, *end_bb;
3438         MonoInst *res, *ins, *call;
3439         MonoInst *args[16];
3440
3441         slot = mini_get_rgctx_entry_slot (entry);
3442
3443         mrgctx = MONO_RGCTX_SLOT_IS_MRGCTX (slot);
3444         index = MONO_RGCTX_SLOT_INDEX (slot);
3445         if (mrgctx)
3446                 index += MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
3447         for (depth = 0; ; ++depth) {
3448                 int size = mono_class_rgctx_get_array_size (depth, mrgctx);
3449
3450                 if (index < size - 1)
3451                         break;
3452                 index -= size - 1;
3453         }
3454
3455         NEW_BBLOCK (cfg, end_bb);
3456         NEW_BBLOCK (cfg, is_null_bb);
3457
3458         if (mrgctx) {
3459                 rgctx_reg = rgctx->dreg;
3460         } else {
3461                 rgctx_reg = alloc_preg (cfg);
3462
3463                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, rgctx_reg, rgctx->dreg, MONO_STRUCT_OFFSET (MonoVTable, runtime_generic_context));
3464                 // FIXME: Avoid this check by allocating the table when the vtable is created etc.
3465                 NEW_BBLOCK (cfg, is_null_bb);
3466
3467                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rgctx_reg, 0);
3468                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3469         }
3470
3471         for (i = 0; i < depth; ++i) {
3472                 int array_reg = alloc_preg (cfg);
3473
3474                 /* load ptr to next array */
3475                 if (mrgctx && i == 0)
3476                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, rgctx_reg, MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT);
3477                 else
3478                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, rgctx_reg, 0);
3479                 rgctx_reg = array_reg;
3480                 /* is the ptr null? */
3481                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rgctx_reg, 0);
3482                 /* if yes, jump to actual trampoline */
3483                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3484         }
3485
3486         /* fetch slot */
3487         val_reg = alloc_preg (cfg);
3488         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, val_reg, rgctx_reg, (index + 1) * sizeof (gpointer));
3489         /* is the slot null? */
3490         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, val_reg, 0);
3491         /* if yes, jump to actual trampoline */
3492         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3493
3494         /* Fastpath */
3495         res_reg = alloc_preg (cfg);
3496         MONO_INST_NEW (cfg, ins, OP_MOVE);
3497         ins->dreg = res_reg;
3498         ins->sreg1 = val_reg;
3499         MONO_ADD_INS (cfg->cbb, ins);
3500         res = ins;
3501         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3502
3503         /* Slowpath */
3504         MONO_START_BB (cfg, is_null_bb);
3505         args [0] = rgctx;
3506         EMIT_NEW_ICONST (cfg, args [1], index);
3507         if (mrgctx)
3508                 call = mono_emit_jit_icall (cfg, mono_fill_method_rgctx, args);
3509         else
3510                 call = mono_emit_jit_icall (cfg, mono_fill_class_rgctx, args);
3511         MONO_INST_NEW (cfg, ins, OP_MOVE);
3512         ins->dreg = res_reg;
3513         ins->sreg1 = call->dreg;
3514         MONO_ADD_INS (cfg->cbb, ins);
3515         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3516
3517         MONO_START_BB (cfg, end_bb);
3518
3519         return res;
3520 #else
3521         return mono_emit_abs_call (cfg, MONO_PATCH_INFO_RGCTX_FETCH, entry, helper_sig_rgctx_lazy_fetch_trampoline, &rgctx);
3522 #endif
3523 }
3524
3525 static MonoInst*
3526 emit_get_rgctx_klass (MonoCompile *cfg, int context_used,
3527                                           MonoClass *klass, MonoRgctxInfoType rgctx_type)
3528 {
3529         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);
3530         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3531
3532         return emit_rgctx_fetch (cfg, rgctx, entry);
3533 }
3534
3535 static MonoInst*
3536 emit_get_rgctx_sig (MonoCompile *cfg, int context_used,
3537                                         MonoMethodSignature *sig, MonoRgctxInfoType rgctx_type)
3538 {
3539         MonoJumpInfoRgctxEntry *entry = mono_patch_info_rgctx_entry_new (cfg->mempool, cfg->current_method, context_used & MONO_GENERIC_CONTEXT_USED_METHOD, MONO_PATCH_INFO_SIGNATURE, sig, rgctx_type);
3540         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3541
3542         return emit_rgctx_fetch (cfg, rgctx, entry);
3543 }
3544
3545 static MonoInst*
3546 emit_get_rgctx_gsharedvt_call (MonoCompile *cfg, int context_used,
3547                                                            MonoMethodSignature *sig, MonoMethod *cmethod, MonoRgctxInfoType rgctx_type)
3548 {
3549         MonoJumpInfoGSharedVtCall *call_info;
3550         MonoJumpInfoRgctxEntry *entry;
3551         MonoInst *rgctx;
3552
3553         call_info = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoGSharedVtCall));
3554         call_info->sig = sig;
3555         call_info->method = cmethod;
3556
3557         entry = mono_patch_info_rgctx_entry_new (cfg->mempool, cfg->current_method, context_used & MONO_GENERIC_CONTEXT_USED_METHOD, MONO_PATCH_INFO_GSHAREDVT_CALL, call_info, rgctx_type);
3558         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3559
3560         return emit_rgctx_fetch (cfg, rgctx, entry);
3561 }
3562
3563 /*
3564  * emit_get_rgctx_virt_method:
3565  *
3566  *   Return data for method VIRT_METHOD for a receiver of type KLASS.
3567  */
3568 static MonoInst*
3569 emit_get_rgctx_virt_method (MonoCompile *cfg, int context_used,
3570                                                         MonoClass *klass, MonoMethod *virt_method, MonoRgctxInfoType rgctx_type)
3571 {
3572         MonoJumpInfoVirtMethod *info;
3573         MonoJumpInfoRgctxEntry *entry;
3574         MonoInst *rgctx;
3575
3576         info = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoVirtMethod));
3577         info->klass = klass;
3578         info->method = virt_method;
3579
3580         entry = mono_patch_info_rgctx_entry_new (cfg->mempool, cfg->current_method, context_used & MONO_GENERIC_CONTEXT_USED_METHOD, MONO_PATCH_INFO_VIRT_METHOD, info, rgctx_type);
3581         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3582
3583         return emit_rgctx_fetch (cfg, rgctx, entry);
3584 }
3585
3586 static MonoInst*
3587 emit_get_rgctx_gsharedvt_method (MonoCompile *cfg, int context_used,
3588                                                                  MonoMethod *cmethod, MonoGSharedVtMethodInfo *info)
3589 {
3590         MonoJumpInfoRgctxEntry *entry;
3591         MonoInst *rgctx;
3592
3593         entry = mono_patch_info_rgctx_entry_new (cfg->mempool, cfg->current_method, context_used & MONO_GENERIC_CONTEXT_USED_METHOD, MONO_PATCH_INFO_GSHAREDVT_METHOD, info, MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO);
3594         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3595
3596         return emit_rgctx_fetch (cfg, rgctx, entry);
3597 }
3598
3599 /*
3600  * emit_get_rgctx_method:
3601  *
3602  *   Emit IR to load the property RGCTX_TYPE of CMETHOD. If context_used is 0, emit
3603  * normal constants, else emit a load from the rgctx.
3604  */
3605 static MonoInst*
3606 emit_get_rgctx_method (MonoCompile *cfg, int context_used,
3607                                            MonoMethod *cmethod, MonoRgctxInfoType rgctx_type)
3608 {
3609         if (!context_used) {
3610                 MonoInst *ins;
3611
3612                 switch (rgctx_type) {
3613                 case MONO_RGCTX_INFO_METHOD:
3614                         EMIT_NEW_METHODCONST (cfg, ins, cmethod);
3615                         return ins;
3616                 case MONO_RGCTX_INFO_METHOD_RGCTX:
3617                         EMIT_NEW_METHOD_RGCTX_CONST (cfg, ins, cmethod);
3618                         return ins;
3619                 default:
3620                         g_assert_not_reached ();
3621                 }
3622         } else {
3623                 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);
3624                 MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3625
3626                 return emit_rgctx_fetch (cfg, rgctx, entry);
3627         }
3628 }
3629
3630 static MonoInst*
3631 emit_get_rgctx_field (MonoCompile *cfg, int context_used,
3632                                           MonoClassField *field, MonoRgctxInfoType rgctx_type)
3633 {
3634         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);
3635         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3636
3637         return emit_rgctx_fetch (cfg, rgctx, entry);
3638 }
3639
3640 static int
3641 get_gsharedvt_info_slot (MonoCompile *cfg, gpointer data, MonoRgctxInfoType rgctx_type)
3642 {
3643         MonoGSharedVtMethodInfo *info = cfg->gsharedvt_info;
3644         MonoRuntimeGenericContextInfoTemplate *template;
3645         int i, idx;
3646
3647         g_assert (info);
3648
3649         for (i = 0; i < info->num_entries; ++i) {
3650                 MonoRuntimeGenericContextInfoTemplate *otemplate = &info->entries [i];
3651
3652                 if (otemplate->info_type == rgctx_type && otemplate->data == data && rgctx_type != MONO_RGCTX_INFO_LOCAL_OFFSET)
3653                         return i;
3654         }
3655
3656         if (info->num_entries == info->count_entries) {
3657                 MonoRuntimeGenericContextInfoTemplate *new_entries;
3658                 int new_count_entries = info->count_entries ? info->count_entries * 2 : 16;
3659
3660                 new_entries = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoRuntimeGenericContextInfoTemplate) * new_count_entries);
3661
3662                 memcpy (new_entries, info->entries, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
3663                 info->entries = new_entries;
3664                 info->count_entries = new_count_entries;
3665         }
3666
3667         idx = info->num_entries;
3668         template = &info->entries [idx];
3669         template->info_type = rgctx_type;
3670         template->data = data;
3671
3672         info->num_entries ++;
3673
3674         return idx;
3675 }
3676
3677 /*
3678  * emit_get_gsharedvt_info:
3679  *
3680  *   This is similar to emit_get_rgctx_.., but loads the data from the gsharedvt info var instead of calling an rgctx fetch trampoline.
3681  */
3682 static MonoInst*
3683 emit_get_gsharedvt_info (MonoCompile *cfg, gpointer data, MonoRgctxInfoType rgctx_type)
3684 {
3685         MonoInst *ins;
3686         int idx, dreg;
3687
3688         idx = get_gsharedvt_info_slot (cfg, data, rgctx_type);
3689         /* Load info->entries [idx] */
3690         dreg = alloc_preg (cfg);
3691         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, cfg->gsharedvt_info_var->dreg, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, entries) + (idx * sizeof (gpointer)));
3692
3693         return ins;
3694 }
3695
3696 static MonoInst*
3697 emit_get_gsharedvt_info_klass (MonoCompile *cfg, MonoClass *klass, MonoRgctxInfoType rgctx_type)
3698 {
3699         return emit_get_gsharedvt_info (cfg, &klass->byval_arg, rgctx_type);
3700 }
3701
3702 /*
3703  * On return the caller must check @klass for load errors.
3704  */
3705 static void
3706 emit_class_init (MonoCompile *cfg, MonoClass *klass)
3707 {
3708         MonoInst *vtable_arg;
3709         int context_used;
3710         gboolean use_op_generic_class_init = FALSE;
3711
3712         context_used = mini_class_check_context_used (cfg, klass);
3713
3714         if (context_used) {
3715                 vtable_arg = emit_get_rgctx_klass (cfg, context_used,
3716                                                                                    klass, MONO_RGCTX_INFO_VTABLE);
3717         } else {
3718                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
3719
3720                 if (!vtable)
3721                         return;
3722                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
3723         }
3724
3725 #ifdef MONO_ARCH_HAVE_OP_GENERIC_CLASS_INIT
3726         if (!COMPILE_LLVM (cfg))
3727                 use_op_generic_class_init = TRUE;
3728 #endif
3729
3730         if (use_op_generic_class_init) {
3731                 MonoInst *ins;
3732
3733                 /*
3734                  * Using an opcode instead of emitting IR here allows the hiding of the call inside the opcode,
3735                  * so this doesn't have to clobber any regs and it doesn't break basic blocks.
3736                  */
3737                 MONO_INST_NEW (cfg, ins, OP_GENERIC_CLASS_INIT);
3738                 ins->sreg1 = vtable_arg->dreg;
3739                 MONO_ADD_INS (cfg->cbb, ins);
3740         } else {
3741                 static int byte_offset = -1;
3742                 static guint8 bitmask;
3743                 int bits_reg, inited_reg;
3744                 MonoBasicBlock *inited_bb;
3745                 MonoInst *args [16];
3746
3747                 if (byte_offset < 0)
3748                         mono_marshal_find_bitfield_offset (MonoVTable, initialized, &byte_offset, &bitmask);
3749
3750                 bits_reg = alloc_ireg (cfg);
3751                 inited_reg = alloc_ireg (cfg);
3752
3753                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, bits_reg, vtable_arg->dreg, byte_offset);
3754                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, inited_reg, bits_reg, bitmask);
3755
3756                 NEW_BBLOCK (cfg, inited_bb);
3757
3758                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, inited_reg, 0);
3759                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, inited_bb);
3760
3761                 args [0] = vtable_arg;
3762                 mono_emit_jit_icall (cfg, mono_generic_class_init, args);
3763
3764                 MONO_START_BB (cfg, inited_bb);
3765         }
3766 }
3767
3768 static void
3769 emit_seq_point (MonoCompile *cfg, MonoMethod *method, guint8* ip, gboolean intr_loc, gboolean nonempty_stack)
3770 {
3771         MonoInst *ins;
3772
3773         if (cfg->gen_seq_points && cfg->method == method) {
3774                 NEW_SEQ_POINT (cfg, ins, ip - cfg->header->code, intr_loc);
3775                 if (nonempty_stack)
3776                         ins->flags |= MONO_INST_NONEMPTY_STACK;
3777                 MONO_ADD_INS (cfg->cbb, ins);
3778         }
3779 }
3780
3781 static void
3782 save_cast_details (MonoCompile *cfg, MonoClass *klass, int obj_reg, gboolean null_check)
3783 {
3784         if (mini_get_debug_options ()->better_cast_details) {
3785                 int vtable_reg = alloc_preg (cfg);
3786                 int klass_reg = alloc_preg (cfg);
3787                 MonoBasicBlock *is_null_bb = NULL;
3788                 MonoInst *tls_get;
3789                 int to_klass_reg, context_used;
3790
3791                 if (null_check) {
3792                         NEW_BBLOCK (cfg, is_null_bb);
3793
3794                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
3795                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3796                 }
3797
3798                 tls_get = mono_get_jit_tls_intrinsic (cfg);
3799                 if (!tls_get) {
3800                         fprintf (stderr, "error: --debug=casts not supported on this platform.\n.");
3801                         exit (1);
3802                 }
3803
3804                 MONO_ADD_INS (cfg->cbb, tls_get);
3805                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3806                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
3807
3808                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), klass_reg);
3809
3810                 context_used = mini_class_check_context_used (cfg, klass);
3811                 if (context_used) {
3812                         MonoInst *class_ins;
3813
3814                         class_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
3815                         to_klass_reg = class_ins->dreg;
3816                 } else {
3817                         to_klass_reg = alloc_preg (cfg);
3818                         MONO_EMIT_NEW_CLASSCONST (cfg, to_klass_reg, klass);
3819                 }
3820                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_to), to_klass_reg);
3821
3822                 if (null_check)
3823                         MONO_START_BB (cfg, is_null_bb);
3824         }
3825 }
3826
3827 static void
3828 reset_cast_details (MonoCompile *cfg)
3829 {
3830         /* Reset the variables holding the cast details */
3831         if (mini_get_debug_options ()->better_cast_details) {
3832                 MonoInst *tls_get = mono_get_jit_tls_intrinsic (cfg);
3833
3834                 MONO_ADD_INS (cfg->cbb, tls_get);
3835                 /* It is enough to reset the from field */
3836                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), 0);
3837         }
3838 }
3839
3840 /*
3841  * On return the caller must check @array_class for load errors
3842  */
3843 static void
3844 mini_emit_check_array_type (MonoCompile *cfg, MonoInst *obj, MonoClass *array_class)
3845 {
3846         int vtable_reg = alloc_preg (cfg);
3847         int context_used;
3848
3849         context_used = mini_class_check_context_used (cfg, array_class);
3850
3851         save_cast_details (cfg, array_class, obj->dreg, FALSE);
3852
3853         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3854
3855         if (cfg->opt & MONO_OPT_SHARED) {
3856                 int class_reg = alloc_preg (cfg);
3857                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, class_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
3858                 if (cfg->compile_aot) {
3859                         int klass_reg = alloc_preg (cfg);
3860                         MONO_EMIT_NEW_CLASSCONST (cfg, klass_reg, array_class);
3861                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, class_reg, klass_reg);
3862                 } else {
3863                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, class_reg, array_class);
3864                 }
3865         } else if (context_used) {
3866                 MonoInst *vtable_ins;
3867
3868                 vtable_ins = emit_get_rgctx_klass (cfg, context_used, array_class, MONO_RGCTX_INFO_VTABLE);
3869                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, vtable_reg, vtable_ins->dreg);
3870         } else {
3871                 if (cfg->compile_aot) {
3872                         int vt_reg;
3873                         MonoVTable *vtable;
3874
3875                         if (!(vtable = mono_class_vtable (cfg->domain, array_class)))
3876                                 return;
3877                         vt_reg = alloc_preg (cfg);
3878                         MONO_EMIT_NEW_VTABLECONST (cfg, vt_reg, vtable);
3879                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, vtable_reg, vt_reg);
3880                 } else {
3881                         MonoVTable *vtable;
3882                         if (!(vtable = mono_class_vtable (cfg->domain, array_class)))
3883                                 return;
3884                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vtable);
3885                 }
3886         }
3887         
3888         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "ArrayTypeMismatchException");
3889
3890         reset_cast_details (cfg);
3891 }
3892
3893 /**
3894  * Handles unbox of a Nullable<T>. If context_used is non zero, then shared 
3895  * generic code is generated.
3896  */
3897 static MonoInst*
3898 handle_unbox_nullable (MonoCompile* cfg, MonoInst* val, MonoClass* klass, int context_used)
3899 {
3900         MonoMethod* method = mono_class_get_method_from_name (klass, "Unbox", 1);
3901
3902         if (context_used) {
3903                 MonoInst *rgctx, *addr;
3904
3905                 /* FIXME: What if the class is shared?  We might not
3906                    have to get the address of the method from the
3907                    RGCTX. */
3908                 addr = emit_get_rgctx_method (cfg, context_used, method,
3909                                                                           MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
3910
3911                 rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3912
3913                 return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
3914         } else {
3915                 gboolean pass_vtable, pass_mrgctx;
3916                 MonoInst *rgctx_arg = NULL;
3917
3918                 check_method_sharing (cfg, method, &pass_vtable, &pass_mrgctx);
3919                 g_assert (!pass_mrgctx);
3920
3921                 if (pass_vtable) {
3922                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
3923
3924                         g_assert (vtable);
3925                         EMIT_NEW_VTABLECONST (cfg, rgctx_arg, vtable);
3926                 }
3927
3928                 return mono_emit_method_call_full (cfg, method, NULL, FALSE, &val, NULL, NULL, rgctx_arg);
3929         }
3930 }
3931
3932 static MonoInst*
3933 handle_unbox (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, int context_used)
3934 {
3935         MonoInst *add;
3936         int obj_reg;
3937         int vtable_reg = alloc_dreg (cfg ,STACK_PTR);
3938         int klass_reg = alloc_dreg (cfg ,STACK_PTR);
3939         int eclass_reg = alloc_dreg (cfg ,STACK_PTR);
3940         int rank_reg = alloc_dreg (cfg ,STACK_I4);
3941
3942         obj_reg = sp [0]->dreg;
3943         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3944         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
3945
3946         /* FIXME: generics */
3947         g_assert (klass->rank == 0);
3948                         
3949         // Check rank == 0
3950         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, 0);
3951         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
3952
3953         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
3954         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, element_class));
3955
3956         if (context_used) {
3957                 MonoInst *element_class;
3958
3959                 /* This assertion is from the unboxcast insn */
3960                 g_assert (klass->rank == 0);
3961
3962                 element_class = emit_get_rgctx_klass (cfg, context_used,
3963                                 klass, MONO_RGCTX_INFO_ELEMENT_KLASS);
3964
3965                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, eclass_reg, element_class->dreg);
3966                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
3967         } else {
3968                 save_cast_details (cfg, klass->element_class, obj_reg, FALSE);
3969                 mini_emit_class_check (cfg, eclass_reg, klass->element_class);
3970                 reset_cast_details (cfg);
3971         }
3972
3973         NEW_BIALU_IMM (cfg, add, OP_ADD_IMM, alloc_dreg (cfg, STACK_MP), obj_reg, sizeof (MonoObject));
3974         MONO_ADD_INS (cfg->cbb, add);
3975         add->type = STACK_MP;
3976         add->klass = klass;
3977
3978         return add;
3979 }
3980
3981 static MonoInst*
3982 handle_unbox_gsharedvt (MonoCompile *cfg, MonoClass *klass, MonoInst *obj)
3983 {
3984         MonoInst *addr, *klass_inst, *is_ref, *args[16];
3985         MonoBasicBlock *is_ref_bb, *is_nullable_bb, *end_bb;
3986         MonoInst *ins;
3987         int dreg, addr_reg;
3988
3989         klass_inst = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_KLASS);
3990
3991         /* obj */
3992         args [0] = obj;
3993
3994         /* klass */
3995         args [1] = klass_inst;
3996
3997         /* CASTCLASS */
3998         obj = mono_emit_jit_icall (cfg, mono_object_castclass_unbox, args);
3999
4000         NEW_BBLOCK (cfg, is_ref_bb);
4001         NEW_BBLOCK (cfg, is_nullable_bb);
4002         NEW_BBLOCK (cfg, end_bb);
4003         is_ref = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_CLASS_BOX_TYPE);
4004         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, 1);
4005         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
4006
4007         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, 2);
4008         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_nullable_bb);
4009
4010         /* This will contain either the address of the unboxed vtype, or an address of the temporary where the ref is stored */
4011         addr_reg = alloc_dreg (cfg, STACK_MP);
4012
4013         /* Non-ref case */
4014         /* UNBOX */
4015         NEW_BIALU_IMM (cfg, addr, OP_ADD_IMM, addr_reg, obj->dreg, sizeof (MonoObject));
4016         MONO_ADD_INS (cfg->cbb, addr);
4017
4018         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4019
4020         /* Ref case */
4021         MONO_START_BB (cfg, is_ref_bb);
4022
4023         /* Save the ref to a temporary */
4024         dreg = alloc_ireg (cfg);
4025         EMIT_NEW_VARLOADA_VREG (cfg, addr, dreg, &klass->byval_arg);
4026         addr->dreg = addr_reg;
4027         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, obj->dreg);
4028         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4029
4030         /* Nullable case */
4031         MONO_START_BB (cfg, is_nullable_bb);
4032
4033         {
4034                 MonoInst *addr = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX);
4035                 MonoInst *unbox_call;
4036                 MonoMethodSignature *unbox_sig;
4037
4038                 unbox_sig = mono_mempool_alloc0 (cfg->mempool, MONO_SIZEOF_METHOD_SIGNATURE + (1 * sizeof (MonoType *)));
4039                 unbox_sig->ret = &klass->byval_arg;
4040                 unbox_sig->param_count = 1;
4041                 unbox_sig->params [0] = &mono_defaults.object_class->byval_arg;
4042                 unbox_call = mono_emit_calli (cfg, unbox_sig, &obj, addr, NULL, NULL);
4043
4044                 EMIT_NEW_VARLOADA_VREG (cfg, addr, unbox_call->dreg, &klass->byval_arg);
4045                 addr->dreg = addr_reg;
4046         }
4047
4048         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4049
4050         /* End */
4051         MONO_START_BB (cfg, end_bb);
4052
4053         /* LDOBJ */
4054         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr_reg, 0);
4055
4056         return ins;
4057 }
4058
4059 /*
4060  * Returns NULL and set the cfg exception on error.
4061  */
4062 static MonoInst*
4063 handle_alloc (MonoCompile *cfg, MonoClass *klass, gboolean for_box, int context_used)
4064 {
4065         MonoInst *iargs [2];
4066         void *alloc_ftn;
4067
4068         if (context_used) {
4069                 MonoInst *data;
4070                 int rgctx_info;
4071                 MonoInst *iargs [2];
4072                 gboolean known_instance_size = !mini_is_gsharedvt_klass (klass);
4073
4074                 MonoMethod *managed_alloc = mono_gc_get_managed_allocator (klass, for_box, known_instance_size);
4075
4076                 if (cfg->opt & MONO_OPT_SHARED)
4077                         rgctx_info = MONO_RGCTX_INFO_KLASS;
4078                 else
4079                         rgctx_info = MONO_RGCTX_INFO_VTABLE;
4080                 data = emit_get_rgctx_klass (cfg, context_used, klass, rgctx_info);
4081
4082                 if (cfg->opt & MONO_OPT_SHARED) {
4083                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
4084                         iargs [1] = data;
4085                         alloc_ftn = mono_object_new;
4086                 } else {
4087                         iargs [0] = data;
4088                         alloc_ftn = mono_object_new_specific;
4089                 }
4090
4091                 if (managed_alloc && !(cfg->opt & MONO_OPT_SHARED)) {
4092                         if (known_instance_size) {
4093                                 int size = mono_class_instance_size (klass);
4094                                 if (size < sizeof (MonoObject))
4095                                         g_error ("Invalid size %d for class %s", size, mono_type_get_full_name (klass));
4096
4097                                 EMIT_NEW_ICONST (cfg, iargs [1], mono_gc_get_aligned_size_for_allocator (size));
4098                         }
4099                         return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
4100                 }
4101
4102                 return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
4103         }
4104
4105         if (cfg->opt & MONO_OPT_SHARED) {
4106                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
4107                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
4108
4109                 alloc_ftn = mono_object_new;
4110         } else if (cfg->compile_aot && cfg->cbb->out_of_line && klass->type_token && klass->image == mono_defaults.corlib && !klass->generic_class) {
4111                 /* This happens often in argument checking code, eg. throw new FooException... */
4112                 /* Avoid relocations and save some space by calling a helper function specialized to mscorlib */
4113                 EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (klass->type_token));
4114                 return mono_emit_jit_icall (cfg, mono_helper_newobj_mscorlib, iargs);
4115         } else {
4116                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
4117                 MonoMethod *managed_alloc = NULL;
4118                 gboolean pass_lw;
4119
4120                 if (!vtable) {
4121                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4122                         cfg->exception_ptr = klass;
4123                         return NULL;
4124                 }
4125
4126                 managed_alloc = mono_gc_get_managed_allocator (klass, for_box, TRUE);
4127
4128                 if (managed_alloc) {
4129                         int size = mono_class_instance_size (klass);
4130                         if (size < sizeof (MonoObject))
4131                                 g_error ("Invalid size %d for class %s", size, mono_type_get_full_name (klass));
4132
4133                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
4134                         EMIT_NEW_ICONST (cfg, iargs [1], mono_gc_get_aligned_size_for_allocator (size));
4135                         return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
4136                 }
4137                 alloc_ftn = mono_class_get_allocation_ftn (vtable, for_box, &pass_lw);
4138                 if (pass_lw) {
4139                         guint32 lw = vtable->klass->instance_size;
4140                         lw = ((lw + (sizeof (gpointer) - 1)) & ~(sizeof (gpointer) - 1)) / sizeof (gpointer);
4141                         EMIT_NEW_ICONST (cfg, iargs [0], lw);
4142                         EMIT_NEW_VTABLECONST (cfg, iargs [1], vtable);
4143                 }
4144                 else {
4145                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
4146                 }
4147         }
4148
4149         return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
4150 }
4151         
4152 /*
4153  * Returns NULL and set the cfg exception on error.
4154  */     
4155 static MonoInst*
4156 handle_box (MonoCompile *cfg, MonoInst *val, MonoClass *klass, int context_used)
4157 {
4158         MonoInst *alloc, *ins;
4159
4160         if (mono_class_is_nullable (klass)) {
4161                 MonoMethod* method = mono_class_get_method_from_name (klass, "Box", 1);
4162
4163                 if (context_used) {
4164                         /* FIXME: What if the class is shared?  We might not
4165                            have to get the method address from the RGCTX. */
4166                         MonoInst *addr = emit_get_rgctx_method (cfg, context_used, method,
4167                                                                                                         MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
4168                         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
4169
4170                         return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
4171                 } else {
4172                         gboolean pass_vtable, pass_mrgctx;
4173                         MonoInst *rgctx_arg = NULL;
4174
4175                         check_method_sharing (cfg, method, &pass_vtable, &pass_mrgctx);
4176                         g_assert (!pass_mrgctx);
4177
4178                         if (pass_vtable) {
4179                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
4180
4181                                 g_assert (vtable);
4182                                 EMIT_NEW_VTABLECONST (cfg, rgctx_arg, vtable);
4183                         }
4184
4185                         return mono_emit_method_call_full (cfg, method, NULL, FALSE, &val, NULL, NULL, rgctx_arg);
4186                 }
4187         }
4188
4189         if (mini_is_gsharedvt_klass (klass)) {
4190                 MonoBasicBlock *is_ref_bb, *is_nullable_bb, *end_bb;
4191                 MonoInst *res, *is_ref, *src_var, *addr;
4192                 int dreg;
4193
4194                 dreg = alloc_ireg (cfg);
4195
4196                 NEW_BBLOCK (cfg, is_ref_bb);
4197                 NEW_BBLOCK (cfg, is_nullable_bb);
4198                 NEW_BBLOCK (cfg, end_bb);
4199                 is_ref = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_CLASS_BOX_TYPE);
4200                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, 1);
4201                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
4202
4203                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, 2);
4204                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_nullable_bb);
4205
4206                 /* Non-ref case */
4207                 alloc = handle_alloc (cfg, klass, TRUE, context_used);
4208                 if (!alloc)
4209                         return NULL;
4210                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
4211                 ins->opcode = OP_STOREV_MEMBASE;
4212
4213                 EMIT_NEW_UNALU (cfg, res, OP_MOVE, dreg, alloc->dreg);
4214                 res->type = STACK_OBJ;
4215                 res->klass = klass;
4216                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4217                 
4218                 /* Ref case */
4219                 MONO_START_BB (cfg, is_ref_bb);
4220
4221                 /* val is a vtype, so has to load the value manually */
4222                 src_var = get_vreg_to_inst (cfg, val->dreg);
4223                 if (!src_var)
4224                         src_var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, val->dreg);
4225                 EMIT_NEW_VARLOADA (cfg, addr, src_var, src_var->inst_vtype);
4226                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, addr->dreg, 0);
4227                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4228
4229                 /* Nullable case */
4230                 MONO_START_BB (cfg, is_nullable_bb);
4231
4232                 {
4233                         MonoInst *addr = emit_get_gsharedvt_info_klass (cfg, klass,
4234                                                                                                         MONO_RGCTX_INFO_NULLABLE_CLASS_BOX);
4235                         MonoInst *box_call;
4236                         MonoMethodSignature *box_sig;
4237
4238                         /*
4239                          * klass is Nullable<T>, need to call Nullable<T>.Box () using a gsharedvt signature, but we cannot
4240                          * construct that method at JIT time, so have to do things by hand.
4241                          */
4242                         box_sig = mono_mempool_alloc0 (cfg->mempool, MONO_SIZEOF_METHOD_SIGNATURE + (1 * sizeof (MonoType *)));
4243                         box_sig->ret = &mono_defaults.object_class->byval_arg;
4244                         box_sig->param_count = 1;
4245                         box_sig->params [0] = &klass->byval_arg;
4246                         box_call = mono_emit_calli (cfg, box_sig, &val, addr, NULL, NULL);
4247                         EMIT_NEW_UNALU (cfg, res, OP_MOVE, dreg, box_call->dreg);
4248                         res->type = STACK_OBJ;
4249                         res->klass = klass;
4250                 }
4251
4252                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4253
4254                 MONO_START_BB (cfg, end_bb);
4255
4256                 return res;
4257         } else {
4258                 alloc = handle_alloc (cfg, klass, TRUE, context_used);
4259                 if (!alloc)
4260                         return NULL;
4261
4262                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
4263                 return alloc;
4264         }
4265 }
4266
4267 static gboolean
4268 mini_class_has_reference_variant_generic_argument (MonoCompile *cfg, MonoClass *klass, int context_used)
4269 {
4270         int i;
4271         MonoGenericContainer *container;
4272         MonoGenericInst *ginst;
4273
4274         if (klass->generic_class) {
4275                 container = klass->generic_class->container_class->generic_container;
4276                 ginst = klass->generic_class->context.class_inst;
4277         } else if (klass->generic_container && context_used) {
4278                 container = klass->generic_container;
4279                 ginst = container->context.class_inst;
4280         } else {
4281                 return FALSE;
4282         }
4283
4284         for (i = 0; i < container->type_argc; ++i) {
4285                 MonoType *type;
4286                 if (!(mono_generic_container_get_param_info (container, i)->flags & (MONO_GEN_PARAM_VARIANT|MONO_GEN_PARAM_COVARIANT)))
4287                         continue;
4288                 type = ginst->type_argv [i];
4289                 if (mini_type_is_reference (type))
4290                         return TRUE;
4291         }
4292         return FALSE;
4293 }
4294
4295 static GHashTable* direct_icall_type_hash;
4296
4297 static gboolean
4298 icall_is_direct_callable (MonoCompile *cfg, MonoMethod *cmethod)
4299 {
4300         /* LLVM on amd64 can't handle calls to non-32 bit addresses */
4301         if (!direct_icalls_enabled (cfg))
4302                 return FALSE;
4303
4304         /*
4305          * An icall is directly callable if it doesn't directly or indirectly call mono_raise_exception ().
4306          * Whitelist a few icalls for now.
4307          */
4308         if (!direct_icall_type_hash) {
4309                 GHashTable *h = g_hash_table_new (g_str_hash, g_str_equal);
4310
4311                 g_hash_table_insert (h, (char*)"Decimal", GUINT_TO_POINTER (1));
4312                 g_hash_table_insert (h, (char*)"Number", GUINT_TO_POINTER (1));
4313                 g_hash_table_insert (h, (char*)"Buffer", GUINT_TO_POINTER (1));
4314                 g_hash_table_insert (h, (char*)"Monitor", GUINT_TO_POINTER (1));
4315                 mono_memory_barrier ();
4316                 direct_icall_type_hash = h;
4317         }
4318
4319         if (cmethod->klass == mono_defaults.math_class)
4320                 return TRUE;
4321         /* No locking needed */
4322         if (cmethod->klass->image == mono_defaults.corlib && g_hash_table_lookup (direct_icall_type_hash, cmethod->klass->name))
4323                 return TRUE;
4324         return FALSE;
4325 }
4326
4327 #define is_complex_isinst(klass) ((klass->flags & TYPE_ATTRIBUTE_INTERFACE) || klass->rank || mono_class_is_nullable (klass) || mono_class_is_marshalbyref (klass) || (klass->flags & TYPE_ATTRIBUTE_SEALED) || klass->byval_arg.type == MONO_TYPE_VAR || klass->byval_arg.type == MONO_TYPE_MVAR)
4328
4329 static MonoInst*
4330 emit_castclass_with_cache (MonoCompile *cfg, MonoClass *klass, MonoInst **args)
4331 {
4332         MonoMethod *mono_castclass;
4333         MonoInst *res;
4334
4335         mono_castclass = mono_marshal_get_castclass_with_cache ();
4336
4337         save_cast_details (cfg, klass, args [0]->dreg, TRUE);
4338         res = mono_emit_method_call (cfg, mono_castclass, args, NULL);
4339         reset_cast_details (cfg);
4340
4341         return res;
4342 }
4343
4344 static int
4345 get_castclass_cache_idx (MonoCompile *cfg)
4346 {
4347         /* Each CASTCLASS_CACHE patch needs a unique index which identifies the call site */
4348         cfg->castclass_cache_index ++;
4349         return (cfg->method_index << 16) | cfg->castclass_cache_index;
4350 }
4351
4352 static MonoInst*
4353 emit_castclass_with_cache_nonshared (MonoCompile *cfg, MonoInst *obj, MonoClass *klass)
4354 {
4355         MonoInst *args [3];
4356         int idx;
4357
4358         /* obj */
4359         args [0] = obj;
4360
4361         /* klass */
4362         EMIT_NEW_CLASSCONST (cfg, args [1], klass);
4363
4364         /* inline cache*/
4365         if (cfg->compile_aot) {
4366                 idx = get_castclass_cache_idx (cfg);
4367                 EMIT_NEW_AOTCONST (cfg, args [2], MONO_PATCH_INFO_CASTCLASS_CACHE, GINT_TO_POINTER (idx));
4368         } else {
4369                 EMIT_NEW_PCONST (cfg, args [2], mono_domain_alloc0 (cfg->domain, sizeof (gpointer)));
4370         }
4371
4372         /*The wrapper doesn't inline well so the bloat of inlining doesn't pay off.*/
4373         return emit_castclass_with_cache (cfg, klass, args);
4374 }
4375
4376 /*
4377  * Returns NULL and set the cfg exception on error.
4378  */
4379 static MonoInst*
4380 handle_castclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src, guint8 *ip, int *inline_costs)
4381 {
4382         MonoBasicBlock *is_null_bb;
4383         int obj_reg = src->dreg;
4384         int vtable_reg = alloc_preg (cfg);
4385         int context_used;
4386         MonoInst *klass_inst = NULL, *res;
4387
4388         context_used = mini_class_check_context_used (cfg, klass);
4389
4390         if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
4391                 res = emit_castclass_with_cache_nonshared (cfg, src, klass);
4392                 (*inline_costs) += 2;
4393                 return res;
4394         } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
4395                 MonoMethod *mono_castclass;
4396                 MonoInst *iargs [1];
4397                 int costs;
4398
4399                 mono_castclass = mono_marshal_get_castclass (klass); 
4400                 iargs [0] = src;
4401                                 
4402                 save_cast_details (cfg, klass, src->dreg, TRUE);
4403                 costs = inline_method (cfg, mono_castclass, mono_method_signature (mono_castclass), 
4404                                                            iargs, ip, cfg->real_offset, TRUE);
4405                 reset_cast_details (cfg);
4406                 CHECK_CFG_EXCEPTION;
4407                 g_assert (costs > 0);
4408                                 
4409                 cfg->real_offset += 5;
4410
4411                 (*inline_costs) += costs;
4412
4413                 return src;
4414         }
4415
4416         if (context_used) {
4417                 MonoInst *args [3];
4418
4419                 if(mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || is_complex_isinst (klass)) {
4420                         MonoInst *cache_ins;
4421
4422                         cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
4423
4424                         /* obj */
4425                         args [0] = src;
4426
4427                         /* klass - it's the second element of the cache entry*/
4428                         EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer));
4429
4430                         /* cache */
4431                         args [2] = cache_ins;
4432
4433                         return emit_castclass_with_cache (cfg, klass, args);
4434                 }
4435
4436                 klass_inst = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
4437         }
4438
4439         NEW_BBLOCK (cfg, is_null_bb);
4440
4441         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4442         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
4443
4444         save_cast_details (cfg, klass, obj_reg, FALSE);
4445
4446         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4447                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4448                 mini_emit_iface_cast (cfg, vtable_reg, klass, NULL, NULL);
4449         } else {
4450                 int klass_reg = alloc_preg (cfg);
4451
4452                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4453
4454                 if (!klass->rank && !cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && (klass->flags & TYPE_ATTRIBUTE_SEALED)) {
4455                         /* the remoting code is broken, access the class for now */
4456                         if (0) { /*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
4457                                 MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
4458                                 if (!vt) {
4459                                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4460                                         cfg->exception_ptr = klass;
4461                                         return NULL;
4462                                 }
4463                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vt);
4464                         } else {
4465                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4466                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
4467                         }
4468                         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
4469                 } else {
4470                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4471                         mini_emit_castclass_inst (cfg, obj_reg, klass_reg, klass, klass_inst, is_null_bb);
4472                 }
4473         }
4474
4475         MONO_START_BB (cfg, is_null_bb);
4476
4477         reset_cast_details (cfg);
4478
4479         return src;
4480
4481 exception_exit:
4482         return NULL;
4483 }
4484
4485 /*
4486  * Returns NULL and set the cfg exception on error.
4487  */
4488 static MonoInst*
4489 handle_isinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context_used)
4490 {
4491         MonoInst *ins;
4492         MonoBasicBlock *is_null_bb, *false_bb, *end_bb;
4493         int obj_reg = src->dreg;
4494         int vtable_reg = alloc_preg (cfg);
4495         int res_reg = alloc_ireg_ref (cfg);
4496         MonoInst *klass_inst = NULL;
4497
4498         if (context_used) {
4499                 MonoInst *args [3];
4500
4501                 if(mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || is_complex_isinst (klass)) {
4502                         MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
4503                         MonoInst *cache_ins;
4504
4505                         cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
4506
4507                         /* obj */
4508                         args [0] = src;
4509
4510                         /* klass - it's the second element of the cache entry*/
4511                         EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer));
4512
4513                         /* cache */
4514                         args [2] = cache_ins;
4515
4516                         return mono_emit_method_call (cfg, mono_isinst, args, NULL);
4517                 }
4518
4519                 klass_inst = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
4520         }
4521
4522         NEW_BBLOCK (cfg, is_null_bb);
4523         NEW_BBLOCK (cfg, false_bb);
4524         NEW_BBLOCK (cfg, end_bb);
4525
4526         /* Do the assignment at the beginning, so the other assignment can be if converted */
4527         EMIT_NEW_UNALU (cfg, ins, OP_MOVE, res_reg, obj_reg);
4528         ins->type = STACK_OBJ;
4529         ins->klass = klass;
4530
4531         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4532         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_null_bb);
4533
4534         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4535
4536         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4537                 g_assert (!context_used);
4538                 /* the is_null_bb target simply copies the input register to the output */
4539                 mini_emit_iface_cast (cfg, vtable_reg, klass, false_bb, is_null_bb);
4540         } else {
4541                 int klass_reg = alloc_preg (cfg);
4542
4543                 if (klass->rank) {
4544                         int rank_reg = alloc_preg (cfg);
4545                         int eclass_reg = alloc_preg (cfg);
4546
4547                         g_assert (!context_used);
4548                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
4549                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank);
4550                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4551                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4552                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, cast_class));
4553                         if (klass->cast_class == mono_defaults.object_class) {
4554                                 int parent_reg = alloc_preg (cfg);
4555                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, parent_reg, eclass_reg, MONO_STRUCT_OFFSET (MonoClass, parent));
4556                                 mini_emit_class_check_branch (cfg, parent_reg, mono_defaults.enum_class->parent, OP_PBNE_UN, is_null_bb);
4557                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);
4558                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4559                         } else if (klass->cast_class == mono_defaults.enum_class->parent) {
4560                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class->parent, OP_PBEQ, is_null_bb);
4561                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);                          
4562                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4563                         } else if (klass->cast_class == mono_defaults.enum_class) {
4564                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);
4565                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4566                         } else if (klass->cast_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
4567                                 mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb);
4568                         } else {
4569                                 if ((klass->rank == 1) && (klass->byval_arg.type == MONO_TYPE_SZARRAY)) {
4570                                         /* Check that the object is a vector too */
4571                                         int bounds_reg = alloc_preg (cfg);
4572                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, obj_reg, MONO_STRUCT_OFFSET (MonoArray, bounds));
4573                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
4574                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4575                                 }
4576
4577                                 /* the is_null_bb target simply copies the input register to the output */
4578                                 mini_emit_isninst_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb);
4579                         }
4580                 } else if (mono_class_is_nullable (klass)) {
4581                         g_assert (!context_used);
4582                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4583                         /* the is_null_bb target simply copies the input register to the output */
4584                         mini_emit_isninst_cast (cfg, klass_reg, klass->cast_class, false_bb, is_null_bb);
4585                 } else {
4586                         if (!cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && (klass->flags & TYPE_ATTRIBUTE_SEALED)) {
4587                                 g_assert (!context_used);
4588                                 /* the remoting code is broken, access the class for now */
4589                                 if (0) {/*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
4590                                         MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
4591                                         if (!vt) {
4592                                                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4593                                                 cfg->exception_ptr = klass;
4594                                                 return NULL;
4595                                         }
4596                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vt);
4597                                 } else {
4598                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4599                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
4600                                 }
4601                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4602                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, is_null_bb);
4603                         } else {
4604                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4605                                 /* the is_null_bb target simply copies the input register to the output */
4606                                 mini_emit_isninst_cast_inst (cfg, klass_reg, klass, klass_inst, false_bb, is_null_bb);
4607                         }
4608                 }
4609         }
4610
4611         MONO_START_BB (cfg, false_bb);
4612
4613         MONO_EMIT_NEW_PCONST (cfg, res_reg, 0);
4614         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4615
4616         MONO_START_BB (cfg, is_null_bb);
4617
4618         MONO_START_BB (cfg, end_bb);
4619
4620         return ins;
4621 }
4622
4623 static MonoInst*
4624 handle_cisinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
4625 {
4626         /* This opcode takes as input an object reference and a class, and returns:
4627         0) if the object is an instance of the class,
4628         1) if the object is not instance of the class,
4629         2) if the object is a proxy whose type cannot be determined */
4630
4631         MonoInst *ins;
4632 #ifndef DISABLE_REMOTING
4633         MonoBasicBlock *true_bb, *false_bb, *false2_bb, *end_bb, *no_proxy_bb, *interface_fail_bb;
4634 #else
4635         MonoBasicBlock *true_bb, *false_bb, *end_bb;
4636 #endif
4637         int obj_reg = src->dreg;
4638         int dreg = alloc_ireg (cfg);
4639         int tmp_reg;
4640 #ifndef DISABLE_REMOTING
4641         int klass_reg = alloc_preg (cfg);
4642 #endif
4643
4644         NEW_BBLOCK (cfg, true_bb);
4645         NEW_BBLOCK (cfg, false_bb);
4646         NEW_BBLOCK (cfg, end_bb);
4647 #ifndef DISABLE_REMOTING
4648         NEW_BBLOCK (cfg, false2_bb);
4649         NEW_BBLOCK (cfg, no_proxy_bb);
4650 #endif
4651
4652         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4653         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, false_bb);
4654
4655         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4656 #ifndef DISABLE_REMOTING
4657                 NEW_BBLOCK (cfg, interface_fail_bb);
4658 #endif
4659
4660                 tmp_reg = alloc_preg (cfg);
4661                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4662 #ifndef DISABLE_REMOTING
4663                 mini_emit_iface_cast (cfg, tmp_reg, klass, interface_fail_bb, true_bb);
4664                 MONO_START_BB (cfg, interface_fail_bb);
4665                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4666                 
4667                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, false_bb);
4668
4669                 tmp_reg = alloc_preg (cfg);
4670                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4671                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4672                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false2_bb);                
4673 #else
4674                 mini_emit_iface_cast (cfg, tmp_reg, klass, false_bb, true_bb);
4675 #endif
4676         } else {
4677 #ifndef DISABLE_REMOTING
4678                 tmp_reg = alloc_preg (cfg);
4679                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4680                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4681
4682                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, no_proxy_bb);          
4683                 tmp_reg = alloc_preg (cfg);
4684                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, remote_class));
4685                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoRemoteClass, proxy_class));
4686
4687                 tmp_reg = alloc_preg (cfg);             
4688                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4689                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4690                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, no_proxy_bb);
4691                 
4692                 mini_emit_isninst_cast (cfg, klass_reg, klass, false2_bb, true_bb);
4693                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false2_bb);
4694
4695                 MONO_START_BB (cfg, no_proxy_bb);
4696
4697                 mini_emit_isninst_cast (cfg, klass_reg, klass, false_bb, true_bb);
4698 #else
4699                 g_error ("transparent proxy support is disabled while trying to JIT code that uses it");
4700 #endif
4701         }
4702
4703         MONO_START_BB (cfg, false_bb);
4704
4705         MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4706         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4707
4708 #ifndef DISABLE_REMOTING
4709         MONO_START_BB (cfg, false2_bb);
4710
4711         MONO_EMIT_NEW_ICONST (cfg, dreg, 2);
4712         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4713 #endif
4714
4715         MONO_START_BB (cfg, true_bb);
4716
4717         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
4718
4719         MONO_START_BB (cfg, end_bb);
4720
4721         /* FIXME: */
4722         MONO_INST_NEW (cfg, ins, OP_ICONST);
4723         ins->dreg = dreg;
4724         ins->type = STACK_I4;
4725
4726         return ins;
4727 }
4728
4729 static MonoInst*
4730 handle_ccastclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
4731 {
4732         /* This opcode takes as input an object reference and a class, and returns:
4733         0) if the object is an instance of the class,
4734         1) if the object is a proxy whose type cannot be determined
4735         an InvalidCastException exception is thrown otherwhise*/
4736         
4737         MonoInst *ins;
4738 #ifndef DISABLE_REMOTING
4739         MonoBasicBlock *end_bb, *ok_result_bb, *no_proxy_bb, *interface_fail_bb, *fail_1_bb;
4740 #else
4741         MonoBasicBlock *ok_result_bb;
4742 #endif
4743         int obj_reg = src->dreg;
4744         int dreg = alloc_ireg (cfg);
4745         int tmp_reg = alloc_preg (cfg);
4746
4747 #ifndef DISABLE_REMOTING
4748         int klass_reg = alloc_preg (cfg);
4749         NEW_BBLOCK (cfg, end_bb);
4750 #endif
4751
4752         NEW_BBLOCK (cfg, ok_result_bb);
4753
4754         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4755         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, ok_result_bb);
4756
4757         save_cast_details (cfg, klass, obj_reg, FALSE);
4758
4759         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4760 #ifndef DISABLE_REMOTING
4761                 NEW_BBLOCK (cfg, interface_fail_bb);
4762         
4763                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4764                 mini_emit_iface_cast (cfg, tmp_reg, klass, interface_fail_bb, ok_result_bb);
4765                 MONO_START_BB (cfg, interface_fail_bb);
4766                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4767
4768                 mini_emit_class_check (cfg, klass_reg, mono_defaults.transparent_proxy_class);
4769
4770                 tmp_reg = alloc_preg (cfg);             
4771                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4772                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4773                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
4774                 
4775                 MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4776                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4777 #else
4778                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4779                 mini_emit_iface_cast (cfg, tmp_reg, klass, NULL, NULL);
4780                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, ok_result_bb);
4781 #endif
4782         } else {
4783 #ifndef DISABLE_REMOTING
4784                 NEW_BBLOCK (cfg, no_proxy_bb);
4785
4786                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4787                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4788                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, no_proxy_bb);          
4789
4790                 tmp_reg = alloc_preg (cfg);
4791                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, remote_class));
4792                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoRemoteClass, proxy_class));
4793
4794                 tmp_reg = alloc_preg (cfg);
4795                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4796                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4797                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, no_proxy_bb);
4798
4799                 NEW_BBLOCK (cfg, fail_1_bb);
4800                 
4801                 mini_emit_isninst_cast (cfg, klass_reg, klass, fail_1_bb, ok_result_bb);
4802
4803                 MONO_START_BB (cfg, fail_1_bb);
4804
4805                 MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4806                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4807
4808                 MONO_START_BB (cfg, no_proxy_bb);
4809
4810                 mini_emit_castclass (cfg, obj_reg, klass_reg, klass, ok_result_bb);
4811 #else
4812                 g_error ("Transparent proxy support is disabled while trying to JIT code that uses it");
4813 #endif
4814         }
4815
4816         MONO_START_BB (cfg, ok_result_bb);
4817
4818         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
4819
4820 #ifndef DISABLE_REMOTING
4821         MONO_START_BB (cfg, end_bb);
4822 #endif
4823
4824         /* FIXME: */
4825         MONO_INST_NEW (cfg, ins, OP_ICONST);
4826         ins->dreg = dreg;
4827         ins->type = STACK_I4;
4828
4829         return ins;
4830 }
4831
4832 static G_GNUC_UNUSED MonoInst*
4833 handle_enum_has_flag (MonoCompile *cfg, MonoClass *klass, MonoInst *enum_this, MonoInst *enum_flag)
4834 {
4835         MonoType *enum_type = mono_type_get_underlying_type (&klass->byval_arg);
4836         guint32 load_opc = mono_type_to_load_membase (cfg, enum_type);
4837         gboolean is_i4;
4838
4839         switch (enum_type->type) {
4840         case MONO_TYPE_I8:
4841         case MONO_TYPE_U8:
4842 #if SIZEOF_REGISTER == 8
4843         case MONO_TYPE_I:
4844         case MONO_TYPE_U:
4845 #endif
4846                 is_i4 = FALSE;
4847                 break;
4848         default:
4849                 is_i4 = TRUE;
4850                 break;
4851         }
4852
4853         {
4854                 MonoInst *load, *and, *cmp, *ceq;
4855                 int enum_reg = is_i4 ? alloc_ireg (cfg) : alloc_lreg (cfg);
4856                 int and_reg = is_i4 ? alloc_ireg (cfg) : alloc_lreg (cfg);
4857                 int dest_reg = alloc_ireg (cfg);
4858
4859                 EMIT_NEW_LOAD_MEMBASE (cfg, load, load_opc, enum_reg, enum_this->dreg, 0);
4860                 EMIT_NEW_BIALU (cfg, and, is_i4 ? OP_IAND : OP_LAND, and_reg, enum_reg, enum_flag->dreg);
4861                 EMIT_NEW_BIALU (cfg, cmp, is_i4 ? OP_ICOMPARE : OP_LCOMPARE, -1, and_reg, enum_flag->dreg);
4862                 EMIT_NEW_UNALU (cfg, ceq, is_i4 ? OP_ICEQ : OP_LCEQ, dest_reg, -1);
4863
4864                 ceq->type = STACK_I4;
4865
4866                 if (!is_i4) {
4867                         load = mono_decompose_opcode (cfg, load);
4868                         and = mono_decompose_opcode (cfg, and);
4869                         cmp = mono_decompose_opcode (cfg, cmp);
4870                         ceq = mono_decompose_opcode (cfg, ceq);
4871                 }
4872
4873                 return ceq;
4874         }
4875 }
4876
4877 /*
4878  * Returns NULL and set the cfg exception on error.
4879  */
4880 static G_GNUC_UNUSED MonoInst*
4881 handle_delegate_ctor (MonoCompile *cfg, MonoClass *klass, MonoInst *target, MonoMethod *method, int context_used, gboolean virtual)
4882 {
4883         MonoInst *ptr;
4884         int dreg;
4885         gpointer trampoline;
4886         MonoInst *obj, *method_ins, *tramp_ins;
4887         MonoDomain *domain;
4888         guint8 **code_slot;
4889
4890         if (virtual) {
4891                 MonoMethod *invoke = mono_get_delegate_invoke (klass);
4892                 g_assert (invoke);
4893
4894                 if (!mono_get_delegate_virtual_invoke_impl (mono_method_signature (invoke), context_used ? NULL : method))
4895                         return NULL;
4896         }
4897
4898         obj = handle_alloc (cfg, klass, FALSE, 0);
4899         if (!obj)
4900                 return NULL;
4901
4902         /* Inline the contents of mono_delegate_ctor */
4903
4904         /* Set target field */
4905         /* Optimize away setting of NULL target */
4906         if (!(target->opcode == OP_PCONST && target->inst_p0 == 0)) {
4907                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, target), target->dreg);
4908                 if (cfg->gen_write_barriers) {
4909                         dreg = alloc_preg (cfg);
4910                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, target));
4911                         emit_write_barrier (cfg, ptr, target);
4912                 }
4913         }
4914
4915         /* Set method field */
4916         method_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD);
4917         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method), method_ins->dreg);
4918
4919         /* 
4920          * To avoid looking up the compiled code belonging to the target method
4921          * in mono_delegate_trampoline (), we allocate a per-domain memory slot to
4922          * store it, and we fill it after the method has been compiled.
4923          */
4924         if (!method->dynamic && !(cfg->opt & MONO_OPT_SHARED)) {
4925                 MonoInst *code_slot_ins;
4926
4927                 if (context_used) {
4928                         code_slot_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD_DELEGATE_CODE);
4929                 } else {
4930                         domain = mono_domain_get ();
4931                         mono_domain_lock (domain);
4932                         if (!domain_jit_info (domain)->method_code_hash)
4933                                 domain_jit_info (domain)->method_code_hash = g_hash_table_new (NULL, NULL);
4934                         code_slot = g_hash_table_lookup (domain_jit_info (domain)->method_code_hash, method);
4935                         if (!code_slot) {
4936                                 code_slot = mono_domain_alloc0 (domain, sizeof (gpointer));
4937                                 g_hash_table_insert (domain_jit_info (domain)->method_code_hash, method, code_slot);
4938                         }
4939                         mono_domain_unlock (domain);
4940
4941                         if (cfg->compile_aot)
4942                                 EMIT_NEW_AOTCONST (cfg, code_slot_ins, MONO_PATCH_INFO_METHOD_CODE_SLOT, method);
4943                         else
4944                                 EMIT_NEW_PCONST (cfg, code_slot_ins, code_slot);
4945                 }
4946                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_code), code_slot_ins->dreg);                
4947         }
4948
4949         if (cfg->compile_aot) {
4950                 MonoDelegateClassMethodPair *del_tramp;
4951
4952                 del_tramp = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoDelegateClassMethodPair));
4953                 del_tramp->klass = klass;
4954                 del_tramp->method = context_used ? NULL : method;
4955                 del_tramp->virtual = virtual;
4956                 EMIT_NEW_AOTCONST (cfg, tramp_ins, MONO_PATCH_INFO_DELEGATE_TRAMPOLINE, del_tramp);
4957         } else {
4958                 if (virtual)
4959                         trampoline = mono_create_delegate_virtual_trampoline (cfg->domain, klass, context_used ? NULL : method);
4960                 else
4961                         trampoline = mono_create_delegate_trampoline_info (cfg->domain, klass, context_used ? NULL : method);
4962                 EMIT_NEW_PCONST (cfg, tramp_ins, trampoline);
4963         }
4964
4965         /* Set invoke_impl field */
4966         if (virtual) {
4967                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl), tramp_ins->dreg);
4968         } else {
4969                 dreg = alloc_preg (cfg);
4970                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, tramp_ins->dreg, MONO_STRUCT_OFFSET (MonoDelegateTrampInfo, invoke_impl));
4971                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl), dreg);
4972
4973                 dreg = alloc_preg (cfg);
4974                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, tramp_ins->dreg, MONO_STRUCT_OFFSET (MonoDelegateTrampInfo, method_ptr));
4975                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr), dreg);
4976         }
4977
4978         dreg = alloc_preg (cfg);
4979         MONO_EMIT_NEW_ICONST (cfg, dreg, virtual ? 1 : 0);
4980         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_is_virtual), dreg);
4981
4982         /* All the checks which are in mono_delegate_ctor () are done by the delegate trampoline */
4983
4984         return obj;
4985 }
4986
4987 static MonoInst*
4988 handle_array_new (MonoCompile *cfg, int rank, MonoInst **sp, unsigned char *ip)
4989 {
4990         MonoJitICallInfo *info;
4991
4992         /* Need to register the icall so it gets an icall wrapper */
4993         info = mono_get_array_new_va_icall (rank);
4994
4995         cfg->flags |= MONO_CFG_HAS_VARARGS;
4996
4997         /* mono_array_new_va () needs a vararg calling convention */
4998         cfg->disable_llvm = TRUE;
4999
5000         /* FIXME: This uses info->sig, but it should use the signature of the wrapper */
5001         return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, sp);
5002 }
5003
5004 /*
5005  * handle_constrained_gsharedvt_call:
5006  *
5007  *   Handle constrained calls where the receiver is a gsharedvt type.
5008  * Return the instruction representing the call. Set the cfg exception on failure.
5009  */
5010 static MonoInst*
5011 handle_constrained_gsharedvt_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp, MonoClass *constrained_class,
5012                                                                    gboolean *ref_emit_widen)
5013 {
5014         MonoInst *ins = NULL;
5015         gboolean emit_widen = *ref_emit_widen;
5016
5017         /*
5018          * Constrained calls need to behave differently at runtime dependending on whenever the receiver is instantiated as ref type or as a vtype.
5019          * This is hard to do with the current call code, since we would have to emit a branch and two different calls. So instead, we
5020          * pack the arguments into an array, and do the rest of the work in in an icall.
5021          */
5022         if (((cmethod->klass == mono_defaults.object_class) || (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) || (!cmethod->klass->valuetype && cmethod->klass->image != mono_defaults.corlib)) &&
5023                 (MONO_TYPE_IS_VOID (fsig->ret) || MONO_TYPE_IS_PRIMITIVE (fsig->ret) || MONO_TYPE_IS_REFERENCE (fsig->ret) || MONO_TYPE_ISSTRUCT (fsig->ret) || mini_is_gsharedvt_type (fsig->ret)) &&
5024                 (fsig->param_count == 0 || (!fsig->hasthis && fsig->param_count == 1) || (fsig->param_count == 1 && (MONO_TYPE_IS_REFERENCE (fsig->params [0]) || fsig->params [0]->byref || mini_is_gsharedvt_type (fsig->params [0]))))) {
5025                 MonoInst *args [16];
5026
5027                 /*
5028                  * This case handles calls to
5029                  * - object:ToString()/Equals()/GetHashCode(),
5030                  * - System.IComparable<T>:CompareTo()
5031                  * - System.IEquatable<T>:Equals ()
5032                  * plus some simple interface calls enough to support AsyncTaskMethodBuilder.
5033                  */
5034
5035                 args [0] = sp [0];
5036                 if (mono_method_check_context_used (cmethod))
5037                         args [1] = emit_get_rgctx_method (cfg, mono_method_check_context_used (cmethod), cmethod, MONO_RGCTX_INFO_METHOD);
5038                 else
5039                         EMIT_NEW_METHODCONST (cfg, args [1], cmethod);
5040                 args [2] = emit_get_rgctx_klass (cfg, mono_class_check_context_used (constrained_class), constrained_class, MONO_RGCTX_INFO_KLASS);
5041
5042                 /* !fsig->hasthis is for the wrapper for the Object.GetType () icall */
5043                 if (fsig->hasthis && fsig->param_count) {
5044                         /* Pass the arguments using a localloc-ed array using the format expected by runtime_invoke () */
5045                         MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
5046                         ins->dreg = alloc_preg (cfg);
5047                         ins->inst_imm = fsig->param_count * sizeof (mgreg_t);
5048                         MONO_ADD_INS (cfg->cbb, ins);
5049                         args [4] = ins;
5050
5051                         if (mini_is_gsharedvt_type (fsig->params [0])) {
5052                                 int addr_reg;
5053
5054                                 args [3] = emit_get_gsharedvt_info_klass (cfg, mono_class_from_mono_type (fsig->params [0]), MONO_RGCTX_INFO_CLASS_BOX_TYPE);
5055
5056                                 EMIT_NEW_VARLOADA_VREG (cfg, ins, sp [1]->dreg, fsig->params [0]);
5057                                 addr_reg = ins->dreg;
5058                                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [4]->dreg, 0, addr_reg);
5059                         } else {
5060                                 EMIT_NEW_ICONST (cfg, args [3], 0);
5061                                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [4]->dreg, 0, sp [1]->dreg);
5062                         }
5063                 } else {
5064                         EMIT_NEW_ICONST (cfg, args [3], 0);
5065                         EMIT_NEW_ICONST (cfg, args [4], 0);
5066                 }
5067                 ins = mono_emit_jit_icall (cfg, mono_gsharedvt_constrained_call, args);
5068                 emit_widen = FALSE;
5069
5070                 if (mini_is_gsharedvt_type (fsig->ret)) {
5071                         ins = handle_unbox_gsharedvt (cfg, mono_class_from_mono_type (fsig->ret), ins);
5072                 } else if (MONO_TYPE_IS_PRIMITIVE (fsig->ret) || MONO_TYPE_ISSTRUCT (fsig->ret)) {
5073                         MonoInst *add;
5074
5075                         /* Unbox */
5076                         NEW_BIALU_IMM (cfg, add, OP_ADD_IMM, alloc_dreg (cfg, STACK_MP), ins->dreg, sizeof (MonoObject));
5077                         MONO_ADD_INS (cfg->cbb, add);
5078                         /* Load value */
5079                         NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, add->dreg, 0);
5080                         MONO_ADD_INS (cfg->cbb, ins);
5081                         /* ins represents the call result */
5082                 }
5083         } else {
5084                 GSHAREDVT_FAILURE (CEE_CALLVIRT);
5085         }
5086
5087         *ref_emit_widen = emit_widen;
5088
5089         return ins;
5090
5091  exception_exit:
5092         return NULL;
5093 }
5094
5095 static void
5096 mono_emit_load_got_addr (MonoCompile *cfg)
5097 {
5098         MonoInst *getaddr, *dummy_use;
5099
5100         if (!cfg->got_var || cfg->got_var_allocated)
5101                 return;
5102
5103         MONO_INST_NEW (cfg, getaddr, OP_LOAD_GOTADDR);
5104         getaddr->cil_code = cfg->header->code;
5105         getaddr->dreg = cfg->got_var->dreg;
5106
5107         /* Add it to the start of the first bblock */
5108         if (cfg->bb_entry->code) {
5109                 getaddr->next = cfg->bb_entry->code;
5110                 cfg->bb_entry->code = getaddr;
5111         }
5112         else
5113                 MONO_ADD_INS (cfg->bb_entry, getaddr);
5114
5115         cfg->got_var_allocated = TRUE;
5116
5117         /* 
5118          * Add a dummy use to keep the got_var alive, since real uses might
5119          * only be generated by the back ends.
5120          * Add it to end_bblock, so the variable's lifetime covers the whole
5121          * method.
5122          * It would be better to make the usage of the got var explicit in all
5123          * cases when the backend needs it (i.e. calls, throw etc.), so this
5124          * wouldn't be needed.
5125          */
5126         NEW_DUMMY_USE (cfg, dummy_use, cfg->got_var);
5127         MONO_ADD_INS (cfg->bb_exit, dummy_use);
5128 }
5129
5130 static int inline_limit;
5131 static gboolean inline_limit_inited;
5132
5133 static gboolean
5134 mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method)
5135 {
5136         MonoMethodHeaderSummary header;
5137         MonoVTable *vtable;
5138 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
5139         MonoMethodSignature *sig = mono_method_signature (method);
5140         int i;
5141 #endif
5142
5143         if (cfg->disable_inline)
5144                 return FALSE;
5145         if (cfg->gshared)
5146                 return FALSE;
5147
5148         if (cfg->inline_depth > 10)
5149                 return FALSE;
5150
5151         if (!mono_method_get_header_summary (method, &header))
5152                 return FALSE;
5153
5154         /*runtime, icall and pinvoke are checked by summary call*/
5155         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_NOINLINING) ||
5156             (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) ||
5157             (mono_class_is_marshalbyref (method->klass)) ||
5158             header.has_clauses)
5159                 return FALSE;
5160
5161         /* also consider num_locals? */
5162         /* Do the size check early to avoid creating vtables */
5163         if (!inline_limit_inited) {
5164                 if (g_getenv ("MONO_INLINELIMIT"))
5165                         inline_limit = atoi (g_getenv ("MONO_INLINELIMIT"));
5166                 else
5167                         inline_limit = INLINE_LENGTH_LIMIT;
5168                 inline_limit_inited = TRUE;
5169         }
5170         if (header.code_size >= inline_limit && !(method->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING))
5171                 return FALSE;
5172
5173         /*
5174          * if we can initialize the class of the method right away, we do,
5175          * otherwise we don't allow inlining if the class needs initialization,
5176          * since it would mean inserting a call to mono_runtime_class_init()
5177          * inside the inlined code
5178          */
5179         if (!(cfg->opt & MONO_OPT_SHARED)) {
5180                 /* The AggressiveInlining hint is a good excuse to force that cctor to run. */
5181                 if (method->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING) {
5182                         vtable = mono_class_vtable (cfg->domain, method->klass);
5183                         if (!vtable)
5184                                 return FALSE;
5185                         if (!cfg->compile_aot)
5186                                 mono_runtime_class_init (vtable);
5187                 } else if (method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) {
5188                         if (cfg->run_cctors && method->klass->has_cctor) {
5189                                 /*FIXME it would easier and lazier to just use mono_class_try_get_vtable */
5190                                 if (!method->klass->runtime_info)
5191                                         /* No vtable created yet */
5192                                         return FALSE;
5193                                 vtable = mono_class_vtable (cfg->domain, method->klass);
5194                                 if (!vtable)
5195                                         return FALSE;
5196                                 /* This makes so that inline cannot trigger */
5197                                 /* .cctors: too many apps depend on them */
5198                                 /* running with a specific order... */
5199                                 if (! vtable->initialized)
5200                                         return FALSE;
5201                                 mono_runtime_class_init (vtable);
5202                         }
5203                 } else if (mono_class_needs_cctor_run (method->klass, NULL)) {
5204                         if (!method->klass->runtime_info)
5205                                 /* No vtable created yet */
5206                                 return FALSE;
5207                         vtable = mono_class_vtable (cfg->domain, method->klass);
5208                         if (!vtable)
5209                                 return FALSE;
5210                         if (!vtable->initialized)
5211                                 return FALSE;
5212                 }
5213         } else {
5214                 /* 
5215                  * If we're compiling for shared code
5216                  * the cctor will need to be run at aot method load time, for example,
5217                  * or at the end of the compilation of the inlining method.
5218                  */
5219                 if (mono_class_needs_cctor_run (method->klass, NULL) && !((method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT)))
5220                         return FALSE;
5221         }
5222
5223 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
5224         if (mono_arch_is_soft_float ()) {
5225                 /* FIXME: */
5226                 if (sig->ret && sig->ret->type == MONO_TYPE_R4)
5227                         return FALSE;
5228                 for (i = 0; i < sig->param_count; ++i)
5229                         if (!sig->params [i]->byref && sig->params [i]->type == MONO_TYPE_R4)
5230                                 return FALSE;
5231         }
5232 #endif
5233
5234         if (g_list_find (cfg->dont_inline, method))
5235                 return FALSE;
5236
5237         return TRUE;
5238 }
5239
5240 static gboolean
5241 mini_field_access_needs_cctor_run (MonoCompile *cfg, MonoMethod *method, MonoClass *klass, MonoVTable *vtable)
5242 {
5243         if (!cfg->compile_aot) {
5244                 g_assert (vtable);
5245                 if (vtable->initialized)
5246                         return FALSE;
5247         }
5248
5249         if (klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) {
5250                 if (cfg->method == method)
5251                         return FALSE;
5252         }
5253
5254         if (!mono_class_needs_cctor_run (klass, method))
5255                 return FALSE;
5256
5257         if (! (method->flags & METHOD_ATTRIBUTE_STATIC) && (klass == method->klass))
5258                 /* The initialization is already done before the method is called */
5259                 return FALSE;
5260
5261         return TRUE;
5262 }
5263
5264 static MonoInst*
5265 mini_emit_ldelema_1_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index, gboolean bcheck)
5266 {
5267         MonoInst *ins;
5268         guint32 size;
5269         int mult_reg, add_reg, array_reg, index_reg, index2_reg;
5270         int context_used;
5271
5272         if (mini_is_gsharedvt_variable_klass (klass)) {
5273                 size = -1;
5274         } else {
5275                 mono_class_init (klass);
5276                 size = mono_class_array_element_size (klass);
5277         }
5278
5279         mult_reg = alloc_preg (cfg);
5280         array_reg = arr->dreg;
5281         index_reg = index->dreg;
5282
5283 #if SIZEOF_REGISTER == 8
5284         /* The array reg is 64 bits but the index reg is only 32 */
5285         if (COMPILE_LLVM (cfg)) {
5286                 /* Not needed */
5287                 index2_reg = index_reg;
5288         } else {
5289                 index2_reg = alloc_preg (cfg);
5290                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index2_reg, index_reg);
5291         }
5292 #else
5293         if (index->type == STACK_I8) {
5294                 index2_reg = alloc_preg (cfg);
5295                 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I4, index2_reg, index_reg);
5296         } else {
5297                 index2_reg = index_reg;
5298         }
5299 #endif
5300
5301         if (bcheck)
5302                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index2_reg);
5303
5304 #if defined(TARGET_X86) || defined(TARGET_AMD64)
5305         if (size == 1 || size == 2 || size == 4 || size == 8) {
5306                 static const int fast_log2 [] = { 1, 0, 1, -1, 2, -1, -1, -1, 3 };
5307
5308                 EMIT_NEW_X86_LEA (cfg, ins, array_reg, index2_reg, fast_log2 [size], MONO_STRUCT_OFFSET (MonoArray, vector));
5309                 ins->klass = mono_class_get_element_class (klass);
5310                 ins->type = STACK_MP;
5311
5312                 return ins;
5313         }
5314 #endif          
5315
5316         add_reg = alloc_ireg_mp (cfg);
5317
5318         if (size == -1) {
5319                 MonoInst *rgctx_ins;
5320
5321                 /* gsharedvt */
5322                 g_assert (cfg->gshared);
5323                 context_used = mini_class_check_context_used (cfg, klass);
5324                 g_assert (context_used);
5325                 rgctx_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE);
5326                 MONO_EMIT_NEW_BIALU (cfg, OP_IMUL, mult_reg, index2_reg, rgctx_ins->dreg);
5327         } else {
5328                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MUL_IMM, mult_reg, index2_reg, size);
5329         }
5330         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, array_reg, mult_reg);
5331         NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, MONO_STRUCT_OFFSET (MonoArray, vector));
5332         ins->klass = mono_class_get_element_class (klass);
5333         ins->type = STACK_MP;
5334         MONO_ADD_INS (cfg->cbb, ins);
5335
5336         return ins;
5337 }
5338
5339 #ifndef MONO_ARCH_EMULATE_MUL_DIV
5340 static MonoInst*
5341 mini_emit_ldelema_2_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index_ins1, MonoInst *index_ins2)
5342 {
5343         int bounds_reg = alloc_preg (cfg);
5344         int add_reg = alloc_ireg_mp (cfg);
5345         int mult_reg = alloc_preg (cfg);
5346         int mult2_reg = alloc_preg (cfg);
5347         int low1_reg = alloc_preg (cfg);
5348         int low2_reg = alloc_preg (cfg);
5349         int high1_reg = alloc_preg (cfg);
5350         int high2_reg = alloc_preg (cfg);
5351         int realidx1_reg = alloc_preg (cfg);
5352         int realidx2_reg = alloc_preg (cfg);
5353         int sum_reg = alloc_preg (cfg);
5354         int index1, index2, tmpreg;
5355         MonoInst *ins;
5356         guint32 size;
5357
5358         mono_class_init (klass);
5359         size = mono_class_array_element_size (klass);
5360
5361         index1 = index_ins1->dreg;
5362         index2 = index_ins2->dreg;
5363
5364 #if SIZEOF_REGISTER == 8
5365         /* The array reg is 64 bits but the index reg is only 32 */
5366         if (COMPILE_LLVM (cfg)) {
5367                 /* Not needed */
5368         } else {
5369                 tmpreg = alloc_preg (cfg);
5370                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, tmpreg, index1);
5371                 index1 = tmpreg;
5372                 tmpreg = alloc_preg (cfg);
5373                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, tmpreg, index2);
5374                 index2 = tmpreg;
5375         }
5376 #else
5377         // FIXME: Do we need to do something here for i8 indexes, like in ldelema_1_ins ?
5378         tmpreg = -1;
5379 #endif
5380
5381         /* range checking */
5382         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, 
5383                                        arr->dreg, MONO_STRUCT_OFFSET (MonoArray, bounds));
5384
5385         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low1_reg, 
5386                                        bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
5387         MONO_EMIT_NEW_BIALU (cfg, OP_PSUB, realidx1_reg, index1, low1_reg);
5388         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high1_reg, 
5389                                        bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, length));
5390         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, high1_reg, realidx1_reg);
5391         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException");
5392
5393         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low2_reg, 
5394                                        bounds_reg, sizeof (MonoArrayBounds) + MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
5395         MONO_EMIT_NEW_BIALU (cfg, OP_PSUB, realidx2_reg, index2, low2_reg);
5396         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high2_reg, 
5397                                        bounds_reg, sizeof (MonoArrayBounds) + MONO_STRUCT_OFFSET (MonoArrayBounds, length));
5398         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, high2_reg, realidx2_reg);
5399         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException");
5400
5401         MONO_EMIT_NEW_BIALU (cfg, OP_PMUL, mult_reg, high2_reg, realidx1_reg);
5402         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, mult_reg, realidx2_reg);
5403         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PMUL_IMM, mult2_reg, sum_reg, size);
5404         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult2_reg, arr->dreg);
5405         NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, MONO_STRUCT_OFFSET (MonoArray, vector));
5406
5407         ins->type = STACK_MP;
5408         ins->klass = klass;
5409         MONO_ADD_INS (cfg->cbb, ins);
5410
5411         return ins;
5412 }
5413 #endif
5414
5415 static MonoInst*
5416 mini_emit_ldelema_ins (MonoCompile *cfg, MonoMethod *cmethod, MonoInst **sp, unsigned char *ip, gboolean is_set)
5417 {
5418         int rank;
5419         MonoInst *addr;
5420         MonoMethod *addr_method;
5421         int element_size;
5422         MonoClass *eclass = cmethod->klass->element_class;
5423
5424         rank = mono_method_signature (cmethod)->param_count - (is_set? 1: 0);
5425
5426         if (rank == 1)
5427                 return mini_emit_ldelema_1_ins (cfg, eclass, sp [0], sp [1], TRUE);
5428
5429 #ifndef MONO_ARCH_EMULATE_MUL_DIV
5430         /* emit_ldelema_2 depends on OP_LMUL */
5431         if (rank == 2 && (cfg->opt & MONO_OPT_INTRINS) && !mini_is_gsharedvt_variable_klass (eclass)) {
5432                 return mini_emit_ldelema_2_ins (cfg, eclass, sp [0], sp [1], sp [2]);
5433         }
5434 #endif
5435
5436         if (mini_is_gsharedvt_variable_klass (eclass))
5437                 element_size = 0;
5438         else
5439                 element_size = mono_class_array_element_size (eclass);
5440         addr_method = mono_marshal_get_array_address (rank, element_size);
5441         addr = mono_emit_method_call (cfg, addr_method, sp, NULL);
5442
5443         return addr;
5444 }
5445
5446 static MonoBreakPolicy
5447 always_insert_breakpoint (MonoMethod *method)
5448 {
5449         return MONO_BREAK_POLICY_ALWAYS;
5450 }
5451
5452 static MonoBreakPolicyFunc break_policy_func = always_insert_breakpoint;
5453
5454 /**
5455  * mono_set_break_policy:
5456  * policy_callback: the new callback function
5457  *
5458  * Allow embedders to decide wherther to actually obey breakpoint instructions
5459  * (both break IL instructions and Debugger.Break () method calls), for example
5460  * to not allow an app to be aborted by a perfectly valid IL opcode when executing
5461  * untrusted or semi-trusted code.
5462  *
5463  * @policy_callback will be called every time a break point instruction needs to
5464  * be inserted with the method argument being the method that calls Debugger.Break()
5465  * or has the IL break instruction. The callback should return #MONO_BREAK_POLICY_NEVER
5466  * if it wants the breakpoint to not be effective in the given method.
5467  * #MONO_BREAK_POLICY_ALWAYS is the default.
5468  */
5469 void
5470 mono_set_break_policy (MonoBreakPolicyFunc policy_callback)
5471 {
5472         if (policy_callback)
5473                 break_policy_func = policy_callback;
5474         else
5475                 break_policy_func = always_insert_breakpoint;
5476 }
5477
5478 static gboolean
5479 should_insert_brekpoint (MonoMethod *method) {
5480         switch (break_policy_func (method)) {
5481         case MONO_BREAK_POLICY_ALWAYS:
5482                 return TRUE;
5483         case MONO_BREAK_POLICY_NEVER:
5484                 return FALSE;
5485         case MONO_BREAK_POLICY_ON_DBG:
5486                 g_warning ("mdb no longer supported");
5487                 return FALSE;
5488         default:
5489                 g_warning ("Incorrect value returned from break policy callback");
5490                 return FALSE;
5491         }
5492 }
5493
5494 /* optimize the simple GetGenericValueImpl/SetGenericValueImpl generic icalls */
5495 static MonoInst*
5496 emit_array_generic_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set)
5497 {
5498         MonoInst *addr, *store, *load;
5499         MonoClass *eklass = mono_class_from_mono_type (fsig->params [2]);
5500
5501         /* the bounds check is already done by the callers */
5502         addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1], FALSE);
5503         if (is_set) {
5504                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, args [2]->dreg, 0);
5505                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, addr->dreg, 0, load->dreg);
5506                 if (mini_type_is_reference (fsig->params [2]))
5507                         emit_write_barrier (cfg, addr, load);
5508         } else {
5509                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, addr->dreg, 0);
5510                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, args [2]->dreg, 0, load->dreg);
5511         }
5512         return store;
5513 }
5514
5515
5516 static gboolean
5517 generic_class_is_reference_type (MonoCompile *cfg, MonoClass *klass)
5518 {
5519         return mini_type_is_reference (&klass->byval_arg);
5520 }
5521
5522 static MonoInst*
5523 emit_array_store (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, gboolean safety_checks)
5524 {
5525         if (safety_checks && generic_class_is_reference_type (cfg, klass) &&
5526                 !(sp [2]->opcode == OP_PCONST && sp [2]->inst_p0 == NULL)) {
5527                 MonoClass *obj_array = mono_array_class_get_cached (mono_defaults.object_class, 1);
5528                 MonoMethod *helper = mono_marshal_get_virtual_stelemref (obj_array);
5529                 MonoInst *iargs [3];
5530
5531                 if (!helper->slot)
5532                         mono_class_setup_vtable (obj_array);
5533                 g_assert (helper->slot);
5534
5535                 if (sp [0]->type != STACK_OBJ)
5536                         return NULL;
5537                 if (sp [2]->type != STACK_OBJ)
5538                         return NULL;
5539
5540                 iargs [2] = sp [2];
5541                 iargs [1] = sp [1];
5542                 iargs [0] = sp [0];
5543
5544                 return mono_emit_method_call (cfg, helper, iargs, sp [0]);
5545         } else {
5546                 MonoInst *ins;
5547
5548                 if (mini_is_gsharedvt_variable_klass (klass)) {
5549                         MonoInst *addr;
5550
5551                         // FIXME-VT: OP_ICONST optimization
5552                         addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
5553                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
5554                         ins->opcode = OP_STOREV_MEMBASE;
5555                 } else if (sp [1]->opcode == OP_ICONST) {
5556                         int array_reg = sp [0]->dreg;
5557                         int index_reg = sp [1]->dreg;
5558                         int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + MONO_STRUCT_OFFSET (MonoArray, vector);
5559
5560                         if (safety_checks)
5561                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
5562                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset, sp [2]->dreg);
5563                 } else {
5564                         MonoInst *addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], safety_checks);
5565                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
5566                         if (generic_class_is_reference_type (cfg, klass))
5567                                 emit_write_barrier (cfg, addr, sp [2]);
5568                 }
5569                 return ins;
5570         }
5571 }
5572
5573 static MonoInst*
5574 emit_array_unsafe_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set)
5575 {
5576         MonoClass *eklass;
5577         
5578         if (is_set)
5579                 eklass = mono_class_from_mono_type (fsig->params [2]);
5580         else
5581                 eklass = mono_class_from_mono_type (fsig->ret);
5582
5583         if (is_set) {
5584                 return emit_array_store (cfg, eklass, args, FALSE);
5585         } else {
5586                 MonoInst *ins, *addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1], FALSE);
5587                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &eklass->byval_arg, addr->dreg, 0);
5588                 return ins;
5589         }
5590 }
5591
5592 static gboolean
5593 is_unsafe_mov_compatible (MonoCompile *cfg, MonoClass *param_klass, MonoClass *return_klass)
5594 {
5595         uint32_t align;
5596
5597         param_klass = mono_class_from_mono_type (mini_get_underlying_type (&param_klass->byval_arg));
5598
5599         //Only allow for valuetypes
5600         if (!param_klass->valuetype || !return_klass->valuetype)
5601                 return FALSE;
5602
5603         //That are blitable
5604         if (param_klass->has_references || return_klass->has_references)
5605                 return FALSE;
5606
5607         /* Avoid mixing structs and primitive types/enums, they need to be handled differently in the JIT */
5608         if ((MONO_TYPE_ISSTRUCT (&param_klass->byval_arg) && !MONO_TYPE_ISSTRUCT (&return_klass->byval_arg)) ||
5609                 (!MONO_TYPE_ISSTRUCT (&param_klass->byval_arg) && MONO_TYPE_ISSTRUCT (&return_klass->byval_arg)))
5610                 return FALSE;
5611
5612         if (param_klass->byval_arg.type == MONO_TYPE_R4 || param_klass->byval_arg.type == MONO_TYPE_R8 ||
5613                 return_klass->byval_arg.type == MONO_TYPE_R4 || return_klass->byval_arg.type == MONO_TYPE_R8)
5614                 return FALSE;
5615
5616         //And have the same size
5617         if (mono_class_value_size (param_klass, &align) != mono_class_value_size (return_klass, &align))
5618                 return FALSE;
5619         return TRUE;
5620 }
5621
5622 static MonoInst*
5623 emit_array_unsafe_mov (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args)
5624 {
5625         MonoClass *param_klass = mono_class_from_mono_type (fsig->params [0]);
5626         MonoClass *return_klass = mono_class_from_mono_type (fsig->ret);
5627
5628         //Valuetypes that are semantically equivalent
5629         if (is_unsafe_mov_compatible (cfg, param_klass, return_klass))
5630                 return args [0];
5631
5632         //Arrays of valuetypes that are semantically equivalent
5633         if (param_klass->rank == 1 && return_klass->rank == 1 && is_unsafe_mov_compatible (cfg, param_klass->element_class, return_klass->element_class))
5634                 return args [0];
5635
5636         return NULL;
5637 }
5638
5639 static MonoInst*
5640 mini_emit_inst_for_ctor (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5641 {
5642 #ifdef MONO_ARCH_SIMD_INTRINSICS
5643         MonoInst *ins = NULL;
5644
5645         if (cfg->opt & MONO_OPT_SIMD) {
5646                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
5647                 if (ins)
5648                         return ins;
5649         }
5650 #endif
5651
5652         return mono_emit_native_types_intrinsics (cfg, cmethod, fsig, args);
5653 }
5654
5655 static MonoInst*
5656 emit_memory_barrier (MonoCompile *cfg, int kind)
5657 {
5658         MonoInst *ins = NULL;
5659         MONO_INST_NEW (cfg, ins, OP_MEMORY_BARRIER);
5660         MONO_ADD_INS (cfg->cbb, ins);
5661         ins->backend.memory_barrier_kind = kind;
5662
5663         return ins;
5664 }
5665
5666 static MonoInst*
5667 llvm_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5668 {
5669         MonoInst *ins = NULL;
5670         int opcode = 0;
5671
5672         /* The LLVM backend supports these intrinsics */
5673         if (cmethod->klass == mono_defaults.math_class) {
5674                 if (strcmp (cmethod->name, "Sin") == 0) {
5675                         opcode = OP_SIN;
5676                 } else if (strcmp (cmethod->name, "Cos") == 0) {
5677                         opcode = OP_COS;
5678                 } else if (strcmp (cmethod->name, "Sqrt") == 0) {
5679                         opcode = OP_SQRT;
5680                 } else if (strcmp (cmethod->name, "Abs") == 0 && fsig->params [0]->type == MONO_TYPE_R8) {
5681                         opcode = OP_ABS;
5682                 }
5683
5684                 if (opcode && fsig->param_count == 1) {
5685                         MONO_INST_NEW (cfg, ins, opcode);
5686                         ins->type = STACK_R8;
5687                         ins->dreg = mono_alloc_freg (cfg);
5688                         ins->sreg1 = args [0]->dreg;
5689                         MONO_ADD_INS (cfg->cbb, ins);
5690                 }
5691
5692                 opcode = 0;
5693                 if (cfg->opt & MONO_OPT_CMOV) {
5694                         if (strcmp (cmethod->name, "Min") == 0) {
5695                                 if (fsig->params [0]->type == MONO_TYPE_I4)
5696                                         opcode = OP_IMIN;
5697                                 if (fsig->params [0]->type == MONO_TYPE_U4)
5698                                         opcode = OP_IMIN_UN;
5699                                 else if (fsig->params [0]->type == MONO_TYPE_I8)
5700                                         opcode = OP_LMIN;
5701                                 else if (fsig->params [0]->type == MONO_TYPE_U8)
5702                                         opcode = OP_LMIN_UN;
5703                         } else if (strcmp (cmethod->name, "Max") == 0) {
5704                                 if (fsig->params [0]->type == MONO_TYPE_I4)
5705                                         opcode = OP_IMAX;
5706                                 if (fsig->params [0]->type == MONO_TYPE_U4)
5707                                         opcode = OP_IMAX_UN;
5708                                 else if (fsig->params [0]->type == MONO_TYPE_I8)
5709                                         opcode = OP_LMAX;
5710                                 else if (fsig->params [0]->type == MONO_TYPE_U8)
5711                                         opcode = OP_LMAX_UN;
5712                         }
5713                 }
5714
5715                 if (opcode && fsig->param_count == 2) {
5716                         MONO_INST_NEW (cfg, ins, opcode);
5717                         ins->type = fsig->params [0]->type == MONO_TYPE_I4 ? STACK_I4 : STACK_I8;
5718                         ins->dreg = mono_alloc_ireg (cfg);
5719                         ins->sreg1 = args [0]->dreg;
5720                         ins->sreg2 = args [1]->dreg;
5721                         MONO_ADD_INS (cfg->cbb, ins);
5722                 }
5723         }
5724
5725         return ins;
5726 }
5727
5728 static MonoInst*
5729 mini_emit_inst_for_sharable_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5730 {
5731         if (cmethod->klass == mono_defaults.array_class) {
5732                 if (strcmp (cmethod->name, "UnsafeStore") == 0)
5733                         return emit_array_unsafe_access (cfg, fsig, args, TRUE);
5734                 else if (strcmp (cmethod->name, "UnsafeLoad") == 0)
5735                         return emit_array_unsafe_access (cfg, fsig, args, FALSE);
5736                 else if (strcmp (cmethod->name, "UnsafeMov") == 0)
5737                         return emit_array_unsafe_mov (cfg, fsig, args);
5738         }
5739
5740         return NULL;
5741 }
5742
5743 static MonoInst*
5744 mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5745 {
5746         MonoInst *ins = NULL;
5747
5748         static MonoClass *runtime_helpers_class = NULL;
5749         if (! runtime_helpers_class)
5750                 runtime_helpers_class = mono_class_from_name (mono_defaults.corlib,
5751                         "System.Runtime.CompilerServices", "RuntimeHelpers");
5752
5753         if (cmethod->klass == mono_defaults.string_class) {
5754                 if (strcmp (cmethod->name, "get_Chars") == 0 && fsig->param_count + fsig->hasthis == 2) {
5755                         int dreg = alloc_ireg (cfg);
5756                         int index_reg = alloc_preg (cfg);
5757                         int add_reg = alloc_preg (cfg);
5758
5759 #if SIZEOF_REGISTER == 8
5760                         /* The array reg is 64 bits but the index reg is only 32 */
5761                         MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index_reg, args [1]->dreg);
5762 #else
5763                         index_reg = args [1]->dreg;
5764 #endif  
5765                         MONO_EMIT_BOUNDS_CHECK (cfg, args [0]->dreg, MonoString, length, index_reg);
5766
5767 #if defined(TARGET_X86) || defined(TARGET_AMD64)
5768                         EMIT_NEW_X86_LEA (cfg, ins, args [0]->dreg, index_reg, 1, MONO_STRUCT_OFFSET (MonoString, chars));
5769                         add_reg = ins->dreg;
5770                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
5771                                                                    add_reg, 0);
5772 #else
5773                         int mult_reg = alloc_preg (cfg);
5774                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, mult_reg, index_reg, 1);
5775                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult_reg, args [0]->dreg);
5776                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
5777                                                                    add_reg, MONO_STRUCT_OFFSET (MonoString, chars));
5778 #endif
5779                         type_from_op (cfg, ins, NULL, NULL);
5780                         return ins;
5781                 } else if (strcmp (cmethod->name, "get_Length") == 0 && fsig->param_count + fsig->hasthis == 1) {
5782                         int dreg = alloc_ireg (cfg);
5783                         /* Decompose later to allow more optimizations */
5784                         EMIT_NEW_UNALU (cfg, ins, OP_STRLEN, dreg, args [0]->dreg);
5785                         ins->type = STACK_I4;
5786                         ins->flags |= MONO_INST_FAULT;
5787                         cfg->cbb->has_array_access = TRUE;
5788                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
5789
5790                         return ins;
5791                 } else 
5792                         return NULL;
5793         } else if (cmethod->klass == mono_defaults.object_class) {
5794
5795                 if (strcmp (cmethod->name, "GetType") == 0 && fsig->param_count + fsig->hasthis == 1) {
5796                         int dreg = alloc_ireg_ref (cfg);
5797                         int vt_reg = alloc_preg (cfg);
5798                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vt_reg, args [0]->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
5799                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, vt_reg, MONO_STRUCT_OFFSET (MonoVTable, type));
5800                         type_from_op (cfg, ins, NULL, NULL);
5801
5802                         return ins;
5803 #if !defined(MONO_ARCH_EMULATE_MUL_DIV)
5804                 } else if (strcmp (cmethod->name, "InternalGetHashCode") == 0 && fsig->param_count == 1 && !mono_gc_is_moving ()) {
5805                         int dreg = alloc_ireg (cfg);
5806                         int t1 = alloc_ireg (cfg);
5807         
5808                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, t1, args [0]->dreg, 3);
5809                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_MUL_IMM, dreg, t1, 2654435761u);
5810                         ins->type = STACK_I4;
5811
5812                         return ins;
5813 #endif
5814                 } else if (strcmp (cmethod->name, ".ctor") == 0 && fsig->param_count == 0) {
5815                         MONO_INST_NEW (cfg, ins, OP_NOP);
5816                         MONO_ADD_INS (cfg->cbb, ins);
5817                         return ins;
5818                 } else
5819                         return NULL;
5820         } else if (cmethod->klass == mono_defaults.array_class) {
5821                 if (strcmp (cmethod->name, "GetGenericValueImpl") == 0 && fsig->param_count + fsig->hasthis == 3 && !cfg->gsharedvt)
5822                         return emit_array_generic_access (cfg, fsig, args, FALSE);
5823                 else if (strcmp (cmethod->name, "SetGenericValueImpl") == 0 && fsig->param_count + fsig->hasthis == 3 && !cfg->gsharedvt)
5824                         return emit_array_generic_access (cfg, fsig, args, TRUE);
5825
5826 #ifndef MONO_BIG_ARRAYS
5827                 /*
5828                  * This is an inline version of GetLength/GetLowerBound(0) used frequently in
5829                  * Array methods.
5830                  */
5831                 else if (((strcmp (cmethod->name, "GetLength") == 0 && fsig->param_count + fsig->hasthis == 2) ||
5832                          (strcmp (cmethod->name, "GetLowerBound") == 0 && fsig->param_count + fsig->hasthis == 2)) &&
5833                          args [1]->opcode == OP_ICONST && args [1]->inst_c0 == 0) {
5834                         int dreg = alloc_ireg (cfg);
5835                         int bounds_reg = alloc_ireg_mp (cfg);
5836                         MonoBasicBlock *end_bb, *szarray_bb;
5837                         gboolean get_length = strcmp (cmethod->name, "GetLength") == 0;
5838
5839                         NEW_BBLOCK (cfg, end_bb);
5840                         NEW_BBLOCK (cfg, szarray_bb);
5841
5842                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOAD_MEMBASE, bounds_reg,
5843                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, bounds));
5844                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
5845                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, szarray_bb);
5846                         /* Non-szarray case */
5847                         if (get_length)
5848                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5849                                                                            bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, length));
5850                         else
5851                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5852                                                                            bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
5853                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
5854                         MONO_START_BB (cfg, szarray_bb);
5855                         /* Szarray case */
5856                         if (get_length)
5857                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5858                                                                            args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, max_length));
5859                         else
5860                                 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
5861                         MONO_START_BB (cfg, end_bb);
5862
5863                         EMIT_NEW_UNALU (cfg, ins, OP_MOVE, dreg, dreg);
5864                         ins->type = STACK_I4;
5865                         
5866                         return ins;
5867                 }
5868 #endif
5869
5870                 if (cmethod->name [0] != 'g')
5871                         return NULL;
5872
5873                 if (strcmp (cmethod->name, "get_Rank") == 0 && fsig->param_count + fsig->hasthis == 1) {
5874                         int dreg = alloc_ireg (cfg);
5875                         int vtable_reg = alloc_preg (cfg);
5876                         MONO_EMIT_NEW_LOAD_MEMBASE_OP_FAULT (cfg, OP_LOAD_MEMBASE, vtable_reg, 
5877                                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
5878                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU1_MEMBASE, dreg,
5879                                                                    vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
5880                         type_from_op (cfg, ins, NULL, NULL);
5881
5882                         return ins;
5883                 } else if (strcmp (cmethod->name, "get_Length") == 0 && fsig->param_count + fsig->hasthis == 1) {
5884                         int dreg = alloc_ireg (cfg);
5885
5886                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOADI4_MEMBASE, dreg, 
5887                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, max_length));
5888                         type_from_op (cfg, ins, NULL, NULL);
5889
5890                         return ins;
5891                 } else
5892                         return NULL;
5893         } else if (cmethod->klass == runtime_helpers_class) {
5894
5895                 if (strcmp (cmethod->name, "get_OffsetToStringData") == 0 && fsig->param_count == 0) {
5896                         EMIT_NEW_ICONST (cfg, ins, MONO_STRUCT_OFFSET (MonoString, chars));
5897                         return ins;
5898                 } else
5899                         return NULL;
5900         } else if (cmethod->klass == mono_defaults.thread_class) {
5901                 if (strcmp (cmethod->name, "SpinWait_nop") == 0 && fsig->param_count == 0) {
5902                         MONO_INST_NEW (cfg, ins, OP_RELAXED_NOP);
5903                         MONO_ADD_INS (cfg->cbb, ins);
5904                         return ins;
5905                 } else if (strcmp (cmethod->name, "MemoryBarrier") == 0 && fsig->param_count == 0) {
5906                         return emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
5907                 } else if (!strcmp (cmethod->name, "VolatileRead") && fsig->param_count == 1) {
5908                         guint32 opcode = 0;
5909                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
5910
5911                         if (fsig->params [0]->type == MONO_TYPE_I1)
5912                                 opcode = OP_LOADI1_MEMBASE;
5913                         else if (fsig->params [0]->type == MONO_TYPE_U1)
5914                                 opcode = OP_LOADU1_MEMBASE;
5915                         else if (fsig->params [0]->type == MONO_TYPE_I2)
5916                                 opcode = OP_LOADI2_MEMBASE;
5917                         else if (fsig->params [0]->type == MONO_TYPE_U2)
5918                                 opcode = OP_LOADU2_MEMBASE;
5919                         else if (fsig->params [0]->type == MONO_TYPE_I4)
5920                                 opcode = OP_LOADI4_MEMBASE;
5921                         else if (fsig->params [0]->type == MONO_TYPE_U4)
5922                                 opcode = OP_LOADU4_MEMBASE;
5923                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_U8)
5924                                 opcode = OP_LOADI8_MEMBASE;
5925                         else if (fsig->params [0]->type == MONO_TYPE_R4)
5926                                 opcode = OP_LOADR4_MEMBASE;
5927                         else if (fsig->params [0]->type == MONO_TYPE_R8)
5928                                 opcode = OP_LOADR8_MEMBASE;
5929                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I || fsig->params [0]->type == MONO_TYPE_U)
5930                                 opcode = OP_LOAD_MEMBASE;
5931
5932                         if (opcode) {
5933                                 MONO_INST_NEW (cfg, ins, opcode);
5934                                 ins->inst_basereg = args [0]->dreg;
5935                                 ins->inst_offset = 0;
5936                                 MONO_ADD_INS (cfg->cbb, ins);
5937
5938                                 switch (fsig->params [0]->type) {
5939                                 case MONO_TYPE_I1:
5940                                 case MONO_TYPE_U1:
5941                                 case MONO_TYPE_I2:
5942                                 case MONO_TYPE_U2:
5943                                 case MONO_TYPE_I4:
5944                                 case MONO_TYPE_U4:
5945                                         ins->dreg = mono_alloc_ireg (cfg);
5946                                         ins->type = STACK_I4;
5947                                         break;
5948                                 case MONO_TYPE_I8:
5949                                 case MONO_TYPE_U8:
5950                                         ins->dreg = mono_alloc_lreg (cfg);
5951                                         ins->type = STACK_I8;
5952                                         break;
5953                                 case MONO_TYPE_I:
5954                                 case MONO_TYPE_U:
5955                                         ins->dreg = mono_alloc_ireg (cfg);
5956 #if SIZEOF_REGISTER == 8
5957                                         ins->type = STACK_I8;
5958 #else
5959                                         ins->type = STACK_I4;
5960 #endif
5961                                         break;
5962                                 case MONO_TYPE_R4:
5963                                 case MONO_TYPE_R8:
5964                                         ins->dreg = mono_alloc_freg (cfg);
5965                                         ins->type = STACK_R8;
5966                                         break;
5967                                 default:
5968                                         g_assert (mini_type_is_reference (fsig->params [0]));
5969                                         ins->dreg = mono_alloc_ireg_ref (cfg);
5970                                         ins->type = STACK_OBJ;
5971                                         break;
5972                                 }
5973
5974                                 if (opcode == OP_LOADI8_MEMBASE)
5975                                         ins = mono_decompose_opcode (cfg, ins);
5976
5977                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
5978
5979                                 return ins;
5980                         }
5981                 } else if (!strcmp (cmethod->name, "VolatileWrite") && fsig->param_count == 2) {
5982                         guint32 opcode = 0;
5983                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
5984
5985                         if (fsig->params [0]->type == MONO_TYPE_I1 || fsig->params [0]->type == MONO_TYPE_U1)
5986                                 opcode = OP_STOREI1_MEMBASE_REG;
5987                         else if (fsig->params [0]->type == MONO_TYPE_I2 || fsig->params [0]->type == MONO_TYPE_U2)
5988                                 opcode = OP_STOREI2_MEMBASE_REG;
5989                         else if (fsig->params [0]->type == MONO_TYPE_I4 || fsig->params [0]->type == MONO_TYPE_U4)
5990                                 opcode = OP_STOREI4_MEMBASE_REG;
5991                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_U8)
5992                                 opcode = OP_STOREI8_MEMBASE_REG;
5993                         else if (fsig->params [0]->type == MONO_TYPE_R4)
5994                                 opcode = OP_STORER4_MEMBASE_REG;
5995                         else if (fsig->params [0]->type == MONO_TYPE_R8)
5996                                 opcode = OP_STORER8_MEMBASE_REG;
5997                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I || fsig->params [0]->type == MONO_TYPE_U)
5998                                 opcode = OP_STORE_MEMBASE_REG;
5999
6000                         if (opcode) {
6001                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
6002
6003                                 MONO_INST_NEW (cfg, ins, opcode);
6004                                 ins->sreg1 = args [1]->dreg;
6005                                 ins->inst_destbasereg = args [0]->dreg;
6006                                 ins->inst_offset = 0;
6007                                 MONO_ADD_INS (cfg->cbb, ins);
6008
6009                                 if (opcode == OP_STOREI8_MEMBASE_REG)
6010                                         ins = mono_decompose_opcode (cfg, ins);
6011
6012                                 return ins;
6013                         }
6014                 }
6015         } else if (cmethod->klass->image == mono_defaults.corlib &&
6016                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
6017                            (strcmp (cmethod->klass->name, "Interlocked") == 0)) {
6018                 ins = NULL;
6019
6020 #if SIZEOF_REGISTER == 8
6021                 if (strcmp (cmethod->name, "Read") == 0 && fsig->param_count == 1 && (fsig->params [0]->type == MONO_TYPE_I8)) {
6022                         if (mono_arch_opcode_supported (OP_ATOMIC_LOAD_I8)) {
6023                                 MONO_INST_NEW (cfg, ins, OP_ATOMIC_LOAD_I8);
6024                                 ins->dreg = mono_alloc_preg (cfg);
6025                                 ins->sreg1 = args [0]->dreg;
6026                                 ins->type = STACK_I8;
6027                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_SEQ;
6028                                 MONO_ADD_INS (cfg->cbb, ins);
6029                         } else {
6030                                 MonoInst *load_ins;
6031
6032                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6033
6034                                 /* 64 bit reads are already atomic */
6035                                 MONO_INST_NEW (cfg, load_ins, OP_LOADI8_MEMBASE);
6036                                 load_ins->dreg = mono_alloc_preg (cfg);
6037                                 load_ins->inst_basereg = args [0]->dreg;
6038                                 load_ins->inst_offset = 0;
6039                                 load_ins->type = STACK_I8;
6040                                 MONO_ADD_INS (cfg->cbb, load_ins);
6041
6042                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6043
6044                                 ins = load_ins;
6045                         }
6046                 }
6047 #endif
6048
6049                 if (strcmp (cmethod->name, "Increment") == 0 && fsig->param_count == 1) {
6050                         MonoInst *ins_iconst;
6051                         guint32 opcode = 0;
6052
6053                         if (fsig->params [0]->type == MONO_TYPE_I4) {
6054                                 opcode = OP_ATOMIC_ADD_I4;
6055                                 cfg->has_atomic_add_i4 = TRUE;
6056                         }
6057 #if SIZEOF_REGISTER == 8
6058                         else if (fsig->params [0]->type == MONO_TYPE_I8)
6059                                 opcode = OP_ATOMIC_ADD_I8;
6060 #endif
6061                         if (opcode) {
6062                                 if (!mono_arch_opcode_supported (opcode))
6063                                         return NULL;
6064                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
6065                                 ins_iconst->inst_c0 = 1;
6066                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
6067                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
6068
6069                                 MONO_INST_NEW (cfg, ins, opcode);
6070                                 ins->dreg = mono_alloc_ireg (cfg);
6071                                 ins->inst_basereg = args [0]->dreg;
6072                                 ins->inst_offset = 0;
6073                                 ins->sreg2 = ins_iconst->dreg;
6074                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
6075                                 MONO_ADD_INS (cfg->cbb, ins);
6076                         }
6077                 } else if (strcmp (cmethod->name, "Decrement") == 0 && fsig->param_count == 1) {
6078                         MonoInst *ins_iconst;
6079                         guint32 opcode = 0;
6080
6081                         if (fsig->params [0]->type == MONO_TYPE_I4) {
6082                                 opcode = OP_ATOMIC_ADD_I4;
6083                                 cfg->has_atomic_add_i4 = TRUE;
6084                         }
6085 #if SIZEOF_REGISTER == 8
6086                         else if (fsig->params [0]->type == MONO_TYPE_I8)
6087                                 opcode = OP_ATOMIC_ADD_I8;
6088 #endif
6089                         if (opcode) {
6090                                 if (!mono_arch_opcode_supported (opcode))
6091                                         return NULL;
6092                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
6093                                 ins_iconst->inst_c0 = -1;
6094                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
6095                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
6096
6097                                 MONO_INST_NEW (cfg, ins, opcode);
6098                                 ins->dreg = mono_alloc_ireg (cfg);
6099                                 ins->inst_basereg = args [0]->dreg;
6100                                 ins->inst_offset = 0;
6101                                 ins->sreg2 = ins_iconst->dreg;
6102                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
6103                                 MONO_ADD_INS (cfg->cbb, ins);
6104                         }
6105                 } else if (strcmp (cmethod->name, "Add") == 0 && fsig->param_count == 2) {
6106                         guint32 opcode = 0;
6107
6108                         if (fsig->params [0]->type == MONO_TYPE_I4) {
6109                                 opcode = OP_ATOMIC_ADD_I4;
6110                                 cfg->has_atomic_add_i4 = TRUE;
6111                         }
6112 #if SIZEOF_REGISTER == 8
6113                         else if (fsig->params [0]->type == MONO_TYPE_I8)
6114                                 opcode = OP_ATOMIC_ADD_I8;
6115 #endif
6116                         if (opcode) {
6117                                 if (!mono_arch_opcode_supported (opcode))
6118                                         return NULL;
6119                                 MONO_INST_NEW (cfg, ins, opcode);
6120                                 ins->dreg = mono_alloc_ireg (cfg);
6121                                 ins->inst_basereg = args [0]->dreg;
6122                                 ins->inst_offset = 0;
6123                                 ins->sreg2 = args [1]->dreg;
6124                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
6125                                 MONO_ADD_INS (cfg->cbb, ins);
6126                         }
6127                 }
6128                 else if (strcmp (cmethod->name, "Exchange") == 0 && fsig->param_count == 2) {
6129                         MonoInst *f2i = NULL, *i2f;
6130                         guint32 opcode, f2i_opcode, i2f_opcode;
6131                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
6132                         gboolean is_float = fsig->params [0]->type == MONO_TYPE_R4 || fsig->params [0]->type == MONO_TYPE_R8;
6133
6134                         if (fsig->params [0]->type == MONO_TYPE_I4 ||
6135                             fsig->params [0]->type == MONO_TYPE_R4) {
6136                                 opcode = OP_ATOMIC_EXCHANGE_I4;
6137                                 f2i_opcode = OP_MOVE_F_TO_I4;
6138                                 i2f_opcode = OP_MOVE_I4_TO_F;
6139                                 cfg->has_atomic_exchange_i4 = TRUE;
6140                         }
6141 #if SIZEOF_REGISTER == 8
6142                         else if (is_ref ||
6143                                  fsig->params [0]->type == MONO_TYPE_I8 ||
6144                                  fsig->params [0]->type == MONO_TYPE_R8 ||
6145                                  fsig->params [0]->type == MONO_TYPE_I) {
6146                                 opcode = OP_ATOMIC_EXCHANGE_I8;
6147                                 f2i_opcode = OP_MOVE_F_TO_I8;
6148                                 i2f_opcode = OP_MOVE_I8_TO_F;
6149                         }
6150 #else
6151                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I) {
6152                                 opcode = OP_ATOMIC_EXCHANGE_I4;
6153                                 cfg->has_atomic_exchange_i4 = TRUE;
6154                         }
6155 #endif
6156                         else
6157                                 return NULL;
6158
6159                         if (!mono_arch_opcode_supported (opcode))
6160                                 return NULL;
6161
6162                         if (is_float) {
6163                                 /* TODO: Decompose these opcodes instead of bailing here. */
6164                                 if (COMPILE_SOFT_FLOAT (cfg))
6165                                         return NULL;
6166
6167                                 MONO_INST_NEW (cfg, f2i, f2i_opcode);
6168                                 f2i->dreg = mono_alloc_ireg (cfg);
6169                                 f2i->sreg1 = args [1]->dreg;
6170                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
6171                                         f2i->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6172                                 MONO_ADD_INS (cfg->cbb, f2i);
6173                         }
6174
6175                         MONO_INST_NEW (cfg, ins, opcode);
6176                         ins->dreg = is_ref ? mono_alloc_ireg_ref (cfg) : mono_alloc_ireg (cfg);
6177                         ins->inst_basereg = args [0]->dreg;
6178                         ins->inst_offset = 0;
6179                         ins->sreg2 = is_float ? f2i->dreg : args [1]->dreg;
6180                         MONO_ADD_INS (cfg->cbb, ins);
6181
6182                         switch (fsig->params [0]->type) {
6183                         case MONO_TYPE_I4:
6184                                 ins->type = STACK_I4;
6185                                 break;
6186                         case MONO_TYPE_I8:
6187                                 ins->type = STACK_I8;
6188                                 break;
6189                         case MONO_TYPE_I:
6190 #if SIZEOF_REGISTER == 8
6191                                 ins->type = STACK_I8;
6192 #else
6193                                 ins->type = STACK_I4;
6194 #endif
6195                                 break;
6196                         case MONO_TYPE_R4:
6197                         case MONO_TYPE_R8:
6198                                 ins->type = STACK_R8;
6199                                 break;
6200                         default:
6201                                 g_assert (mini_type_is_reference (fsig->params [0]));
6202                                 ins->type = STACK_OBJ;
6203                                 break;
6204                         }
6205
6206                         if (is_float) {
6207                                 MONO_INST_NEW (cfg, i2f, i2f_opcode);
6208                                 i2f->dreg = mono_alloc_freg (cfg);
6209                                 i2f->sreg1 = ins->dreg;
6210                                 i2f->type = STACK_R8;
6211                                 if (i2f_opcode == OP_MOVE_I4_TO_F)
6212                                         i2f->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6213                                 MONO_ADD_INS (cfg->cbb, i2f);
6214
6215                                 ins = i2f;
6216                         }
6217
6218                         if (cfg->gen_write_barriers && is_ref)
6219                                 emit_write_barrier (cfg, args [0], args [1]);
6220                 }
6221                 else if ((strcmp (cmethod->name, "CompareExchange") == 0) && fsig->param_count == 3) {
6222                         MonoInst *f2i_new = NULL, *f2i_cmp = NULL, *i2f;
6223                         guint32 opcode, f2i_opcode, i2f_opcode;
6224                         gboolean is_ref = mini_type_is_reference (fsig->params [1]);
6225                         gboolean is_float = fsig->params [1]->type == MONO_TYPE_R4 || fsig->params [1]->type == MONO_TYPE_R8;
6226
6227                         if (fsig->params [1]->type == MONO_TYPE_I4 ||
6228                             fsig->params [1]->type == MONO_TYPE_R4) {
6229                                 opcode = OP_ATOMIC_CAS_I4;
6230                                 f2i_opcode = OP_MOVE_F_TO_I4;
6231                                 i2f_opcode = OP_MOVE_I4_TO_F;
6232                                 cfg->has_atomic_cas_i4 = TRUE;
6233                         }
6234 #if SIZEOF_REGISTER == 8
6235                         else if (is_ref ||
6236                                  fsig->params [1]->type == MONO_TYPE_I8 ||
6237                                  fsig->params [1]->type == MONO_TYPE_R8 ||
6238                                  fsig->params [1]->type == MONO_TYPE_I) {
6239                                 opcode = OP_ATOMIC_CAS_I8;
6240                                 f2i_opcode = OP_MOVE_F_TO_I8;
6241                                 i2f_opcode = OP_MOVE_I8_TO_F;
6242                         }
6243 #else
6244                         else if (is_ref || fsig->params [1]->type == MONO_TYPE_I) {
6245                                 opcode = OP_ATOMIC_CAS_I4;
6246                                 cfg->has_atomic_cas_i4 = TRUE;
6247                         }
6248 #endif
6249                         else
6250                                 return NULL;
6251
6252                         if (!mono_arch_opcode_supported (opcode))
6253                                 return NULL;
6254
6255                         if (is_float) {
6256                                 /* TODO: Decompose these opcodes instead of bailing here. */
6257                                 if (COMPILE_SOFT_FLOAT (cfg))
6258                                         return NULL;
6259
6260                                 MONO_INST_NEW (cfg, f2i_new, f2i_opcode);
6261                                 f2i_new->dreg = mono_alloc_ireg (cfg);
6262                                 f2i_new->sreg1 = args [1]->dreg;
6263                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
6264                                         f2i_new->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6265                                 MONO_ADD_INS (cfg->cbb, f2i_new);
6266
6267                                 MONO_INST_NEW (cfg, f2i_cmp, f2i_opcode);
6268                                 f2i_cmp->dreg = mono_alloc_ireg (cfg);
6269                                 f2i_cmp->sreg1 = args [2]->dreg;
6270                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
6271                                         f2i_cmp->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6272                                 MONO_ADD_INS (cfg->cbb, f2i_cmp);
6273                         }
6274
6275                         MONO_INST_NEW (cfg, ins, opcode);
6276                         ins->dreg = is_ref ? alloc_ireg_ref (cfg) : alloc_ireg (cfg);
6277                         ins->sreg1 = args [0]->dreg;
6278                         ins->sreg2 = is_float ? f2i_new->dreg : args [1]->dreg;
6279                         ins->sreg3 = is_float ? f2i_cmp->dreg : args [2]->dreg;
6280                         MONO_ADD_INS (cfg->cbb, ins);
6281
6282                         switch (fsig->params [1]->type) {
6283                         case MONO_TYPE_I4:
6284                                 ins->type = STACK_I4;
6285                                 break;
6286                         case MONO_TYPE_I8:
6287                                 ins->type = STACK_I8;
6288                                 break;
6289                         case MONO_TYPE_I:
6290 #if SIZEOF_REGISTER == 8
6291                                 ins->type = STACK_I8;
6292 #else
6293                                 ins->type = STACK_I4;
6294 #endif
6295                                 break;
6296                         case MONO_TYPE_R4:
6297                                 ins->type = cfg->r4_stack_type;
6298                                 break;
6299                         case MONO_TYPE_R8:
6300                                 ins->type = STACK_R8;
6301                                 break;
6302                         default:
6303                                 g_assert (mini_type_is_reference (fsig->params [1]));
6304                                 ins->type = STACK_OBJ;
6305                                 break;
6306                         }
6307
6308                         if (is_float) {
6309                                 MONO_INST_NEW (cfg, i2f, i2f_opcode);
6310                                 i2f->dreg = mono_alloc_freg (cfg);
6311                                 i2f->sreg1 = ins->dreg;
6312                                 i2f->type = STACK_R8;
6313                                 if (i2f_opcode == OP_MOVE_I4_TO_F)
6314                                         i2f->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6315                                 MONO_ADD_INS (cfg->cbb, i2f);
6316
6317                                 ins = i2f;
6318                         }
6319
6320                         if (cfg->gen_write_barriers && is_ref)
6321                                 emit_write_barrier (cfg, args [0], args [1]);
6322                 }
6323                 else if ((strcmp (cmethod->name, "CompareExchange") == 0) && fsig->param_count == 4 &&
6324                          fsig->params [1]->type == MONO_TYPE_I4) {
6325                         MonoInst *cmp, *ceq;
6326
6327                         if (!mono_arch_opcode_supported (OP_ATOMIC_CAS_I4))
6328                                 return NULL;
6329
6330                         /* int32 r = CAS (location, value, comparand); */
6331                         MONO_INST_NEW (cfg, ins, OP_ATOMIC_CAS_I4);
6332                         ins->dreg = alloc_ireg (cfg);
6333                         ins->sreg1 = args [0]->dreg;
6334                         ins->sreg2 = args [1]->dreg;
6335                         ins->sreg3 = args [2]->dreg;
6336                         ins->type = STACK_I4;
6337                         MONO_ADD_INS (cfg->cbb, ins);
6338
6339                         /* bool result = r == comparand; */
6340                         MONO_INST_NEW (cfg, cmp, OP_ICOMPARE);
6341                         cmp->sreg1 = ins->dreg;
6342                         cmp->sreg2 = args [2]->dreg;
6343                         cmp->type = STACK_I4;
6344                         MONO_ADD_INS (cfg->cbb, cmp);
6345
6346                         MONO_INST_NEW (cfg, ceq, OP_ICEQ);
6347                         ceq->dreg = alloc_ireg (cfg);
6348                         ceq->type = STACK_I4;
6349                         MONO_ADD_INS (cfg->cbb, ceq);
6350
6351                         /* *success = result; */
6352                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, args [3]->dreg, 0, ceq->dreg);
6353
6354                         cfg->has_atomic_cas_i4 = TRUE;
6355                 }
6356                 else if (strcmp (cmethod->name, "MemoryBarrier") == 0 && fsig->param_count == 0)
6357                         ins = emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6358
6359                 if (ins)
6360                         return ins;
6361         } else if (cmethod->klass->image == mono_defaults.corlib &&
6362                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
6363                            (strcmp (cmethod->klass->name, "Volatile") == 0)) {
6364                 ins = NULL;
6365
6366                 if (!strcmp (cmethod->name, "Read") && fsig->param_count == 1) {
6367                         guint32 opcode = 0;
6368                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
6369                         gboolean is_float = fsig->params [0]->type == MONO_TYPE_R4 || fsig->params [0]->type == MONO_TYPE_R8;
6370
6371                         if (fsig->params [0]->type == MONO_TYPE_I1)
6372                                 opcode = OP_ATOMIC_LOAD_I1;
6373                         else if (fsig->params [0]->type == MONO_TYPE_U1 || fsig->params [0]->type == MONO_TYPE_BOOLEAN)
6374                                 opcode = OP_ATOMIC_LOAD_U1;
6375                         else if (fsig->params [0]->type == MONO_TYPE_I2)
6376                                 opcode = OP_ATOMIC_LOAD_I2;
6377                         else if (fsig->params [0]->type == MONO_TYPE_U2)
6378                                 opcode = OP_ATOMIC_LOAD_U2;
6379                         else if (fsig->params [0]->type == MONO_TYPE_I4)
6380                                 opcode = OP_ATOMIC_LOAD_I4;
6381                         else if (fsig->params [0]->type == MONO_TYPE_U4)
6382                                 opcode = OP_ATOMIC_LOAD_U4;
6383                         else if (fsig->params [0]->type == MONO_TYPE_R4)
6384                                 opcode = OP_ATOMIC_LOAD_R4;
6385                         else if (fsig->params [0]->type == MONO_TYPE_R8)
6386                                 opcode = OP_ATOMIC_LOAD_R8;
6387 #if SIZEOF_REGISTER == 8
6388                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_I)
6389                                 opcode = OP_ATOMIC_LOAD_I8;
6390                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_U8 || fsig->params [0]->type == MONO_TYPE_U)
6391                                 opcode = OP_ATOMIC_LOAD_U8;
6392 #else
6393                         else if (fsig->params [0]->type == MONO_TYPE_I)
6394                                 opcode = OP_ATOMIC_LOAD_I4;
6395                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_U)
6396                                 opcode = OP_ATOMIC_LOAD_U4;
6397 #endif
6398
6399                         if (opcode) {
6400                                 if (!mono_arch_opcode_supported (opcode))
6401                                         return NULL;
6402
6403                                 MONO_INST_NEW (cfg, ins, opcode);
6404                                 ins->dreg = is_ref ? mono_alloc_ireg_ref (cfg) : (is_float ? mono_alloc_freg (cfg) : mono_alloc_ireg (cfg));
6405                                 ins->sreg1 = args [0]->dreg;
6406                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_ACQ;
6407                                 MONO_ADD_INS (cfg->cbb, ins);
6408
6409                                 switch (fsig->params [0]->type) {
6410                                 case MONO_TYPE_BOOLEAN:
6411                                 case MONO_TYPE_I1:
6412                                 case MONO_TYPE_U1:
6413                                 case MONO_TYPE_I2:
6414                                 case MONO_TYPE_U2:
6415                                 case MONO_TYPE_I4:
6416                                 case MONO_TYPE_U4:
6417                                         ins->type = STACK_I4;
6418                                         break;
6419                                 case MONO_TYPE_I8:
6420                                 case MONO_TYPE_U8:
6421                                         ins->type = STACK_I8;
6422                                         break;
6423                                 case MONO_TYPE_I:
6424                                 case MONO_TYPE_U:
6425 #if SIZEOF_REGISTER == 8
6426                                         ins->type = STACK_I8;
6427 #else
6428                                         ins->type = STACK_I4;
6429 #endif
6430                                         break;
6431                                 case MONO_TYPE_R4:
6432                                         ins->type = cfg->r4_stack_type;
6433                                         break;
6434                                 case MONO_TYPE_R8:
6435                                         ins->type = STACK_R8;
6436                                         break;
6437                                 default:
6438                                         g_assert (mini_type_is_reference (fsig->params [0]));
6439                                         ins->type = STACK_OBJ;
6440                                         break;
6441                                 }
6442                         }
6443                 }
6444
6445                 if (!strcmp (cmethod->name, "Write") && fsig->param_count == 2) {
6446                         guint32 opcode = 0;
6447                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
6448
6449                         if (fsig->params [0]->type == MONO_TYPE_I1)
6450                                 opcode = OP_ATOMIC_STORE_I1;
6451                         else if (fsig->params [0]->type == MONO_TYPE_U1 || fsig->params [0]->type == MONO_TYPE_BOOLEAN)
6452                                 opcode = OP_ATOMIC_STORE_U1;
6453                         else if (fsig->params [0]->type == MONO_TYPE_I2)
6454                                 opcode = OP_ATOMIC_STORE_I2;
6455                         else if (fsig->params [0]->type == MONO_TYPE_U2)
6456                                 opcode = OP_ATOMIC_STORE_U2;
6457                         else if (fsig->params [0]->type == MONO_TYPE_I4)
6458                                 opcode = OP_ATOMIC_STORE_I4;
6459                         else if (fsig->params [0]->type == MONO_TYPE_U4)
6460                                 opcode = OP_ATOMIC_STORE_U4;
6461                         else if (fsig->params [0]->type == MONO_TYPE_R4)
6462                                 opcode = OP_ATOMIC_STORE_R4;
6463                         else if (fsig->params [0]->type == MONO_TYPE_R8)
6464                                 opcode = OP_ATOMIC_STORE_R8;
6465 #if SIZEOF_REGISTER == 8
6466                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_I)
6467                                 opcode = OP_ATOMIC_STORE_I8;
6468                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_U8 || fsig->params [0]->type == MONO_TYPE_U)
6469                                 opcode = OP_ATOMIC_STORE_U8;
6470 #else
6471                         else if (fsig->params [0]->type == MONO_TYPE_I)
6472                                 opcode = OP_ATOMIC_STORE_I4;
6473                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_U)
6474                                 opcode = OP_ATOMIC_STORE_U4;
6475 #endif
6476
6477                         if (opcode) {
6478                                 if (!mono_arch_opcode_supported (opcode))
6479                                         return NULL;
6480
6481                                 MONO_INST_NEW (cfg, ins, opcode);
6482                                 ins->dreg = args [0]->dreg;
6483                                 ins->sreg1 = args [1]->dreg;
6484                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_REL;
6485                                 MONO_ADD_INS (cfg->cbb, ins);
6486
6487                                 if (cfg->gen_write_barriers && is_ref)
6488                                         emit_write_barrier (cfg, args [0], args [1]);
6489                         }
6490                 }
6491
6492                 if (ins)
6493                         return ins;
6494         } else if (cmethod->klass->image == mono_defaults.corlib &&
6495                            (strcmp (cmethod->klass->name_space, "System.Diagnostics") == 0) &&
6496                            (strcmp (cmethod->klass->name, "Debugger") == 0)) {
6497                 if (!strcmp (cmethod->name, "Break") && fsig->param_count == 0) {
6498                         if (should_insert_brekpoint (cfg->method)) {
6499                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
6500                         } else {
6501                                 MONO_INST_NEW (cfg, ins, OP_NOP);
6502                                 MONO_ADD_INS (cfg->cbb, ins);
6503                         }
6504                         return ins;
6505                 }
6506         } else if (cmethod->klass->image == mono_defaults.corlib &&
6507                    (strcmp (cmethod->klass->name_space, "System") == 0) &&
6508                    (strcmp (cmethod->klass->name, "Environment") == 0)) {
6509                 if (!strcmp (cmethod->name, "get_IsRunningOnWindows") && fsig->param_count == 0) {
6510 #ifdef TARGET_WIN32
6511                         EMIT_NEW_ICONST (cfg, ins, 1);
6512 #else
6513                         EMIT_NEW_ICONST (cfg, ins, 0);
6514 #endif
6515                 }
6516         } else if (cmethod->klass == mono_defaults.math_class) {
6517                 /* 
6518                  * There is general branchless code for Min/Max, but it does not work for 
6519                  * all inputs:
6520                  * http://everything2.com/?node_id=1051618
6521                  */
6522         } else if (((!strcmp (cmethod->klass->image->assembly->aname.name, "MonoMac") ||
6523                     !strcmp (cmethod->klass->image->assembly->aname.name, "monotouch")) &&
6524                                 !strcmp (cmethod->klass->name_space, "XamCore.ObjCRuntime") &&
6525                                 !strcmp (cmethod->klass->name, "Selector")) ||
6526                            (!strcmp (cmethod->klass->image->assembly->aname.name, "Xamarin.iOS") &&
6527                                 !strcmp (cmethod->klass->name_space, "ObjCRuntime") &&
6528                                 !strcmp (cmethod->klass->name, "Selector"))
6529                            ) {
6530 #ifdef MONO_ARCH_HAVE_OBJC_GET_SELECTOR
6531                 if (!strcmp (cmethod->name, "GetHandle") && fsig->param_count == 1 &&
6532                     (args [0]->opcode == OP_GOT_ENTRY || args [0]->opcode == OP_AOTCONST) &&
6533                     cfg->compile_aot) {
6534                         MonoInst *pi;
6535                         MonoJumpInfoToken *ji;
6536                         MonoString *s;
6537
6538                         cfg->disable_llvm = TRUE;
6539
6540                         if (args [0]->opcode == OP_GOT_ENTRY) {
6541                                 pi = args [0]->inst_p1;
6542                                 g_assert (pi->opcode == OP_PATCH_INFO);
6543                                 g_assert (GPOINTER_TO_INT (pi->inst_p1) == MONO_PATCH_INFO_LDSTR);
6544                                 ji = pi->inst_p0;
6545                         } else {
6546                                 g_assert (GPOINTER_TO_INT (args [0]->inst_p1) == MONO_PATCH_INFO_LDSTR);
6547                                 ji = args [0]->inst_p0;
6548                         }
6549
6550                         NULLIFY_INS (args [0]);
6551
6552                         // FIXME: Ugly
6553                         s = mono_ldstr (cfg->domain, ji->image, mono_metadata_token_index (ji->token));
6554                         MONO_INST_NEW (cfg, ins, OP_OBJC_GET_SELECTOR);
6555                         ins->dreg = mono_alloc_ireg (cfg);
6556                         // FIXME: Leaks
6557                         ins->inst_p0 = mono_string_to_utf8 (s);
6558                         MONO_ADD_INS (cfg->cbb, ins);
6559                         return ins;
6560                 }
6561 #endif
6562         }
6563
6564 #ifdef MONO_ARCH_SIMD_INTRINSICS
6565         if (cfg->opt & MONO_OPT_SIMD) {
6566                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
6567                 if (ins)
6568                         return ins;
6569         }
6570 #endif
6571
6572         ins = mono_emit_native_types_intrinsics (cfg, cmethod, fsig, args);
6573         if (ins)
6574                 return ins;
6575
6576         if (COMPILE_LLVM (cfg)) {
6577                 ins = llvm_emit_inst_for_method (cfg, cmethod, fsig, args);
6578                 if (ins)
6579                         return ins;
6580         }
6581
6582         return mono_arch_emit_inst_for_method (cfg, cmethod, fsig, args);
6583 }
6584
6585 /*
6586  * This entry point could be used later for arbitrary method
6587  * redirection.
6588  */
6589 inline static MonoInst*
6590 mini_redirect_call (MonoCompile *cfg, MonoMethod *method,  
6591                                         MonoMethodSignature *signature, MonoInst **args, MonoInst *this_ins)
6592 {
6593         if (method->klass == mono_defaults.string_class) {
6594                 /* managed string allocation support */
6595                 if (strcmp (method->name, "InternalAllocateStr") == 0 && !(mono_profiler_events & MONO_PROFILE_ALLOCATIONS) && !(cfg->opt & MONO_OPT_SHARED)) {
6596                         MonoInst *iargs [2];
6597                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
6598                         MonoMethod *managed_alloc = NULL;
6599
6600                         g_assert (vtable); /*Should not fail since it System.String*/
6601 #ifndef MONO_CROSS_COMPILE
6602                         managed_alloc = mono_gc_get_managed_allocator (method->klass, FALSE, FALSE);
6603 #endif
6604                         if (!managed_alloc)
6605                                 return NULL;
6606                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
6607                         iargs [1] = args [0];
6608                         return mono_emit_method_call (cfg, managed_alloc, iargs, this_ins);
6609                 }
6610         }
6611         return NULL;
6612 }
6613
6614 static void
6615 mono_save_args (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **sp)
6616 {
6617         MonoInst *store, *temp;
6618         int i;
6619
6620         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
6621                 MonoType *argtype = (sig->hasthis && (i == 0)) ? type_from_stack_type (*sp) : sig->params [i - sig->hasthis];
6622
6623                 /*
6624                  * FIXME: We should use *args++ = sp [0], but that would mean the arg
6625                  * would be different than the MonoInst's used to represent arguments, and
6626                  * the ldelema implementation can't deal with that.
6627                  * Solution: When ldelema is used on an inline argument, create a var for 
6628                  * it, emit ldelema on that var, and emit the saving code below in
6629                  * inline_method () if needed.
6630                  */
6631                 temp = mono_compile_create_var (cfg, argtype, OP_LOCAL);
6632                 cfg->args [i] = temp;
6633                 /* This uses cfg->args [i] which is set by the preceeding line */
6634                 EMIT_NEW_ARGSTORE (cfg, store, i, *sp);
6635                 store->cil_code = sp [0]->cil_code;
6636                 sp++;
6637         }
6638 }
6639
6640 #define MONO_INLINE_CALLED_LIMITED_METHODS 1
6641 #define MONO_INLINE_CALLER_LIMITED_METHODS 1
6642
6643 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
6644 static gboolean
6645 check_inline_called_method_name_limit (MonoMethod *called_method)
6646 {
6647         int strncmp_result;
6648         static const char *limit = NULL;
6649         
6650         if (limit == NULL) {
6651                 const char *limit_string = g_getenv ("MONO_INLINE_CALLED_METHOD_NAME_LIMIT");
6652
6653                 if (limit_string != NULL)
6654                         limit = limit_string;
6655                 else
6656                         limit = "";
6657         }
6658
6659         if (limit [0] != '\0') {
6660                 char *called_method_name = mono_method_full_name (called_method, TRUE);
6661
6662                 strncmp_result = strncmp (called_method_name, limit, strlen (limit));
6663                 g_free (called_method_name);
6664         
6665                 //return (strncmp_result <= 0);
6666                 return (strncmp_result == 0);
6667         } else {
6668                 return TRUE;
6669         }
6670 }
6671 #endif
6672
6673 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
6674 static gboolean
6675 check_inline_caller_method_name_limit (MonoMethod *caller_method)
6676 {
6677         int strncmp_result;
6678         static const char *limit = NULL;
6679         
6680         if (limit == NULL) {
6681                 const char *limit_string = g_getenv ("MONO_INLINE_CALLER_METHOD_NAME_LIMIT");
6682                 if (limit_string != NULL) {
6683                         limit = limit_string;
6684                 } else {
6685                         limit = "";
6686                 }
6687         }
6688
6689         if (limit [0] != '\0') {
6690                 char *caller_method_name = mono_method_full_name (caller_method, TRUE);
6691
6692                 strncmp_result = strncmp (caller_method_name, limit, strlen (limit));
6693                 g_free (caller_method_name);
6694         
6695                 //return (strncmp_result <= 0);
6696                 return (strncmp_result == 0);
6697         } else {
6698                 return TRUE;
6699         }
6700 }
6701 #endif
6702
6703 static void
6704 emit_init_rvar (MonoCompile *cfg, int dreg, MonoType *rtype)
6705 {
6706         static double r8_0 = 0.0;
6707         static float r4_0 = 0.0;
6708         MonoInst *ins;
6709         int t;
6710
6711         rtype = mini_get_underlying_type (rtype);
6712         t = rtype->type;
6713
6714         if (rtype->byref) {
6715                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
6716         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
6717                 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
6718         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
6719                 MONO_EMIT_NEW_I8CONST (cfg, dreg, 0);
6720         } else if (cfg->r4fp && t == MONO_TYPE_R4) {
6721                 MONO_INST_NEW (cfg, ins, OP_R4CONST);
6722                 ins->type = STACK_R4;
6723                 ins->inst_p0 = (void*)&r4_0;
6724                 ins->dreg = dreg;
6725                 MONO_ADD_INS (cfg->cbb, ins);
6726         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
6727                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
6728                 ins->type = STACK_R8;
6729                 ins->inst_p0 = (void*)&r8_0;
6730                 ins->dreg = dreg;
6731                 MONO_ADD_INS (cfg->cbb, ins);
6732         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
6733                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (rtype))) {
6734                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (rtype));
6735         } else if (((t == MONO_TYPE_VAR) || (t == MONO_TYPE_MVAR)) && mini_type_var_is_vt (rtype)) {
6736                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (rtype));
6737         } else {
6738                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
6739         }
6740 }
6741
6742 static void
6743 emit_dummy_init_rvar (MonoCompile *cfg, int dreg, MonoType *rtype)
6744 {
6745         int t;
6746
6747         rtype = mini_get_underlying_type (rtype);
6748         t = rtype->type;
6749
6750         if (rtype->byref) {
6751                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_PCONST);
6752         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
6753                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_ICONST);
6754         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
6755                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_I8CONST);
6756         } else if (cfg->r4fp && t == MONO_TYPE_R4) {
6757                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_R4CONST);
6758         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
6759                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_R8CONST);
6760         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
6761                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (rtype))) {
6762                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_VZERO);
6763         } else if (((t == MONO_TYPE_VAR) || (t == MONO_TYPE_MVAR)) && mini_type_var_is_vt (rtype)) {
6764                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_VZERO);
6765         } else {
6766                 emit_init_rvar (cfg, dreg, rtype);
6767         }
6768 }
6769
6770 /* If INIT is FALSE, emit dummy initialization statements to keep the IR valid */
6771 static void
6772 emit_init_local (MonoCompile *cfg, int local, MonoType *type, gboolean init)
6773 {
6774         MonoInst *var = cfg->locals [local];
6775         if (COMPILE_SOFT_FLOAT (cfg)) {
6776                 MonoInst *store;
6777                 int reg = alloc_dreg (cfg, var->type);
6778                 emit_init_rvar (cfg, reg, type);
6779                 EMIT_NEW_LOCSTORE (cfg, store, local, cfg->cbb->last_ins);
6780         } else {
6781                 if (init)
6782                         emit_init_rvar (cfg, var->dreg, type);
6783                 else
6784                         emit_dummy_init_rvar (cfg, var->dreg, type);
6785         }
6786 }
6787
6788 /*
6789  * inline_method:
6790  *
6791  *   Return the cost of inlining CMETHOD.
6792  */
6793 static int
6794 inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp,
6795                            guchar *ip, guint real_offset, gboolean inline_always)
6796 {
6797         MonoInst *ins, *rvar = NULL;
6798         MonoMethodHeader *cheader;
6799         MonoBasicBlock *ebblock, *sbblock;
6800         int i, costs;
6801         MonoMethod *prev_inlined_method;
6802         MonoInst **prev_locals, **prev_args;
6803         MonoType **prev_arg_types;
6804         guint prev_real_offset;
6805         GHashTable *prev_cbb_hash;
6806         MonoBasicBlock **prev_cil_offset_to_bb;
6807         MonoBasicBlock *prev_cbb;
6808         unsigned char* prev_cil_start;
6809         guint32 prev_cil_offset_to_bb_len;
6810         MonoMethod *prev_current_method;
6811         MonoGenericContext *prev_generic_context;
6812         gboolean ret_var_set, prev_ret_var_set, prev_disable_inline, virtual = FALSE;
6813
6814         g_assert (cfg->exception_type == MONO_EXCEPTION_NONE);
6815
6816 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
6817         if ((! inline_always) && ! check_inline_called_method_name_limit (cmethod))
6818                 return 0;
6819 #endif
6820 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
6821         if ((! inline_always) && ! check_inline_caller_method_name_limit (cfg->method))
6822                 return 0;
6823 #endif
6824
6825         if (!fsig)
6826                 fsig = mono_method_signature (cmethod);
6827
6828         if (cfg->verbose_level > 2)
6829                 printf ("INLINE START %p %s -> %s\n", cmethod,  mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
6830
6831         if (!cmethod->inline_info) {
6832                 cfg->stat_inlineable_methods++;
6833                 cmethod->inline_info = 1;
6834         }
6835
6836         /* allocate local variables */
6837         cheader = mono_method_get_header (cmethod);
6838
6839         if (cheader == NULL || mono_loader_get_last_error ()) {
6840                 MonoLoaderError *error = mono_loader_get_last_error ();
6841
6842                 if (cheader)
6843                         mono_metadata_free_mh (cheader);
6844                 if (inline_always && error)
6845                         mono_cfg_set_exception (cfg, error->exception_type);
6846
6847                 mono_loader_clear_error ();
6848                 return 0;
6849         }
6850
6851         /*Must verify before creating locals as it can cause the JIT to assert.*/
6852         if (mono_compile_is_broken (cfg, cmethod, FALSE)) {
6853                 mono_metadata_free_mh (cheader);
6854                 return 0;
6855         }
6856
6857         /* allocate space to store the return value */
6858         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
6859                 rvar = mono_compile_create_var (cfg, fsig->ret, OP_LOCAL);
6860         }
6861
6862         prev_locals = cfg->locals;
6863         cfg->locals = mono_mempool_alloc0 (cfg->mempool, cheader->num_locals * sizeof (MonoInst*));     
6864         for (i = 0; i < cheader->num_locals; ++i)
6865                 cfg->locals [i] = mono_compile_create_var (cfg, cheader->locals [i], OP_LOCAL);
6866
6867         /* allocate start and end blocks */
6868         /* This is needed so if the inline is aborted, we can clean up */
6869         NEW_BBLOCK (cfg, sbblock);
6870         sbblock->real_offset = real_offset;
6871
6872         NEW_BBLOCK (cfg, ebblock);
6873         ebblock->block_num = cfg->num_bblocks++;
6874         ebblock->real_offset = real_offset;
6875
6876         prev_args = cfg->args;
6877         prev_arg_types = cfg->arg_types;
6878         prev_inlined_method = cfg->inlined_method;
6879         cfg->inlined_method = cmethod;
6880         cfg->ret_var_set = FALSE;
6881         cfg->inline_depth ++;
6882         prev_real_offset = cfg->real_offset;
6883         prev_cbb_hash = cfg->cbb_hash;
6884         prev_cil_offset_to_bb = cfg->cil_offset_to_bb;
6885         prev_cil_offset_to_bb_len = cfg->cil_offset_to_bb_len;
6886         prev_cil_start = cfg->cil_start;
6887         prev_cbb = cfg->cbb;
6888         prev_current_method = cfg->current_method;
6889         prev_generic_context = cfg->generic_context;
6890         prev_ret_var_set = cfg->ret_var_set;
6891         prev_disable_inline = cfg->disable_inline;
6892
6893         if (ip && *ip == CEE_CALLVIRT && !(cmethod->flags & METHOD_ATTRIBUTE_STATIC))
6894                 virtual = TRUE;
6895
6896         costs = mono_method_to_ir (cfg, cmethod, sbblock, ebblock, rvar, sp, real_offset, virtual);
6897
6898         ret_var_set = cfg->ret_var_set;
6899
6900         cfg->inlined_method = prev_inlined_method;
6901         cfg->real_offset = prev_real_offset;
6902         cfg->cbb_hash = prev_cbb_hash;
6903         cfg->cil_offset_to_bb = prev_cil_offset_to_bb;
6904         cfg->cil_offset_to_bb_len = prev_cil_offset_to_bb_len;
6905         cfg->cil_start = prev_cil_start;
6906         cfg->locals = prev_locals;
6907         cfg->args = prev_args;
6908         cfg->arg_types = prev_arg_types;
6909         cfg->current_method = prev_current_method;
6910         cfg->generic_context = prev_generic_context;
6911         cfg->ret_var_set = prev_ret_var_set;
6912         cfg->disable_inline = prev_disable_inline;
6913         cfg->inline_depth --;
6914
6915         if ((costs >= 0 && costs < 60) || inline_always || (costs >= 0 && (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING))) {
6916                 if (cfg->verbose_level > 2)
6917                         printf ("INLINE END %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
6918                 
6919                 cfg->stat_inlined_methods++;
6920
6921                 /* always add some code to avoid block split failures */
6922                 MONO_INST_NEW (cfg, ins, OP_NOP);
6923                 MONO_ADD_INS (prev_cbb, ins);
6924
6925                 prev_cbb->next_bb = sbblock;
6926                 link_bblock (cfg, prev_cbb, sbblock);
6927
6928                 /* 
6929                  * Get rid of the begin and end bblocks if possible to aid local
6930                  * optimizations.
6931                  */
6932                 mono_merge_basic_blocks (cfg, prev_cbb, sbblock);
6933
6934                 if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] != ebblock))
6935                         mono_merge_basic_blocks (cfg, prev_cbb, prev_cbb->out_bb [0]);
6936
6937                 if ((ebblock->in_count == 1) && ebblock->in_bb [0]->out_count == 1) {
6938                         MonoBasicBlock *prev = ebblock->in_bb [0];
6939                         mono_merge_basic_blocks (cfg, prev, ebblock);
6940                         cfg->cbb = prev;
6941                         if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] == prev)) {
6942                                 mono_merge_basic_blocks (cfg, prev_cbb, prev);
6943                                 cfg->cbb = prev_cbb;
6944                         }
6945                 } else {
6946                         /* 
6947                          * Its possible that the rvar is set in some prev bblock, but not in others.
6948                          * (#1835).
6949                          */
6950                         if (rvar) {
6951                                 MonoBasicBlock *bb;
6952
6953                                 for (i = 0; i < ebblock->in_count; ++i) {
6954                                         bb = ebblock->in_bb [i];
6955
6956                                         if (bb->last_ins && bb->last_ins->opcode == OP_NOT_REACHED) {
6957                                                 cfg->cbb = bb;
6958
6959                                                 emit_init_rvar (cfg, rvar->dreg, fsig->ret);
6960                                         }
6961                                 }
6962                         }
6963
6964                         cfg->cbb = ebblock;
6965                 }
6966
6967                 if (rvar) {
6968                         /*
6969                          * If the inlined method contains only a throw, then the ret var is not 
6970                          * set, so set it to a dummy value.
6971                          */
6972                         if (!ret_var_set)
6973                                 emit_init_rvar (cfg, rvar->dreg, fsig->ret);
6974
6975                         EMIT_NEW_TEMPLOAD (cfg, ins, rvar->inst_c0);
6976                         *sp++ = ins;
6977                 }
6978                 cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
6979                 return costs + 1;
6980         } else {
6981                 if (cfg->verbose_level > 2)
6982                         printf ("INLINE ABORTED %s (cost %d)\n", mono_method_full_name (cmethod, TRUE), costs);
6983                 cfg->exception_type = MONO_EXCEPTION_NONE;
6984                 mono_loader_clear_error ();
6985
6986                 /* This gets rid of the newly added bblocks */
6987                 cfg->cbb = prev_cbb;
6988         }
6989         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
6990         return 0;
6991 }
6992
6993 /*
6994  * Some of these comments may well be out-of-date.
6995  * Design decisions: we do a single pass over the IL code (and we do bblock 
6996  * splitting/merging in the few cases when it's required: a back jump to an IL
6997  * address that was not already seen as bblock starting point).
6998  * Code is validated as we go (full verification is still better left to metadata/verify.c).
6999  * Complex operations are decomposed in simpler ones right away. We need to let the 
7000  * arch-specific code peek and poke inside this process somehow (except when the 
7001  * optimizations can take advantage of the full semantic info of coarse opcodes).
7002  * All the opcodes of the form opcode.s are 'normalized' to opcode.
7003  * MonoInst->opcode initially is the IL opcode or some simplification of that 
7004  * (OP_LOAD, OP_STORE). The arch-specific code may rearrange it to an arch-specific 
7005  * opcode with value bigger than OP_LAST.
7006  * At this point the IR can be handed over to an interpreter, a dumb code generator
7007  * or to the optimizing code generator that will translate it to SSA form.
7008  *
7009  * Profiling directed optimizations.
7010  * We may compile by default with few or no optimizations and instrument the code
7011  * or the user may indicate what methods to optimize the most either in a config file
7012  * or through repeated runs where the compiler applies offline the optimizations to 
7013  * each method and then decides if it was worth it.
7014  */
7015
7016 #define CHECK_TYPE(ins) if (!(ins)->type) UNVERIFIED
7017 #define CHECK_STACK(num) if ((sp - stack_start) < (num)) UNVERIFIED
7018 #define CHECK_STACK_OVF(num) if (((sp - stack_start) + (num)) > header->max_stack) UNVERIFIED
7019 #define CHECK_ARG(num) if ((unsigned)(num) >= (unsigned)num_args) UNVERIFIED
7020 #define CHECK_LOCAL(num) if ((unsigned)(num) >= (unsigned)header->num_locals) UNVERIFIED
7021 #define CHECK_OPSIZE(size) if (ip + size > end) UNVERIFIED
7022 #define CHECK_UNVERIFIABLE(cfg) if (cfg->unverifiable) UNVERIFIED
7023 #define CHECK_TYPELOAD(klass) if (!(klass) || (klass)->exception_type) TYPE_LOAD_ERROR ((klass))
7024
7025 /* offset from br.s -> br like opcodes */
7026 #define BIG_BRANCH_OFFSET 13
7027
7028 static gboolean
7029 ip_in_bb (MonoCompile *cfg, MonoBasicBlock *bb, const guint8* ip)
7030 {
7031         MonoBasicBlock *b = cfg->cil_offset_to_bb [ip - cfg->cil_start];
7032
7033         return b == NULL || b == bb;
7034 }
7035
7036 static int
7037 get_basic_blocks (MonoCompile *cfg, MonoMethodHeader* header, guint real_offset, unsigned char *start, unsigned char *end, unsigned char **pos)
7038 {
7039         unsigned char *ip = start;
7040         unsigned char *target;
7041         int i;
7042         guint cli_addr;
7043         MonoBasicBlock *bblock;
7044         const MonoOpcode *opcode;
7045
7046         while (ip < end) {
7047                 cli_addr = ip - start;
7048                 i = mono_opcode_value ((const guint8 **)&ip, end);
7049                 if (i < 0)
7050                         UNVERIFIED;
7051                 opcode = &mono_opcodes [i];
7052                 switch (opcode->argument) {
7053                 case MonoInlineNone:
7054                         ip++; 
7055                         break;
7056                 case MonoInlineString:
7057                 case MonoInlineType:
7058                 case MonoInlineField:
7059                 case MonoInlineMethod:
7060                 case MonoInlineTok:
7061                 case MonoInlineSig:
7062                 case MonoShortInlineR:
7063                 case MonoInlineI:
7064                         ip += 5;
7065                         break;
7066                 case MonoInlineVar:
7067                         ip += 3;
7068                         break;
7069                 case MonoShortInlineVar:
7070                 case MonoShortInlineI:
7071                         ip += 2;
7072                         break;
7073                 case MonoShortInlineBrTarget:
7074                         target = start + cli_addr + 2 + (signed char)ip [1];
7075                         GET_BBLOCK (cfg, bblock, target);
7076                         ip += 2;
7077                         if (ip < end)
7078                                 GET_BBLOCK (cfg, bblock, ip);
7079                         break;
7080                 case MonoInlineBrTarget:
7081                         target = start + cli_addr + 5 + (gint32)read32 (ip + 1);
7082                         GET_BBLOCK (cfg, bblock, target);
7083                         ip += 5;
7084                         if (ip < end)
7085                                 GET_BBLOCK (cfg, bblock, ip);
7086                         break;
7087                 case MonoInlineSwitch: {
7088                         guint32 n = read32 (ip + 1);
7089                         guint32 j;
7090                         ip += 5;
7091                         cli_addr += 5 + 4 * n;
7092                         target = start + cli_addr;
7093                         GET_BBLOCK (cfg, bblock, target);
7094                         
7095                         for (j = 0; j < n; ++j) {
7096                                 target = start + cli_addr + (gint32)read32 (ip);
7097                                 GET_BBLOCK (cfg, bblock, target);
7098                                 ip += 4;
7099                         }
7100                         break;
7101                 }
7102                 case MonoInlineR:
7103                 case MonoInlineI8:
7104                         ip += 9;
7105                         break;
7106                 default:
7107                         g_assert_not_reached ();
7108                 }
7109
7110                 if (i == CEE_THROW) {
7111                         unsigned char *bb_start = ip - 1;
7112                         
7113                         /* Find the start of the bblock containing the throw */
7114                         bblock = NULL;
7115                         while ((bb_start >= start) && !bblock) {
7116                                 bblock = cfg->cil_offset_to_bb [(bb_start) - start];
7117                                 bb_start --;
7118                         }
7119                         if (bblock)
7120                                 bblock->out_of_line = 1;
7121                 }
7122         }
7123         return 0;
7124 unverified:
7125 exception_exit:
7126         *pos = ip;
7127         return 1;
7128 }
7129
7130 static inline MonoMethod *
7131 mini_get_method_allow_open (MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
7132 {
7133         MonoMethod *method;
7134
7135         if (m->wrapper_type != MONO_WRAPPER_NONE) {
7136                 method = mono_method_get_wrapper_data (m, token);
7137                 if (context) {
7138                         MonoError error;
7139                         method = mono_class_inflate_generic_method_checked (method, context, &error);
7140                         g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
7141                 }
7142         } else {
7143                 method = mono_get_method_full (m->klass->image, token, klass, context);
7144         }
7145
7146         return method;
7147 }
7148
7149 static inline MonoMethod *
7150 mini_get_method (MonoCompile *cfg, MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
7151 {
7152         MonoMethod *method = mini_get_method_allow_open (m, token, klass, context);
7153
7154         if (method && cfg && !cfg->gshared && mono_class_is_open_constructed_type (&method->klass->byval_arg))
7155                 return NULL;
7156
7157         return method;
7158 }
7159
7160 static inline MonoClass*
7161 mini_get_class (MonoMethod *method, guint32 token, MonoGenericContext *context)
7162 {
7163         MonoError error;
7164         MonoClass *klass;
7165
7166         if (method->wrapper_type != MONO_WRAPPER_NONE) {
7167                 klass = mono_method_get_wrapper_data (method, token);
7168                 if (context)
7169                         klass = mono_class_inflate_generic_class (klass, context);
7170         } else {
7171                 klass = mono_class_get_and_inflate_typespec_checked (method->klass->image, token, context, &error);
7172                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
7173         }
7174         if (klass)
7175                 mono_class_init (klass);
7176         return klass;
7177 }
7178
7179 static inline MonoMethodSignature*
7180 mini_get_signature (MonoMethod *method, guint32 token, MonoGenericContext *context)
7181 {
7182         MonoMethodSignature *fsig;
7183
7184         if (method->wrapper_type != MONO_WRAPPER_NONE) {
7185                 fsig = (MonoMethodSignature *)mono_method_get_wrapper_data (method, token);
7186         } else {
7187                 fsig = mono_metadata_parse_signature (method->klass->image, token);
7188         }
7189         if (context) {
7190                 MonoError error;
7191                 fsig = mono_inflate_generic_signature(fsig, context, &error);
7192                 // FIXME:
7193                 g_assert(mono_error_ok(&error));
7194         }
7195         return fsig;
7196 }
7197
7198 static MonoMethod*
7199 throw_exception (void)
7200 {
7201         static MonoMethod *method = NULL;
7202
7203         if (!method) {
7204                 MonoSecurityManager *secman = mono_security_manager_get_methods ();
7205                 method = mono_class_get_method_from_name (secman->securitymanager, "ThrowException", 1);
7206         }
7207         g_assert (method);
7208         return method;
7209 }
7210
7211 static void
7212 emit_throw_exception (MonoCompile *cfg, MonoException *ex)
7213 {
7214         MonoMethod *thrower = throw_exception ();
7215         MonoInst *args [1];
7216
7217         EMIT_NEW_PCONST (cfg, args [0], ex);
7218         mono_emit_method_call (cfg, thrower, args, NULL);
7219 }
7220
7221 /*
7222  * Return the original method is a wrapper is specified. We can only access 
7223  * the custom attributes from the original method.
7224  */
7225 static MonoMethod*
7226 get_original_method (MonoMethod *method)
7227 {
7228         if (method->wrapper_type == MONO_WRAPPER_NONE)
7229                 return method;
7230
7231         /* native code (which is like Critical) can call any managed method XXX FIXME XXX to validate all usages */
7232         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED)
7233                 return NULL;
7234
7235         /* in other cases we need to find the original method */
7236         return mono_marshal_method_from_wrapper (method);
7237 }
7238
7239 static void
7240 ensure_method_is_allowed_to_access_field (MonoCompile *cfg, MonoMethod *caller, MonoClassField *field)
7241 {
7242         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
7243         MonoException *ex = mono_security_core_clr_is_field_access_allowed (get_original_method (caller), field);
7244         if (ex)
7245                 emit_throw_exception (cfg, ex);
7246 }
7247
7248 static void
7249 ensure_method_is_allowed_to_call_method (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee)
7250 {
7251         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
7252         MonoException *ex = mono_security_core_clr_is_call_allowed (get_original_method (caller), callee);
7253         if (ex)
7254                 emit_throw_exception (cfg, ex);
7255 }
7256
7257 /*
7258  * Check that the IL instructions at ip are the array initialization
7259  * sequence and return the pointer to the data and the size.
7260  */
7261 static const char*
7262 initialize_array_data (MonoMethod *method, gboolean aot, unsigned char *ip, MonoClass *klass, guint32 len, int *out_size, guint32 *out_field_token)
7263 {
7264         /*
7265          * newarr[System.Int32]
7266          * dup
7267          * ldtoken field valuetype ...
7268          * call void class [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype [mscorlib]System.RuntimeFieldHandle)
7269          */
7270         if (ip [0] == CEE_DUP && ip [1] == CEE_LDTOKEN && ip [5] == 0x4 && ip [6] == CEE_CALL) {
7271                 MonoError error;
7272                 guint32 token = read32 (ip + 7);
7273                 guint32 field_token = read32 (ip + 2);
7274                 guint32 field_index = field_token & 0xffffff;
7275                 guint32 rva;
7276                 const char *data_ptr;
7277                 int size = 0;
7278                 MonoMethod *cmethod;
7279                 MonoClass *dummy_class;
7280                 MonoClassField *field = mono_field_from_token_checked (method->klass->image, field_token, &dummy_class, NULL, &error);
7281                 int dummy_align;
7282
7283                 if (!field) {
7284                         mono_error_cleanup (&error); /* FIXME don't swallow the error */
7285                         return NULL;
7286                 }
7287
7288                 *out_field_token = field_token;
7289
7290                 cmethod = mini_get_method (NULL, method, token, NULL, NULL);
7291                 if (!cmethod)
7292                         return NULL;
7293                 if (strcmp (cmethod->name, "InitializeArray") || strcmp (cmethod->klass->name, "RuntimeHelpers") || cmethod->klass->image != mono_defaults.corlib)
7294                         return NULL;
7295                 switch (mono_type_get_underlying_type (&klass->byval_arg)->type) {
7296                 case MONO_TYPE_BOOLEAN:
7297                 case MONO_TYPE_I1:
7298                 case MONO_TYPE_U1:
7299                         size = 1; break;
7300                 /* we need to swap on big endian, so punt. Should we handle R4 and R8 as well? */
7301 #if TARGET_BYTE_ORDER == G_LITTLE_ENDIAN
7302                 case MONO_TYPE_CHAR:
7303                 case MONO_TYPE_I2:
7304                 case MONO_TYPE_U2:
7305                         size = 2; break;
7306                 case MONO_TYPE_I4:
7307                 case MONO_TYPE_U4:
7308                 case MONO_TYPE_R4:
7309                         size = 4; break;
7310                 case MONO_TYPE_R8:
7311                 case MONO_TYPE_I8:
7312                 case MONO_TYPE_U8:
7313                         size = 8; break;
7314 #endif
7315                 default:
7316                         return NULL;
7317                 }
7318                 size *= len;
7319                 if (size > mono_type_size (field->type, &dummy_align))
7320                     return NULL;
7321                 *out_size = size;
7322                 /*g_print ("optimized in %s: size: %d, numelems: %d\n", method->name, size, newarr->inst_newa_len->inst_c0);*/
7323                 if (!image_is_dynamic (method->klass->image)) {
7324                         field_index = read32 (ip + 2) & 0xffffff;
7325                         mono_metadata_field_info (method->klass->image, field_index - 1, NULL, &rva, NULL);
7326                         data_ptr = mono_image_rva_map (method->klass->image, rva);
7327                         /*g_print ("field: 0x%08x, rva: %d, rva_ptr: %p\n", read32 (ip + 2), rva, data_ptr);*/
7328                         /* for aot code we do the lookup on load */
7329                         if (aot && data_ptr)
7330                                 return GUINT_TO_POINTER (rva);
7331                 } else {
7332                         /*FIXME is it possible to AOT a SRE assembly not meant to be saved? */ 
7333                         g_assert (!aot);
7334                         data_ptr = mono_field_get_data (field);
7335                 }
7336                 return data_ptr;
7337         }
7338         return NULL;
7339 }
7340
7341 static void
7342 set_exception_type_from_invalid_il (MonoCompile *cfg, MonoMethod *method, unsigned char *ip)
7343 {
7344         char *method_fname = mono_method_full_name (method, TRUE);
7345         char *method_code;
7346         MonoMethodHeader *header = mono_method_get_header (method);
7347
7348         if (header->code_size == 0)
7349                 method_code = g_strdup ("method body is empty.");
7350         else
7351                 method_code = mono_disasm_code_one (NULL, method, ip, NULL);
7352         mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
7353         cfg->exception_message = g_strdup_printf ("Invalid IL code in %s: %s\n", method_fname, method_code);
7354         g_free (method_fname);
7355         g_free (method_code);
7356         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
7357 }
7358
7359 static void
7360 set_exception_object (MonoCompile *cfg, MonoException *exception)
7361 {
7362         mono_cfg_set_exception (cfg, MONO_EXCEPTION_OBJECT_SUPPLIED);
7363         MONO_GC_REGISTER_ROOT_SINGLE (cfg->exception_ptr, MONO_ROOT_SOURCE_JIT, "jit exception");
7364         cfg->exception_ptr = exception;
7365 }
7366
7367 static void
7368 emit_stloc_ir (MonoCompile *cfg, MonoInst **sp, MonoMethodHeader *header, int n)
7369 {
7370         MonoInst *ins;
7371         guint32 opcode = mono_type_to_regmove (cfg, header->locals [n]);
7372         if ((opcode == OP_MOVE) && cfg->cbb->last_ins == sp [0]  &&
7373                         ((sp [0]->opcode == OP_ICONST) || (sp [0]->opcode == OP_I8CONST))) {
7374                 /* Optimize reg-reg moves away */
7375                 /* 
7376                  * Can't optimize other opcodes, since sp[0] might point to
7377                  * the last ins of a decomposed opcode.
7378                  */
7379                 sp [0]->dreg = (cfg)->locals [n]->dreg;
7380         } else {
7381                 EMIT_NEW_LOCSTORE (cfg, ins, n, *sp);
7382         }
7383 }
7384
7385 /*
7386  * ldloca inhibits many optimizations so try to get rid of it in common
7387  * cases.
7388  */
7389 static inline unsigned char *
7390 emit_optimized_ldloca_ir (MonoCompile *cfg, unsigned char *ip, unsigned char *end, int size)
7391 {
7392         int local, token;
7393         MonoClass *klass;
7394         MonoType *type;
7395
7396         if (size == 1) {
7397                 local = ip [1];
7398                 ip += 2;
7399         } else {
7400                 local = read16 (ip + 2);
7401                 ip += 4;
7402         }
7403         
7404         if (ip + 6 < end && (ip [0] == CEE_PREFIX1) && (ip [1] == CEE_INITOBJ) && ip_in_bb (cfg, cfg->cbb, ip + 1)) {
7405                 /* From the INITOBJ case */
7406                 token = read32 (ip + 2);
7407                 klass = mini_get_class (cfg->current_method, token, cfg->generic_context);
7408                 CHECK_TYPELOAD (klass);
7409                 type = mini_get_underlying_type (&klass->byval_arg);
7410                 emit_init_local (cfg, local, type, TRUE);
7411                 return ip + 6;
7412         }
7413  exception_exit:
7414         return NULL;
7415 }
7416
7417 static gboolean
7418 is_exception_class (MonoClass *klass)
7419 {
7420         while (klass) {
7421                 if (klass == mono_defaults.exception_class)
7422                         return TRUE;
7423                 klass = klass->parent;
7424         }
7425         return FALSE;
7426 }
7427
7428 /*
7429  * is_jit_optimizer_disabled:
7430  *
7431  *   Determine whenever M's assembly has a DebuggableAttribute with the
7432  * IsJITOptimizerDisabled flag set.
7433  */
7434 static gboolean
7435 is_jit_optimizer_disabled (MonoMethod *m)
7436 {
7437         MonoAssembly *ass = m->klass->image->assembly;
7438         MonoCustomAttrInfo* attrs;
7439         static MonoClass *klass;
7440         int i;
7441         gboolean val = FALSE;
7442
7443         g_assert (ass);
7444         if (ass->jit_optimizer_disabled_inited)
7445                 return ass->jit_optimizer_disabled;
7446
7447         if (!klass)
7448                 klass = mono_class_from_name (mono_defaults.corlib, "System.Diagnostics", "DebuggableAttribute");
7449         if (!klass) {
7450                 /* Linked away */
7451                 ass->jit_optimizer_disabled = FALSE;
7452                 mono_memory_barrier ();
7453                 ass->jit_optimizer_disabled_inited = TRUE;
7454                 return FALSE;
7455         }
7456
7457         attrs = mono_custom_attrs_from_assembly (ass);
7458         if (attrs) {
7459                 for (i = 0; i < attrs->num_attrs; ++i) {
7460                         MonoCustomAttrEntry *attr = &attrs->attrs [i];
7461                         const gchar *p;
7462                         MonoMethodSignature *sig;
7463
7464                         if (!attr->ctor || attr->ctor->klass != klass)
7465                                 continue;
7466                         /* Decode the attribute. See reflection.c */
7467                         p = (const char*)attr->data;
7468                         g_assert (read16 (p) == 0x0001);
7469                         p += 2;
7470
7471                         // FIXME: Support named parameters
7472                         sig = mono_method_signature (attr->ctor);
7473                         if (sig->param_count != 2 || sig->params [0]->type != MONO_TYPE_BOOLEAN || sig->params [1]->type != MONO_TYPE_BOOLEAN)
7474                                 continue;
7475                         /* Two boolean arguments */
7476                         p ++;
7477                         val = *p;
7478                 }
7479                 mono_custom_attrs_free (attrs);
7480         }
7481
7482         ass->jit_optimizer_disabled = val;
7483         mono_memory_barrier ();
7484         ass->jit_optimizer_disabled_inited = TRUE;
7485
7486         return val;
7487 }
7488
7489 static gboolean
7490 is_supported_tail_call (MonoCompile *cfg, MonoMethod *method, MonoMethod *cmethod, MonoMethodSignature *fsig, int call_opcode)
7491 {
7492         gboolean supported_tail_call;
7493         int i;
7494
7495 #ifdef MONO_ARCH_HAVE_OP_TAIL_CALL
7496         supported_tail_call = mono_arch_tail_call_supported (cfg, mono_method_signature (method), mono_method_signature (cmethod));
7497 #else
7498         supported_tail_call = mono_metadata_signature_equal (mono_method_signature (method), mono_method_signature (cmethod)) && !MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->ret);
7499 #endif
7500
7501         for (i = 0; i < fsig->param_count; ++i) {
7502                 if (fsig->params [i]->byref || fsig->params [i]->type == MONO_TYPE_PTR || fsig->params [i]->type == MONO_TYPE_FNPTR)
7503                         /* These can point to the current method's stack */
7504                         supported_tail_call = FALSE;
7505         }
7506         if (fsig->hasthis && cmethod->klass->valuetype)
7507                 /* this might point to the current method's stack */
7508                 supported_tail_call = FALSE;
7509         if (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
7510                 supported_tail_call = FALSE;
7511         if (cfg->method->save_lmf)
7512                 supported_tail_call = FALSE;
7513         if (cmethod->wrapper_type && cmethod->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD)
7514                 supported_tail_call = FALSE;
7515         if (call_opcode != CEE_CALL)
7516                 supported_tail_call = FALSE;
7517
7518         /* Debugging support */
7519 #if 0
7520         if (supported_tail_call) {
7521                 if (!mono_debug_count ())
7522                         supported_tail_call = FALSE;
7523         }
7524 #endif
7525
7526         return supported_tail_call;
7527 }
7528
7529 /*
7530  * handle_ctor_call:
7531  *
7532  *   Handle calls made to ctors from NEWOBJ opcodes.
7533  */
7534 static void
7535 handle_ctor_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, int context_used,
7536                                   MonoInst **sp, guint8 *ip, int *inline_costs)
7537 {
7538         MonoInst *vtable_arg = NULL, *callvirt_this_arg = NULL, *ins;
7539
7540         if (cmethod->klass->valuetype && mono_class_generic_sharing_enabled (cmethod->klass) &&
7541                                         mono_method_is_generic_sharable (cmethod, TRUE)) {
7542                 if (cmethod->is_inflated && mono_method_get_context (cmethod)->method_inst) {
7543                         mono_class_vtable (cfg->domain, cmethod->klass);
7544                         CHECK_TYPELOAD (cmethod->klass);
7545
7546                         vtable_arg = emit_get_rgctx_method (cfg, context_used,
7547                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
7548                 } else {
7549                         if (context_used) {
7550                                 vtable_arg = emit_get_rgctx_klass (cfg, context_used,
7551                                                                                                    cmethod->klass, MONO_RGCTX_INFO_VTABLE);
7552                         } else {
7553                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
7554
7555                                 CHECK_TYPELOAD (cmethod->klass);
7556                                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
7557                         }
7558                 }
7559         }
7560
7561         /* Avoid virtual calls to ctors if possible */
7562         if (mono_class_is_marshalbyref (cmethod->klass))
7563                 callvirt_this_arg = sp [0];
7564
7565         if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_ctor (cfg, cmethod, fsig, sp))) {
7566                 g_assert (MONO_TYPE_IS_VOID (fsig->ret));
7567                 CHECK_CFG_EXCEPTION;
7568         } else if ((cfg->opt & MONO_OPT_INLINE) && cmethod && !context_used && !vtable_arg &&
7569                            mono_method_check_inlining (cfg, cmethod) &&
7570                            !mono_class_is_subclass_of (cmethod->klass, mono_defaults.exception_class, FALSE)) {
7571                 int costs;
7572
7573                 if ((costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, FALSE))) {
7574                         cfg->real_offset += 5;
7575
7576                         *inline_costs += costs - 5;
7577                 } else {
7578                         INLINE_FAILURE ("inline failure");
7579                         // FIXME-VT: Clean this up
7580                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig))
7581                                 GSHAREDVT_FAILURE(*ip);
7582                         mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, callvirt_this_arg, NULL, NULL);
7583                 }
7584         } else if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) {
7585                 MonoInst *addr;
7586
7587                 addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE);
7588                 mono_emit_calli (cfg, fsig, sp, addr, NULL, vtable_arg);
7589         } else if (context_used &&
7590                            ((!mono_method_is_generic_sharable_full (cmethod, TRUE, FALSE, FALSE) ||
7591                                  !mono_class_generic_sharing_enabled (cmethod->klass)) || cfg->gsharedvt)) {
7592                 MonoInst *cmethod_addr;
7593
7594                 /* Generic calls made out of gsharedvt methods cannot be patched, so use an indirect call */
7595
7596                 cmethod_addr = emit_get_rgctx_method (cfg, context_used,
7597                                                                                           cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
7598
7599                 mono_emit_calli (cfg, fsig, sp, cmethod_addr, NULL, vtable_arg);
7600         } else {
7601                 INLINE_FAILURE ("ctor call");
7602                 ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp,
7603                                                                                   callvirt_this_arg, NULL, vtable_arg);
7604         }
7605  exception_exit:
7606         return;
7607 }
7608
7609 /*
7610  * mono_method_to_ir:
7611  *
7612  *   Translate the .net IL into linear IR.
7613  */
7614 int
7615 mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock, 
7616                    MonoInst *return_var, MonoInst **inline_args, 
7617                    guint inline_offset, gboolean is_virtual_call)
7618 {
7619         MonoError error;
7620         MonoInst *ins, **sp, **stack_start;
7621         MonoBasicBlock *tblock = NULL, *init_localsbb = NULL;
7622         MonoSimpleBasicBlock *bb = NULL, *original_bb = NULL;
7623         MonoMethod *cmethod, *method_definition;
7624         MonoInst **arg_array;
7625         MonoMethodHeader *header;
7626         MonoImage *image;
7627         guint32 token, ins_flag;
7628         MonoClass *klass;
7629         MonoClass *constrained_class = NULL;
7630         unsigned char *ip, *end, *target, *err_pos;
7631         MonoMethodSignature *sig;
7632         MonoGenericContext *generic_context = NULL;
7633         MonoGenericContainer *generic_container = NULL;
7634         MonoType **param_types;
7635         int i, n, start_new_bblock, dreg;
7636         int num_calls = 0, inline_costs = 0;
7637         int breakpoint_id = 0;
7638         guint num_args;
7639         GSList *class_inits = NULL;
7640         gboolean dont_verify, dont_verify_stloc, readonly = FALSE;
7641         int context_used;
7642         gboolean init_locals, seq_points, skip_dead_blocks;
7643         gboolean sym_seq_points = FALSE;
7644         MonoDebugMethodInfo *minfo;
7645         MonoBitSet *seq_point_locs = NULL;
7646         MonoBitSet *seq_point_set_locs = NULL;
7647
7648         cfg->disable_inline = is_jit_optimizer_disabled (method);
7649
7650         /* serialization and xdomain stuff may need access to private fields and methods */
7651         dont_verify = method->klass->image->assembly->corlib_internal? TRUE: FALSE;
7652         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE;
7653         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH;
7654         dont_verify |= method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE; /* bug #77896 */
7655         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP;
7656         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP_INVOKE;
7657
7658         /* still some type unsafety issues in marshal wrappers... (unknown is PtrToStructure) */
7659         dont_verify_stloc = method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE;
7660         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_UNKNOWN;
7661         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED;
7662         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_STELEMREF;
7663
7664         image = method->klass->image;
7665         header = mono_method_get_header (method);
7666         if (!header) {
7667                 MonoLoaderError *error;
7668
7669                 if ((error = mono_loader_get_last_error ())) {
7670                         mono_cfg_set_exception (cfg, error->exception_type);
7671                 } else {
7672                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
7673                         cfg->exception_message = g_strdup_printf ("Missing or incorrect header for method %s", cfg->method->name);
7674                 }
7675                 goto exception_exit;
7676         }
7677         generic_container = mono_method_get_generic_container (method);
7678         sig = mono_method_signature (method);
7679         num_args = sig->hasthis + sig->param_count;
7680         ip = (unsigned char*)header->code;
7681         cfg->cil_start = ip;
7682         end = ip + header->code_size;
7683         cfg->stat_cil_code_size += header->code_size;
7684
7685         seq_points = cfg->gen_seq_points && cfg->method == method;
7686
7687         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
7688                 /* We could hit a seq point before attaching to the JIT (#8338) */
7689                 seq_points = FALSE;
7690         }
7691
7692         if (cfg->gen_sdb_seq_points && cfg->method == method) {
7693                 minfo = mono_debug_lookup_method (method);
7694                 if (minfo) {
7695                         MonoSymSeqPoint *sps;
7696                         int i, n_il_offsets;
7697
7698                         mono_debug_get_seq_points (minfo, NULL, NULL, NULL, &sps, &n_il_offsets);
7699                         seq_point_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
7700                         seq_point_set_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
7701                         sym_seq_points = TRUE;
7702                         for (i = 0; i < n_il_offsets; ++i) {
7703                                 if (sps [i].il_offset < header->code_size)
7704                                         mono_bitset_set_fast (seq_point_locs, sps [i].il_offset);
7705                         }
7706                         g_free (sps);
7707                 } else if (!method->wrapper_type && !method->dynamic && mono_debug_image_has_debug_info (method->klass->image)) {
7708                         /* Methods without line number info like auto-generated property accessors */
7709                         seq_point_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
7710                         seq_point_set_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
7711                         sym_seq_points = TRUE;
7712                 }
7713         }
7714
7715         /* 
7716          * Methods without init_locals set could cause asserts in various passes
7717          * (#497220). To work around this, we emit dummy initialization opcodes
7718          * (OP_DUMMY_ICONST etc.) which generate no code. These are only supported
7719          * on some platforms.
7720          */
7721         if ((cfg->opt & MONO_OPT_UNSAFE) && ARCH_HAVE_DUMMY_INIT)
7722                 init_locals = header->init_locals;
7723         else
7724                 init_locals = TRUE;
7725
7726         method_definition = method;
7727         while (method_definition->is_inflated) {
7728                 MonoMethodInflated *imethod = (MonoMethodInflated *) method_definition;
7729                 method_definition = imethod->declaring;
7730         }
7731
7732         /* SkipVerification is not allowed if core-clr is enabled */
7733         if (!dont_verify && mini_assembly_can_skip_verification (cfg->domain, method)) {
7734                 dont_verify = TRUE;
7735                 dont_verify_stloc = TRUE;
7736         }
7737
7738         if (sig->is_inflated)
7739                 generic_context = mono_method_get_context (method);
7740         else if (generic_container)
7741                 generic_context = &generic_container->context;
7742         cfg->generic_context = generic_context;
7743
7744         if (!cfg->gshared)
7745                 g_assert (!sig->has_type_parameters);
7746
7747         if (sig->generic_param_count && method->wrapper_type == MONO_WRAPPER_NONE) {
7748                 g_assert (method->is_inflated);
7749                 g_assert (mono_method_get_context (method)->method_inst);
7750         }
7751         if (method->is_inflated && mono_method_get_context (method)->method_inst)
7752                 g_assert (sig->generic_param_count);
7753
7754         if (cfg->method == method) {
7755                 cfg->real_offset = 0;
7756         } else {
7757                 cfg->real_offset = inline_offset;
7758         }
7759
7760         cfg->cil_offset_to_bb = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoBasicBlock*) * header->code_size);
7761         cfg->cil_offset_to_bb_len = header->code_size;
7762
7763         cfg->current_method = method;
7764
7765         if (cfg->verbose_level > 2)
7766                 printf ("method to IR %s\n", mono_method_full_name (method, TRUE));
7767
7768         param_types = mono_mempool_alloc (cfg->mempool, sizeof (MonoType*) * num_args);
7769         if (sig->hasthis)
7770                 param_types [0] = method->klass->valuetype?&method->klass->this_arg:&method->klass->byval_arg;
7771         for (n = 0; n < sig->param_count; ++n)
7772                 param_types [n + sig->hasthis] = sig->params [n];
7773         cfg->arg_types = param_types;
7774
7775         cfg->dont_inline = g_list_prepend (cfg->dont_inline, method);
7776         if (cfg->method == method) {
7777
7778                 if (cfg->prof_options & MONO_PROFILE_INS_COVERAGE)
7779                         cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, header->code_size);
7780
7781                 /* ENTRY BLOCK */
7782                 NEW_BBLOCK (cfg, start_bblock);
7783                 cfg->bb_entry = start_bblock;
7784                 start_bblock->cil_code = NULL;
7785                 start_bblock->cil_length = 0;
7786
7787                 /* EXIT BLOCK */
7788                 NEW_BBLOCK (cfg, end_bblock);
7789                 cfg->bb_exit = end_bblock;
7790                 end_bblock->cil_code = NULL;
7791                 end_bblock->cil_length = 0;
7792                 end_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
7793                 g_assert (cfg->num_bblocks == 2);
7794
7795                 arg_array = cfg->args;
7796
7797                 if (header->num_clauses) {
7798                         cfg->spvars = g_hash_table_new (NULL, NULL);
7799                         cfg->exvars = g_hash_table_new (NULL, NULL);
7800                 }
7801                 /* handle exception clauses */
7802                 for (i = 0; i < header->num_clauses; ++i) {
7803                         MonoBasicBlock *try_bb;
7804                         MonoExceptionClause *clause = &header->clauses [i];
7805                         GET_BBLOCK (cfg, try_bb, ip + clause->try_offset);
7806                         try_bb->real_offset = clause->try_offset;
7807                         try_bb->try_start = TRUE;
7808                         try_bb->region = ((i + 1) << 8) | clause->flags;
7809                         GET_BBLOCK (cfg, tblock, ip + clause->handler_offset);
7810                         tblock->real_offset = clause->handler_offset;
7811                         tblock->flags |= BB_EXCEPTION_HANDLER;
7812
7813                         /*
7814                          * Linking the try block with the EH block hinders inlining as we won't be able to 
7815                          * merge the bblocks from inlining and produce an artificial hole for no good reason.
7816                          */
7817                         if (COMPILE_LLVM (cfg))
7818                                 link_bblock (cfg, try_bb, tblock);
7819
7820                         if (*(ip + clause->handler_offset) == CEE_POP)
7821                                 tblock->flags |= BB_EXCEPTION_DEAD_OBJ;
7822
7823                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY ||
7824                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER ||
7825                             clause->flags == MONO_EXCEPTION_CLAUSE_FAULT) {
7826                                 MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
7827                                 MONO_ADD_INS (tblock, ins);
7828
7829                                 if (seq_points && clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY && clause->flags != MONO_EXCEPTION_CLAUSE_FILTER) {
7830                                         /* finally clauses already have a seq point */
7831                                         /* seq points for filter clauses are emitted below */
7832                                         NEW_SEQ_POINT (cfg, ins, clause->handler_offset, TRUE);
7833                                         MONO_ADD_INS (tblock, ins);
7834                                 }
7835
7836                                 /* todo: is a fault block unsafe to optimize? */
7837                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
7838                                         tblock->flags |= BB_EXCEPTION_UNSAFE;
7839                         }
7840
7841                         /*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);
7842                           while (p < end) {
7843                           printf ("%s", mono_disasm_code_one (NULL, method, p, &p));
7844                           }*/
7845                         /* catch and filter blocks get the exception object on the stack */
7846                         if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE ||
7847                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
7848
7849                                 /* mostly like handle_stack_args (), but just sets the input args */
7850                                 /* printf ("handling clause at IL_%04x\n", clause->handler_offset); */
7851                                 tblock->in_scount = 1;
7852                                 tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
7853                                 tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
7854
7855                                 cfg->cbb = tblock;
7856
7857 #ifdef MONO_CONTEXT_SET_LLVM_EXC_REG
7858                                 /* The EH code passes in the exception in a register to both JITted and LLVM compiled code */
7859                                 if (!cfg->compile_llvm) {
7860                                         MONO_INST_NEW (cfg, ins, OP_GET_EX_OBJ);
7861                                         ins->dreg = tblock->in_stack [0]->dreg;
7862                                         MONO_ADD_INS (tblock, ins);
7863                                 }
7864 #else
7865                                 MonoInst *dummy_use;
7866
7867                                 /* 
7868                                  * Add a dummy use for the exvar so its liveness info will be
7869                                  * correct.
7870                                  */
7871                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, tblock->in_stack [0]);
7872 #endif
7873
7874                                 if (seq_points && clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
7875                                         NEW_SEQ_POINT (cfg, ins, clause->handler_offset, TRUE);
7876                                         MONO_ADD_INS (tblock, ins);
7877                                 }
7878                                 
7879                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
7880                                         GET_BBLOCK (cfg, tblock, ip + clause->data.filter_offset);
7881                                         tblock->flags |= BB_EXCEPTION_HANDLER;
7882                                         tblock->real_offset = clause->data.filter_offset;
7883                                         tblock->in_scount = 1;
7884                                         tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
7885                                         /* The filter block shares the exvar with the handler block */
7886                                         tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
7887                                         MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
7888                                         MONO_ADD_INS (tblock, ins);
7889                                 }
7890                         }
7891
7892                         if (clause->flags != MONO_EXCEPTION_CLAUSE_FILTER &&
7893                                         clause->data.catch_class &&
7894                                         cfg->gshared &&
7895                                         mono_class_check_context_used (clause->data.catch_class)) {
7896                                 /*
7897                                  * In shared generic code with catch
7898                                  * clauses containing type variables
7899                                  * the exception handling code has to
7900                                  * be able to get to the rgctx.
7901                                  * Therefore we have to make sure that
7902                                  * the vtable/mrgctx argument (for
7903                                  * static or generic methods) or the
7904                                  * "this" argument (for non-static
7905                                  * methods) are live.
7906                                  */
7907                                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
7908                                                 mini_method_get_context (method)->method_inst ||
7909                                                 method->klass->valuetype) {
7910                                         mono_get_vtable_var (cfg);
7911                                 } else {
7912                                         MonoInst *dummy_use;
7913
7914                                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, arg_array [0]);
7915                                 }
7916                         }
7917                 }
7918         } else {
7919                 arg_array = (MonoInst **) alloca (sizeof (MonoInst *) * num_args);
7920                 cfg->cbb = start_bblock;
7921                 cfg->args = arg_array;
7922                 mono_save_args (cfg, sig, inline_args);
7923         }
7924
7925         /* FIRST CODE BLOCK */
7926         NEW_BBLOCK (cfg, tblock);
7927         tblock->cil_code = ip;
7928         cfg->cbb = tblock;
7929         cfg->ip = ip;
7930
7931         ADD_BBLOCK (cfg, tblock);
7932
7933         if (cfg->method == method) {
7934                 breakpoint_id = mono_debugger_method_has_breakpoint (method);
7935                 if (breakpoint_id) {
7936                         MONO_INST_NEW (cfg, ins, OP_BREAK);
7937                         MONO_ADD_INS (cfg->cbb, ins);
7938                 }
7939         }
7940
7941         /* we use a separate basic block for the initialization code */
7942         NEW_BBLOCK (cfg, init_localsbb);
7943         cfg->bb_init = init_localsbb;
7944         init_localsbb->real_offset = cfg->real_offset;
7945         start_bblock->next_bb = init_localsbb;
7946         init_localsbb->next_bb = cfg->cbb;
7947         link_bblock (cfg, start_bblock, init_localsbb);
7948         link_bblock (cfg, init_localsbb, cfg->cbb);
7949                 
7950         cfg->cbb = init_localsbb;
7951
7952         if (cfg->gsharedvt && cfg->method == method) {
7953                 MonoGSharedVtMethodInfo *info;
7954                 MonoInst *var, *locals_var;
7955                 int dreg;
7956
7957                 info = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoGSharedVtMethodInfo));
7958                 info->method = cfg->method;
7959                 info->count_entries = 16;
7960                 info->entries = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
7961                 cfg->gsharedvt_info = info;
7962
7963                 var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
7964                 /* prevent it from being register allocated */
7965                 //var->flags |= MONO_INST_VOLATILE;
7966                 cfg->gsharedvt_info_var = var;
7967
7968                 ins = emit_get_rgctx_gsharedvt_method (cfg, mini_method_check_context_used (cfg, method), method, info);
7969                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, var->dreg, ins->dreg);
7970
7971                 /* Allocate locals */
7972                 locals_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
7973                 /* prevent it from being register allocated */
7974                 //locals_var->flags |= MONO_INST_VOLATILE;
7975                 cfg->gsharedvt_locals_var = locals_var;
7976
7977                 dreg = alloc_ireg (cfg);
7978                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, dreg, var->dreg, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, locals_size));
7979
7980                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
7981                 ins->dreg = locals_var->dreg;
7982                 ins->sreg1 = dreg;
7983                 MONO_ADD_INS (cfg->cbb, ins);
7984                 cfg->gsharedvt_locals_var_ins = ins;
7985                 
7986                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
7987                 /*
7988                 if (init_locals)
7989                         ins->flags |= MONO_INST_INIT;
7990                 */
7991         }
7992
7993         if (mono_security_core_clr_enabled ()) {
7994                 /* check if this is native code, e.g. an icall or a p/invoke */
7995                 if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
7996                         MonoMethod *wrapped = mono_marshal_method_from_wrapper (method);
7997                         if (wrapped) {
7998                                 gboolean pinvk = (wrapped->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL);
7999                                 gboolean icall = (wrapped->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL);
8000
8001                                 /* if this ia a native call then it can only be JITted from platform code */
8002                                 if ((icall || pinvk) && method->klass && method->klass->image) {
8003                                         if (!mono_security_core_clr_is_platform_image (method->klass->image)) {
8004                                                 MonoException *ex = icall ? mono_get_exception_security () : 
8005                                                         mono_get_exception_method_access ();
8006                                                 emit_throw_exception (cfg, ex);
8007                                         }
8008                                 }
8009                         }
8010                 }
8011         }
8012
8013         CHECK_CFG_EXCEPTION;
8014
8015         if (header->code_size == 0)
8016                 UNVERIFIED;
8017
8018         if (get_basic_blocks (cfg, header, cfg->real_offset, ip, end, &err_pos)) {
8019                 ip = err_pos;
8020                 UNVERIFIED;
8021         }
8022
8023         if (cfg->method == method)
8024                 mono_debug_init_method (cfg, cfg->cbb, breakpoint_id);
8025
8026         for (n = 0; n < header->num_locals; ++n) {
8027                 if (header->locals [n]->type == MONO_TYPE_VOID && !header->locals [n]->byref)
8028                         UNVERIFIED;
8029         }
8030         class_inits = NULL;
8031
8032         /* We force the vtable variable here for all shared methods
8033            for the possibility that they might show up in a stack
8034            trace where their exact instantiation is needed. */
8035         if (cfg->gshared && method == cfg->method) {
8036                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
8037                                 mini_method_get_context (method)->method_inst ||
8038                                 method->klass->valuetype) {
8039                         mono_get_vtable_var (cfg);
8040                 } else {
8041                         /* FIXME: Is there a better way to do this?
8042                            We need the variable live for the duration
8043                            of the whole method. */
8044                         cfg->args [0]->flags |= MONO_INST_VOLATILE;
8045                 }
8046         }
8047
8048         /* add a check for this != NULL to inlined methods */
8049         if (is_virtual_call) {
8050                 MonoInst *arg_ins;
8051
8052                 NEW_ARGLOAD (cfg, arg_ins, 0);
8053                 MONO_ADD_INS (cfg->cbb, arg_ins);
8054                 MONO_EMIT_NEW_CHECK_THIS (cfg, arg_ins->dreg);
8055         }
8056
8057         skip_dead_blocks = !dont_verify;
8058         if (skip_dead_blocks) {
8059                 original_bb = bb = mono_basic_block_split (method, &cfg->error);
8060                 CHECK_CFG_ERROR;
8061                 g_assert (bb);
8062         }
8063
8064         /* we use a spare stack slot in SWITCH and NEWOBJ and others */
8065         stack_start = sp = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (header->max_stack + 1));
8066
8067         ins_flag = 0;
8068         start_new_bblock = 0;
8069         while (ip < end) {
8070                 if (cfg->method == method)
8071                         cfg->real_offset = ip - header->code;
8072                 else
8073                         cfg->real_offset = inline_offset;
8074                 cfg->ip = ip;
8075
8076                 context_used = 0;
8077
8078                 if (start_new_bblock) {
8079                         cfg->cbb->cil_length = ip - cfg->cbb->cil_code;
8080                         if (start_new_bblock == 2) {
8081                                 g_assert (ip == tblock->cil_code);
8082                         } else {
8083                                 GET_BBLOCK (cfg, tblock, ip);
8084                         }
8085                         cfg->cbb->next_bb = tblock;
8086                         cfg->cbb = tblock;
8087                         start_new_bblock = 0;
8088                         for (i = 0; i < cfg->cbb->in_scount; ++i) {
8089                                 if (cfg->verbose_level > 3)
8090                                         printf ("loading %d from temp %d\n", i, (int)cfg->cbb->in_stack [i]->inst_c0);
8091                                 EMIT_NEW_TEMPLOAD (cfg, ins, cfg->cbb->in_stack [i]->inst_c0);
8092                                 *sp++ = ins;
8093                         }
8094                         if (class_inits)
8095                                 g_slist_free (class_inits);
8096                         class_inits = NULL;
8097                 } else {
8098                         if ((tblock = cfg->cil_offset_to_bb [ip - cfg->cil_start]) && (tblock != cfg->cbb)) {
8099                                 link_bblock (cfg, cfg->cbb, tblock);
8100                                 if (sp != stack_start) {
8101                                         handle_stack_args (cfg, stack_start, sp - stack_start);
8102                                         sp = stack_start;
8103                                         CHECK_UNVERIFIABLE (cfg);
8104                                 }
8105                                 cfg->cbb->next_bb = tblock;
8106                                 cfg->cbb = tblock;
8107                                 for (i = 0; i < cfg->cbb->in_scount; ++i) {
8108                                         if (cfg->verbose_level > 3)
8109                                                 printf ("loading %d from temp %d\n", i, (int)cfg->cbb->in_stack [i]->inst_c0);
8110                                         EMIT_NEW_TEMPLOAD (cfg, ins, cfg->cbb->in_stack [i]->inst_c0);
8111                                         *sp++ = ins;
8112                                 }
8113                                 g_slist_free (class_inits);
8114                                 class_inits = NULL;
8115                         }
8116                 }
8117
8118                 if (skip_dead_blocks) {
8119                         int ip_offset = ip - header->code;
8120
8121                         if (ip_offset == bb->end)
8122                                 bb = bb->next;
8123
8124                         if (bb->dead) {
8125                                 int op_size = mono_opcode_size (ip, end);
8126                                 g_assert (op_size > 0); /*The BB formation pass must catch all bad ops*/
8127
8128                                 if (cfg->verbose_level > 3) printf ("SKIPPING DEAD OP at %x\n", ip_offset);
8129
8130                                 if (ip_offset + op_size == bb->end) {
8131                                         MONO_INST_NEW (cfg, ins, OP_NOP);
8132                                         MONO_ADD_INS (cfg->cbb, ins);
8133                                         start_new_bblock = 1;
8134                                 }
8135
8136                                 ip += op_size;
8137                                 continue;
8138                         }
8139                 }
8140                 /*
8141                  * Sequence points are points where the debugger can place a breakpoint.
8142                  * Currently, we generate these automatically at points where the IL
8143                  * stack is empty.
8144                  */
8145                 if (seq_points && ((!sym_seq_points && (sp == stack_start)) || (sym_seq_points && mono_bitset_test_fast (seq_point_locs, ip - header->code)))) {
8146                         /*
8147                          * Make methods interruptable at the beginning, and at the targets of
8148                          * backward branches.
8149                          * Also, do this at the start of every bblock in methods with clauses too,
8150                          * to be able to handle instructions with inprecise control flow like
8151                          * throw/endfinally.
8152                          * Backward branches are handled at the end of method-to-ir ().
8153                          */
8154                         gboolean intr_loc = ip == header->code || (!cfg->cbb->last_ins && cfg->header->num_clauses);
8155                         gboolean sym_seq_point = sym_seq_points && mono_bitset_test_fast (seq_point_locs, ip - header->code);
8156
8157                         /* Avoid sequence points on empty IL like .volatile */
8158                         // FIXME: Enable this
8159                         //if (!(cfg->cbb->last_ins && cfg->cbb->last_ins->opcode == OP_SEQ_POINT)) {
8160                         NEW_SEQ_POINT (cfg, ins, ip - header->code, intr_loc);
8161                         if ((sp != stack_start) && !sym_seq_point)
8162                                 ins->flags |= MONO_INST_NONEMPTY_STACK;
8163                         MONO_ADD_INS (cfg->cbb, ins);
8164
8165                         if (sym_seq_points)
8166                                 mono_bitset_set_fast (seq_point_set_locs, ip - header->code);
8167                 }
8168
8169                 cfg->cbb->real_offset = cfg->real_offset;
8170
8171                 if ((cfg->method == method) && cfg->coverage_info) {
8172                         guint32 cil_offset = ip - header->code;
8173                         cfg->coverage_info->data [cil_offset].cil_code = ip;
8174
8175                         /* TODO: Use an increment here */
8176 #if defined(TARGET_X86)
8177                         MONO_INST_NEW (cfg, ins, OP_STORE_MEM_IMM);
8178                         ins->inst_p0 = &(cfg->coverage_info->data [cil_offset].count);
8179                         ins->inst_imm = 1;
8180                         MONO_ADD_INS (cfg->cbb, ins);
8181 #else
8182                         EMIT_NEW_PCONST (cfg, ins, &(cfg->coverage_info->data [cil_offset].count));
8183                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, ins->dreg, 0, 1);
8184 #endif
8185                 }
8186
8187                 if (cfg->verbose_level > 3)
8188                         printf ("converting (in B%d: stack: %d) %s", cfg->cbb->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
8189
8190                 switch (*ip) {
8191                 case CEE_NOP:
8192                         if (seq_points && !sym_seq_points && sp != stack_start) {
8193                                 /*
8194                                  * The C# compiler uses these nops to notify the JIT that it should
8195                                  * insert seq points.
8196                                  */
8197                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, FALSE);
8198                                 MONO_ADD_INS (cfg->cbb, ins);
8199                         }
8200                         if (cfg->keep_cil_nops)
8201                                 MONO_INST_NEW (cfg, ins, OP_HARD_NOP);
8202                         else
8203                                 MONO_INST_NEW (cfg, ins, OP_NOP);
8204                         ip++;
8205                         MONO_ADD_INS (cfg->cbb, ins);
8206                         break;
8207                 case CEE_BREAK:
8208                         if (should_insert_brekpoint (cfg->method)) {
8209                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
8210                         } else {
8211                                 MONO_INST_NEW (cfg, ins, OP_NOP);
8212                         }
8213                         ip++;
8214                         MONO_ADD_INS (cfg->cbb, ins);
8215                         break;
8216                 case CEE_LDARG_0:
8217                 case CEE_LDARG_1:
8218                 case CEE_LDARG_2:
8219                 case CEE_LDARG_3:
8220                         CHECK_STACK_OVF (1);
8221                         n = (*ip)-CEE_LDARG_0;
8222                         CHECK_ARG (n);
8223                         EMIT_NEW_ARGLOAD (cfg, ins, n);
8224                         ip++;
8225                         *sp++ = ins;
8226                         break;
8227                 case CEE_LDLOC_0:
8228                 case CEE_LDLOC_1:
8229                 case CEE_LDLOC_2:
8230                 case CEE_LDLOC_3:
8231                         CHECK_STACK_OVF (1);
8232                         n = (*ip)-CEE_LDLOC_0;
8233                         CHECK_LOCAL (n);
8234                         EMIT_NEW_LOCLOAD (cfg, ins, n);
8235                         ip++;
8236                         *sp++ = ins;
8237                         break;
8238                 case CEE_STLOC_0:
8239                 case CEE_STLOC_1:
8240                 case CEE_STLOC_2:
8241                 case CEE_STLOC_3: {
8242                         CHECK_STACK (1);
8243                         n = (*ip)-CEE_STLOC_0;
8244                         CHECK_LOCAL (n);
8245                         --sp;
8246                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
8247                                 UNVERIFIED;
8248                         emit_stloc_ir (cfg, sp, header, n);
8249                         ++ip;
8250                         inline_costs += 1;
8251                         break;
8252                         }
8253                 case CEE_LDARG_S:
8254                         CHECK_OPSIZE (2);
8255                         CHECK_STACK_OVF (1);
8256                         n = ip [1];
8257                         CHECK_ARG (n);
8258                         EMIT_NEW_ARGLOAD (cfg, ins, n);
8259                         *sp++ = ins;
8260                         ip += 2;
8261                         break;
8262                 case CEE_LDARGA_S:
8263                         CHECK_OPSIZE (2);
8264                         CHECK_STACK_OVF (1);
8265                         n = ip [1];
8266                         CHECK_ARG (n);
8267                         NEW_ARGLOADA (cfg, ins, n);
8268                         MONO_ADD_INS (cfg->cbb, ins);
8269                         *sp++ = ins;
8270                         ip += 2;
8271                         break;
8272                 case CEE_STARG_S:
8273                         CHECK_OPSIZE (2);
8274                         CHECK_STACK (1);
8275                         --sp;
8276                         n = ip [1];
8277                         CHECK_ARG (n);
8278                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [ip [1]], *sp))
8279                                 UNVERIFIED;
8280                         EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
8281                         ip += 2;
8282                         break;
8283                 case CEE_LDLOC_S:
8284                         CHECK_OPSIZE (2);
8285                         CHECK_STACK_OVF (1);
8286                         n = ip [1];
8287                         CHECK_LOCAL (n);
8288                         EMIT_NEW_LOCLOAD (cfg, ins, n);
8289                         *sp++ = ins;
8290                         ip += 2;
8291                         break;
8292                 case CEE_LDLOCA_S: {
8293                         unsigned char *tmp_ip;
8294                         CHECK_OPSIZE (2);
8295                         CHECK_STACK_OVF (1);
8296                         CHECK_LOCAL (ip [1]);
8297
8298                         if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 1))) {
8299                                 ip = tmp_ip;
8300                                 inline_costs += 1;
8301                                 break;
8302                         }
8303
8304                         EMIT_NEW_LOCLOADA (cfg, ins, ip [1]);
8305                         *sp++ = ins;
8306                         ip += 2;
8307                         break;
8308                 }
8309                 case CEE_STLOC_S:
8310                         CHECK_OPSIZE (2);
8311                         CHECK_STACK (1);
8312                         --sp;
8313                         CHECK_LOCAL (ip [1]);
8314                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [ip [1]], *sp))
8315                                 UNVERIFIED;
8316                         emit_stloc_ir (cfg, sp, header, ip [1]);
8317                         ip += 2;
8318                         inline_costs += 1;
8319                         break;
8320                 case CEE_LDNULL:
8321                         CHECK_STACK_OVF (1);
8322                         EMIT_NEW_PCONST (cfg, ins, NULL);
8323                         ins->type = STACK_OBJ;
8324                         ++ip;
8325                         *sp++ = ins;
8326                         break;
8327                 case CEE_LDC_I4_M1:
8328                         CHECK_STACK_OVF (1);
8329                         EMIT_NEW_ICONST (cfg, ins, -1);
8330                         ++ip;
8331                         *sp++ = ins;
8332                         break;
8333                 case CEE_LDC_I4_0:
8334                 case CEE_LDC_I4_1:
8335                 case CEE_LDC_I4_2:
8336                 case CEE_LDC_I4_3:
8337                 case CEE_LDC_I4_4:
8338                 case CEE_LDC_I4_5:
8339                 case CEE_LDC_I4_6:
8340                 case CEE_LDC_I4_7:
8341                 case CEE_LDC_I4_8:
8342                         CHECK_STACK_OVF (1);
8343                         EMIT_NEW_ICONST (cfg, ins, (*ip) - CEE_LDC_I4_0);
8344                         ++ip;
8345                         *sp++ = ins;
8346                         break;
8347                 case CEE_LDC_I4_S:
8348                         CHECK_OPSIZE (2);
8349                         CHECK_STACK_OVF (1);
8350                         ++ip;
8351                         EMIT_NEW_ICONST (cfg, ins, *((signed char*)ip));
8352                         ++ip;
8353                         *sp++ = ins;
8354                         break;
8355                 case CEE_LDC_I4:
8356                         CHECK_OPSIZE (5);
8357                         CHECK_STACK_OVF (1);
8358                         EMIT_NEW_ICONST (cfg, ins, (gint32)read32 (ip + 1));
8359                         ip += 5;
8360                         *sp++ = ins;
8361                         break;
8362                 case CEE_LDC_I8:
8363                         CHECK_OPSIZE (9);
8364                         CHECK_STACK_OVF (1);
8365                         MONO_INST_NEW (cfg, ins, OP_I8CONST);
8366                         ins->type = STACK_I8;
8367                         ins->dreg = alloc_dreg (cfg, STACK_I8);
8368                         ++ip;
8369                         ins->inst_l = (gint64)read64 (ip);
8370                         MONO_ADD_INS (cfg->cbb, ins);
8371                         ip += 8;
8372                         *sp++ = ins;
8373                         break;
8374                 case CEE_LDC_R4: {
8375                         float *f;
8376                         gboolean use_aotconst = FALSE;
8377
8378 #ifdef TARGET_POWERPC
8379                         /* FIXME: Clean this up */
8380                         if (cfg->compile_aot)
8381                                 use_aotconst = TRUE;
8382 #endif
8383
8384                         /* FIXME: we should really allocate this only late in the compilation process */
8385                         f = mono_domain_alloc (cfg->domain, sizeof (float));
8386                         CHECK_OPSIZE (5);
8387                         CHECK_STACK_OVF (1);
8388
8389                         if (use_aotconst) {
8390                                 MonoInst *cons;
8391                                 int dreg;
8392
8393                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R4, f);
8394
8395                                 dreg = alloc_freg (cfg);
8396                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR4_MEMBASE, dreg, cons->dreg, 0);
8397                                 ins->type = cfg->r4_stack_type;
8398                         } else {
8399                                 MONO_INST_NEW (cfg, ins, OP_R4CONST);
8400                                 ins->type = cfg->r4_stack_type;
8401                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
8402                                 ins->inst_p0 = f;
8403                                 MONO_ADD_INS (cfg->cbb, ins);
8404                         }
8405                         ++ip;
8406                         readr4 (ip, f);
8407                         ip += 4;
8408                         *sp++ = ins;                    
8409                         break;
8410                 }
8411                 case CEE_LDC_R8: {
8412                         double *d;
8413                         gboolean use_aotconst = FALSE;
8414
8415 #ifdef TARGET_POWERPC
8416                         /* FIXME: Clean this up */
8417                         if (cfg->compile_aot)
8418                                 use_aotconst = TRUE;
8419 #endif
8420
8421                         /* FIXME: we should really allocate this only late in the compilation process */
8422                         d = mono_domain_alloc (cfg->domain, sizeof (double));
8423                         CHECK_OPSIZE (9);
8424                         CHECK_STACK_OVF (1);
8425
8426                         if (use_aotconst) {
8427                                 MonoInst *cons;
8428                                 int dreg;
8429
8430                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R8, d);
8431
8432                                 dreg = alloc_freg (cfg);
8433                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR8_MEMBASE, dreg, cons->dreg, 0);
8434                                 ins->type = STACK_R8;
8435                         } else {
8436                                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
8437                                 ins->type = STACK_R8;
8438                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
8439                                 ins->inst_p0 = d;
8440                                 MONO_ADD_INS (cfg->cbb, ins);
8441                         }
8442                         ++ip;
8443                         readr8 (ip, d);
8444                         ip += 8;
8445                         *sp++ = ins;
8446                         break;
8447                 }
8448                 case CEE_DUP: {
8449                         MonoInst *temp, *store;
8450                         CHECK_STACK (1);
8451                         CHECK_STACK_OVF (1);
8452                         sp--;
8453                         ins = *sp;
8454
8455                         temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
8456                         EMIT_NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
8457
8458                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
8459                         *sp++ = ins;
8460
8461                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
8462                         *sp++ = ins;
8463
8464                         ++ip;
8465                         inline_costs += 2;
8466                         break;
8467                 }
8468                 case CEE_POP:
8469                         CHECK_STACK (1);
8470                         ip++;
8471                         --sp;
8472
8473 #ifdef TARGET_X86
8474                         if (sp [0]->type == STACK_R8)
8475                                 /* we need to pop the value from the x86 FP stack */
8476                                 MONO_EMIT_NEW_UNALU (cfg, OP_X86_FPOP, -1, sp [0]->dreg);
8477 #endif
8478                         break;
8479                 case CEE_JMP: {
8480                         MonoCallInst *call;
8481
8482                         INLINE_FAILURE ("jmp");
8483                         GSHAREDVT_FAILURE (*ip);
8484
8485                         CHECK_OPSIZE (5);
8486                         if (stack_start != sp)
8487                                 UNVERIFIED;
8488                         token = read32 (ip + 1);
8489                         /* FIXME: check the signature matches */
8490                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
8491
8492                         if (!cmethod || mono_loader_get_last_error ())
8493                                 LOAD_ERROR;
8494  
8495                         if (cfg->gshared && mono_method_check_context_used (cmethod))
8496                                 GENERIC_SHARING_FAILURE (CEE_JMP);
8497
8498                         emit_instrumentation_call (cfg, mono_profiler_method_leave);
8499
8500                         if (ARCH_HAVE_OP_TAIL_CALL) {
8501                                 MonoMethodSignature *fsig = mono_method_signature (cmethod);
8502                                 int i, n;
8503
8504                                 /* Handle tail calls similarly to calls */
8505                                 n = fsig->param_count + fsig->hasthis;
8506
8507                                 DISABLE_AOT (cfg);
8508
8509                                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
8510                                 call->method = cmethod;
8511                                 call->tail_call = TRUE;
8512                                 call->signature = mono_method_signature (cmethod);
8513                                 call->args = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * n);
8514                                 call->inst.inst_p0 = cmethod;
8515                                 for (i = 0; i < n; ++i)
8516                                         EMIT_NEW_ARGLOAD (cfg, call->args [i], i);
8517
8518                                 mono_arch_emit_call (cfg, call);
8519                                 cfg->param_area = MAX(cfg->param_area, call->stack_usage);
8520                                 MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
8521                         } else {
8522                                 for (i = 0; i < num_args; ++i)
8523                                         /* Prevent arguments from being optimized away */
8524                                         arg_array [i]->flags |= MONO_INST_VOLATILE;
8525
8526                                 MONO_INST_NEW_CALL (cfg, call, OP_JMP);
8527                                 ins = (MonoInst*)call;
8528                                 ins->inst_p0 = cmethod;
8529                                 MONO_ADD_INS (cfg->cbb, ins);
8530                         }
8531
8532                         ip += 5;
8533                         start_new_bblock = 1;
8534                         break;
8535                 }
8536                 case CEE_CALLI: {
8537                         MonoInst *addr;
8538                         MonoMethodSignature *fsig;
8539
8540                         CHECK_OPSIZE (5);
8541                         token = read32 (ip + 1);
8542
8543                         ins = NULL;
8544
8545                         //GSHAREDVT_FAILURE (*ip);
8546                         cmethod = NULL;
8547                         CHECK_STACK (1);
8548                         --sp;
8549                         addr = *sp;
8550                         fsig = mini_get_signature (method, token, generic_context);
8551
8552                         if (method->dynamic && fsig->pinvoke) {
8553                                 MonoInst *args [3];
8554
8555                                 /*
8556                                  * This is a call through a function pointer using a pinvoke
8557                                  * signature. Have to create a wrapper and call that instead.
8558                                  * FIXME: This is very slow, need to create a wrapper at JIT time
8559                                  * instead based on the signature.
8560                                  */
8561                                 EMIT_NEW_IMAGECONST (cfg, args [0], method->klass->image);
8562                                 EMIT_NEW_PCONST (cfg, args [1], fsig);
8563                                 args [2] = addr;
8564                                 addr = mono_emit_jit_icall (cfg, mono_get_native_calli_wrapper, args);
8565                         }
8566
8567                         n = fsig->param_count + fsig->hasthis;
8568
8569                         CHECK_STACK (n);
8570
8571                         //g_assert (!virtual || fsig->hasthis);
8572
8573                         sp -= n;
8574
8575                         inline_costs += 10 * num_calls++;
8576
8577                         /*
8578                          * Making generic calls out of gsharedvt methods.
8579                          * This needs to be used for all generic calls, not just ones with a gsharedvt signature, to avoid
8580                          * patching gshared method addresses into a gsharedvt method.
8581                          */
8582                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) {
8583                                 /*
8584                                  * We pass the address to the gsharedvt trampoline in the rgctx reg
8585                                  */
8586                                 MonoInst *callee = addr;
8587
8588                                 if (method->wrapper_type != MONO_WRAPPER_DELEGATE_INVOKE)
8589                                         /* Not tested */
8590                                         GSHAREDVT_FAILURE (*ip);
8591
8592                                 addr = emit_get_rgctx_sig (cfg, context_used,
8593                                                                                           fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
8594                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, callee);
8595                                 goto calli_end;
8596                         }
8597
8598                         /* Prevent inlining of methods with indirect calls */
8599                         INLINE_FAILURE ("indirect call");
8600
8601                         if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST || addr->opcode == OP_GOT_ENTRY) {
8602                                 int info_type;
8603                                 gpointer info_data;
8604
8605                                 /*
8606                                  * Instead of emitting an indirect call, emit a direct call
8607                                  * with the contents of the aotconst as the patch info.
8608                                  */
8609                                 if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST) {
8610                                         info_type = addr->inst_c1;
8611                                         info_data = addr->inst_p0;
8612                                 } else {
8613                                         info_type = addr->inst_right->inst_c1;
8614                                         info_data = addr->inst_right->inst_left;
8615                                 }
8616
8617                                 if (info_type == MONO_PATCH_INFO_ICALL_ADDR || info_type == MONO_PATCH_INFO_JIT_ICALL_ADDR) {
8618                                         ins = (MonoInst*)mono_emit_abs_call (cfg, info_type, info_data, fsig, sp);
8619                                         NULLIFY_INS (addr);
8620                                         goto calli_end;
8621                                 }
8622                         }
8623                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
8624
8625                         calli_end:
8626
8627                         /* End of call, INS should contain the result of the call, if any */
8628
8629                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
8630                                 g_assert (ins);
8631                                 *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
8632                         }
8633
8634                         CHECK_CFG_EXCEPTION;
8635
8636                         ip += 5;
8637                         ins_flag = 0;
8638                         constrained_class = NULL;
8639                         break;
8640                 }
8641                 case CEE_CALL:
8642                 case CEE_CALLVIRT: {
8643                         MonoInst *addr = NULL;
8644                         MonoMethodSignature *fsig = NULL;
8645                         int array_rank = 0;
8646                         int virtual = *ip == CEE_CALLVIRT;
8647                         gboolean pass_imt_from_rgctx = FALSE;
8648                         MonoInst *imt_arg = NULL;
8649                         MonoInst *keep_this_alive = NULL;
8650                         gboolean pass_vtable = FALSE;
8651                         gboolean pass_mrgctx = FALSE;
8652                         MonoInst *vtable_arg = NULL;
8653                         gboolean check_this = FALSE;
8654                         gboolean supported_tail_call = FALSE;
8655                         gboolean tail_call = FALSE;
8656                         gboolean need_seq_point = FALSE;
8657                         guint32 call_opcode = *ip;
8658                         gboolean emit_widen = TRUE;
8659                         gboolean push_res = TRUE;
8660                         gboolean skip_ret = FALSE;
8661                         gboolean delegate_invoke = FALSE;
8662                         gboolean direct_icall = FALSE;
8663                         gboolean constrained_partial_call = FALSE;
8664                         MonoMethod *cil_method;
8665
8666                         CHECK_OPSIZE (5);
8667                         token = read32 (ip + 1);
8668
8669                         ins = NULL;
8670
8671                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
8672                         cil_method = cmethod;
8673                                 
8674                         if (constrained_class) {
8675                                 if ((constrained_class->byval_arg.type == MONO_TYPE_VAR || constrained_class->byval_arg.type == MONO_TYPE_MVAR) && cfg->gshared) {
8676                                         if (!mini_is_gsharedvt_klass (constrained_class)) {
8677                                                 g_assert (!cmethod->klass->valuetype);
8678                                                 if (!mini_type_is_reference (&constrained_class->byval_arg))
8679                                                         constrained_partial_call = TRUE;
8680                                         }
8681                                 }
8682
8683                                 if (method->wrapper_type != MONO_WRAPPER_NONE) {
8684                                         if (cfg->verbose_level > 2)
8685                                                 printf ("DM Constrained call to %s\n", mono_type_get_full_name (constrained_class));
8686                                         if (!((constrained_class->byval_arg.type == MONO_TYPE_VAR ||
8687                                                    constrained_class->byval_arg.type == MONO_TYPE_MVAR) &&
8688                                                   cfg->gshared)) {
8689                                                 cmethod = mono_get_method_constrained_with_method (image, cil_method, constrained_class, generic_context, &cfg->error);
8690                                                 CHECK_CFG_ERROR;
8691                                         }
8692                                 } else {
8693                                         if (cfg->verbose_level > 2)
8694                                                 printf ("Constrained call to %s\n", mono_type_get_full_name (constrained_class));
8695
8696                                         if ((constrained_class->byval_arg.type == MONO_TYPE_VAR || constrained_class->byval_arg.type == MONO_TYPE_MVAR) && cfg->gshared) {
8697                                                 /* 
8698                                                  * This is needed since get_method_constrained can't find 
8699                                                  * the method in klass representing a type var.
8700                                                  * The type var is guaranteed to be a reference type in this
8701                                                  * case.
8702                                                  */
8703                                                 if (!mini_is_gsharedvt_klass (constrained_class))
8704                                                         g_assert (!cmethod->klass->valuetype);
8705                                         } else {
8706                                                 cmethod = mono_get_method_constrained_checked (image, token, constrained_class, generic_context, &cil_method, &cfg->error);
8707                                                 CHECK_CFG_ERROR;
8708                                         }
8709                                 }
8710                         }
8711                                         
8712                         if (!cmethod || mono_loader_get_last_error ())
8713                                 LOAD_ERROR;
8714                         if (!dont_verify && !cfg->skip_visibility) {
8715                                 MonoMethod *target_method = cil_method;
8716                                 if (method->is_inflated) {
8717                                         target_method = mini_get_method_allow_open (method, token, NULL, &(mono_method_get_generic_container (method_definition)->context));
8718                                 }
8719                                 if (!mono_method_can_access_method (method_definition, target_method) &&
8720                                         !mono_method_can_access_method (method, cil_method))
8721                                         METHOD_ACCESS_FAILURE (method, cil_method);
8722                         }
8723
8724                         if (mono_security_core_clr_enabled ())
8725                                 ensure_method_is_allowed_to_call_method (cfg, method, cil_method);
8726
8727                         if (!virtual && (cmethod->flags & METHOD_ATTRIBUTE_ABSTRACT))
8728                                 /* MS.NET seems to silently convert this to a callvirt */
8729                                 virtual = 1;
8730
8731                         {
8732                                 /*
8733                                  * MS.NET accepts non virtual calls to virtual final methods of transparent proxy classes and
8734                                  * converts to a callvirt.
8735                                  *
8736                                  * tests/bug-515884.il is an example of this behavior
8737                                  */
8738                                 const int test_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_STATIC;
8739                                 const int expected_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL;
8740                                 if (!virtual && mono_class_is_marshalbyref (cmethod->klass) && (cmethod->flags & test_flags) == expected_flags && cfg->method->wrapper_type == MONO_WRAPPER_NONE)
8741                                         virtual = 1;
8742                         }
8743
8744                         if (!cmethod->klass->inited)
8745                                 if (!mono_class_init (cmethod->klass))
8746                                         TYPE_LOAD_ERROR (cmethod->klass);
8747
8748                         fsig = mono_method_signature (cmethod);
8749                         if (!fsig)
8750                                 LOAD_ERROR;
8751                         if (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL &&
8752                                 mini_class_is_system_array (cmethod->klass)) {
8753                                 array_rank = cmethod->klass->rank;
8754                         } else if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && icall_is_direct_callable (cfg, cmethod)) {
8755                                 direct_icall = TRUE;
8756                         } else if (fsig->pinvoke) {
8757                                 MonoMethod *wrapper = mono_marshal_get_native_wrapper (cmethod, TRUE, cfg->compile_aot);
8758                                 fsig = mono_method_signature (wrapper);
8759                         } else if (constrained_class) {
8760                         } else {
8761                                 fsig = mono_method_get_signature_checked (cmethod, image, token, generic_context, &cfg->error);
8762                                 CHECK_CFG_ERROR;
8763                         }
8764
8765                         /* See code below */
8766                         if (cmethod->klass == mono_defaults.monitor_class && !strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1) {
8767                                 MonoBasicBlock *tbb;
8768
8769                                 GET_BBLOCK (cfg, tbb, ip + 5);
8770                                 if (tbb->try_start && MONO_REGION_FLAGS(tbb->region) == MONO_EXCEPTION_CLAUSE_FINALLY) {
8771                                         /*
8772                                          * We want to extend the try block to cover the call, but we can't do it if the
8773                                          * call is made directly since its followed by an exception check.
8774                                          */
8775                                         direct_icall = FALSE;
8776                                 }
8777                         }
8778
8779                         mono_save_token_info (cfg, image, token, cil_method);
8780
8781                         if (!(seq_point_locs && mono_bitset_test_fast (seq_point_locs, ip + 5 - header->code)))
8782                                 need_seq_point = TRUE;
8783
8784                         /* Don't support calls made using type arguments for now */
8785                         /*
8786                           if (cfg->gsharedvt) {
8787                           if (mini_is_gsharedvt_signature (fsig))
8788                           GSHAREDVT_FAILURE (*ip);
8789                           }
8790                         */
8791
8792                         if (cmethod->string_ctor && method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE)
8793                                 g_assert_not_reached ();
8794
8795                         n = fsig->param_count + fsig->hasthis;
8796
8797                         if (!cfg->gshared && cmethod->klass->generic_container)
8798                                 UNVERIFIED;
8799
8800                         if (!cfg->gshared)
8801                                 g_assert (!mono_method_check_context_used (cmethod));
8802
8803                         CHECK_STACK (n);
8804
8805                         //g_assert (!virtual || fsig->hasthis);
8806
8807                         sp -= n;
8808
8809                         if (constrained_class) {
8810                                 if (mini_is_gsharedvt_klass (constrained_class)) {
8811                                         if ((cmethod->klass != mono_defaults.object_class) && constrained_class->valuetype && cmethod->klass->valuetype) {
8812                                                 /* The 'Own method' case below */
8813                                         } else if (cmethod->klass->image != mono_defaults.corlib && !(cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) && !cmethod->klass->valuetype) {
8814                                                 /* 'The type parameter is instantiated as a reference type' case below. */
8815                                         } else {
8816                                                 ins = handle_constrained_gsharedvt_call (cfg, cmethod, fsig, sp, constrained_class, &emit_widen);
8817                                                 CHECK_CFG_EXCEPTION;
8818                                                 g_assert (ins);
8819                                                 goto call_end;
8820                                         }
8821                                 }
8822
8823                                 /*
8824                                  * We have the `constrained.' prefix opcode.
8825                                  */
8826                                 if (constrained_partial_call) {
8827                                         gboolean need_box = TRUE;
8828
8829                                         /*
8830                                          * The receiver is a valuetype, but the exact type is not known at compile time. This means the
8831                                          * called method is not known at compile time either. The called method could end up being
8832                                          * one of the methods on the parent classes (object/valuetype/enum), in which case we need
8833                                          * to box the receiver.
8834                                          * A simple solution would be to box always and make a normal virtual call, but that would
8835                                          * be bad performance wise.
8836                                          */
8837                                         if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE && cmethod->klass->generic_class) {
8838                                                 /*
8839                                                  * The parent classes implement no generic interfaces, so the called method will be a vtype method, so no boxing neccessary.
8840                                                  */
8841                                                 need_box = FALSE;
8842                                         }
8843
8844                                         if (!(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) && (cmethod->klass == mono_defaults.object_class || cmethod->klass == mono_defaults.enum_class->parent || cmethod->klass == mono_defaults.enum_class)) {
8845                                                 /* The called method is not virtual, i.e. Object:GetType (), the receiver is a vtype, has to box */
8846                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
8847                                                 ins->klass = constrained_class;
8848                                                 sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
8849                                                 CHECK_CFG_EXCEPTION;
8850                                         } else if (need_box) {
8851                                                 MonoInst *box_type;
8852                                                 MonoBasicBlock *is_ref_bb, *end_bb;
8853                                                 MonoInst *nonbox_call;
8854
8855                                                 /*
8856                                                  * Determine at runtime whenever the called method is defined on object/valuetype/enum, and emit a boxing call
8857                                                  * if needed.
8858                                                  * FIXME: It is possible to inline the called method in a lot of cases, i.e. for T_INT,
8859                                                  * the no-box case goes to a method in Int32, while the box case goes to a method in Enum.
8860                                                  */
8861                                                 addr = emit_get_rgctx_virt_method (cfg, mono_class_check_context_used (constrained_class), constrained_class, cmethod, MONO_RGCTX_INFO_VIRT_METHOD_CODE);
8862
8863                                                 NEW_BBLOCK (cfg, is_ref_bb);
8864                                                 NEW_BBLOCK (cfg, end_bb);
8865
8866                                                 box_type = emit_get_rgctx_virt_method (cfg, mono_class_check_context_used (constrained_class), constrained_class, cmethod, MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE);
8867                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, box_type->dreg, 1);
8868                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
8869
8870                                                 /* Non-ref case */
8871                                                 nonbox_call = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
8872
8873                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
8874
8875                                                 /* Ref case */
8876                                                 MONO_START_BB (cfg, is_ref_bb);
8877                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
8878                                                 ins->klass = constrained_class;
8879                                                 sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
8880                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
8881
8882                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
8883
8884                                                 MONO_START_BB (cfg, end_bb);
8885                                                 cfg->cbb = end_bb;
8886
8887                                                 nonbox_call->dreg = ins->dreg;
8888                                                 goto call_end;
8889                                         } else {
8890                                                 g_assert (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE);
8891                                                 addr = emit_get_rgctx_virt_method (cfg, mono_class_check_context_used (constrained_class), constrained_class, cmethod, MONO_RGCTX_INFO_VIRT_METHOD_CODE);
8892                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
8893                                                 goto call_end;
8894                                         }
8895                                 } else if (constrained_class->valuetype && (cmethod->klass == mono_defaults.object_class || cmethod->klass == mono_defaults.enum_class->parent || cmethod->klass == mono_defaults.enum_class)) {
8896                                         /*
8897                                          * The type parameter is instantiated as a valuetype,
8898                                          * but that type doesn't override the method we're
8899                                          * calling, so we need to box `this'.
8900                                          */
8901                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
8902                                         ins->klass = constrained_class;
8903                                         sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
8904                                         CHECK_CFG_EXCEPTION;
8905                                 } else if (!constrained_class->valuetype) {
8906                                         int dreg = alloc_ireg_ref (cfg);
8907
8908                                         /*
8909                                          * The type parameter is instantiated as a reference
8910                                          * type.  We have a managed pointer on the stack, so
8911                                          * we need to dereference it here.
8912                                          */
8913                                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, sp [0]->dreg, 0);
8914                                         ins->type = STACK_OBJ;
8915                                         sp [0] = ins;
8916                                 } else {
8917                                         if (cmethod->klass->valuetype) {
8918                                                 /* Own method */
8919                                         } else {
8920                                                 /* Interface method */
8921                                                 int ioffset, slot;
8922
8923                                                 mono_class_setup_vtable (constrained_class);
8924                                                 CHECK_TYPELOAD (constrained_class);
8925                                                 ioffset = mono_class_interface_offset (constrained_class, cmethod->klass);
8926                                                 if (ioffset == -1)
8927                                                         TYPE_LOAD_ERROR (constrained_class);
8928                                                 slot = mono_method_get_vtable_slot (cmethod);
8929                                                 if (slot == -1)
8930                                                         TYPE_LOAD_ERROR (cmethod->klass);
8931                                                 cmethod = constrained_class->vtable [ioffset + slot];
8932
8933                                                 if (cmethod->klass == mono_defaults.enum_class) {
8934                                                         /* Enum implements some interfaces, so treat this as the first case */
8935                                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
8936                                                         ins->klass = constrained_class;
8937                                                         sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
8938                                                         CHECK_CFG_EXCEPTION;
8939                                                 }
8940                                         }
8941                                         virtual = 0;
8942                                 }
8943                                 constrained_class = NULL;
8944                         }
8945
8946                         if (check_call_signature (cfg, fsig, sp))
8947                                 UNVERIFIED;
8948
8949                         if ((cmethod->klass->parent == mono_defaults.multicastdelegate_class) && !strcmp (cmethod->name, "Invoke"))
8950                                 delegate_invoke = TRUE;
8951
8952                         if ((cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_sharable_method (cfg, cmethod, fsig, sp))) {
8953                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
8954                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
8955                                         emit_widen = FALSE;
8956                                 }
8957
8958                                 goto call_end;
8959                         }
8960
8961                         /* 
8962                          * If the callee is a shared method, then its static cctor
8963                          * might not get called after the call was patched.
8964                          */
8965                         if (cfg->gshared && cmethod->klass != method->klass && cmethod->klass->generic_class && mono_method_is_generic_sharable (cmethod, TRUE) && mono_class_needs_cctor_run (cmethod->klass, method)) {
8966                                 emit_class_init (cfg, cmethod->klass);
8967                                 CHECK_TYPELOAD (cmethod->klass);
8968                         }
8969
8970                         check_method_sharing (cfg, cmethod, &pass_vtable, &pass_mrgctx);
8971
8972                         if (cfg->gshared) {
8973                                 MonoGenericContext *cmethod_context = mono_method_get_context (cmethod);
8974
8975                                 context_used = mini_method_check_context_used (cfg, cmethod);
8976
8977                                 if (context_used && (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
8978                                         /* Generic method interface
8979                                            calls are resolved via a
8980                                            helper function and don't
8981                                            need an imt. */
8982                                         if (!cmethod_context || !cmethod_context->method_inst)
8983                                                 pass_imt_from_rgctx = TRUE;
8984                                 }
8985
8986                                 /*
8987                                  * If a shared method calls another
8988                                  * shared method then the caller must
8989                                  * have a generic sharing context
8990                                  * because the magic trampoline
8991                                  * requires it.  FIXME: We shouldn't
8992                                  * have to force the vtable/mrgctx
8993                                  * variable here.  Instead there
8994                                  * should be a flag in the cfg to
8995                                  * request a generic sharing context.
8996                                  */
8997                                 if (context_used &&
8998                                                 ((method->flags & METHOD_ATTRIBUTE_STATIC) || method->klass->valuetype))
8999                                         mono_get_vtable_var (cfg);
9000                         }
9001
9002                         if (pass_vtable) {
9003                                 if (context_used) {
9004                                         vtable_arg = emit_get_rgctx_klass (cfg, context_used, cmethod->klass, MONO_RGCTX_INFO_VTABLE);
9005                                 } else {
9006                                         MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
9007
9008                                         CHECK_TYPELOAD (cmethod->klass);
9009                                         EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
9010                                 }
9011                         }
9012
9013                         if (pass_mrgctx) {
9014                                 g_assert (!vtable_arg);
9015
9016                                 if (!cfg->compile_aot) {
9017                                         /* 
9018                                          * emit_get_rgctx_method () calls mono_class_vtable () so check 
9019                                          * for type load errors before.
9020                                          */
9021                                         mono_class_setup_vtable (cmethod->klass);
9022                                         CHECK_TYPELOAD (cmethod->klass);
9023                                 }
9024
9025                                 vtable_arg = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
9026
9027                                 /* !marshalbyref is needed to properly handle generic methods + remoting */
9028                                 if ((!(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
9029                                          MONO_METHOD_IS_FINAL (cmethod)) &&
9030                                         !mono_class_is_marshalbyref (cmethod->klass)) {
9031                                         if (virtual)
9032                                                 check_this = TRUE;
9033                                         virtual = 0;
9034                                 }
9035                         }
9036
9037                         if (pass_imt_from_rgctx) {
9038                                 g_assert (!pass_vtable);
9039
9040                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9041                                         cmethod, MONO_RGCTX_INFO_METHOD);
9042                         }
9043
9044                         if (check_this)
9045                                 MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
9046
9047                         /* Calling virtual generic methods */
9048                         if (virtual && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) && 
9049                             !(MONO_METHOD_IS_FINAL (cmethod) && 
9050                               cmethod->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK) &&
9051                             fsig->generic_param_count && 
9052                                 !(cfg->gsharedvt && mini_is_gsharedvt_signature (fsig))) {
9053                                 MonoInst *this_temp, *this_arg_temp, *store;
9054                                 MonoInst *iargs [4];
9055                                 gboolean use_imt = FALSE;
9056
9057                                 g_assert (fsig->is_inflated);
9058
9059                                 /* Prevent inlining of methods that contain indirect calls */
9060                                 INLINE_FAILURE ("virtual generic call");
9061
9062                                 if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig))
9063                                         GSHAREDVT_FAILURE (*ip);
9064
9065 #if MONO_ARCH_HAVE_GENERALIZED_IMT_THUNK && defined(MONO_ARCH_GSHARED_SUPPORTED)
9066                                 if (cmethod->wrapper_type == MONO_WRAPPER_NONE)
9067                                         use_imt = TRUE;
9068 #endif
9069
9070                                 if (use_imt) {
9071                                         g_assert (!imt_arg);
9072                                         if (!context_used)
9073                                                 g_assert (cmethod->is_inflated);
9074                                         imt_arg = emit_get_rgctx_method (cfg, context_used,
9075                                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
9076                                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, sp [0], imt_arg, NULL);
9077                                 } else {
9078                                         this_temp = mono_compile_create_var (cfg, type_from_stack_type (sp [0]), OP_LOCAL);
9079                                         NEW_TEMPSTORE (cfg, store, this_temp->inst_c0, sp [0]);
9080                                         MONO_ADD_INS (cfg->cbb, store);
9081
9082                                         /* FIXME: This should be a managed pointer */
9083                                         this_arg_temp = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
9084
9085                                         EMIT_NEW_TEMPLOAD (cfg, iargs [0], this_temp->inst_c0);
9086                                         iargs [1] = emit_get_rgctx_method (cfg, context_used,
9087                                                                                                            cmethod, MONO_RGCTX_INFO_METHOD);
9088                                         EMIT_NEW_TEMPLOADA (cfg, iargs [2], this_arg_temp->inst_c0);
9089                                         addr = mono_emit_jit_icall (cfg,
9090                                                                                                 mono_helper_compile_generic_method, iargs);
9091
9092                                         EMIT_NEW_TEMPLOAD (cfg, sp [0], this_arg_temp->inst_c0);
9093
9094                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9095                                 }
9096
9097                                 goto call_end;
9098                         }
9099
9100                         /*
9101                          * Implement a workaround for the inherent races involved in locking:
9102                          * Monitor.Enter ()
9103                          * try {
9104                          * } finally {
9105                          *    Monitor.Exit ()
9106                          * }
9107                          * If a thread abort happens between the call to Monitor.Enter () and the start of the
9108                          * try block, the Exit () won't be executed, see:
9109                          * http://www.bluebytesoftware.com/blog/2007/01/30/MonitorEnterThreadAbortsAndOrphanedLocks.aspx
9110                          * To work around this, we extend such try blocks to include the last x bytes
9111                          * of the Monitor.Enter () call.
9112                          */
9113                         if (cmethod->klass == mono_defaults.monitor_class && !strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1) {
9114                                 MonoBasicBlock *tbb;
9115
9116                                 GET_BBLOCK (cfg, tbb, ip + 5);
9117                                 /* 
9118                                  * Only extend try blocks with a finally, to avoid catching exceptions thrown
9119                                  * from Monitor.Enter like ArgumentNullException.
9120                                  */
9121                                 if (tbb->try_start && MONO_REGION_FLAGS(tbb->region) == MONO_EXCEPTION_CLAUSE_FINALLY) {
9122                                         /* Mark this bblock as needing to be extended */
9123                                         tbb->extend_try_block = TRUE;
9124                                 }
9125                         }
9126
9127                         /* Conversion to a JIT intrinsic */
9128                         if ((cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_method (cfg, cmethod, fsig, sp))) {
9129                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9130                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
9131                                         emit_widen = FALSE;
9132                                 }
9133                                 goto call_end;
9134                         }
9135
9136                         /* Inlining */
9137                         if ((cfg->opt & MONO_OPT_INLINE) &&
9138                                 (!virtual || !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) || MONO_METHOD_IS_FINAL (cmethod)) &&
9139                             mono_method_check_inlining (cfg, cmethod)) {
9140                                 int costs;
9141                                 gboolean always = FALSE;
9142
9143                                 if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
9144                                         (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
9145                                         /* Prevent inlining of methods that call wrappers */
9146                                         INLINE_FAILURE ("wrapper call");
9147                                         cmethod = mono_marshal_get_native_wrapper (cmethod, TRUE, FALSE);
9148                                         always = TRUE;
9149                                 }
9150
9151                                 costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, always);
9152                                 if (costs) {
9153                                         cfg->real_offset += 5;
9154
9155                                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9156                                                 /* *sp is already set by inline_method */
9157                                                 sp++;
9158                                                 push_res = FALSE;
9159                                         }
9160
9161                                         inline_costs += costs;
9162
9163                                         goto call_end;
9164                                 }
9165                         }
9166
9167                         /* Tail recursion elimination */
9168                         if ((cfg->opt & MONO_OPT_TAILC) && call_opcode == CEE_CALL && cmethod == method && ip [5] == CEE_RET && !vtable_arg) {
9169                                 gboolean has_vtargs = FALSE;
9170                                 int i;
9171
9172                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
9173                                 INLINE_FAILURE ("tail call");
9174
9175                                 /* keep it simple */
9176                                 for (i =  fsig->param_count - 1; i >= 0; i--) {
9177                                         if (MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->params [i])) 
9178                                                 has_vtargs = TRUE;
9179                                 }
9180
9181                                 if (!has_vtargs) {
9182                                         for (i = 0; i < n; ++i)
9183                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
9184                                         MONO_INST_NEW (cfg, ins, OP_BR);
9185                                         MONO_ADD_INS (cfg->cbb, ins);
9186                                         tblock = start_bblock->out_bb [0];
9187                                         link_bblock (cfg, cfg->cbb, tblock);
9188                                         ins->inst_target_bb = tblock;
9189                                         start_new_bblock = 1;
9190
9191                                         /* skip the CEE_RET, too */
9192                                         if (ip_in_bb (cfg, cfg->cbb, ip + 5))
9193                                                 skip_ret = TRUE;
9194                                         push_res = FALSE;
9195                                         goto call_end;
9196                                 }
9197                         }
9198
9199                         inline_costs += 10 * num_calls++;
9200
9201                         /*
9202                          * Making generic calls out of gsharedvt methods.
9203                          * This needs to be used for all generic calls, not just ones with a gsharedvt signature, to avoid
9204                          * patching gshared method addresses into a gsharedvt method.
9205                          */
9206                         if (cfg->gsharedvt && (mini_is_gsharedvt_signature (fsig) || cmethod->is_inflated || cmethod->klass->generic_class) &&
9207                                 !(cmethod->klass->rank && cmethod->klass->byval_arg.type != MONO_TYPE_SZARRAY)) {
9208                                 MonoRgctxInfoType info_type;
9209
9210                                 if (virtual) {
9211                                         //if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)
9212                                                 //GSHAREDVT_FAILURE (*ip);
9213                                         // disable for possible remoting calls
9214                                         if (fsig->hasthis && (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class))
9215                                                 GSHAREDVT_FAILURE (*ip);
9216                                         if (fsig->generic_param_count) {
9217                                                 /* virtual generic call */
9218                                                 g_assert (!imt_arg);
9219                                                 /* Same as the virtual generic case above */
9220                                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9221                                                                                                                  cmethod, MONO_RGCTX_INFO_METHOD);
9222                                                 /* This is not needed, as the trampoline code will pass one, and it might be passed in the same reg as the imt arg */
9223                                                 vtable_arg = NULL;
9224                                         } else if ((cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) && !imt_arg) {
9225                                                 /* This can happen when we call a fully instantiated iface method */
9226                                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9227                                                                                                                  cmethod, MONO_RGCTX_INFO_METHOD);
9228                                                 vtable_arg = NULL;
9229                                         }
9230                                 }
9231
9232                                 if ((cmethod->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (cmethod->name, "Invoke")))
9233                                         keep_this_alive = sp [0];
9234
9235                                 if (virtual && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))
9236                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
9237                                 else
9238                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE;
9239                                 addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, info_type);
9240
9241                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
9242                                 goto call_end;
9243                         }
9244
9245                         /* Generic sharing */
9246
9247                         /*
9248                          * Use this if the callee is gsharedvt sharable too, since
9249                          * at runtime we might find an instantiation so the call cannot
9250                          * be patched (the 'no_patch' code path in mini-trampolines.c).
9251                          */
9252                         if (context_used && !imt_arg && !array_rank && !delegate_invoke &&
9253                                 (!mono_method_is_generic_sharable_full (cmethod, TRUE, FALSE, FALSE) ||
9254                                  !mono_class_generic_sharing_enabled (cmethod->klass)) &&
9255                                 (!virtual || MONO_METHOD_IS_FINAL (cmethod) ||
9256                                  !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))) {
9257                                 INLINE_FAILURE ("gshared");
9258
9259                                 g_assert (cfg->gshared && cmethod);
9260                                 g_assert (!addr);
9261
9262                                 /*
9263                                  * We are compiling a call to a
9264                                  * generic method from shared code,
9265                                  * which means that we have to look up
9266                                  * the method in the rgctx and do an
9267                                  * indirect call.
9268                                  */
9269                                 if (fsig->hasthis)
9270                                         MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
9271
9272                                 addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
9273                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
9274                                 goto call_end;
9275                         }
9276
9277                         /* Direct calls to icalls */
9278                         if (direct_icall) {
9279                                 MonoMethod *wrapper;
9280                                 int costs;
9281
9282                                 /* Inline the wrapper */
9283                                 wrapper = mono_marshal_get_native_wrapper (cmethod, TRUE, cfg->compile_aot);
9284
9285                                 costs = inline_method (cfg, wrapper, fsig, sp, ip, cfg->real_offset, TRUE);
9286                                 g_assert (costs > 0);
9287                                 cfg->real_offset += 5;
9288
9289                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9290                                         /* *sp is already set by inline_method */
9291                                         sp++;
9292                                         push_res = FALSE;
9293                                 }
9294
9295                                 inline_costs += costs;
9296
9297                                 goto call_end;
9298                         }
9299                                         
9300                         /* Array methods */
9301                         if (array_rank) {
9302                                 MonoInst *addr;
9303
9304                                 if (strcmp (cmethod->name, "Set") == 0) { /* array Set */ 
9305                                         MonoInst *val = sp [fsig->param_count];
9306
9307                                         if (val->type == STACK_OBJ) {
9308                                                 MonoInst *iargs [2];
9309
9310                                                 iargs [0] = sp [0];
9311                                                 iargs [1] = val;
9312                                                 
9313                                                 mono_emit_jit_icall (cfg, mono_helper_stelem_ref_check, iargs);
9314                                         }
9315                                         
9316                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, TRUE);
9317                                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, fsig->params [fsig->param_count - 1], addr->dreg, 0, val->dreg);
9318                                         if (cfg->gen_write_barriers && val->type == STACK_OBJ && !(val->opcode == OP_PCONST && val->inst_c0 == 0))
9319                                                 emit_write_barrier (cfg, addr, val);
9320                                         if (cfg->gen_write_barriers && mini_is_gsharedvt_klass (cmethod->klass))
9321                                                 GSHAREDVT_FAILURE (*ip);
9322                                 } else if (strcmp (cmethod->name, "Get") == 0) { /* array Get */
9323                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
9324
9325                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, addr->dreg, 0);
9326                                 } else if (strcmp (cmethod->name, "Address") == 0) { /* array Address */
9327                                         if (!cmethod->klass->element_class->valuetype && !readonly)
9328                                                 mini_emit_check_array_type (cfg, sp [0], cmethod->klass);
9329                                         CHECK_TYPELOAD (cmethod->klass);
9330                                         
9331                                         readonly = FALSE;
9332                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
9333                                         ins = addr;
9334                                 } else {
9335                                         g_assert_not_reached ();
9336                                 }
9337
9338                                 emit_widen = FALSE;
9339                                 goto call_end;
9340                         }
9341
9342                         ins = mini_redirect_call (cfg, cmethod, fsig, sp, virtual ? sp [0] : NULL);
9343                         if (ins)
9344                                 goto call_end;
9345
9346                         /* Tail prefix / tail call optimization */
9347
9348                         /* FIXME: Enabling TAILC breaks some inlining/stack trace/etc tests */
9349                         /* FIXME: runtime generic context pointer for jumps? */
9350                         /* FIXME: handle this for generic sharing eventually */
9351                         if ((ins_flag & MONO_INST_TAILCALL) &&
9352                                 !vtable_arg && !cfg->gshared && is_supported_tail_call (cfg, method, cmethod, fsig, call_opcode))
9353                                 supported_tail_call = TRUE;
9354
9355                         if (supported_tail_call) {
9356                                 MonoCallInst *call;
9357
9358                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
9359                                 INLINE_FAILURE ("tail call");
9360
9361                                 //printf ("HIT: %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
9362
9363                                 if (ARCH_HAVE_OP_TAIL_CALL) {
9364                                         /* Handle tail calls similarly to normal calls */
9365                                         tail_call = TRUE;
9366                                 } else {
9367                                         emit_instrumentation_call (cfg, mono_profiler_method_leave);
9368
9369                                         MONO_INST_NEW_CALL (cfg, call, OP_JMP);
9370                                         call->tail_call = TRUE;
9371                                         call->method = cmethod;
9372                                         call->signature = mono_method_signature (cmethod);
9373
9374                                         /*
9375                                          * We implement tail calls by storing the actual arguments into the 
9376                                          * argument variables, then emitting a CEE_JMP.
9377                                          */
9378                                         for (i = 0; i < n; ++i) {
9379                                                 /* Prevent argument from being register allocated */
9380                                                 arg_array [i]->flags |= MONO_INST_VOLATILE;
9381                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
9382                                         }
9383                                         ins = (MonoInst*)call;
9384                                         ins->inst_p0 = cmethod;
9385                                         ins->inst_p1 = arg_array [0];
9386                                         MONO_ADD_INS (cfg->cbb, ins);
9387                                         link_bblock (cfg, cfg->cbb, end_bblock);
9388                                         start_new_bblock = 1;
9389
9390                                         // FIXME: Eliminate unreachable epilogs
9391
9392                                         /*
9393                                          * OP_TAILCALL has no return value, so skip the CEE_RET if it is
9394                                          * only reachable from this call.
9395                                          */
9396                                         GET_BBLOCK (cfg, tblock, ip + 5);
9397                                         if (tblock == cfg->cbb || tblock->in_count == 0)
9398                                                 skip_ret = TRUE;
9399                                         push_res = FALSE;
9400
9401                                         goto call_end;
9402                                 }
9403                         }
9404
9405                         /* 
9406                          * Synchronized wrappers.
9407                          * Its hard to determine where to replace a method with its synchronized
9408                          * wrapper without causing an infinite recursion. The current solution is
9409                          * to add the synchronized wrapper in the trampolines, and to
9410                          * change the called method to a dummy wrapper, and resolve that wrapper
9411                          * to the real method in mono_jit_compile_method ().
9412                          */
9413                         if (cfg->method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
9414                                 MonoMethod *orig = mono_marshal_method_from_wrapper (cfg->method);
9415                                 if (cmethod == orig || (cmethod->is_inflated && mono_method_get_declaring_generic_method (cmethod) == orig))
9416                                         cmethod = mono_marshal_get_synchronized_inner_wrapper (cmethod);
9417                         }
9418
9419                         /* Common call */
9420                         INLINE_FAILURE ("call");
9421                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, tail_call, sp, virtual ? sp [0] : NULL,
9422                                                                                           imt_arg, vtable_arg);
9423
9424                         if (tail_call) {
9425                                 link_bblock (cfg, cfg->cbb, end_bblock);
9426                                 start_new_bblock = 1;
9427
9428                                 // FIXME: Eliminate unreachable epilogs
9429
9430                                 /*
9431                                  * OP_TAILCALL has no return value, so skip the CEE_RET if it is
9432                                  * only reachable from this call.
9433                                  */
9434                                 GET_BBLOCK (cfg, tblock, ip + 5);
9435                                 if (tblock == cfg->cbb || tblock->in_count == 0)
9436                                         skip_ret = TRUE;
9437                                 push_res = FALSE;
9438                         }
9439
9440                         call_end:
9441
9442                         /* End of call, INS should contain the result of the call, if any */
9443
9444                         if (push_res && !MONO_TYPE_IS_VOID (fsig->ret)) {
9445                                 g_assert (ins);
9446                                 if (emit_widen)
9447                                         *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
9448                                 else
9449                                         *sp++ = ins;
9450                         }
9451
9452                         if (keep_this_alive) {
9453                                 MonoInst *dummy_use;
9454
9455                                 /* See mono_emit_method_call_full () */
9456                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, keep_this_alive);
9457                         }
9458
9459                         CHECK_CFG_EXCEPTION;
9460
9461                         ip += 5;
9462                         if (skip_ret) {
9463                                 g_assert (*ip == CEE_RET);
9464                                 ip += 1;
9465                         }
9466                         ins_flag = 0;
9467                         constrained_class = NULL;
9468                         if (need_seq_point)
9469                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
9470                         break;
9471                 }
9472                 case CEE_RET:
9473                         if (cfg->method != method) {
9474                                 /* return from inlined method */
9475                                 /* 
9476                                  * If in_count == 0, that means the ret is unreachable due to
9477                                  * being preceeded by a throw. In that case, inline_method () will
9478                                  * handle setting the return value 
9479                                  * (test case: test_0_inline_throw ()).
9480                                  */
9481                                 if (return_var && cfg->cbb->in_count) {
9482                                         MonoType *ret_type = mono_method_signature (method)->ret;
9483
9484                                         MonoInst *store;
9485                                         CHECK_STACK (1);
9486                                         --sp;
9487
9488                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
9489                                                 UNVERIFIED;
9490
9491                                         //g_assert (returnvar != -1);
9492                                         EMIT_NEW_TEMPSTORE (cfg, store, return_var->inst_c0, *sp);
9493                                         cfg->ret_var_set = TRUE;
9494                                 } 
9495                         } else {
9496                                 emit_instrumentation_call (cfg, mono_profiler_method_leave);
9497
9498                                 if (cfg->lmf_var && cfg->cbb->in_count)
9499                                         emit_pop_lmf (cfg);
9500
9501                                 if (cfg->ret) {
9502                                         MonoType *ret_type = mini_get_underlying_type (mono_method_signature (method)->ret);
9503
9504                                         if (seq_points && !sym_seq_points) {
9505                                                 /* 
9506                                                  * Place a seq point here too even through the IL stack is not
9507                                                  * empty, so a step over on
9508                                                  * call <FOO>
9509                                                  * ret
9510                                                  * will work correctly.
9511                                                  */
9512                                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, TRUE);
9513                                                 MONO_ADD_INS (cfg->cbb, ins);
9514                                         }
9515
9516                                         g_assert (!return_var);
9517                                         CHECK_STACK (1);
9518                                         --sp;
9519
9520                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
9521                                                 UNVERIFIED;
9522
9523                                         if (mini_type_to_stind (cfg, ret_type) == CEE_STOBJ) {
9524                                                 MonoInst *ret_addr;
9525
9526                                                 if (!cfg->vret_addr) {
9527                                                         MonoInst *ins;
9528
9529                                                         EMIT_NEW_VARSTORE (cfg, ins, cfg->ret, ret_type, (*sp));
9530                                                 } else {
9531                                                         EMIT_NEW_RETLOADA (cfg, ret_addr);
9532
9533                                                         EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STOREV_MEMBASE, ret_addr->dreg, 0, (*sp)->dreg);
9534                                                         ins->klass = mono_class_from_mono_type (ret_type);
9535                                                 }
9536                                         } else {
9537 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
9538                                                 if (COMPILE_SOFT_FLOAT (cfg) && !ret_type->byref && ret_type->type == MONO_TYPE_R4) {
9539                                                         MonoInst *iargs [1];
9540                                                         MonoInst *conv;
9541
9542                                                         iargs [0] = *sp;
9543                                                         conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
9544                                                         mono_arch_emit_setret (cfg, method, conv);
9545                                                 } else {
9546                                                         mono_arch_emit_setret (cfg, method, *sp);
9547                                                 }
9548 #else
9549                                                 mono_arch_emit_setret (cfg, method, *sp);
9550 #endif
9551                                         }
9552                                 }
9553                         }
9554                         if (sp != stack_start)
9555                                 UNVERIFIED;
9556                         MONO_INST_NEW (cfg, ins, OP_BR);
9557                         ip++;
9558                         ins->inst_target_bb = end_bblock;
9559                         MONO_ADD_INS (cfg->cbb, ins);
9560                         link_bblock (cfg, cfg->cbb, end_bblock);
9561                         start_new_bblock = 1;
9562                         break;
9563                 case CEE_BR_S:
9564                         CHECK_OPSIZE (2);
9565                         MONO_INST_NEW (cfg, ins, OP_BR);
9566                         ip++;
9567                         target = ip + 1 + (signed char)(*ip);
9568                         ++ip;
9569                         GET_BBLOCK (cfg, tblock, target);
9570                         link_bblock (cfg, cfg->cbb, tblock);
9571                         ins->inst_target_bb = tblock;
9572                         if (sp != stack_start) {
9573                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9574                                 sp = stack_start;
9575                                 CHECK_UNVERIFIABLE (cfg);
9576                         }
9577                         MONO_ADD_INS (cfg->cbb, ins);
9578                         start_new_bblock = 1;
9579                         inline_costs += BRANCH_COST;
9580                         break;
9581                 case CEE_BEQ_S:
9582                 case CEE_BGE_S:
9583                 case CEE_BGT_S:
9584                 case CEE_BLE_S:
9585                 case CEE_BLT_S:
9586                 case CEE_BNE_UN_S:
9587                 case CEE_BGE_UN_S:
9588                 case CEE_BGT_UN_S:
9589                 case CEE_BLE_UN_S:
9590                 case CEE_BLT_UN_S:
9591                         CHECK_OPSIZE (2);
9592                         CHECK_STACK (2);
9593                         MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
9594                         ip++;
9595                         target = ip + 1 + *(signed char*)ip;
9596                         ip++;
9597
9598                         ADD_BINCOND (NULL);
9599
9600                         sp = stack_start;
9601                         inline_costs += BRANCH_COST;
9602                         break;
9603                 case CEE_BR:
9604                         CHECK_OPSIZE (5);
9605                         MONO_INST_NEW (cfg, ins, OP_BR);
9606                         ip++;
9607
9608                         target = ip + 4 + (gint32)read32(ip);
9609                         ip += 4;
9610                         GET_BBLOCK (cfg, tblock, target);
9611                         link_bblock (cfg, cfg->cbb, tblock);
9612                         ins->inst_target_bb = tblock;
9613                         if (sp != stack_start) {
9614                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9615                                 sp = stack_start;
9616                                 CHECK_UNVERIFIABLE (cfg);
9617                         }
9618
9619                         MONO_ADD_INS (cfg->cbb, ins);
9620
9621                         start_new_bblock = 1;
9622                         inline_costs += BRANCH_COST;
9623                         break;
9624                 case CEE_BRFALSE_S:
9625                 case CEE_BRTRUE_S:
9626                 case CEE_BRFALSE:
9627                 case CEE_BRTRUE: {
9628                         MonoInst *cmp;
9629                         gboolean is_short = ((*ip) == CEE_BRFALSE_S) || ((*ip) == CEE_BRTRUE_S);
9630                         gboolean is_true = ((*ip) == CEE_BRTRUE_S) || ((*ip) == CEE_BRTRUE);
9631                         guint32 opsize = is_short ? 1 : 4;
9632
9633                         CHECK_OPSIZE (opsize);
9634                         CHECK_STACK (1);
9635                         if (sp [-1]->type == STACK_VTYPE || sp [-1]->type == STACK_R8)
9636                                 UNVERIFIED;
9637                         ip ++;
9638                         target = ip + opsize + (is_short ? *(signed char*)ip : (gint32)read32(ip));
9639                         ip += opsize;
9640
9641                         sp--;
9642
9643                         GET_BBLOCK (cfg, tblock, target);
9644                         link_bblock (cfg, cfg->cbb, tblock);
9645                         GET_BBLOCK (cfg, tblock, ip);
9646                         link_bblock (cfg, cfg->cbb, tblock);
9647
9648                         if (sp != stack_start) {
9649                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9650                                 CHECK_UNVERIFIABLE (cfg);
9651                         }
9652
9653                         MONO_INST_NEW(cfg, cmp, OP_ICOMPARE_IMM);
9654                         cmp->sreg1 = sp [0]->dreg;
9655                         type_from_op (cfg, cmp, sp [0], NULL);
9656                         CHECK_TYPE (cmp);
9657
9658 #if SIZEOF_REGISTER == 4
9659                         if (cmp->opcode == OP_LCOMPARE_IMM) {
9660                                 /* Convert it to OP_LCOMPARE */
9661                                 MONO_INST_NEW (cfg, ins, OP_I8CONST);
9662                                 ins->type = STACK_I8;
9663                                 ins->dreg = alloc_dreg (cfg, STACK_I8);
9664                                 ins->inst_l = 0;
9665                                 MONO_ADD_INS (cfg->cbb, ins);
9666                                 cmp->opcode = OP_LCOMPARE;
9667                                 cmp->sreg2 = ins->dreg;
9668                         }
9669 #endif
9670                         MONO_ADD_INS (cfg->cbb, cmp);
9671
9672                         MONO_INST_NEW (cfg, ins, is_true ? CEE_BNE_UN : CEE_BEQ);
9673                         type_from_op (cfg, ins, sp [0], NULL);
9674                         MONO_ADD_INS (cfg->cbb, ins);
9675                         ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);
9676                         GET_BBLOCK (cfg, tblock, target);
9677                         ins->inst_true_bb = tblock;
9678                         GET_BBLOCK (cfg, tblock, ip);
9679                         ins->inst_false_bb = tblock;
9680                         start_new_bblock = 2;
9681
9682                         sp = stack_start;
9683                         inline_costs += BRANCH_COST;
9684                         break;
9685                 }
9686                 case CEE_BEQ:
9687                 case CEE_BGE:
9688                 case CEE_BGT:
9689                 case CEE_BLE:
9690                 case CEE_BLT:
9691                 case CEE_BNE_UN:
9692                 case CEE_BGE_UN:
9693                 case CEE_BGT_UN:
9694                 case CEE_BLE_UN:
9695                 case CEE_BLT_UN:
9696                         CHECK_OPSIZE (5);
9697                         CHECK_STACK (2);
9698                         MONO_INST_NEW (cfg, ins, *ip);
9699                         ip++;
9700                         target = ip + 4 + (gint32)read32(ip);
9701                         ip += 4;
9702
9703                         ADD_BINCOND (NULL);
9704
9705                         sp = stack_start;
9706                         inline_costs += BRANCH_COST;
9707                         break;
9708                 case CEE_SWITCH: {
9709                         MonoInst *src1;
9710                         MonoBasicBlock **targets;
9711                         MonoBasicBlock *default_bblock;
9712                         MonoJumpInfoBBTable *table;
9713                         int offset_reg = alloc_preg (cfg);
9714                         int target_reg = alloc_preg (cfg);
9715                         int table_reg = alloc_preg (cfg);
9716                         int sum_reg = alloc_preg (cfg);
9717                         gboolean use_op_switch;
9718
9719                         CHECK_OPSIZE (5);
9720                         CHECK_STACK (1);
9721                         n = read32 (ip + 1);
9722                         --sp;
9723                         src1 = sp [0];
9724                         if ((src1->type != STACK_I4) && (src1->type != STACK_PTR)) 
9725                                 UNVERIFIED;
9726
9727                         ip += 5;
9728                         CHECK_OPSIZE (n * sizeof (guint32));
9729                         target = ip + n * sizeof (guint32);
9730
9731                         GET_BBLOCK (cfg, default_bblock, target);
9732                         default_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
9733
9734                         targets = mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * n);
9735                         for (i = 0; i < n; ++i) {
9736                                 GET_BBLOCK (cfg, tblock, target + (gint32)read32(ip));
9737                                 targets [i] = tblock;
9738                                 targets [i]->flags |= BB_INDIRECT_JUMP_TARGET;
9739                                 ip += 4;
9740                         }
9741
9742                         if (sp != stack_start) {
9743                                 /* 
9744                                  * Link the current bb with the targets as well, so handle_stack_args
9745                                  * will set their in_stack correctly.
9746                                  */
9747                                 link_bblock (cfg, cfg->cbb, default_bblock);
9748                                 for (i = 0; i < n; ++i)
9749                                         link_bblock (cfg, cfg->cbb, targets [i]);
9750
9751                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9752                                 sp = stack_start;
9753                                 CHECK_UNVERIFIABLE (cfg);
9754
9755                                 /* Undo the links */
9756                                 mono_unlink_bblock (cfg, cfg->cbb, default_bblock);
9757                                 for (i = 0; i < n; ++i)
9758                                         mono_unlink_bblock (cfg, cfg->cbb, targets [i]);
9759                         }
9760
9761                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, src1->dreg, n);
9762                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBGE_UN, default_bblock);
9763
9764                         for (i = 0; i < n; ++i)
9765                                 link_bblock (cfg, cfg->cbb, targets [i]);
9766
9767                         table = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfoBBTable));
9768                         table->table = targets;
9769                         table->table_size = n;
9770
9771                         use_op_switch = FALSE;
9772 #ifdef TARGET_ARM
9773                         /* ARM implements SWITCH statements differently */
9774                         /* FIXME: Make it use the generic implementation */
9775                         if (!cfg->compile_aot)
9776                                 use_op_switch = TRUE;
9777 #endif
9778
9779                         if (COMPILE_LLVM (cfg))
9780                                 use_op_switch = TRUE;
9781
9782                         cfg->cbb->has_jump_table = 1;
9783
9784                         if (use_op_switch) {
9785                                 MONO_INST_NEW (cfg, ins, OP_SWITCH);
9786                                 ins->sreg1 = src1->dreg;
9787                                 ins->inst_p0 = table;
9788                                 ins->inst_many_bb = targets;
9789                                 ins->klass = GUINT_TO_POINTER (n);
9790                                 MONO_ADD_INS (cfg->cbb, ins);
9791                         } else {
9792                                 if (sizeof (gpointer) == 8)
9793                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 3);
9794                                 else
9795                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 2);
9796
9797 #if SIZEOF_REGISTER == 8
9798                                 /* The upper word might not be zero, and we add it to a 64 bit address later */
9799                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, offset_reg, offset_reg);
9800 #endif
9801
9802                                 if (cfg->compile_aot) {
9803                                         MONO_EMIT_NEW_AOTCONST (cfg, table_reg, table, MONO_PATCH_INFO_SWITCH);
9804                                 } else {
9805                                         MONO_INST_NEW (cfg, ins, OP_JUMP_TABLE);
9806                                         ins->inst_c1 = MONO_PATCH_INFO_SWITCH;
9807                                         ins->inst_p0 = table;
9808                                         ins->dreg = table_reg;
9809                                         MONO_ADD_INS (cfg->cbb, ins);
9810                                 }
9811
9812                                 /* FIXME: Use load_memindex */
9813                                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, table_reg, offset_reg);
9814                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, target_reg, sum_reg, 0);
9815                                 MONO_EMIT_NEW_UNALU (cfg, OP_BR_REG, -1, target_reg);
9816                         }
9817                         start_new_bblock = 1;
9818                         inline_costs += (BRANCH_COST * 2);
9819                         break;
9820                 }
9821                 case CEE_LDIND_I1:
9822                 case CEE_LDIND_U1:
9823                 case CEE_LDIND_I2:
9824                 case CEE_LDIND_U2:
9825                 case CEE_LDIND_I4:
9826                 case CEE_LDIND_U4:
9827                 case CEE_LDIND_I8:
9828                 case CEE_LDIND_I:
9829                 case CEE_LDIND_R4:
9830                 case CEE_LDIND_R8:
9831                 case CEE_LDIND_REF:
9832                         CHECK_STACK (1);
9833                         --sp;
9834
9835                         switch (*ip) {
9836                         case CEE_LDIND_R4:
9837                         case CEE_LDIND_R8:
9838                                 dreg = alloc_freg (cfg);
9839                                 break;
9840                         case CEE_LDIND_I8:
9841                                 dreg = alloc_lreg (cfg);
9842                                 break;
9843                         case CEE_LDIND_REF:
9844                                 dreg = alloc_ireg_ref (cfg);
9845                                 break;
9846                         default:
9847                                 dreg = alloc_preg (cfg);
9848                         }
9849
9850                         NEW_LOAD_MEMBASE (cfg, ins, ldind_to_load_membase (*ip), dreg, sp [0]->dreg, 0);
9851                         ins->type = ldind_type [*ip - CEE_LDIND_I1];
9852                         if (*ip == CEE_LDIND_R4)
9853                                 ins->type = cfg->r4_stack_type;
9854                         ins->flags |= ins_flag;
9855                         MONO_ADD_INS (cfg->cbb, ins);
9856                         *sp++ = ins;
9857                         if (ins_flag & MONO_INST_VOLATILE) {
9858                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
9859                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
9860                         }
9861                         ins_flag = 0;
9862                         ++ip;
9863                         break;
9864                 case CEE_STIND_REF:
9865                 case CEE_STIND_I1:
9866                 case CEE_STIND_I2:
9867                 case CEE_STIND_I4:
9868                 case CEE_STIND_I8:
9869                 case CEE_STIND_R4:
9870                 case CEE_STIND_R8:
9871                 case CEE_STIND_I:
9872                         CHECK_STACK (2);
9873                         sp -= 2;
9874
9875                         if (ins_flag & MONO_INST_VOLATILE) {
9876                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
9877                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
9878                         }
9879
9880                         NEW_STORE_MEMBASE (cfg, ins, stind_to_store_membase (*ip), sp [0]->dreg, 0, sp [1]->dreg);
9881                         ins->flags |= ins_flag;
9882                         ins_flag = 0;
9883
9884                         MONO_ADD_INS (cfg->cbb, ins);
9885
9886                         if (cfg->gen_write_barriers && *ip == CEE_STIND_REF && method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER && !((sp [1]->opcode == OP_PCONST) && (sp [1]->inst_p0 == 0)))
9887                                 emit_write_barrier (cfg, sp [0], sp [1]);
9888
9889                         inline_costs += 1;
9890                         ++ip;
9891                         break;
9892
9893                 case CEE_MUL:
9894                         CHECK_STACK (2);
9895
9896                         MONO_INST_NEW (cfg, ins, (*ip));
9897                         sp -= 2;
9898                         ins->sreg1 = sp [0]->dreg;
9899                         ins->sreg2 = sp [1]->dreg;
9900                         type_from_op (cfg, ins, sp [0], sp [1]);
9901                         CHECK_TYPE (ins);
9902                         ins->dreg = alloc_dreg ((cfg), (ins)->type);
9903
9904                         /* Use the immediate opcodes if possible */
9905                         if ((sp [1]->opcode == OP_ICONST) && mono_arch_is_inst_imm (sp [1]->inst_c0)) {
9906                                 int imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
9907                                 if (imm_opcode != -1) {
9908                                         ins->opcode = imm_opcode;
9909                                         ins->inst_p1 = (gpointer)(gssize)(sp [1]->inst_c0);
9910                                         ins->sreg2 = -1;
9911
9912                                         NULLIFY_INS (sp [1]);
9913                                 }
9914                         }
9915
9916                         MONO_ADD_INS ((cfg)->cbb, (ins));
9917
9918                         *sp++ = mono_decompose_opcode (cfg, ins);
9919                         ip++;
9920                         break;
9921                 case CEE_ADD:
9922                 case CEE_SUB:
9923                 case CEE_DIV:
9924                 case CEE_DIV_UN:
9925                 case CEE_REM:
9926                 case CEE_REM_UN:
9927                 case CEE_AND:
9928                 case CEE_OR:
9929                 case CEE_XOR:
9930                 case CEE_SHL:
9931                 case CEE_SHR:
9932                 case CEE_SHR_UN:
9933                         CHECK_STACK (2);
9934
9935                         MONO_INST_NEW (cfg, ins, (*ip));
9936                         sp -= 2;
9937                         ins->sreg1 = sp [0]->dreg;
9938                         ins->sreg2 = sp [1]->dreg;
9939                         type_from_op (cfg, ins, sp [0], sp [1]);
9940                         CHECK_TYPE (ins);
9941                         add_widen_op (cfg, ins, &sp [0], &sp [1]);
9942                         ins->dreg = alloc_dreg ((cfg), (ins)->type);
9943
9944                         /* FIXME: Pass opcode to is_inst_imm */
9945
9946                         /* Use the immediate opcodes if possible */
9947                         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)) {
9948                                 int imm_opcode;
9949
9950                                 imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
9951 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
9952                                 /* Keep emulated opcodes which are optimized away later */
9953                                 if ((ins->opcode == OP_IREM_UN || ins->opcode == OP_IDIV_UN_IMM) && (cfg->opt & (MONO_OPT_CONSPROP | MONO_OPT_COPYPROP)) && sp [1]->opcode == OP_ICONST && mono_is_power_of_two (sp [1]->inst_c0) >= 0) {
9954                                         imm_opcode = mono_op_to_op_imm (ins->opcode);
9955                                 }
9956 #endif
9957                                 if (imm_opcode != -1) {
9958                                         ins->opcode = imm_opcode;
9959                                         if (sp [1]->opcode == OP_I8CONST) {
9960 #if SIZEOF_REGISTER == 8
9961                                                 ins->inst_imm = sp [1]->inst_l;
9962 #else
9963                                                 ins->inst_ls_word = sp [1]->inst_ls_word;
9964                                                 ins->inst_ms_word = sp [1]->inst_ms_word;
9965 #endif
9966                                         }
9967                                         else
9968                                                 ins->inst_imm = (gssize)(sp [1]->inst_c0);
9969                                         ins->sreg2 = -1;
9970
9971                                         /* Might be followed by an instruction added by add_widen_op */
9972                                         if (sp [1]->next == NULL)
9973                                                 NULLIFY_INS (sp [1]);
9974                                 }
9975                         }
9976                         MONO_ADD_INS ((cfg)->cbb, (ins));
9977
9978                         *sp++ = mono_decompose_opcode (cfg, ins);
9979                         ip++;
9980                         break;
9981                 case CEE_NEG:
9982                 case CEE_NOT:
9983                 case CEE_CONV_I1:
9984                 case CEE_CONV_I2:
9985                 case CEE_CONV_I4:
9986                 case CEE_CONV_R4:
9987                 case CEE_CONV_R8:
9988                 case CEE_CONV_U4:
9989                 case CEE_CONV_I8:
9990                 case CEE_CONV_U8:
9991                 case CEE_CONV_OVF_I8:
9992                 case CEE_CONV_OVF_U8:
9993                 case CEE_CONV_R_UN:
9994                         CHECK_STACK (1);
9995
9996                         /* Special case this earlier so we have long constants in the IR */
9997                         if ((((*ip) == CEE_CONV_I8) || ((*ip) == CEE_CONV_U8)) && (sp [-1]->opcode == OP_ICONST)) {
9998                                 int data = sp [-1]->inst_c0;
9999                                 sp [-1]->opcode = OP_I8CONST;
10000                                 sp [-1]->type = STACK_I8;
10001 #if SIZEOF_REGISTER == 8
10002                                 if ((*ip) == CEE_CONV_U8)
10003                                         sp [-1]->inst_c0 = (guint32)data;
10004                                 else
10005                                         sp [-1]->inst_c0 = data;
10006 #else
10007                                 sp [-1]->inst_ls_word = data;
10008                                 if ((*ip) == CEE_CONV_U8)
10009                                         sp [-1]->inst_ms_word = 0;
10010                                 else
10011                                         sp [-1]->inst_ms_word = (data < 0) ? -1 : 0;
10012 #endif
10013                                 sp [-1]->dreg = alloc_dreg (cfg, STACK_I8);
10014                         }
10015                         else {
10016                                 ADD_UNOP (*ip);
10017                         }
10018                         ip++;
10019                         break;
10020                 case CEE_CONV_OVF_I4:
10021                 case CEE_CONV_OVF_I1:
10022                 case CEE_CONV_OVF_I2:
10023                 case CEE_CONV_OVF_I:
10024                 case CEE_CONV_OVF_U:
10025                         CHECK_STACK (1);
10026
10027                         if (sp [-1]->type == STACK_R8 || sp [-1]->type == STACK_R4) {
10028                                 ADD_UNOP (CEE_CONV_OVF_I8);
10029                                 ADD_UNOP (*ip);
10030                         } else {
10031                                 ADD_UNOP (*ip);
10032                         }
10033                         ip++;
10034                         break;
10035                 case CEE_CONV_OVF_U1:
10036                 case CEE_CONV_OVF_U2:
10037                 case CEE_CONV_OVF_U4:
10038                         CHECK_STACK (1);
10039
10040                         if (sp [-1]->type == STACK_R8 || sp [-1]->type == STACK_R4) {
10041                                 ADD_UNOP (CEE_CONV_OVF_U8);
10042                                 ADD_UNOP (*ip);
10043                         } else {
10044                                 ADD_UNOP (*ip);
10045                         }
10046                         ip++;
10047                         break;
10048                 case CEE_CONV_OVF_I1_UN:
10049                 case CEE_CONV_OVF_I2_UN:
10050                 case CEE_CONV_OVF_I4_UN:
10051                 case CEE_CONV_OVF_I8_UN:
10052                 case CEE_CONV_OVF_U1_UN:
10053                 case CEE_CONV_OVF_U2_UN:
10054                 case CEE_CONV_OVF_U4_UN:
10055                 case CEE_CONV_OVF_U8_UN:
10056                 case CEE_CONV_OVF_I_UN:
10057                 case CEE_CONV_OVF_U_UN:
10058                 case CEE_CONV_U2:
10059                 case CEE_CONV_U1:
10060                 case CEE_CONV_I:
10061                 case CEE_CONV_U:
10062                         CHECK_STACK (1);
10063                         ADD_UNOP (*ip);
10064                         CHECK_CFG_EXCEPTION;
10065                         ip++;
10066                         break;
10067                 case CEE_ADD_OVF:
10068                 case CEE_ADD_OVF_UN:
10069                 case CEE_MUL_OVF:
10070                 case CEE_MUL_OVF_UN:
10071                 case CEE_SUB_OVF:
10072                 case CEE_SUB_OVF_UN:
10073                         CHECK_STACK (2);
10074                         ADD_BINOP (*ip);
10075                         ip++;
10076                         break;
10077                 case CEE_CPOBJ:
10078                         GSHAREDVT_FAILURE (*ip);
10079                         CHECK_OPSIZE (5);
10080                         CHECK_STACK (2);
10081                         token = read32 (ip + 1);
10082                         klass = mini_get_class (method, token, generic_context);
10083                         CHECK_TYPELOAD (klass);
10084                         sp -= 2;
10085                         if (generic_class_is_reference_type (cfg, klass)) {
10086                                 MonoInst *store, *load;
10087                                 int dreg = alloc_ireg_ref (cfg);
10088
10089                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, dreg, sp [1]->dreg, 0);
10090                                 load->flags |= ins_flag;
10091                                 MONO_ADD_INS (cfg->cbb, load);
10092
10093                                 NEW_STORE_MEMBASE (cfg, store, OP_STORE_MEMBASE_REG, sp [0]->dreg, 0, dreg);
10094                                 store->flags |= ins_flag;
10095                                 MONO_ADD_INS (cfg->cbb, store);
10096
10097                                 if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER)
10098                                         emit_write_barrier (cfg, sp [0], sp [1]);
10099                         } else {
10100                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
10101                         }
10102                         ins_flag = 0;
10103                         ip += 5;
10104                         break;
10105                 case CEE_LDOBJ: {
10106                         int loc_index = -1;
10107                         int stloc_len = 0;
10108
10109                         CHECK_OPSIZE (5);
10110                         CHECK_STACK (1);
10111                         --sp;
10112                         token = read32 (ip + 1);
10113                         klass = mini_get_class (method, token, generic_context);
10114                         CHECK_TYPELOAD (klass);
10115
10116                         /* Optimize the common ldobj+stloc combination */
10117                         switch (ip [5]) {
10118                         case CEE_STLOC_S:
10119                                 loc_index = ip [6];
10120                                 stloc_len = 2;
10121                                 break;
10122                         case CEE_STLOC_0:
10123                         case CEE_STLOC_1:
10124                         case CEE_STLOC_2:
10125                         case CEE_STLOC_3:
10126                                 loc_index = ip [5] - CEE_STLOC_0;
10127                                 stloc_len = 1;
10128                                 break;
10129                         default:
10130                                 break;
10131                         }
10132
10133                         if ((loc_index != -1) && ip_in_bb (cfg, cfg->cbb, ip + 5)) {
10134                                 CHECK_LOCAL (loc_index);
10135
10136                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
10137                                 ins->dreg = cfg->locals [loc_index]->dreg;
10138                                 ins->flags |= ins_flag;
10139                                 ip += 5;
10140                                 ip += stloc_len;
10141                                 if (ins_flag & MONO_INST_VOLATILE) {
10142                                         /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10143                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10144                                 }
10145                                 ins_flag = 0;
10146                                 break;
10147                         }
10148
10149                         /* Optimize the ldobj+stobj combination */
10150                         /* The reference case ends up being a load+store anyway */
10151                         /* Skip this if the operation is volatile. */
10152                         if (((ip [5] == CEE_STOBJ) && ip_in_bb (cfg, cfg->cbb, ip + 5) && read32 (ip + 6) == token) && !generic_class_is_reference_type (cfg, klass) && !(ins_flag & MONO_INST_VOLATILE)) {
10153                                 CHECK_STACK (1);
10154
10155                                 sp --;
10156
10157                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
10158
10159                                 ip += 5 + 5;
10160                                 ins_flag = 0;
10161                                 break;
10162                         }
10163
10164                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
10165                         ins->flags |= ins_flag;
10166                         *sp++ = ins;
10167
10168                         if (ins_flag & MONO_INST_VOLATILE) {
10169                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10170                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10171                         }
10172
10173                         ip += 5;
10174                         ins_flag = 0;
10175                         inline_costs += 1;
10176                         break;
10177                 }
10178                 case CEE_LDSTR:
10179                         CHECK_STACK_OVF (1);
10180                         CHECK_OPSIZE (5);
10181                         n = read32 (ip + 1);
10182
10183                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
10184                                 EMIT_NEW_PCONST (cfg, ins, mono_method_get_wrapper_data (method, n));
10185                                 ins->type = STACK_OBJ;
10186                                 *sp = ins;
10187                         }
10188                         else if (method->wrapper_type != MONO_WRAPPER_NONE) {
10189                                 MonoInst *iargs [1];
10190                                 char *str = mono_method_get_wrapper_data (method, n);
10191
10192                                 if (cfg->compile_aot)
10193                                         EMIT_NEW_LDSTRLITCONST (cfg, iargs [0], str);
10194                                 else
10195                                         EMIT_NEW_PCONST (cfg, iargs [0], str);
10196                                 *sp = mono_emit_jit_icall (cfg, mono_string_new_wrapper, iargs);
10197                         } else {
10198                                 if (cfg->opt & MONO_OPT_SHARED) {
10199                                         MonoInst *iargs [3];
10200
10201                                         if (cfg->compile_aot) {
10202                                                 cfg->ldstr_list = g_list_prepend (cfg->ldstr_list, GINT_TO_POINTER (n));
10203                                         }
10204                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
10205                                         EMIT_NEW_IMAGECONST (cfg, iargs [1], image);
10206                                         EMIT_NEW_ICONST (cfg, iargs [2], mono_metadata_token_index (n));
10207                                         *sp = mono_emit_jit_icall (cfg, mono_ldstr, iargs);
10208                                         mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
10209                                 } else {
10210                                         if (cfg->cbb->out_of_line) {
10211                                                 MonoInst *iargs [2];
10212
10213                                                 if (image == mono_defaults.corlib) {
10214                                                         /* 
10215                                                          * Avoid relocations in AOT and save some space by using a 
10216                                                          * version of helper_ldstr specialized to mscorlib.
10217                                                          */
10218                                                         EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (n));
10219                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr_mscorlib, iargs);
10220                                                 } else {
10221                                                         /* Avoid creating the string object */
10222                                                         EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
10223                                                         EMIT_NEW_ICONST (cfg, iargs [1], mono_metadata_token_index (n));
10224                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr, iargs);
10225                                                 }
10226                                         } 
10227                                         else
10228                                         if (cfg->compile_aot) {
10229                                                 NEW_LDSTRCONST (cfg, ins, image, n);
10230                                                 *sp = ins;
10231                                                 MONO_ADD_INS (cfg->cbb, ins);
10232                                         } 
10233                                         else {
10234                                                 NEW_PCONST (cfg, ins, NULL);
10235                                                 ins->type = STACK_OBJ;
10236                                                 ins->inst_p0 = mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
10237                                                 if (!ins->inst_p0)
10238                                                         OUT_OF_MEMORY_FAILURE;
10239
10240                                                 *sp = ins;
10241                                                 MONO_ADD_INS (cfg->cbb, ins);
10242                                         }
10243                                 }
10244                         }
10245
10246                         sp++;
10247                         ip += 5;
10248                         break;
10249                 case CEE_NEWOBJ: {
10250                         MonoInst *iargs [2];
10251                         MonoMethodSignature *fsig;
10252                         MonoInst this_ins;
10253                         MonoInst *alloc;
10254                         MonoInst *vtable_arg = NULL;
10255
10256                         CHECK_OPSIZE (5);
10257                         token = read32 (ip + 1);
10258                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
10259                         if (!cmethod || mono_loader_get_last_error ())
10260                                 LOAD_ERROR;
10261                         fsig = mono_method_get_signature_checked (cmethod, image, token, generic_context, &cfg->error);
10262                         CHECK_CFG_ERROR;
10263
10264                         mono_save_token_info (cfg, image, token, cmethod);
10265
10266                         if (!mono_class_init (cmethod->klass))
10267                                 TYPE_LOAD_ERROR (cmethod->klass);
10268
10269                         context_used = mini_method_check_context_used (cfg, cmethod);
10270
10271                         if (mono_security_core_clr_enabled ())
10272                                 ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
10273
10274                         if (cfg->gshared && cmethod && cmethod->klass != method->klass && cmethod->klass->generic_class && mono_method_is_generic_sharable (cmethod, TRUE) && mono_class_needs_cctor_run (cmethod->klass, method)) {
10275                                 emit_class_init (cfg, cmethod->klass);
10276                                 CHECK_TYPELOAD (cmethod->klass);
10277                         }
10278
10279                         /*
10280                         if (cfg->gsharedvt) {
10281                                 if (mini_is_gsharedvt_variable_signature (sig))
10282                                         GSHAREDVT_FAILURE (*ip);
10283                         }
10284                         */
10285
10286                         n = fsig->param_count;
10287                         CHECK_STACK (n);
10288
10289                         /* 
10290                          * Generate smaller code for the common newobj <exception> instruction in
10291                          * argument checking code.
10292                          */
10293                         if (cfg->cbb->out_of_line && cmethod->klass->image == mono_defaults.corlib &&
10294                                 is_exception_class (cmethod->klass) && n <= 2 &&
10295                                 ((n < 1) || (!fsig->params [0]->byref && fsig->params [0]->type == MONO_TYPE_STRING)) && 
10296                                 ((n < 2) || (!fsig->params [1]->byref && fsig->params [1]->type == MONO_TYPE_STRING))) {
10297                                 MonoInst *iargs [3];
10298
10299                                 sp -= n;
10300
10301                                 EMIT_NEW_ICONST (cfg, iargs [0], cmethod->klass->type_token);
10302                                 switch (n) {
10303                                 case 0:
10304                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_0, iargs);
10305                                         break;
10306                                 case 1:
10307                                         iargs [1] = sp [0];
10308                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_1, iargs);
10309                                         break;
10310                                 case 2:
10311                                         iargs [1] = sp [0];
10312                                         iargs [2] = sp [1];
10313                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_2, iargs);
10314                                         break;
10315                                 default:
10316                                         g_assert_not_reached ();
10317                                 }
10318
10319                                 ip += 5;
10320                                 inline_costs += 5;
10321                                 break;
10322                         }
10323
10324                         /* move the args to allow room for 'this' in the first position */
10325                         while (n--) {
10326                                 --sp;
10327                                 sp [1] = sp [0];
10328                         }
10329
10330                         /* check_call_signature () requires sp[0] to be set */
10331                         this_ins.type = STACK_OBJ;
10332                         sp [0] = &this_ins;
10333                         if (check_call_signature (cfg, fsig, sp))
10334                                 UNVERIFIED;
10335
10336                         iargs [0] = NULL;
10337
10338                         if (mini_class_is_system_array (cmethod->klass)) {
10339                                 *sp = emit_get_rgctx_method (cfg, context_used,
10340                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
10341
10342                                 /* Avoid varargs in the common case */
10343                                 if (fsig->param_count == 1)
10344                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_1, sp);
10345                                 else if (fsig->param_count == 2)
10346                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_2, sp);
10347                                 else if (fsig->param_count == 3)
10348                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_3, sp);
10349                                 else if (fsig->param_count == 4)
10350                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_4, sp);
10351                                 else
10352                                         alloc = handle_array_new (cfg, fsig->param_count, sp, ip);
10353                         } else if (cmethod->string_ctor) {
10354                                 g_assert (!context_used);
10355                                 g_assert (!vtable_arg);
10356                                 /* we simply pass a null pointer */
10357                                 EMIT_NEW_PCONST (cfg, *sp, NULL); 
10358                                 /* now call the string ctor */
10359                                 alloc = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, NULL, NULL, NULL);
10360                         } else {
10361                                 if (cmethod->klass->valuetype) {
10362                                         iargs [0] = mono_compile_create_var (cfg, &cmethod->klass->byval_arg, OP_LOCAL);
10363                                         emit_init_rvar (cfg, iargs [0]->dreg, &cmethod->klass->byval_arg);
10364                                         EMIT_NEW_TEMPLOADA (cfg, *sp, iargs [0]->inst_c0);
10365
10366                                         alloc = NULL;
10367
10368                                         /* 
10369                                          * The code generated by mini_emit_virtual_call () expects
10370                                          * iargs [0] to be a boxed instance, but luckily the vcall
10371                                          * will be transformed into a normal call there.
10372                                          */
10373                                 } else if (context_used) {
10374                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, context_used);
10375                                         *sp = alloc;
10376                                 } else {
10377                                         MonoVTable *vtable = NULL;
10378
10379                                         if (!cfg->compile_aot)
10380                                                 vtable = mono_class_vtable (cfg->domain, cmethod->klass);
10381                                         CHECK_TYPELOAD (cmethod->klass);
10382
10383                                         /*
10384                                          * TypeInitializationExceptions thrown from the mono_runtime_class_init
10385                                          * call in mono_jit_runtime_invoke () can abort the finalizer thread.
10386                                          * As a workaround, we call class cctors before allocating objects.
10387                                          */
10388                                         if (mini_field_access_needs_cctor_run (cfg, method, cmethod->klass, vtable) && !(g_slist_find (class_inits, cmethod->klass))) {
10389                                                 emit_class_init (cfg, cmethod->klass);
10390                                                 if (cfg->verbose_level > 2)
10391                                                         printf ("class %s.%s needs init call for ctor\n", cmethod->klass->name_space, cmethod->klass->name);
10392                                                 class_inits = g_slist_prepend (class_inits, cmethod->klass);
10393                                         }
10394
10395                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, 0);
10396                                         *sp = alloc;
10397                                 }
10398                                 CHECK_CFG_EXCEPTION; /*for handle_alloc*/
10399
10400                                 if (alloc)
10401                                         MONO_EMIT_NEW_UNALU (cfg, OP_NOT_NULL, -1, alloc->dreg);
10402
10403                                 /* Now call the actual ctor */
10404                                 handle_ctor_call (cfg, cmethod, fsig, context_used, sp, ip, &inline_costs);
10405                                 CHECK_CFG_EXCEPTION;
10406                         }
10407
10408                         if (alloc == NULL) {
10409                                 /* Valuetype */
10410                                 EMIT_NEW_TEMPLOAD (cfg, ins, iargs [0]->inst_c0);
10411                                 type_to_eval_stack_type (cfg, &ins->klass->byval_arg, ins);
10412                                 *sp++= ins;
10413                         } else {
10414                                 *sp++ = alloc;
10415                         }
10416                         
10417                         ip += 5;
10418                         inline_costs += 5;
10419                         if (!(seq_point_locs && mono_bitset_test_fast (seq_point_locs, ip - header->code)))
10420                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
10421                         break;
10422                 }
10423                 case CEE_CASTCLASS:
10424                         CHECK_STACK (1);
10425                         --sp;
10426                         CHECK_OPSIZE (5);
10427                         token = read32 (ip + 1);
10428                         klass = mini_get_class (method, token, generic_context);
10429                         CHECK_TYPELOAD (klass);
10430                         if (sp [0]->type != STACK_OBJ)
10431                                 UNVERIFIED;
10432
10433                         ins = handle_castclass (cfg, klass, *sp, ip, &inline_costs);
10434                         CHECK_CFG_EXCEPTION;
10435
10436                         *sp ++ = ins;
10437                         ip += 5;
10438                         break;
10439                 case CEE_ISINST: {
10440                         CHECK_STACK (1);
10441                         --sp;
10442                         CHECK_OPSIZE (5);
10443                         token = read32 (ip + 1);
10444                         klass = mini_get_class (method, token, generic_context);
10445                         CHECK_TYPELOAD (klass);
10446                         if (sp [0]->type != STACK_OBJ)
10447                                 UNVERIFIED;
10448  
10449                         context_used = mini_class_check_context_used (cfg, klass);
10450
10451                         if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
10452                                 MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
10453                                 MonoInst *args [3];
10454                                 int idx;
10455
10456                                 /* obj */
10457                                 args [0] = *sp;
10458
10459                                 /* klass */
10460                                 EMIT_NEW_CLASSCONST (cfg, args [1], klass);
10461
10462                                 /* inline cache*/
10463                                 if (cfg->compile_aot) {
10464                                         idx = get_castclass_cache_idx (cfg);
10465                                         EMIT_NEW_AOTCONST (cfg, args [2], MONO_PATCH_INFO_CASTCLASS_CACHE, GINT_TO_POINTER (idx));
10466                                 } else {
10467                                         EMIT_NEW_PCONST (cfg, args [2], mono_domain_alloc0 (cfg->domain, sizeof (gpointer)));
10468                                 }
10469
10470                                 *sp++ = mono_emit_method_call (cfg, mono_isinst, args, NULL);
10471                                 ip += 5;
10472                                 inline_costs += 2;
10473                         } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
10474                                 MonoMethod *mono_isinst;
10475                                 MonoInst *iargs [1];
10476                                 int costs;
10477
10478                                 mono_isinst = mono_marshal_get_isinst (klass); 
10479                                 iargs [0] = sp [0];
10480
10481                                 costs = inline_method (cfg, mono_isinst, mono_method_signature (mono_isinst), 
10482                                                                            iargs, ip, cfg->real_offset, TRUE);
10483                                 CHECK_CFG_EXCEPTION;
10484                                 g_assert (costs > 0);
10485                                 
10486                                 ip += 5;
10487                                 cfg->real_offset += 5;
10488
10489                                 *sp++= iargs [0];
10490
10491                                 inline_costs += costs;
10492                         }
10493                         else {
10494                                 ins = handle_isinst (cfg, klass, *sp, context_used);
10495                                 CHECK_CFG_EXCEPTION;
10496                                 *sp ++ = ins;
10497                                 ip += 5;
10498                         }
10499                         break;
10500                 }
10501                 case CEE_UNBOX_ANY: {
10502                         MonoInst *res, *addr;
10503
10504                         CHECK_STACK (1);
10505                         --sp;
10506                         CHECK_OPSIZE (5);
10507                         token = read32 (ip + 1);
10508                         klass = mini_get_class (method, token, generic_context);
10509                         CHECK_TYPELOAD (klass);
10510
10511                         mono_save_token_info (cfg, image, token, klass);
10512
10513                         context_used = mini_class_check_context_used (cfg, klass);
10514
10515                         if (mini_is_gsharedvt_klass (klass)) {
10516                                 res = handle_unbox_gsharedvt (cfg, klass, *sp);
10517                                 inline_costs += 2;
10518                         } else if (generic_class_is_reference_type (cfg, klass)) {
10519                                 res = handle_castclass (cfg, klass, *sp, ip, &inline_costs);
10520                                 CHECK_CFG_EXCEPTION;
10521                         } else if (mono_class_is_nullable (klass)) {
10522                                 res = handle_unbox_nullable (cfg, *sp, klass, context_used);
10523                         } else {
10524                                 addr = handle_unbox (cfg, klass, sp, context_used);
10525                                 /* LDOBJ */
10526                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
10527                                 res = ins;
10528                                 inline_costs += 2;
10529                         }
10530
10531                         *sp ++ = res;
10532                         ip += 5;
10533                         break;
10534                 }
10535                 case CEE_BOX: {
10536                         MonoInst *val;
10537                         MonoClass *enum_class;
10538                         MonoMethod *has_flag;
10539
10540                         CHECK_STACK (1);
10541                         --sp;
10542                         val = *sp;
10543                         CHECK_OPSIZE (5);
10544                         token = read32 (ip + 1);
10545                         klass = mini_get_class (method, token, generic_context);
10546                         CHECK_TYPELOAD (klass);
10547
10548                         mono_save_token_info (cfg, image, token, klass);
10549
10550                         context_used = mini_class_check_context_used (cfg, klass);
10551
10552                         if (generic_class_is_reference_type (cfg, klass)) {
10553                                 *sp++ = val;
10554                                 ip += 5;
10555                                 break;
10556                         }
10557
10558                         if (klass == mono_defaults.void_class)
10559                                 UNVERIFIED;
10560                         if (target_type_is_incompatible (cfg, &klass->byval_arg, *sp))
10561                                 UNVERIFIED;
10562                         /* frequent check in generic code: box (struct), brtrue */
10563
10564                         /*
10565                          * Look for:
10566                          *
10567                          *   <push int/long ptr>
10568                          *   <push int/long>
10569                          *   box MyFlags
10570                          *   constrained. MyFlags
10571                          *   callvirt instace bool class [mscorlib] System.Enum::HasFlag (class [mscorlib] System.Enum)
10572                          *
10573                          * If we find this sequence and the operand types on box and constrained
10574                          * are equal, we can emit a specialized instruction sequence instead of
10575                          * the very slow HasFlag () call.
10576                          */
10577                         if ((cfg->opt & MONO_OPT_INTRINS) &&
10578                             /* Cheap checks first. */
10579                             ip + 5 + 6 + 5 < end &&
10580                             ip [5] == CEE_PREFIX1 &&
10581                             ip [6] == CEE_CONSTRAINED_ &&
10582                             ip [11] == CEE_CALLVIRT &&
10583                             ip_in_bb (cfg, cfg->cbb, ip + 5 + 6 + 5) &&
10584                             mono_class_is_enum (klass) &&
10585                             (enum_class = mini_get_class (method, read32 (ip + 7), generic_context)) &&
10586                             (has_flag = mini_get_method (cfg, method, read32 (ip + 12), NULL, generic_context)) &&
10587                             has_flag->klass == mono_defaults.enum_class &&
10588                             !strcmp (has_flag->name, "HasFlag") &&
10589                             has_flag->signature->hasthis &&
10590                             has_flag->signature->param_count == 1) {
10591                                 CHECK_TYPELOAD (enum_class);
10592
10593                                 if (enum_class == klass) {
10594                                         MonoInst *enum_this, *enum_flag;
10595
10596                                         ip += 5 + 6 + 5;
10597                                         --sp;
10598
10599                                         enum_this = sp [0];
10600                                         enum_flag = sp [1];
10601
10602                                         *sp++ = handle_enum_has_flag (cfg, klass, enum_this, enum_flag);
10603                                         break;
10604                                 }
10605                         }
10606
10607                         // FIXME: LLVM can't handle the inconsistent bb linking
10608                         if (!mono_class_is_nullable (klass) &&
10609                                 !mini_is_gsharedvt_klass (klass) &&
10610                                 ip + 5 < end && ip_in_bb (cfg, cfg->cbb, ip + 5) &&
10611                                 (ip [5] == CEE_BRTRUE || 
10612                                  ip [5] == CEE_BRTRUE_S ||
10613                                  ip [5] == CEE_BRFALSE ||
10614                                  ip [5] == CEE_BRFALSE_S)) {
10615                                 gboolean is_true = ip [5] == CEE_BRTRUE || ip [5] == CEE_BRTRUE_S;
10616                                 int dreg;
10617                                 MonoBasicBlock *true_bb, *false_bb;
10618
10619                                 ip += 5;
10620
10621                                 if (cfg->verbose_level > 3) {
10622                                         printf ("converting (in B%d: stack: %d) %s", cfg->cbb->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
10623                                         printf ("<box+brtrue opt>\n");
10624                                 }
10625
10626                                 switch (*ip) {
10627                                 case CEE_BRTRUE_S:
10628                                 case CEE_BRFALSE_S:
10629                                         CHECK_OPSIZE (2);
10630                                         ip++;
10631                                         target = ip + 1 + (signed char)(*ip);
10632                                         ip++;
10633                                         break;
10634                                 case CEE_BRTRUE:
10635                                 case CEE_BRFALSE:
10636                                         CHECK_OPSIZE (5);
10637                                         ip++;
10638                                         target = ip + 4 + (gint)(read32 (ip));
10639                                         ip += 4;
10640                                         break;
10641                                 default:
10642                                         g_assert_not_reached ();
10643                                 }
10644
10645                                 /* 
10646                                  * We need to link both bblocks, since it is needed for handling stack
10647                                  * arguments correctly (See test_0_box_brtrue_opt_regress_81102).
10648                                  * Branching to only one of them would lead to inconsistencies, so
10649                                  * generate an ICONST+BRTRUE, the branch opts will get rid of them.
10650                                  */
10651                                 GET_BBLOCK (cfg, true_bb, target);
10652                                 GET_BBLOCK (cfg, false_bb, ip);
10653
10654                                 mono_link_bblock (cfg, cfg->cbb, true_bb);
10655                                 mono_link_bblock (cfg, cfg->cbb, false_bb);
10656
10657                                 if (sp != stack_start) {
10658                                         handle_stack_args (cfg, stack_start, sp - stack_start);
10659                                         sp = stack_start;
10660                                         CHECK_UNVERIFIABLE (cfg);
10661                                 }
10662
10663                                 if (COMPILE_LLVM (cfg)) {
10664                                         dreg = alloc_ireg (cfg);
10665                                         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
10666                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, dreg, is_true ? 0 : 1);
10667
10668                                         MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, OP_IBEQ, true_bb, false_bb);
10669                                 } else {
10670                                         /* The JIT can't eliminate the iconst+compare */
10671                                         MONO_INST_NEW (cfg, ins, OP_BR);
10672                                         ins->inst_target_bb = is_true ? true_bb : false_bb;
10673                                         MONO_ADD_INS (cfg->cbb, ins);
10674                                 }
10675
10676                                 start_new_bblock = 1;
10677                                 break;
10678                         }
10679
10680                         *sp++ = handle_box (cfg, val, klass, context_used);
10681
10682                         CHECK_CFG_EXCEPTION;
10683                         ip += 5;
10684                         inline_costs += 1;
10685                         break;
10686                 }
10687                 case CEE_UNBOX: {
10688                         CHECK_STACK (1);
10689                         --sp;
10690                         CHECK_OPSIZE (5);
10691                         token = read32 (ip + 1);
10692                         klass = mini_get_class (method, token, generic_context);
10693                         CHECK_TYPELOAD (klass);
10694
10695                         mono_save_token_info (cfg, image, token, klass);
10696
10697                         context_used = mini_class_check_context_used (cfg, klass);
10698
10699                         if (mono_class_is_nullable (klass)) {
10700                                 MonoInst *val;
10701
10702                                 val = handle_unbox_nullable (cfg, *sp, klass, context_used);
10703                                 EMIT_NEW_VARLOADA (cfg, ins, get_vreg_to_inst (cfg, val->dreg), &val->klass->byval_arg);
10704
10705                                 *sp++= ins;
10706                         } else {
10707                                 ins = handle_unbox (cfg, klass, sp, context_used);
10708                                 *sp++ = ins;
10709                         }
10710                         ip += 5;
10711                         inline_costs += 2;
10712                         break;
10713                 }
10714                 case CEE_LDFLD:
10715                 case CEE_LDFLDA:
10716                 case CEE_STFLD:
10717                 case CEE_LDSFLD:
10718                 case CEE_LDSFLDA:
10719                 case CEE_STSFLD: {
10720                         MonoClassField *field;
10721 #ifndef DISABLE_REMOTING
10722                         int costs;
10723 #endif
10724                         guint foffset;
10725                         gboolean is_instance;
10726                         int op;
10727                         gpointer addr = NULL;
10728                         gboolean is_special_static;
10729                         MonoType *ftype;
10730                         MonoInst *store_val = NULL;
10731                         MonoInst *thread_ins;
10732
10733                         op = *ip;
10734                         is_instance = (op == CEE_LDFLD || op == CEE_LDFLDA || op == CEE_STFLD);
10735                         if (is_instance) {
10736                                 if (op == CEE_STFLD) {
10737                                         CHECK_STACK (2);
10738                                         sp -= 2;
10739                                         store_val = sp [1];
10740                                 } else {
10741                                         CHECK_STACK (1);
10742                                         --sp;
10743                                 }
10744                                 if (sp [0]->type == STACK_I4 || sp [0]->type == STACK_I8 || sp [0]->type == STACK_R8)
10745                                         UNVERIFIED;
10746                                 if (*ip != CEE_LDFLD && sp [0]->type == STACK_VTYPE)
10747                                         UNVERIFIED;
10748                         } else {
10749                                 if (op == CEE_STSFLD) {
10750                                         CHECK_STACK (1);
10751                                         sp--;
10752                                         store_val = sp [0];
10753                                 }
10754                         }
10755
10756                         CHECK_OPSIZE (5);
10757                         token = read32 (ip + 1);
10758                         if (method->wrapper_type != MONO_WRAPPER_NONE) {
10759                                 field = mono_method_get_wrapper_data (method, token);
10760                                 klass = field->parent;
10761                         }
10762                         else {
10763                                 field = mono_field_from_token_checked (image, token, &klass, generic_context, &cfg->error);
10764                                 CHECK_CFG_ERROR;
10765                         }
10766                         if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_field (method, field))
10767                                 FIELD_ACCESS_FAILURE (method, field);
10768                         mono_class_init (klass);
10769
10770                         /* if the class is Critical then transparent code cannot access it's fields */
10771                         if (!is_instance && mono_security_core_clr_enabled ())
10772                                 ensure_method_is_allowed_to_access_field (cfg, method, field);
10773
10774                         /* XXX this is technically required but, so far (SL2), no [SecurityCritical] types (not many exists) have
10775                            any visible *instance* field  (in fact there's a single case for a static field in Marshal) XXX
10776                         if (mono_security_core_clr_enabled ())
10777                                 ensure_method_is_allowed_to_access_field (cfg, method, field);
10778                         */
10779
10780                         ftype = mono_field_get_type (field);
10781
10782                         /*
10783                          * LDFLD etc. is usable on static fields as well, so convert those cases to
10784                          * the static case.
10785                          */
10786                         if (is_instance && ftype->attrs & FIELD_ATTRIBUTE_STATIC) {
10787                                 switch (op) {
10788                                 case CEE_LDFLD:
10789                                         op = CEE_LDSFLD;
10790                                         break;
10791                                 case CEE_STFLD:
10792                                         op = CEE_STSFLD;
10793                                         break;
10794                                 case CEE_LDFLDA:
10795                                         op = CEE_LDSFLDA;
10796                                         break;
10797                                 default:
10798                                         g_assert_not_reached ();
10799                                 }
10800                                 is_instance = FALSE;
10801                         }
10802
10803                         context_used = mini_class_check_context_used (cfg, klass);
10804
10805                         /* INSTANCE CASE */
10806
10807                         foffset = klass->valuetype? field->offset - sizeof (MonoObject): field->offset;
10808                         if (op == CEE_STFLD) {
10809                                 if (target_type_is_incompatible (cfg, field->type, sp [1]))
10810                                         UNVERIFIED;
10811 #ifndef DISABLE_REMOTING
10812                                 if ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class) {
10813                                         MonoMethod *stfld_wrapper = mono_marshal_get_stfld_wrapper (field->type); 
10814                                         MonoInst *iargs [5];
10815
10816                                         GSHAREDVT_FAILURE (op);
10817
10818                                         iargs [0] = sp [0];
10819                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
10820                                         EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
10821                                         EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : 
10822                                                     field->offset);
10823                                         iargs [4] = sp [1];
10824
10825                                         if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
10826                                                 costs = inline_method (cfg, stfld_wrapper, mono_method_signature (stfld_wrapper), 
10827                                                                                            iargs, ip, cfg->real_offset, TRUE);
10828                                                 CHECK_CFG_EXCEPTION;
10829                                                 g_assert (costs > 0);
10830                                                       
10831                                                 cfg->real_offset += 5;
10832
10833                                                 inline_costs += costs;
10834                                         } else {
10835                                                 mono_emit_method_call (cfg, stfld_wrapper, iargs, NULL);
10836                                         }
10837                                 } else
10838 #endif
10839                                 {
10840                                         MonoInst *store;
10841
10842                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
10843
10844                                         if (mini_is_gsharedvt_klass (klass)) {
10845                                                 MonoInst *offset_ins;
10846
10847                                                 context_used = mini_class_check_context_used (cfg, klass);
10848
10849                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
10850                                                 dreg = alloc_ireg_mp (cfg);
10851                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
10852                                                 /* The decomposition will call mini_emit_stobj () which will emit a wbarrier if needed */
10853                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, dreg, 0, sp [1]->dreg);
10854                                         } else {
10855                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, sp [0]->dreg, foffset, sp [1]->dreg);
10856                                         }
10857                                         if (sp [0]->opcode != OP_LDADDR)
10858                                                 store->flags |= MONO_INST_FAULT;
10859
10860                                 if (cfg->gen_write_barriers && mini_type_to_stind (cfg, field->type) == CEE_STIND_REF && !(sp [1]->opcode == OP_PCONST && sp [1]->inst_c0 == 0)) {
10861                                         /* insert call to write barrier */
10862                                         MonoInst *ptr;
10863                                         int dreg;
10864
10865                                         dreg = alloc_ireg_mp (cfg);
10866                                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
10867                                         emit_write_barrier (cfg, ptr, sp [1]);
10868                                 }
10869
10870                                         store->flags |= ins_flag;
10871                                 }
10872                                 ins_flag = 0;
10873                                 ip += 5;
10874                                 break;
10875                         }
10876
10877 #ifndef DISABLE_REMOTING
10878                         if (is_instance && ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class)) {
10879                                 MonoMethod *wrapper = (op == CEE_LDFLDA) ? mono_marshal_get_ldflda_wrapper (field->type) : mono_marshal_get_ldfld_wrapper (field->type); 
10880                                 MonoInst *iargs [4];
10881
10882                                 GSHAREDVT_FAILURE (op);
10883
10884                                 iargs [0] = sp [0];
10885                                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
10886                                 EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
10887                                 EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset);
10888                                 if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
10889                                         costs = inline_method (cfg, wrapper, mono_method_signature (wrapper), 
10890                                                                                    iargs, ip, cfg->real_offset, TRUE);
10891                                         CHECK_CFG_EXCEPTION;
10892                                         g_assert (costs > 0);
10893                                                       
10894                                         cfg->real_offset += 5;
10895
10896                                         *sp++ = iargs [0];
10897
10898                                         inline_costs += costs;
10899                                 } else {
10900                                         ins = mono_emit_method_call (cfg, wrapper, iargs, NULL);
10901                                         *sp++ = ins;
10902                                 }
10903                         } else 
10904 #endif
10905                         if (is_instance) {
10906                                 if (sp [0]->type == STACK_VTYPE) {
10907                                         MonoInst *var;
10908
10909                                         /* Have to compute the address of the variable */
10910
10911                                         var = get_vreg_to_inst (cfg, sp [0]->dreg);
10912                                         if (!var)
10913                                                 var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, sp [0]->dreg);
10914                                         else
10915                                                 g_assert (var->klass == klass);
10916                                         
10917                                         EMIT_NEW_VARLOADA (cfg, ins, var, &var->klass->byval_arg);
10918                                         sp [0] = ins;
10919                                 }
10920
10921                                 if (op == CEE_LDFLDA) {
10922                                         if (sp [0]->type == STACK_OBJ) {
10923                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, sp [0]->dreg, 0);
10924                                                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "NullReferenceException");
10925                                         }
10926
10927                                         dreg = alloc_ireg_mp (cfg);
10928
10929                                         if (mini_is_gsharedvt_klass (klass)) {
10930                                                 MonoInst *offset_ins;
10931
10932                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
10933                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
10934                                         } else {
10935                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
10936                                         }
10937                                         ins->klass = mono_class_from_mono_type (field->type);
10938                                         ins->type = STACK_MP;
10939                                         *sp++ = ins;
10940                                 } else {
10941                                         MonoInst *load;
10942
10943                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
10944
10945                                         if (mini_is_gsharedvt_klass (klass)) {
10946                                                 MonoInst *offset_ins;
10947
10948                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
10949                                                 dreg = alloc_ireg_mp (cfg);
10950                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
10951                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, dreg, 0);
10952                                         } else {
10953                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, sp [0]->dreg, foffset);
10954                                         }
10955                                         load->flags |= ins_flag;
10956                                         if (sp [0]->opcode != OP_LDADDR)
10957                                                 load->flags |= MONO_INST_FAULT;
10958                                         *sp++ = load;
10959                                 }
10960                         }
10961
10962                         if (is_instance) {
10963                                 ins_flag = 0;
10964                                 ip += 5;
10965                                 break;
10966                         }
10967
10968                         /* STATIC CASE */
10969                         context_used = mini_class_check_context_used (cfg, klass);
10970
10971                         if (ftype->attrs & FIELD_ATTRIBUTE_LITERAL)
10972                                 UNVERIFIED;
10973
10974                         /* The special_static_fields field is init'd in mono_class_vtable, so it needs
10975                          * to be called here.
10976                          */
10977                         if (!context_used && !(cfg->opt & MONO_OPT_SHARED)) {
10978                                 mono_class_vtable (cfg->domain, klass);
10979                                 CHECK_TYPELOAD (klass);
10980                         }
10981                         mono_domain_lock (cfg->domain);
10982                         if (cfg->domain->special_static_fields)
10983                                 addr = g_hash_table_lookup (cfg->domain->special_static_fields, field);
10984                         mono_domain_unlock (cfg->domain);
10985
10986                         is_special_static = mono_class_field_is_special_static (field);
10987
10988                         if (is_special_static && ((gsize)addr & 0x80000000) == 0)
10989                                 thread_ins = mono_get_thread_intrinsic (cfg);
10990                         else
10991                                 thread_ins = NULL;
10992
10993                         /* Generate IR to compute the field address */
10994                         if (is_special_static && ((gsize)addr & 0x80000000) == 0 && thread_ins && !(cfg->opt & MONO_OPT_SHARED) && !context_used) {
10995                                 /*
10996                                  * Fast access to TLS data
10997                                  * Inline version of get_thread_static_data () in
10998                                  * threads.c.
10999                                  */
11000                                 guint32 offset;
11001                                 int idx, static_data_reg, array_reg, dreg;
11002
11003                                 GSHAREDVT_FAILURE (op);
11004
11005                                 MONO_ADD_INS (cfg->cbb, thread_ins);
11006                                 static_data_reg = alloc_ireg (cfg);
11007                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, static_data_reg, thread_ins->dreg, MONO_STRUCT_OFFSET (MonoInternalThread, static_data));
11008
11009                                 if (cfg->compile_aot) {
11010                                         int offset_reg, offset2_reg, idx_reg;
11011
11012                                         /* For TLS variables, this will return the TLS offset */
11013                                         EMIT_NEW_SFLDACONST (cfg, ins, field);
11014                                         offset_reg = ins->dreg;
11015                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset_reg, offset_reg, 0x7fffffff);
11016                                         idx_reg = alloc_ireg (cfg);
11017                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, idx_reg, offset_reg, 0x3f);
11018                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHL_IMM, idx_reg, idx_reg, sizeof (gpointer) == 8 ? 3 : 2);
11019                                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, static_data_reg, static_data_reg, idx_reg);
11020                                         array_reg = alloc_ireg (cfg);
11021                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, 0);
11022                                         offset2_reg = alloc_ireg (cfg);
11023                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, offset2_reg, offset_reg, 6);
11024                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset2_reg, offset2_reg, 0x1ffffff);
11025                                         dreg = alloc_ireg (cfg);
11026                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, array_reg, offset2_reg);
11027                                 } else {
11028                                         offset = (gsize)addr & 0x7fffffff;
11029                                         idx = offset & 0x3f;
11030
11031                                         array_reg = alloc_ireg (cfg);
11032                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, idx * sizeof (gpointer));
11033                                         dreg = alloc_ireg (cfg);
11034                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_ADD_IMM, dreg, array_reg, ((offset >> 6) & 0x1ffffff));
11035                                 }
11036                         } else if ((cfg->opt & MONO_OPT_SHARED) ||
11037                                         (cfg->compile_aot && is_special_static) ||
11038                                         (context_used && is_special_static)) {
11039                                 MonoInst *iargs [2];
11040
11041                                 g_assert (field->parent);
11042                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11043                                 if (context_used) {
11044                                         iargs [1] = emit_get_rgctx_field (cfg, context_used,
11045                                                 field, MONO_RGCTX_INFO_CLASS_FIELD);
11046                                 } else {
11047                                         EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
11048                                 }
11049                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
11050                         } else if (context_used) {
11051                                 MonoInst *static_data;
11052
11053                                 /*
11054                                 g_print ("sharing static field access in %s.%s.%s - depth %d offset %d\n",
11055                                         method->klass->name_space, method->klass->name, method->name,
11056                                         depth, field->offset);
11057                                 */
11058
11059                                 if (mono_class_needs_cctor_run (klass, method))
11060                                         emit_class_init (cfg, klass);
11061
11062                                 /*
11063                                  * The pointer we're computing here is
11064                                  *
11065                                  *   super_info.static_data + field->offset
11066                                  */
11067                                 static_data = emit_get_rgctx_klass (cfg, context_used,
11068                                         klass, MONO_RGCTX_INFO_STATIC_DATA);
11069
11070                                 if (mini_is_gsharedvt_klass (klass)) {
11071                                         MonoInst *offset_ins;
11072
11073                                         offset_ins = emit_get_rgctx_field (cfg, context_used, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11074                                         dreg = alloc_ireg_mp (cfg);
11075                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, static_data->dreg, offset_ins->dreg);
11076                                 } else if (field->offset == 0) {
11077                                         ins = static_data;
11078                                 } else {
11079                                         int addr_reg = mono_alloc_preg (cfg);
11080                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, addr_reg, static_data->dreg, field->offset);
11081                                 }
11082                                 } else if ((cfg->opt & MONO_OPT_SHARED) || (cfg->compile_aot && addr)) {
11083                                 MonoInst *iargs [2];
11084
11085                                 g_assert (field->parent);
11086                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11087                                 EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
11088                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
11089                         } else {
11090                                 MonoVTable *vtable = NULL;
11091
11092                                 if (!cfg->compile_aot)
11093                                         vtable = mono_class_vtable (cfg->domain, klass);
11094                                 CHECK_TYPELOAD (klass);
11095
11096                                 if (!addr) {
11097                                         if (mini_field_access_needs_cctor_run (cfg, method, klass, vtable)) {
11098                                                 if (!(g_slist_find (class_inits, klass))) {
11099                                                         emit_class_init (cfg, klass);
11100                                                         if (cfg->verbose_level > 2)
11101                                                                 printf ("class %s.%s needs init call for %s\n", klass->name_space, klass->name, mono_field_get_name (field));
11102                                                         class_inits = g_slist_prepend (class_inits, klass);
11103                                                 }
11104                                         } else {
11105                                                 if (cfg->run_cctors) {
11106                                                         MonoException *ex;
11107                                                         /* This makes so that inline cannot trigger */
11108                                                         /* .cctors: too many apps depend on them */
11109                                                         /* running with a specific order... */
11110                                                         g_assert (vtable);
11111                                                         if (! vtable->initialized)
11112                                                                 INLINE_FAILURE ("class init");
11113                                                         ex = mono_runtime_class_init_full (vtable, FALSE);
11114                                                         if (ex) {
11115                                                                 set_exception_object (cfg, ex);
11116                                                                 goto exception_exit;
11117                                                         }
11118                                                 }
11119                                         }
11120                                         if (cfg->compile_aot)
11121                                                 EMIT_NEW_SFLDACONST (cfg, ins, field);
11122                                         else {
11123                                                 g_assert (vtable);
11124                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
11125                                                 g_assert (addr);
11126                                                 EMIT_NEW_PCONST (cfg, ins, addr);
11127                                         }
11128                                 } else {
11129                                         MonoInst *iargs [1];
11130                                         EMIT_NEW_ICONST (cfg, iargs [0], GPOINTER_TO_UINT (addr));
11131                                         ins = mono_emit_jit_icall (cfg, mono_get_special_static_data, iargs);
11132                                 }
11133                         }
11134
11135                         /* Generate IR to do the actual load/store operation */
11136
11137                         if ((op == CEE_STFLD || op == CEE_STSFLD) && (ins_flag & MONO_INST_VOLATILE)) {
11138                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
11139                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
11140                         }
11141
11142                         if (op == CEE_LDSFLDA) {
11143                                 ins->klass = mono_class_from_mono_type (ftype);
11144                                 ins->type = STACK_PTR;
11145                                 *sp++ = ins;
11146                         } else if (op == CEE_STSFLD) {
11147                                 MonoInst *store;
11148
11149                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, ftype, ins->dreg, 0, store_val->dreg);
11150                                 store->flags |= ins_flag;
11151                         } else {
11152                                 gboolean is_const = FALSE;
11153                                 MonoVTable *vtable = NULL;
11154                                 gpointer addr = NULL;
11155
11156                                 if (!context_used) {
11157                                         vtable = mono_class_vtable (cfg->domain, klass);
11158                                         CHECK_TYPELOAD (klass);
11159                                 }
11160                                 if ((ftype->attrs & FIELD_ATTRIBUTE_INIT_ONLY) && (((addr = mono_aot_readonly_field_override (field)) != NULL) ||
11161                                                 (!context_used && !((cfg->opt & MONO_OPT_SHARED) || cfg->compile_aot) && vtable->initialized))) {
11162                                         int ro_type = ftype->type;
11163                                         if (!addr)
11164                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
11165                                         if (ro_type == MONO_TYPE_VALUETYPE && ftype->data.klass->enumtype) {
11166                                                 ro_type = mono_class_enum_basetype (ftype->data.klass)->type;
11167                                         }
11168
11169                                         GSHAREDVT_FAILURE (op);
11170
11171                                         /* printf ("RO-FIELD %s.%s:%s\n", klass->name_space, klass->name, mono_field_get_name (field));*/
11172                                         is_const = TRUE;
11173                                         switch (ro_type) {
11174                                         case MONO_TYPE_BOOLEAN:
11175                                         case MONO_TYPE_U1:
11176                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint8 *)addr));
11177                                                 sp++;
11178                                                 break;
11179                                         case MONO_TYPE_I1:
11180                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint8 *)addr));
11181                                                 sp++;
11182                                                 break;                                          
11183                                         case MONO_TYPE_CHAR:
11184                                         case MONO_TYPE_U2:
11185                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint16 *)addr));
11186                                                 sp++;
11187                                                 break;
11188                                         case MONO_TYPE_I2:
11189                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint16 *)addr));
11190                                                 sp++;
11191                                                 break;
11192                                                 break;
11193                                         case MONO_TYPE_I4:
11194                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint32 *)addr));
11195                                                 sp++;
11196                                                 break;                                          
11197                                         case MONO_TYPE_U4:
11198                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint32 *)addr));
11199                                                 sp++;
11200                                                 break;
11201                                         case MONO_TYPE_I:
11202                                         case MONO_TYPE_U:
11203                                         case MONO_TYPE_PTR:
11204                                         case MONO_TYPE_FNPTR:
11205                                                 EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
11206                                                 type_to_eval_stack_type ((cfg), field->type, *sp);
11207                                                 sp++;
11208                                                 break;
11209                                         case MONO_TYPE_STRING:
11210                                         case MONO_TYPE_OBJECT:
11211                                         case MONO_TYPE_CLASS:
11212                                         case MONO_TYPE_SZARRAY:
11213                                         case MONO_TYPE_ARRAY:
11214                                                 if (!mono_gc_is_moving ()) {
11215                                                         EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
11216                                                         type_to_eval_stack_type ((cfg), field->type, *sp);
11217                                                         sp++;
11218                                                 } else {
11219                                                         is_const = FALSE;
11220                                                 }
11221                                                 break;
11222                                         case MONO_TYPE_I8:
11223                                         case MONO_TYPE_U8:
11224                                                 EMIT_NEW_I8CONST (cfg, *sp, *((gint64 *)addr));
11225                                                 sp++;
11226                                                 break;
11227                                         case MONO_TYPE_R4:
11228                                         case MONO_TYPE_R8:
11229                                         case MONO_TYPE_VALUETYPE:
11230                                         default:
11231                                                 is_const = FALSE;
11232                                                 break;
11233                                         }
11234                                 }
11235
11236                                 if (!is_const) {
11237                                         MonoInst *load;
11238
11239                                         CHECK_STACK_OVF (1);
11240
11241                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, ins->dreg, 0);
11242                                         load->flags |= ins_flag;
11243                                         ins_flag = 0;
11244                                         *sp++ = load;
11245                                 }
11246                         }
11247
11248                         if ((op == CEE_LDFLD || op == CEE_LDSFLD) && (ins_flag & MONO_INST_VOLATILE)) {
11249                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
11250                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
11251                         }
11252
11253                         ins_flag = 0;
11254                         ip += 5;
11255                         break;
11256                 }
11257                 case CEE_STOBJ:
11258                         CHECK_STACK (2);
11259                         sp -= 2;
11260                         CHECK_OPSIZE (5);
11261                         token = read32 (ip + 1);
11262                         klass = mini_get_class (method, token, generic_context);
11263                         CHECK_TYPELOAD (klass);
11264                         if (ins_flag & MONO_INST_VOLATILE) {
11265                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
11266                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
11267                         }
11268                         /* FIXME: should check item at sp [1] is compatible with the type of the store. */
11269                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0, sp [1]->dreg);
11270                         ins->flags |= ins_flag;
11271                         if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER &&
11272                                         generic_class_is_reference_type (cfg, klass)) {
11273                                 /* insert call to write barrier */
11274                                 emit_write_barrier (cfg, sp [0], sp [1]);
11275                         }
11276                         ins_flag = 0;
11277                         ip += 5;
11278                         inline_costs += 1;
11279                         break;
11280
11281                         /*
11282                          * Array opcodes
11283                          */
11284                 case CEE_NEWARR: {
11285                         MonoInst *len_ins;
11286                         const char *data_ptr;
11287                         int data_size = 0;
11288                         guint32 field_token;
11289
11290                         CHECK_STACK (1);
11291                         --sp;
11292
11293                         CHECK_OPSIZE (5);
11294                         token = read32 (ip + 1);
11295
11296                         klass = mini_get_class (method, token, generic_context);
11297                         CHECK_TYPELOAD (klass);
11298
11299                         context_used = mini_class_check_context_used (cfg, klass);
11300
11301                         if (sp [0]->type == STACK_I8 || (SIZEOF_VOID_P == 8 && sp [0]->type == STACK_PTR)) {
11302                                 MONO_INST_NEW (cfg, ins, OP_LCONV_TO_OVF_U4);
11303                                 ins->sreg1 = sp [0]->dreg;
11304                                 ins->type = STACK_I4;
11305                                 ins->dreg = alloc_ireg (cfg);
11306                                 MONO_ADD_INS (cfg->cbb, ins);
11307                                 *sp = mono_decompose_opcode (cfg, ins);
11308                         }
11309
11310                         if (context_used) {
11311                                 MonoInst *args [3];
11312                                 MonoClass *array_class = mono_array_class_get (klass, 1);
11313                                 MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (array_class);
11314
11315                                 /* FIXME: Use OP_NEWARR and decompose later to help abcrem */
11316
11317                                 /* vtable */
11318                                 args [0] = emit_get_rgctx_klass (cfg, context_used,
11319                                         array_class, MONO_RGCTX_INFO_VTABLE);
11320                                 /* array len */
11321                                 args [1] = sp [0];
11322
11323                                 if (managed_alloc)
11324                                         ins = mono_emit_method_call (cfg, managed_alloc, args, NULL);
11325                                 else
11326                                         ins = mono_emit_jit_icall (cfg, mono_array_new_specific, args);
11327                         } else {
11328                                 if (cfg->opt & MONO_OPT_SHARED) {
11329                                         /* Decompose now to avoid problems with references to the domainvar */
11330                                         MonoInst *iargs [3];
11331
11332                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11333                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
11334                                         iargs [2] = sp [0];
11335
11336                                         ins = mono_emit_jit_icall (cfg, mono_array_new, iargs);
11337                                 } else {
11338                                         /* Decompose later since it is needed by abcrem */
11339                                         MonoClass *array_type = mono_array_class_get (klass, 1);
11340                                         mono_class_vtable (cfg->domain, array_type);
11341                                         CHECK_TYPELOAD (array_type);
11342
11343                                         MONO_INST_NEW (cfg, ins, OP_NEWARR);
11344                                         ins->dreg = alloc_ireg_ref (cfg);
11345                                         ins->sreg1 = sp [0]->dreg;
11346                                         ins->inst_newa_class = klass;
11347                                         ins->type = STACK_OBJ;
11348                                         ins->klass = array_type;
11349                                         MONO_ADD_INS (cfg->cbb, ins);
11350                                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
11351                                         cfg->cbb->has_array_access = TRUE;
11352
11353                                         /* Needed so mono_emit_load_get_addr () gets called */
11354                                         mono_get_got_var (cfg);
11355                                 }
11356                         }
11357
11358                         len_ins = sp [0];
11359                         ip += 5;
11360                         *sp++ = ins;
11361                         inline_costs += 1;
11362
11363                         /* 
11364                          * we inline/optimize the initialization sequence if possible.
11365                          * we should also allocate the array as not cleared, since we spend as much time clearing to 0 as initializing
11366                          * for small sizes open code the memcpy
11367                          * ensure the rva field is big enough
11368                          */
11369                         if ((cfg->opt & MONO_OPT_INTRINS) && ip + 6 < end && ip_in_bb (cfg, cfg->cbb, 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))) {
11370                                 MonoMethod *memcpy_method = get_memcpy_method ();
11371                                 MonoInst *iargs [3];
11372                                 int add_reg = alloc_ireg_mp (cfg);
11373
11374                                 EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, add_reg, ins->dreg, MONO_STRUCT_OFFSET (MonoArray, vector));
11375                                 if (cfg->compile_aot) {
11376                                         EMIT_NEW_AOTCONST_TOKEN (cfg, iargs [1], MONO_PATCH_INFO_RVA, method->klass->image, GPOINTER_TO_UINT(field_token), STACK_PTR, NULL);
11377                                 } else {
11378                                         EMIT_NEW_PCONST (cfg, iargs [1], (char*)data_ptr);
11379                                 }
11380                                 EMIT_NEW_ICONST (cfg, iargs [2], data_size);
11381                                 mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
11382                                 ip += 11;
11383                         }
11384
11385                         break;
11386                 }
11387                 case CEE_LDLEN:
11388                         CHECK_STACK (1);
11389                         --sp;
11390                         if (sp [0]->type != STACK_OBJ)
11391                                 UNVERIFIED;
11392
11393                         MONO_INST_NEW (cfg, ins, OP_LDLEN);
11394                         ins->dreg = alloc_preg (cfg);
11395                         ins->sreg1 = sp [0]->dreg;
11396                         ins->type = STACK_I4;
11397                         /* This flag will be inherited by the decomposition */
11398                         ins->flags |= MONO_INST_FAULT;
11399                         MONO_ADD_INS (cfg->cbb, ins);
11400                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
11401                         cfg->cbb->has_array_access = TRUE;
11402                         ip ++;
11403                         *sp++ = ins;
11404                         break;
11405                 case CEE_LDELEMA:
11406                         CHECK_STACK (2);
11407                         sp -= 2;
11408                         CHECK_OPSIZE (5);
11409                         if (sp [0]->type != STACK_OBJ)
11410                                 UNVERIFIED;
11411
11412                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11413
11414                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
11415                         CHECK_TYPELOAD (klass);
11416                         /* we need to make sure that this array is exactly the type it needs
11417                          * to be for correctness. the wrappers are lax with their usage
11418                          * so we need to ignore them here
11419                          */
11420                         if (!klass->valuetype && method->wrapper_type == MONO_WRAPPER_NONE && !readonly) {
11421                                 MonoClass *array_class = mono_array_class_get (klass, 1);
11422                                 mini_emit_check_array_type (cfg, sp [0], array_class);
11423                                 CHECK_TYPELOAD (array_class);
11424                         }
11425
11426                         readonly = FALSE;
11427                         ins = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11428                         *sp++ = ins;
11429                         ip += 5;
11430                         break;
11431                 case CEE_LDELEM:
11432                 case CEE_LDELEM_I1:
11433                 case CEE_LDELEM_U1:
11434                 case CEE_LDELEM_I2:
11435                 case CEE_LDELEM_U2:
11436                 case CEE_LDELEM_I4:
11437                 case CEE_LDELEM_U4:
11438                 case CEE_LDELEM_I8:
11439                 case CEE_LDELEM_I:
11440                 case CEE_LDELEM_R4:
11441                 case CEE_LDELEM_R8:
11442                 case CEE_LDELEM_REF: {
11443                         MonoInst *addr;
11444
11445                         CHECK_STACK (2);
11446                         sp -= 2;
11447
11448                         if (*ip == CEE_LDELEM) {
11449                                 CHECK_OPSIZE (5);
11450                                 token = read32 (ip + 1);
11451                                 klass = mini_get_class (method, token, generic_context);
11452                                 CHECK_TYPELOAD (klass);
11453                                 mono_class_init (klass);
11454                         }
11455                         else
11456                                 klass = array_access_to_klass (*ip);
11457
11458                         if (sp [0]->type != STACK_OBJ)
11459                                 UNVERIFIED;
11460
11461                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11462
11463                         if (mini_is_gsharedvt_variable_klass (klass)) {
11464                                 // FIXME-VT: OP_ICONST optimization
11465                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11466                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
11467                                 ins->opcode = OP_LOADV_MEMBASE;
11468                         } else if (sp [1]->opcode == OP_ICONST) {
11469                                 int array_reg = sp [0]->dreg;
11470                                 int index_reg = sp [1]->dreg;
11471                                 int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + MONO_STRUCT_OFFSET (MonoArray, vector);
11472
11473                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
11474                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset);
11475                         } else {
11476                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11477                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
11478                         }
11479                         *sp++ = ins;
11480                         if (*ip == CEE_LDELEM)
11481                                 ip += 5;
11482                         else
11483                                 ++ip;
11484                         break;
11485                 }
11486                 case CEE_STELEM_I:
11487                 case CEE_STELEM_I1:
11488                 case CEE_STELEM_I2:
11489                 case CEE_STELEM_I4:
11490                 case CEE_STELEM_I8:
11491                 case CEE_STELEM_R4:
11492                 case CEE_STELEM_R8:
11493                 case CEE_STELEM_REF:
11494                 case CEE_STELEM: {
11495                         CHECK_STACK (3);
11496                         sp -= 3;
11497
11498                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11499
11500                         if (*ip == CEE_STELEM) {
11501                                 CHECK_OPSIZE (5);
11502                                 token = read32 (ip + 1);
11503                                 klass = mini_get_class (method, token, generic_context);
11504                                 CHECK_TYPELOAD (klass);
11505                                 mono_class_init (klass);
11506                         }
11507                         else
11508                                 klass = array_access_to_klass (*ip);
11509
11510                         if (sp [0]->type != STACK_OBJ)
11511                                 UNVERIFIED;
11512
11513                         emit_array_store (cfg, klass, sp, TRUE);
11514
11515                         if (*ip == CEE_STELEM)
11516                                 ip += 5;
11517                         else
11518                                 ++ip;
11519                         inline_costs += 1;
11520                         break;
11521                 }
11522                 case CEE_CKFINITE: {
11523                         CHECK_STACK (1);
11524                         --sp;
11525
11526                         MONO_INST_NEW (cfg, ins, OP_CKFINITE);
11527                         ins->sreg1 = sp [0]->dreg;
11528                         ins->dreg = alloc_freg (cfg);
11529                         ins->type = STACK_R8;
11530                         MONO_ADD_INS (cfg->cbb, ins);
11531
11532                         *sp++ = mono_decompose_opcode (cfg, ins);
11533
11534                         ++ip;
11535                         break;
11536                 }
11537                 case CEE_REFANYVAL: {
11538                         MonoInst *src_var, *src;
11539
11540                         int klass_reg = alloc_preg (cfg);
11541                         int dreg = alloc_preg (cfg);
11542
11543                         GSHAREDVT_FAILURE (*ip);
11544
11545                         CHECK_STACK (1);
11546                         MONO_INST_NEW (cfg, ins, *ip);
11547                         --sp;
11548                         CHECK_OPSIZE (5);
11549                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
11550                         CHECK_TYPELOAD (klass);
11551
11552                         context_used = mini_class_check_context_used (cfg, klass);
11553
11554                         // FIXME:
11555                         src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
11556                         if (!src_var)
11557                                 src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
11558                         EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
11559                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass));
11560
11561                         if (context_used) {
11562                                 MonoInst *klass_ins;
11563
11564                                 klass_ins = emit_get_rgctx_klass (cfg, context_used,
11565                                                 klass, MONO_RGCTX_INFO_KLASS);
11566
11567                                 // FIXME:
11568                                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_ins->dreg);
11569                                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
11570                         } else {
11571                                 mini_emit_class_check (cfg, klass_reg, klass);
11572                         }
11573                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, value));
11574                         ins->type = STACK_MP;
11575                         ins->klass = klass;
11576                         *sp++ = ins;
11577                         ip += 5;
11578                         break;
11579                 }
11580                 case CEE_MKREFANY: {
11581                         MonoInst *loc, *addr;
11582
11583                         GSHAREDVT_FAILURE (*ip);
11584
11585                         CHECK_STACK (1);
11586                         MONO_INST_NEW (cfg, ins, *ip);
11587                         --sp;
11588                         CHECK_OPSIZE (5);
11589                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
11590                         CHECK_TYPELOAD (klass);
11591
11592                         context_used = mini_class_check_context_used (cfg, klass);
11593
11594                         loc = mono_compile_create_var (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL);
11595                         EMIT_NEW_TEMPLOADA (cfg, addr, loc->inst_c0);
11596
11597                         if (context_used) {
11598                                 MonoInst *const_ins;
11599                                 int type_reg = alloc_preg (cfg);
11600
11601                                 const_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
11602                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), const_ins->dreg);
11603                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_ins->dreg, MONO_STRUCT_OFFSET (MonoClass, byval_arg));
11604                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
11605                         } else if (cfg->compile_aot) {
11606                                 int const_reg = alloc_preg (cfg);
11607                                 int type_reg = alloc_preg (cfg);
11608
11609                                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
11610                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), const_reg);
11611                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_reg, MONO_STRUCT_OFFSET (MonoClass, byval_arg));
11612                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
11613                         } else {
11614                                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), &klass->byval_arg);
11615                                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), klass);
11616                         }
11617                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, value), sp [0]->dreg);
11618
11619                         EMIT_NEW_TEMPLOAD (cfg, ins, loc->inst_c0);
11620                         ins->type = STACK_VTYPE;
11621                         ins->klass = mono_defaults.typed_reference_class;
11622                         *sp++ = ins;
11623                         ip += 5;
11624                         break;
11625                 }
11626                 case CEE_LDTOKEN: {
11627                         gpointer handle;
11628                         MonoClass *handle_class;
11629
11630                         CHECK_STACK_OVF (1);
11631
11632                         CHECK_OPSIZE (5);
11633                         n = read32 (ip + 1);
11634
11635                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD ||
11636                                         method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
11637                                 handle = mono_method_get_wrapper_data (method, n);
11638                                 handle_class = mono_method_get_wrapper_data (method, n + 1);
11639                                 if (handle_class == mono_defaults.typehandle_class)
11640                                         handle = &((MonoClass*)handle)->byval_arg;
11641                         }
11642                         else {
11643                                 handle = mono_ldtoken_checked (image, n, &handle_class, generic_context, &cfg->error);
11644                                 CHECK_CFG_ERROR;
11645                         }
11646                         if (!handle)
11647                                 LOAD_ERROR;
11648                         mono_class_init (handle_class);
11649                         if (cfg->gshared) {
11650                                 if (mono_metadata_token_table (n) == MONO_TABLE_TYPEDEF ||
11651                                                 mono_metadata_token_table (n) == MONO_TABLE_TYPEREF) {
11652                                         /* This case handles ldtoken
11653                                            of an open type, like for
11654                                            typeof(Gen<>). */
11655                                         context_used = 0;
11656                                 } else if (handle_class == mono_defaults.typehandle_class) {
11657                                         context_used = mini_class_check_context_used (cfg, mono_class_from_mono_type (handle));
11658                                 } else if (handle_class == mono_defaults.fieldhandle_class)
11659                                         context_used = mini_class_check_context_used (cfg, ((MonoClassField*)handle)->parent);
11660                                 else if (handle_class == mono_defaults.methodhandle_class)
11661                                         context_used = mini_method_check_context_used (cfg, handle);
11662                                 else
11663                                         g_assert_not_reached ();
11664                         }
11665
11666                         if ((cfg->opt & MONO_OPT_SHARED) &&
11667                                         method->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD &&
11668                                         method->wrapper_type != MONO_WRAPPER_SYNCHRONIZED) {
11669                                 MonoInst *addr, *vtvar, *iargs [3];
11670                                 int method_context_used;
11671
11672                                 method_context_used = mini_method_check_context_used (cfg, method);
11673
11674                                 vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL); 
11675
11676                                 EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
11677                                 EMIT_NEW_ICONST (cfg, iargs [1], n);
11678                                 if (method_context_used) {
11679                                         iargs [2] = emit_get_rgctx_method (cfg, method_context_used,
11680                                                 method, MONO_RGCTX_INFO_METHOD);
11681                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper_generic_shared, iargs);
11682                                 } else {
11683                                         EMIT_NEW_PCONST (cfg, iargs [2], generic_context);
11684                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper, iargs);
11685                                 }
11686                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
11687
11688                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
11689
11690                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
11691                         } else {
11692                                 if ((ip + 5 < end) && ip_in_bb (cfg, cfg->cbb, ip + 5) && 
11693                                         ((ip [5] == CEE_CALL) || (ip [5] == CEE_CALLVIRT)) && 
11694                                         (cmethod = mini_get_method (cfg, method, read32 (ip + 6), NULL, generic_context)) &&
11695                                         (cmethod->klass == mono_defaults.systemtype_class) &&
11696                                         (strcmp (cmethod->name, "GetTypeFromHandle") == 0)) {
11697                                         MonoClass *tclass = mono_class_from_mono_type (handle);
11698
11699                                         mono_class_init (tclass);
11700                                         if (context_used) {
11701                                                 ins = emit_get_rgctx_klass (cfg, context_used,
11702                                                         tclass, MONO_RGCTX_INFO_REFLECTION_TYPE);
11703                                         } else if (cfg->compile_aot) {
11704                                                 if (method->wrapper_type) {
11705                                                         mono_error_init (&error); //got to do it since there are multiple conditionals below
11706                                                         if (mono_class_get_checked (tclass->image, tclass->type_token, &error) == tclass && !generic_context) {
11707                                                                 /* Special case for static synchronized wrappers */
11708                                                                 EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, tclass->image, tclass->type_token, generic_context);
11709                                                         } else {
11710                                                                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
11711                                                                 /* FIXME: n is not a normal token */
11712                                                                 DISABLE_AOT (cfg);
11713                                                                 EMIT_NEW_PCONST (cfg, ins, NULL);
11714                                                         }
11715                                                 } else {
11716                                                         EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, image, n, generic_context);
11717                                                 }
11718                                         } else {
11719                                                 EMIT_NEW_PCONST (cfg, ins, mono_type_get_object (cfg->domain, handle));
11720                                         }
11721                                         ins->type = STACK_OBJ;
11722                                         ins->klass = cmethod->klass;
11723                                         ip += 5;
11724                                 } else {
11725                                         MonoInst *addr, *vtvar;
11726
11727                                         vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL);
11728
11729                                         if (context_used) {
11730                                                 if (handle_class == mono_defaults.typehandle_class) {
11731                                                         ins = emit_get_rgctx_klass (cfg, context_used,
11732                                                                         mono_class_from_mono_type (handle),
11733                                                                         MONO_RGCTX_INFO_TYPE);
11734                                                 } else if (handle_class == mono_defaults.methodhandle_class) {
11735                                                         ins = emit_get_rgctx_method (cfg, context_used,
11736                                                                         handle, MONO_RGCTX_INFO_METHOD);
11737                                                 } else if (handle_class == mono_defaults.fieldhandle_class) {
11738                                                         ins = emit_get_rgctx_field (cfg, context_used,
11739                                                                         handle, MONO_RGCTX_INFO_CLASS_FIELD);
11740                                                 } else {
11741                                                         g_assert_not_reached ();
11742                                                 }
11743                                         } else if (cfg->compile_aot) {
11744                                                 EMIT_NEW_LDTOKENCONST (cfg, ins, image, n, generic_context);
11745                                         } else {
11746                                                 EMIT_NEW_PCONST (cfg, ins, handle);
11747                                         }
11748                                         EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
11749                                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
11750                                         EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
11751                                 }
11752                         }
11753
11754                         *sp++ = ins;
11755                         ip += 5;
11756                         break;
11757                 }
11758                 case CEE_THROW:
11759                         CHECK_STACK (1);
11760                         MONO_INST_NEW (cfg, ins, OP_THROW);
11761                         --sp;
11762                         ins->sreg1 = sp [0]->dreg;
11763                         ip++;
11764                         cfg->cbb->out_of_line = TRUE;
11765                         MONO_ADD_INS (cfg->cbb, ins);
11766                         MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
11767                         MONO_ADD_INS (cfg->cbb, ins);
11768                         sp = stack_start;
11769                         
11770                         link_bblock (cfg, cfg->cbb, end_bblock);
11771                         start_new_bblock = 1;
11772                         break;
11773                 case CEE_ENDFINALLY:
11774                         /* mono_save_seq_point_info () depends on this */
11775                         if (sp != stack_start)
11776                                 emit_seq_point (cfg, method, ip, FALSE, FALSE);
11777                         MONO_INST_NEW (cfg, ins, OP_ENDFINALLY);
11778                         MONO_ADD_INS (cfg->cbb, ins);
11779                         ip++;
11780                         start_new_bblock = 1;
11781
11782                         /*
11783                          * Control will leave the method so empty the stack, otherwise
11784                          * the next basic block will start with a nonempty stack.
11785                          */
11786                         while (sp != stack_start) {
11787                                 sp--;
11788                         }
11789                         break;
11790                 case CEE_LEAVE:
11791                 case CEE_LEAVE_S: {
11792                         GList *handlers;
11793
11794                         if (*ip == CEE_LEAVE) {
11795                                 CHECK_OPSIZE (5);
11796                                 target = ip + 5 + (gint32)read32(ip + 1);
11797                         } else {
11798                                 CHECK_OPSIZE (2);
11799                                 target = ip + 2 + (signed char)(ip [1]);
11800                         }
11801
11802                         /* empty the stack */
11803                         while (sp != stack_start) {
11804                                 sp--;
11805                         }
11806
11807                         /* 
11808                          * If this leave statement is in a catch block, check for a
11809                          * pending exception, and rethrow it if necessary.
11810                          * We avoid doing this in runtime invoke wrappers, since those are called
11811                          * by native code which excepts the wrapper to catch all exceptions.
11812                          */
11813                         for (i = 0; i < header->num_clauses; ++i) {
11814                                 MonoExceptionClause *clause = &header->clauses [i];
11815
11816                                 /* 
11817                                  * Use <= in the final comparison to handle clauses with multiple
11818                                  * leave statements, like in bug #78024.
11819                                  * The ordering of the exception clauses guarantees that we find the
11820                                  * innermost clause.
11821                                  */
11822                                 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) {
11823                                         MonoInst *exc_ins;
11824                                         MonoBasicBlock *dont_throw;
11825
11826                                         /*
11827                                           MonoInst *load;
11828
11829                                           NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, clause->handler_offset)->inst_c0);
11830                                         */
11831
11832                                         exc_ins = mono_emit_jit_icall (cfg, mono_thread_get_undeniable_exception, NULL);
11833
11834                                         NEW_BBLOCK (cfg, dont_throw);
11835
11836                                         /*
11837                                          * Currently, we always rethrow the abort exception, despite the 
11838                                          * fact that this is not correct. See thread6.cs for an example. 
11839                                          * But propagating the abort exception is more important than 
11840                                          * getting the sematics right.
11841                                          */
11842                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, exc_ins->dreg, 0);
11843                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, dont_throw);
11844                                         MONO_EMIT_NEW_UNALU (cfg, OP_THROW, -1, exc_ins->dreg);
11845
11846                                         MONO_START_BB (cfg, dont_throw);
11847                                 }
11848                         }
11849
11850                         if ((handlers = mono_find_final_block (cfg, ip, target, MONO_EXCEPTION_CLAUSE_FINALLY))) {
11851                                 GList *tmp;
11852                                 MonoExceptionClause *clause;
11853
11854                                 for (tmp = handlers; tmp; tmp = tmp->next) {
11855                                         clause = tmp->data;
11856                                         tblock = cfg->cil_offset_to_bb [clause->handler_offset];
11857                                         g_assert (tblock);
11858                                         link_bblock (cfg, cfg->cbb, tblock);
11859                                         MONO_INST_NEW (cfg, ins, OP_CALL_HANDLER);
11860                                         ins->inst_target_bb = tblock;
11861                                         ins->inst_eh_block = clause;
11862                                         MONO_ADD_INS (cfg->cbb, ins);
11863                                         cfg->cbb->has_call_handler = 1;
11864                                         if (COMPILE_LLVM (cfg)) {
11865                                                 MonoBasicBlock *target_bb;
11866
11867                                                 /* 
11868                                                  * Link the finally bblock with the target, since it will
11869                                                  * conceptually branch there.
11870                                                  * FIXME: Have to link the bblock containing the endfinally.
11871                                                  */
11872                                                 GET_BBLOCK (cfg, target_bb, target);
11873                                                 link_bblock (cfg, tblock, target_bb);
11874                                         }
11875                                 }
11876                                 g_list_free (handlers);
11877                         } 
11878
11879                         MONO_INST_NEW (cfg, ins, OP_BR);
11880                         MONO_ADD_INS (cfg->cbb, ins);
11881                         GET_BBLOCK (cfg, tblock, target);
11882                         link_bblock (cfg, cfg->cbb, tblock);
11883                         ins->inst_target_bb = tblock;
11884                         start_new_bblock = 1;
11885
11886                         if (*ip == CEE_LEAVE)
11887                                 ip += 5;
11888                         else
11889                                 ip += 2;
11890
11891                         break;
11892                 }
11893
11894                         /*
11895                          * Mono specific opcodes
11896                          */
11897                 case MONO_CUSTOM_PREFIX: {
11898
11899                         g_assert (method->wrapper_type != MONO_WRAPPER_NONE);
11900
11901                         CHECK_OPSIZE (2);
11902                         switch (ip [1]) {
11903                         case CEE_MONO_ICALL: {
11904                                 gpointer func;
11905                                 MonoJitICallInfo *info;
11906
11907                                 token = read32 (ip + 2);
11908                                 func = mono_method_get_wrapper_data (method, token);
11909                                 info = mono_find_jit_icall_by_addr (func);
11910                                 if (!info)
11911                                         g_error ("Could not find icall address in wrapper %s", mono_method_full_name (method, 1));
11912                                 g_assert (info);
11913
11914                                 CHECK_STACK (info->sig->param_count);
11915                                 sp -= info->sig->param_count;
11916
11917                                 ins = mono_emit_jit_icall (cfg, info->func, sp);
11918                                 if (!MONO_TYPE_IS_VOID (info->sig->ret))
11919                                         *sp++ = ins;
11920
11921                                 ip += 6;
11922                                 inline_costs += 10 * num_calls++;
11923
11924                                 break;
11925                         }
11926                         case CEE_MONO_LDPTR_CARD_TABLE: {
11927                                 int shift_bits;
11928                                 gpointer card_mask;
11929                                 CHECK_STACK_OVF (1);
11930
11931                                 if (cfg->compile_aot)
11932                                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_GC_CARD_TABLE_ADDR, NULL);
11933                                 else
11934                                         EMIT_NEW_PCONST (cfg, ins, mono_gc_get_card_table (&shift_bits, &card_mask));
11935
11936                                 *sp++ = ins;
11937                                 ip += 2;
11938                                 inline_costs += 10 * num_calls++;
11939                                 break;
11940                         }
11941                         case CEE_MONO_LDPTR_NURSERY_START: {
11942                                 int shift_bits;
11943                                 size_t size;
11944                                 CHECK_STACK_OVF (1);
11945
11946                                 if (cfg->compile_aot)
11947                                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_GC_NURSERY_START, NULL);
11948                                 else
11949                                         EMIT_NEW_PCONST (cfg, ins, mono_gc_get_nursery (&shift_bits, &size));
11950
11951                                 *sp++ = ins;
11952                                 ip += 2;
11953                                 inline_costs += 10 * num_calls++;
11954                                 break;
11955                         }
11956                         case CEE_MONO_LDPTR_INT_REQ_FLAG: {
11957                                 CHECK_STACK_OVF (1);
11958
11959                                 if (cfg->compile_aot)
11960                                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG, NULL);
11961                                 else
11962                                         EMIT_NEW_PCONST (cfg, ins, mono_thread_interruption_request_flag ());
11963
11964                                 *sp++ = ins;
11965                                 ip += 2;
11966                                 inline_costs += 10 * num_calls++;
11967                                 break;
11968                         }
11969                         case CEE_MONO_LDPTR: {
11970                                 gpointer ptr;
11971
11972                                 CHECK_STACK_OVF (1);
11973                                 CHECK_OPSIZE (6);
11974                                 token = read32 (ip + 2);
11975
11976                                 ptr = mono_method_get_wrapper_data (method, token);
11977                                 EMIT_NEW_PCONST (cfg, ins, ptr);
11978                                 *sp++ = ins;
11979                                 ip += 6;
11980                                 inline_costs += 10 * num_calls++;
11981                                 /* Can't embed random pointers into AOT code */
11982                                 DISABLE_AOT (cfg);
11983                                 break;
11984                         }
11985                         case CEE_MONO_JIT_ICALL_ADDR: {
11986                                 MonoJitICallInfo *callinfo;
11987                                 gpointer ptr;
11988
11989                                 CHECK_STACK_OVF (1);
11990                                 CHECK_OPSIZE (6);
11991                                 token = read32 (ip + 2);
11992
11993                                 ptr = mono_method_get_wrapper_data (method, token);
11994                                 callinfo = mono_find_jit_icall_by_addr (ptr);
11995                                 g_assert (callinfo);
11996                                 EMIT_NEW_JIT_ICALL_ADDRCONST (cfg, ins, (char*)callinfo->name);
11997                                 *sp++ = ins;
11998                                 ip += 6;
11999                                 inline_costs += 10 * num_calls++;
12000                                 break;
12001                         }
12002                         case CEE_MONO_ICALL_ADDR: {
12003                                 MonoMethod *cmethod;
12004                                 gpointer ptr;
12005
12006                                 CHECK_STACK_OVF (1);
12007                                 CHECK_OPSIZE (6);
12008                                 token = read32 (ip + 2);
12009
12010                                 cmethod = mono_method_get_wrapper_data (method, token);
12011
12012                                 if (cfg->compile_aot) {
12013                                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_ICALL_ADDR, cmethod);
12014                                 } else {
12015                                         ptr = mono_lookup_internal_call (cmethod);
12016                                         g_assert (ptr);
12017                                         EMIT_NEW_PCONST (cfg, ins, ptr);
12018                                 }
12019                                 *sp++ = ins;
12020                                 ip += 6;
12021                                 break;
12022                         }
12023                         case CEE_MONO_VTADDR: {
12024                                 MonoInst *src_var, *src;
12025
12026                                 CHECK_STACK (1);
12027                                 --sp;
12028
12029                                 // FIXME:
12030                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
12031                                 EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
12032                                 *sp++ = src;
12033                                 ip += 2;
12034                                 break;
12035                         }
12036                         case CEE_MONO_NEWOBJ: {
12037                                 MonoInst *iargs [2];
12038
12039                                 CHECK_STACK_OVF (1);
12040                                 CHECK_OPSIZE (6);
12041                                 token = read32 (ip + 2);
12042                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12043                                 mono_class_init (klass);
12044                                 NEW_DOMAINCONST (cfg, iargs [0]);
12045                                 MONO_ADD_INS (cfg->cbb, iargs [0]);
12046                                 NEW_CLASSCONST (cfg, iargs [1], klass);
12047                                 MONO_ADD_INS (cfg->cbb, iargs [1]);
12048                                 *sp++ = mono_emit_jit_icall (cfg, mono_object_new, iargs);
12049                                 ip += 6;
12050                                 inline_costs += 10 * num_calls++;
12051                                 break;
12052                         }
12053                         case CEE_MONO_OBJADDR:
12054                                 CHECK_STACK (1);
12055                                 --sp;
12056                                 MONO_INST_NEW (cfg, ins, OP_MOVE);
12057                                 ins->dreg = alloc_ireg_mp (cfg);
12058                                 ins->sreg1 = sp [0]->dreg;
12059                                 ins->type = STACK_MP;
12060                                 MONO_ADD_INS (cfg->cbb, ins);
12061                                 *sp++ = ins;
12062                                 ip += 2;
12063                                 break;
12064                         case CEE_MONO_LDNATIVEOBJ:
12065                                 /*
12066                                  * Similar to LDOBJ, but instead load the unmanaged 
12067                                  * representation of the vtype to the stack.
12068                                  */
12069                                 CHECK_STACK (1);
12070                                 CHECK_OPSIZE (6);
12071                                 --sp;
12072                                 token = read32 (ip + 2);
12073                                 klass = mono_method_get_wrapper_data (method, token);
12074                                 g_assert (klass->valuetype);
12075                                 mono_class_init (klass);
12076
12077                                 {
12078                                         MonoInst *src, *dest, *temp;
12079
12080                                         src = sp [0];
12081                                         temp = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
12082                                         temp->backend.is_pinvoke = 1;
12083                                         EMIT_NEW_TEMPLOADA (cfg, dest, temp->inst_c0);
12084                                         mini_emit_stobj (cfg, dest, src, klass, TRUE);
12085
12086                                         EMIT_NEW_TEMPLOAD (cfg, dest, temp->inst_c0);
12087                                         dest->type = STACK_VTYPE;
12088                                         dest->klass = klass;
12089
12090                                         *sp ++ = dest;
12091                                         ip += 6;
12092                                 }
12093                                 break;
12094                         case CEE_MONO_RETOBJ: {
12095                                 /*
12096                                  * Same as RET, but return the native representation of a vtype
12097                                  * to the caller.
12098                                  */
12099                                 g_assert (cfg->ret);
12100                                 g_assert (mono_method_signature (method)->pinvoke); 
12101                                 CHECK_STACK (1);
12102                                 --sp;
12103                                 
12104                                 CHECK_OPSIZE (6);
12105                                 token = read32 (ip + 2);    
12106                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12107
12108                                 if (!cfg->vret_addr) {
12109                                         g_assert (cfg->ret_var_is_local);
12110
12111                                         EMIT_NEW_VARLOADA (cfg, ins, cfg->ret, cfg->ret->inst_vtype);
12112                                 } else {
12113                                         EMIT_NEW_RETLOADA (cfg, ins);
12114                                 }
12115                                 mini_emit_stobj (cfg, ins, sp [0], klass, TRUE);
12116                                 
12117                                 if (sp != stack_start)
12118                                         UNVERIFIED;
12119                                 
12120                                 MONO_INST_NEW (cfg, ins, OP_BR);
12121                                 ins->inst_target_bb = end_bblock;
12122                                 MONO_ADD_INS (cfg->cbb, ins);
12123                                 link_bblock (cfg, cfg->cbb, end_bblock);
12124                                 start_new_bblock = 1;
12125                                 ip += 6;
12126                                 break;
12127                         }
12128                         case CEE_MONO_CISINST:
12129                         case CEE_MONO_CCASTCLASS: {
12130                                 int token;
12131                                 CHECK_STACK (1);
12132                                 --sp;
12133                                 CHECK_OPSIZE (6);
12134                                 token = read32 (ip + 2);
12135                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12136                                 if (ip [1] == CEE_MONO_CISINST)
12137                                         ins = handle_cisinst (cfg, klass, sp [0]);
12138                                 else
12139                                         ins = handle_ccastclass (cfg, klass, sp [0]);
12140                                 *sp++ = ins;
12141                                 ip += 6;
12142                                 break;
12143                         }
12144                         case CEE_MONO_SAVE_LMF:
12145                         case CEE_MONO_RESTORE_LMF:
12146                                 ip += 2;
12147                                 break;
12148                         case CEE_MONO_CLASSCONST:
12149                                 CHECK_STACK_OVF (1);
12150                                 CHECK_OPSIZE (6);
12151                                 token = read32 (ip + 2);
12152                                 EMIT_NEW_CLASSCONST (cfg, ins, mono_method_get_wrapper_data (method, token));
12153                                 *sp++ = ins;
12154                                 ip += 6;
12155                                 inline_costs += 10 * num_calls++;
12156                                 break;
12157                         case CEE_MONO_NOT_TAKEN:
12158                                 cfg->cbb->out_of_line = TRUE;
12159                                 ip += 2;
12160                                 break;
12161                         case CEE_MONO_TLS: {
12162                                 int key;
12163
12164                                 CHECK_STACK_OVF (1);
12165                                 CHECK_OPSIZE (6);
12166                                 key = (gint32)read32 (ip + 2);
12167                                 g_assert (key < TLS_KEY_NUM);
12168
12169                                 ins = mono_create_tls_get (cfg, key);
12170                                 if (!ins) {
12171                                         if (cfg->compile_aot) {
12172                                                 DISABLE_AOT (cfg);
12173                                                 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
12174                                                 ins->dreg = alloc_preg (cfg);
12175                                                 ins->type = STACK_PTR;
12176                                         } else {
12177                                                 g_assert_not_reached ();
12178                                         }
12179                                 }
12180                                 ins->type = STACK_PTR;
12181                                 MONO_ADD_INS (cfg->cbb, ins);
12182                                 *sp++ = ins;
12183                                 ip += 6;
12184                                 break;
12185                         }
12186                         case CEE_MONO_DYN_CALL: {
12187                                 MonoCallInst *call;
12188
12189                                 /* It would be easier to call a trampoline, but that would put an
12190                                  * extra frame on the stack, confusing exception handling. So
12191                                  * implement it inline using an opcode for now.
12192                                  */
12193
12194                                 if (!cfg->dyn_call_var) {
12195                                         cfg->dyn_call_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
12196                                         /* prevent it from being register allocated */
12197                                         cfg->dyn_call_var->flags |= MONO_INST_VOLATILE;
12198                                 }
12199
12200                                 /* Has to use a call inst since it local regalloc expects it */
12201                                 MONO_INST_NEW_CALL (cfg, call, OP_DYN_CALL);
12202                                 ins = (MonoInst*)call;
12203                                 sp -= 2;
12204                                 ins->sreg1 = sp [0]->dreg;
12205                                 ins->sreg2 = sp [1]->dreg;
12206                                 MONO_ADD_INS (cfg->cbb, ins);
12207
12208                                 cfg->param_area = MAX (cfg->param_area, MONO_ARCH_DYN_CALL_PARAM_AREA);
12209
12210                                 ip += 2;
12211                                 inline_costs += 10 * num_calls++;
12212
12213                                 break;
12214                         }
12215                         case CEE_MONO_MEMORY_BARRIER: {
12216                                 CHECK_OPSIZE (6);
12217                                 emit_memory_barrier (cfg, (int)read32 (ip + 2));
12218                                 ip += 6;
12219                                 break;
12220                         }
12221                         case CEE_MONO_JIT_ATTACH: {
12222                                 MonoInst *args [16], *domain_ins;
12223                                 MonoInst *ad_ins, *jit_tls_ins;
12224                                 MonoBasicBlock *next_bb = NULL, *call_bb = NULL;
12225
12226                                 cfg->orig_domain_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
12227
12228                                 EMIT_NEW_PCONST (cfg, ins, NULL);
12229                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
12230
12231                                 ad_ins = mono_get_domain_intrinsic (cfg);
12232                                 jit_tls_ins = mono_get_jit_tls_intrinsic (cfg);
12233
12234                                 if (MONO_ARCH_HAVE_TLS_GET && ad_ins && jit_tls_ins) {
12235                                         NEW_BBLOCK (cfg, next_bb);
12236                                         NEW_BBLOCK (cfg, call_bb);
12237
12238                                         if (cfg->compile_aot) {
12239                                                 /* AOT code is only used in the root domain */
12240                                                 EMIT_NEW_PCONST (cfg, domain_ins, NULL);
12241                                         } else {
12242                                                 EMIT_NEW_PCONST (cfg, domain_ins, cfg->domain);
12243                                         }
12244                                         MONO_ADD_INS (cfg->cbb, ad_ins);
12245                                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, ad_ins->dreg, domain_ins->dreg);
12246                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, call_bb);
12247
12248                                         MONO_ADD_INS (cfg->cbb, jit_tls_ins);
12249                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, jit_tls_ins->dreg, 0);
12250                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, call_bb);
12251
12252                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, next_bb);
12253                                         MONO_START_BB (cfg, call_bb);
12254                                 }
12255
12256                                 if (cfg->compile_aot) {
12257                                         /* AOT code is only used in the root domain */
12258                                         EMIT_NEW_PCONST (cfg, args [0], NULL);
12259                                 } else {
12260                                         EMIT_NEW_PCONST (cfg, args [0], cfg->domain);
12261                                 }
12262                                 ins = mono_emit_jit_icall (cfg, mono_jit_thread_attach, args);
12263                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
12264
12265                                 if (next_bb)
12266                                         MONO_START_BB (cfg, next_bb);
12267                                 ip += 2;
12268                                 break;
12269                         }
12270                         case CEE_MONO_JIT_DETACH: {
12271                                 MonoInst *args [16];
12272
12273                                 /* Restore the original domain */
12274                                 dreg = alloc_ireg (cfg);
12275                                 EMIT_NEW_UNALU (cfg, args [0], OP_MOVE, dreg, cfg->orig_domain_var->dreg);
12276                                 mono_emit_jit_icall (cfg, mono_jit_set_domain, args);
12277                                 ip += 2;
12278                                 break;
12279                         }
12280                         default:
12281                                 g_error ("opcode 0x%02x 0x%02x not handled", MONO_CUSTOM_PREFIX, ip [1]);
12282                                 break;
12283                         }
12284                         break;
12285                 }
12286
12287                 case CEE_PREFIX1: {
12288                         CHECK_OPSIZE (2);
12289                         switch (ip [1]) {
12290                         case CEE_ARGLIST: {
12291                                 /* somewhat similar to LDTOKEN */
12292                                 MonoInst *addr, *vtvar;
12293                                 CHECK_STACK_OVF (1);
12294                                 vtvar = mono_compile_create_var (cfg, &mono_defaults.argumenthandle_class->byval_arg, OP_LOCAL); 
12295
12296                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
12297                                 EMIT_NEW_UNALU (cfg, ins, OP_ARGLIST, -1, addr->dreg);
12298
12299                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
12300                                 ins->type = STACK_VTYPE;
12301                                 ins->klass = mono_defaults.argumenthandle_class;
12302                                 *sp++ = ins;
12303                                 ip += 2;
12304                                 break;
12305                         }
12306                         case CEE_CEQ:
12307                         case CEE_CGT:
12308                         case CEE_CGT_UN:
12309                         case CEE_CLT:
12310                         case CEE_CLT_UN: {
12311                                 MonoInst *cmp, *arg1, *arg2;
12312
12313                                 CHECK_STACK (2);
12314                                 sp -= 2;
12315                                 arg1 = sp [0];
12316                                 arg2 = sp [1];
12317
12318                                 /*
12319                                  * The following transforms:
12320                                  *    CEE_CEQ    into OP_CEQ
12321                                  *    CEE_CGT    into OP_CGT
12322                                  *    CEE_CGT_UN into OP_CGT_UN
12323                                  *    CEE_CLT    into OP_CLT
12324                                  *    CEE_CLT_UN into OP_CLT_UN
12325                                  */
12326                                 MONO_INST_NEW (cfg, cmp, (OP_CEQ - CEE_CEQ) + ip [1]);
12327
12328                                 MONO_INST_NEW (cfg, ins, cmp->opcode);
12329                                 cmp->sreg1 = arg1->dreg;
12330                                 cmp->sreg2 = arg2->dreg;
12331                                 type_from_op (cfg, cmp, arg1, arg2);
12332                                 CHECK_TYPE (cmp);
12333                                 add_widen_op (cfg, cmp, &arg1, &arg2);
12334                                 if ((arg1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((arg1->type == STACK_PTR) || (arg1->type == STACK_OBJ) || (arg1->type == STACK_MP))))
12335                                         cmp->opcode = OP_LCOMPARE;
12336                                 else if (arg1->type == STACK_R4)
12337                                         cmp->opcode = OP_RCOMPARE;
12338                                 else if (arg1->type == STACK_R8)
12339                                         cmp->opcode = OP_FCOMPARE;
12340                                 else
12341                                         cmp->opcode = OP_ICOMPARE;
12342                                 MONO_ADD_INS (cfg->cbb, cmp);
12343                                 ins->type = STACK_I4;
12344                                 ins->dreg = alloc_dreg (cfg, ins->type);
12345                                 type_from_op (cfg, ins, arg1, arg2);
12346
12347                                 if (cmp->opcode == OP_FCOMPARE || cmp->opcode == OP_RCOMPARE) {
12348                                         /*
12349                                          * The backends expect the fceq opcodes to do the
12350                                          * comparison too.
12351                                          */
12352                                         ins->sreg1 = cmp->sreg1;
12353                                         ins->sreg2 = cmp->sreg2;
12354                                         NULLIFY_INS (cmp);
12355                                 }
12356                                 MONO_ADD_INS (cfg->cbb, ins);
12357                                 *sp++ = ins;
12358                                 ip += 2;
12359                                 break;
12360                         }
12361                         case CEE_LDFTN: {
12362                                 MonoInst *argconst;
12363                                 MonoMethod *cil_method;
12364
12365                                 CHECK_STACK_OVF (1);
12366                                 CHECK_OPSIZE (6);
12367                                 n = read32 (ip + 2);
12368                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
12369                                 if (!cmethod || mono_loader_get_last_error ())
12370                                         LOAD_ERROR;
12371                                 mono_class_init (cmethod->klass);
12372
12373                                 mono_save_token_info (cfg, image, n, cmethod);
12374
12375                                 context_used = mini_method_check_context_used (cfg, cmethod);
12376
12377                                 cil_method = cmethod;
12378                                 if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_method (method, cmethod))
12379                                         METHOD_ACCESS_FAILURE (method, cil_method);
12380
12381                                 if (mono_security_core_clr_enabled ())
12382                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
12383
12384                                 /* 
12385                                  * Optimize the common case of ldftn+delegate creation
12386                                  */
12387                                 if ((sp > stack_start) && (ip + 6 + 5 < end) && ip_in_bb (cfg, cfg->cbb, ip + 6) && (ip [6] == CEE_NEWOBJ)) {
12388                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
12389                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
12390                                                 MonoInst *target_ins, *handle_ins;
12391                                                 MonoMethod *invoke;
12392                                                 int invoke_context_used;
12393
12394                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
12395                                                 if (!invoke || !mono_method_signature (invoke))
12396                                                         LOAD_ERROR;
12397
12398                                                 invoke_context_used = mini_method_check_context_used (cfg, invoke);
12399
12400                                                 target_ins = sp [-1];
12401
12402                                                 if (mono_security_core_clr_enabled ())
12403                                                         ensure_method_is_allowed_to_call_method (cfg, method, ctor_method);
12404
12405                                                 if (!(cmethod->flags & METHOD_ATTRIBUTE_STATIC)) {
12406                                                         /*LAME IMPL: We must not add a null check for virtual invoke delegates.*/
12407                                                         if (mono_method_signature (invoke)->param_count == mono_method_signature (cmethod)->param_count) {
12408                                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, target_ins->dreg, 0);
12409                                                                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "ArgumentException");
12410                                                         }
12411                                                 }
12412
12413                                                 /* FIXME: SGEN support */
12414                                                 if (invoke_context_used == 0) {
12415                                                         ip += 6;
12416                                                         if (cfg->verbose_level > 3)
12417                                                                 g_print ("converting (in B%d: stack: %d) %s", cfg->cbb->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
12418                                                         if ((handle_ins = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used, FALSE))) {
12419                                                                 sp --;
12420                                                                 *sp = handle_ins;
12421                                                                 CHECK_CFG_EXCEPTION;
12422                                                                 ip += 5;
12423                                                                 sp ++;
12424                                                                 break;
12425                                                         }
12426                                                         ip -= 6;
12427                                                 }
12428                                         }
12429                                 }
12430
12431                                 argconst = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD);
12432                                 ins = mono_emit_jit_icall (cfg, mono_ldftn, &argconst);
12433                                 *sp++ = ins;
12434                                 
12435                                 ip += 6;
12436                                 inline_costs += 10 * num_calls++;
12437                                 break;
12438                         }
12439                         case CEE_LDVIRTFTN: {
12440                                 MonoInst *args [2];
12441
12442                                 CHECK_STACK (1);
12443                                 CHECK_OPSIZE (6);
12444                                 n = read32 (ip + 2);
12445                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
12446                                 if (!cmethod || mono_loader_get_last_error ())
12447                                         LOAD_ERROR;
12448                                 mono_class_init (cmethod->klass);
12449  
12450                                 context_used = mini_method_check_context_used (cfg, cmethod);
12451
12452                                 if (mono_security_core_clr_enabled ())
12453                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
12454
12455                                 /*
12456                                  * Optimize the common case of ldvirtftn+delegate creation
12457                                  */
12458                                 if ((sp > stack_start) && (ip + 6 + 5 < end) && ip_in_bb (cfg, cfg->cbb, ip + 6) && (ip [6] == CEE_NEWOBJ) && (ip > header->code && ip [-1] == CEE_DUP)) {
12459                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
12460                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
12461                                                 MonoInst *target_ins, *handle_ins;
12462                                                 MonoMethod *invoke;
12463                                                 int invoke_context_used;
12464                                                 gboolean is_virtual = cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL;
12465
12466                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
12467                                                 if (!invoke || !mono_method_signature (invoke))
12468                                                         LOAD_ERROR;
12469
12470                                                 invoke_context_used = mini_method_check_context_used (cfg, invoke);
12471
12472                                                 target_ins = sp [-1];
12473
12474                                                 if (mono_security_core_clr_enabled ())
12475                                                         ensure_method_is_allowed_to_call_method (cfg, method, ctor_method);
12476
12477                                                 /* FIXME: SGEN support */
12478                                                 if (invoke_context_used == 0) {
12479                                                         ip += 6;
12480                                                         if (cfg->verbose_level > 3)
12481                                                                 g_print ("converting (in B%d: stack: %d) %s", cfg->cbb->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
12482                                                         if ((handle_ins = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used, is_virtual))) {
12483                                                                 sp -= 2;
12484                                                                 *sp = handle_ins;
12485                                                                 CHECK_CFG_EXCEPTION;
12486                                                                 ip += 5;
12487                                                                 sp ++;
12488                                                                 break;
12489                                                         }
12490                                                         ip -= 6;
12491                                                 }
12492                                         }
12493                                 }
12494
12495                                 --sp;
12496                                 args [0] = *sp;
12497
12498                                 args [1] = emit_get_rgctx_method (cfg, context_used,
12499                                                                                                   cmethod, MONO_RGCTX_INFO_METHOD);
12500
12501                                 if (context_used)
12502                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn_gshared, args);
12503                                 else
12504                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn, args);
12505
12506                                 ip += 6;
12507                                 inline_costs += 10 * num_calls++;
12508                                 break;
12509                         }
12510                         case CEE_LDARG:
12511                                 CHECK_STACK_OVF (1);
12512                                 CHECK_OPSIZE (4);
12513                                 n = read16 (ip + 2);
12514                                 CHECK_ARG (n);
12515                                 EMIT_NEW_ARGLOAD (cfg, ins, n);
12516                                 *sp++ = ins;
12517                                 ip += 4;
12518                                 break;
12519                         case CEE_LDARGA:
12520                                 CHECK_STACK_OVF (1);
12521                                 CHECK_OPSIZE (4);
12522                                 n = read16 (ip + 2);
12523                                 CHECK_ARG (n);
12524                                 NEW_ARGLOADA (cfg, ins, n);
12525                                 MONO_ADD_INS (cfg->cbb, ins);
12526                                 *sp++ = ins;
12527                                 ip += 4;
12528                                 break;
12529                         case CEE_STARG:
12530                                 CHECK_STACK (1);
12531                                 --sp;
12532                                 CHECK_OPSIZE (4);
12533                                 n = read16 (ip + 2);
12534                                 CHECK_ARG (n);
12535                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [n], *sp))
12536                                         UNVERIFIED;
12537                                 EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
12538                                 ip += 4;
12539                                 break;
12540                         case CEE_LDLOC:
12541                                 CHECK_STACK_OVF (1);
12542                                 CHECK_OPSIZE (4);
12543                                 n = read16 (ip + 2);
12544                                 CHECK_LOCAL (n);
12545                                 EMIT_NEW_LOCLOAD (cfg, ins, n);
12546                                 *sp++ = ins;
12547                                 ip += 4;
12548                                 break;
12549                         case CEE_LDLOCA: {
12550                                 unsigned char *tmp_ip;
12551                                 CHECK_STACK_OVF (1);
12552                                 CHECK_OPSIZE (4);
12553                                 n = read16 (ip + 2);
12554                                 CHECK_LOCAL (n);
12555
12556                                 if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 2))) {
12557                                         ip = tmp_ip;
12558                                         inline_costs += 1;
12559                                         break;
12560                                 }                       
12561                                 
12562                                 EMIT_NEW_LOCLOADA (cfg, ins, n);
12563                                 *sp++ = ins;
12564                                 ip += 4;
12565                                 break;
12566                         }
12567                         case CEE_STLOC:
12568                                 CHECK_STACK (1);
12569                                 --sp;
12570                                 CHECK_OPSIZE (4);
12571                                 n = read16 (ip + 2);
12572                                 CHECK_LOCAL (n);
12573                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
12574                                         UNVERIFIED;
12575                                 emit_stloc_ir (cfg, sp, header, n);
12576                                 ip += 4;
12577                                 inline_costs += 1;
12578                                 break;
12579                         case CEE_LOCALLOC:
12580                                 CHECK_STACK (1);
12581                                 --sp;
12582                                 if (sp != stack_start) 
12583                                         UNVERIFIED;
12584                                 if (cfg->method != method) 
12585                                         /* 
12586                                          * Inlining this into a loop in a parent could lead to 
12587                                          * stack overflows which is different behavior than the
12588                                          * non-inlined case, thus disable inlining in this case.
12589                                          */
12590                                         INLINE_FAILURE("localloc");
12591
12592                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
12593                                 ins->dreg = alloc_preg (cfg);
12594                                 ins->sreg1 = sp [0]->dreg;
12595                                 ins->type = STACK_PTR;
12596                                 MONO_ADD_INS (cfg->cbb, ins);
12597
12598                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
12599                                 if (init_locals)
12600                                         ins->flags |= MONO_INST_INIT;
12601
12602                                 *sp++ = ins;
12603                                 ip += 2;
12604                                 break;
12605                         case CEE_ENDFILTER: {
12606                                 MonoExceptionClause *clause, *nearest;
12607                                 int cc;
12608
12609                                 CHECK_STACK (1);
12610                                 --sp;
12611                                 if ((sp != stack_start) || (sp [0]->type != STACK_I4)) 
12612                                         UNVERIFIED;
12613                                 MONO_INST_NEW (cfg, ins, OP_ENDFILTER);
12614                                 ins->sreg1 = (*sp)->dreg;
12615                                 MONO_ADD_INS (cfg->cbb, ins);
12616                                 start_new_bblock = 1;
12617                                 ip += 2;
12618
12619                                 nearest = NULL;
12620                                 for (cc = 0; cc < header->num_clauses; ++cc) {
12621                                         clause = &header->clauses [cc];
12622                                         if ((clause->flags & MONO_EXCEPTION_CLAUSE_FILTER) &&
12623                                                 ((ip - header->code) > clause->data.filter_offset && (ip - header->code) <= clause->handler_offset) &&
12624                                             (!nearest || (clause->data.filter_offset < nearest->data.filter_offset)))
12625                                                 nearest = clause;
12626                                 }
12627                                 g_assert (nearest);
12628                                 if ((ip - header->code) != nearest->handler_offset)
12629                                         UNVERIFIED;
12630
12631                                 break;
12632                         }
12633                         case CEE_UNALIGNED_:
12634                                 ins_flag |= MONO_INST_UNALIGNED;
12635                                 /* FIXME: record alignment? we can assume 1 for now */
12636                                 CHECK_OPSIZE (3);
12637                                 ip += 3;
12638                                 break;
12639                         case CEE_VOLATILE_:
12640                                 ins_flag |= MONO_INST_VOLATILE;
12641                                 ip += 2;
12642                                 break;
12643                         case CEE_TAIL_:
12644                                 ins_flag   |= MONO_INST_TAILCALL;
12645                                 cfg->flags |= MONO_CFG_HAS_TAIL;
12646                                 /* Can't inline tail calls at this time */
12647                                 inline_costs += 100000;
12648                                 ip += 2;
12649                                 break;
12650                         case CEE_INITOBJ:
12651                                 CHECK_STACK (1);
12652                                 --sp;
12653                                 CHECK_OPSIZE (6);
12654                                 token = read32 (ip + 2);
12655                                 klass = mini_get_class (method, token, generic_context);
12656                                 CHECK_TYPELOAD (klass);
12657                                 if (generic_class_is_reference_type (cfg, klass))
12658                                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, sp [0]->dreg, 0, 0);
12659                                 else
12660                                         mini_emit_initobj (cfg, *sp, NULL, klass);
12661                                 ip += 6;
12662                                 inline_costs += 1;
12663                                 break;
12664                         case CEE_CONSTRAINED_:
12665                                 CHECK_OPSIZE (6);
12666                                 token = read32 (ip + 2);
12667                                 constrained_class = mini_get_class (method, token, generic_context);
12668                                 CHECK_TYPELOAD (constrained_class);
12669                                 ip += 6;
12670                                 break;
12671                         case CEE_CPBLK:
12672                         case CEE_INITBLK: {
12673                                 MonoInst *iargs [3];
12674                                 CHECK_STACK (3);
12675                                 sp -= 3;
12676
12677                                 /* Skip optimized paths for volatile operations. */
12678                                 if ((ip [1] == CEE_CPBLK) && !(ins_flag & MONO_INST_VOLATILE) && (cfg->opt & MONO_OPT_INTRINS) && (sp [2]->opcode == OP_ICONST) && ((n = sp [2]->inst_c0) <= sizeof (gpointer) * 5)) {
12679                                         mini_emit_memcpy (cfg, sp [0]->dreg, 0, sp [1]->dreg, 0, sp [2]->inst_c0, 0);
12680                                 } else if ((ip [1] == CEE_INITBLK) && !(ins_flag & MONO_INST_VOLATILE) && (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)) {
12681                                         /* emit_memset only works when val == 0 */
12682                                         mini_emit_memset (cfg, sp [0]->dreg, 0, sp [2]->inst_c0, sp [1]->inst_c0, 0);
12683                                 } else {
12684                                         MonoInst *call;
12685                                         iargs [0] = sp [0];
12686                                         iargs [1] = sp [1];
12687                                         iargs [2] = sp [2];
12688                                         if (ip [1] == CEE_CPBLK) {
12689                                                 /*
12690                                                  * FIXME: It's unclear whether we should be emitting both the acquire
12691                                                  * and release barriers for cpblk. It is technically both a load and
12692                                                  * store operation, so it seems like that's the sensible thing to do.
12693                                                  *
12694                                                  * FIXME: We emit full barriers on both sides of the operation for
12695                                                  * simplicity. We should have a separate atomic memcpy method instead.
12696                                                  */
12697                                                 MonoMethod *memcpy_method = get_memcpy_method ();
12698
12699                                                 if (ins_flag & MONO_INST_VOLATILE)
12700                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
12701
12702                                                 call = mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
12703                                                 call->flags |= ins_flag;
12704
12705                                                 if (ins_flag & MONO_INST_VOLATILE)
12706                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
12707                                         } else {
12708                                                 MonoMethod *memset_method = get_memset_method ();
12709                                                 if (ins_flag & MONO_INST_VOLATILE) {
12710                                                         /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
12711                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
12712                                                 }
12713                                                 call = mono_emit_method_call (cfg, memset_method, iargs, NULL);
12714                                                 call->flags |= ins_flag;
12715                                         }
12716                                 }
12717                                 ip += 2;
12718                                 ins_flag = 0;
12719                                 inline_costs += 1;
12720                                 break;
12721                         }
12722                         case CEE_NO_:
12723                                 CHECK_OPSIZE (3);
12724                                 if (ip [2] & 0x1)
12725                                         ins_flag |= MONO_INST_NOTYPECHECK;
12726                                 if (ip [2] & 0x2)
12727                                         ins_flag |= MONO_INST_NORANGECHECK;
12728                                 /* we ignore the no-nullcheck for now since we
12729                                  * really do it explicitly only when doing callvirt->call
12730                                  */
12731                                 ip += 3;
12732                                 break;
12733                         case CEE_RETHROW: {
12734                                 MonoInst *load;
12735                                 int handler_offset = -1;
12736
12737                                 for (i = 0; i < header->num_clauses; ++i) {
12738                                         MonoExceptionClause *clause = &header->clauses [i];
12739                                         if (MONO_OFFSET_IN_HANDLER (clause, ip - header->code) && !(clause->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
12740                                                 handler_offset = clause->handler_offset;
12741                                                 break;
12742                                         }
12743                                 }
12744
12745                                 cfg->cbb->flags |= BB_EXCEPTION_UNSAFE;
12746
12747                                 if (handler_offset == -1)
12748                                         UNVERIFIED;
12749
12750                                 EMIT_NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, handler_offset)->inst_c0);
12751                                 MONO_INST_NEW (cfg, ins, OP_RETHROW);
12752                                 ins->sreg1 = load->dreg;
12753                                 MONO_ADD_INS (cfg->cbb, ins);
12754
12755                                 MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
12756                                 MONO_ADD_INS (cfg->cbb, ins);
12757
12758                                 sp = stack_start;
12759                                 link_bblock (cfg, cfg->cbb, end_bblock);
12760                                 start_new_bblock = 1;
12761                                 ip += 2;
12762                                 break;
12763                         }
12764                         case CEE_SIZEOF: {
12765                                 guint32 val;
12766                                 int ialign;
12767
12768                                 CHECK_STACK_OVF (1);
12769                                 CHECK_OPSIZE (6);
12770                                 token = read32 (ip + 2);
12771                                 if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC && !image_is_dynamic (method->klass->image) && !generic_context) {
12772                                         MonoType *type = mono_type_create_from_typespec_checked (image, token, &cfg->error);
12773                                         CHECK_CFG_ERROR;
12774
12775                                         val = mono_type_size (type, &ialign);
12776                                 } else {
12777                                         MonoClass *klass = mini_get_class (method, token, generic_context);
12778                                         CHECK_TYPELOAD (klass);
12779
12780                                         val = mono_type_size (&klass->byval_arg, &ialign);
12781
12782                                         if (mini_is_gsharedvt_klass (klass))
12783                                                 GSHAREDVT_FAILURE (*ip);
12784                                 }
12785                                 EMIT_NEW_ICONST (cfg, ins, val);
12786                                 *sp++= ins;
12787                                 ip += 6;
12788                                 break;
12789                         }
12790                         case CEE_REFANYTYPE: {
12791                                 MonoInst *src_var, *src;
12792
12793                                 GSHAREDVT_FAILURE (*ip);
12794
12795                                 CHECK_STACK (1);
12796                                 --sp;
12797
12798                                 // FIXME:
12799                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
12800                                 if (!src_var)
12801                                         src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
12802                                 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
12803                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &mono_defaults.typehandle_class->byval_arg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type));
12804                                 *sp++ = ins;
12805                                 ip += 2;
12806                                 break;
12807                         }
12808                         case CEE_READONLY_:
12809                                 readonly = TRUE;
12810                                 ip += 2;
12811                                 break;
12812
12813                         case CEE_UNUSED56:
12814                         case CEE_UNUSED57:
12815                         case CEE_UNUSED70:
12816                         case CEE_UNUSED:
12817                         case CEE_UNUSED99:
12818                                 UNVERIFIED;
12819                                 
12820                         default:
12821                                 g_warning ("opcode 0xfe 0x%02x not handled", ip [1]);
12822                                 UNVERIFIED;
12823                         }
12824                         break;
12825                 }
12826                 case CEE_UNUSED58:
12827                 case CEE_UNUSED1:
12828                         UNVERIFIED;
12829
12830                 default:
12831                         g_warning ("opcode 0x%02x not handled", *ip);
12832                         UNVERIFIED;
12833                 }
12834         }
12835         if (start_new_bblock != 1)
12836                 UNVERIFIED;
12837
12838         cfg->cbb->cil_length = ip - cfg->cbb->cil_code;
12839         if (cfg->cbb->next_bb) {
12840                 /* This could already be set because of inlining, #693905 */
12841                 MonoBasicBlock *bb = cfg->cbb;
12842
12843                 while (bb->next_bb)
12844                         bb = bb->next_bb;
12845                 bb->next_bb = end_bblock;
12846         } else {
12847                 cfg->cbb->next_bb = end_bblock;
12848         }
12849
12850         if (cfg->method == method && cfg->domainvar) {
12851                 MonoInst *store;
12852                 MonoInst *get_domain;
12853
12854                 cfg->cbb = init_localsbb;
12855
12856                 if ((get_domain = mono_get_domain_intrinsic (cfg))) {
12857                         MONO_ADD_INS (cfg->cbb, get_domain);
12858                 } else {
12859                         get_domain = mono_emit_jit_icall (cfg, mono_domain_get, NULL);
12860                 }
12861                 NEW_TEMPSTORE (cfg, store, cfg->domainvar->inst_c0, get_domain);
12862                 MONO_ADD_INS (cfg->cbb, store);
12863         }
12864
12865 #if defined(TARGET_POWERPC) || defined(TARGET_X86)
12866         if (cfg->compile_aot)
12867                 /* FIXME: The plt slots require a GOT var even if the method doesn't use it */
12868                 mono_get_got_var (cfg);
12869 #endif
12870
12871         if (cfg->method == method && cfg->got_var)
12872                 mono_emit_load_got_addr (cfg);
12873
12874         if (init_localsbb) {
12875                 cfg->cbb = init_localsbb;
12876                 cfg->ip = NULL;
12877                 for (i = 0; i < header->num_locals; ++i) {
12878                         emit_init_local (cfg, i, header->locals [i], init_locals);
12879                 }
12880         }
12881
12882         if (cfg->init_ref_vars && cfg->method == method) {
12883                 /* Emit initialization for ref vars */
12884                 // FIXME: Avoid duplication initialization for IL locals.
12885                 for (i = 0; i < cfg->num_varinfo; ++i) {
12886                         MonoInst *ins = cfg->varinfo [i];
12887
12888                         if (ins->opcode == OP_LOCAL && ins->type == STACK_OBJ)
12889                                 MONO_EMIT_NEW_PCONST (cfg, ins->dreg, NULL);
12890                 }
12891         }
12892
12893         if (cfg->lmf_var && cfg->method == method) {
12894                 cfg->cbb = init_localsbb;
12895                 emit_push_lmf (cfg);
12896         }
12897
12898         cfg->cbb = init_localsbb;
12899         emit_instrumentation_call (cfg, mono_profiler_method_enter);
12900
12901         if (seq_points) {
12902                 MonoBasicBlock *bb;
12903
12904                 /*
12905                  * Make seq points at backward branch targets interruptable.
12906                  */
12907                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
12908                         if (bb->code && bb->in_count > 1 && bb->code->opcode == OP_SEQ_POINT)
12909                                 bb->code->flags |= MONO_INST_SINGLE_STEP_LOC;
12910         }
12911
12912         /* Add a sequence point for method entry/exit events */
12913         if (seq_points && cfg->gen_sdb_seq_points) {
12914                 NEW_SEQ_POINT (cfg, ins, METHOD_ENTRY_IL_OFFSET, FALSE);
12915                 MONO_ADD_INS (init_localsbb, ins);
12916                 NEW_SEQ_POINT (cfg, ins, METHOD_EXIT_IL_OFFSET, FALSE);
12917                 MONO_ADD_INS (cfg->bb_exit, ins);
12918         }
12919
12920         /*
12921          * Add seq points for IL offsets which have line number info, but wasn't generated a seq point during JITting because
12922          * the code they refer to was dead (#11880).
12923          */
12924         if (sym_seq_points) {
12925                 for (i = 0; i < header->code_size; ++i) {
12926                         if (mono_bitset_test_fast (seq_point_locs, i) && !mono_bitset_test_fast (seq_point_set_locs, i)) {
12927                                 MonoInst *ins;
12928
12929                                 NEW_SEQ_POINT (cfg, ins, i, FALSE);
12930                                 mono_add_seq_point (cfg, NULL, ins, SEQ_POINT_NATIVE_OFFSET_DEAD_CODE);
12931                         }
12932                 }
12933         }
12934
12935         cfg->ip = NULL;
12936
12937         if (cfg->method == method) {
12938                 MonoBasicBlock *bb;
12939                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
12940                         bb->region = mono_find_block_region (cfg, bb->real_offset);
12941                         if (cfg->spvars)
12942                                 mono_create_spvar_for_region (cfg, bb->region);
12943                         if (cfg->verbose_level > 2)
12944                                 printf ("REGION BB%d IL_%04x ID_%08X\n", bb->block_num, bb->real_offset, bb->region);
12945                 }
12946         }
12947
12948         if (inline_costs < 0) {
12949                 char *mname;
12950
12951                 /* Method is too large */
12952                 mname = mono_method_full_name (method, TRUE);
12953                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
12954                 cfg->exception_message = g_strdup_printf ("Method %s is too complex.", mname);
12955                 g_free (mname);
12956         }
12957
12958         if ((cfg->verbose_level > 2) && (cfg->method == method)) 
12959                 mono_print_code (cfg, "AFTER METHOD-TO-IR");
12960
12961         goto cleanup;
12962
12963 mono_error_exit:
12964         g_assert (!mono_error_ok (&cfg->error));
12965         goto cleanup;
12966  
12967  exception_exit:
12968         g_assert (cfg->exception_type != MONO_EXCEPTION_NONE);
12969         goto cleanup;
12970
12971  unverified:
12972         set_exception_type_from_invalid_il (cfg, method, ip);
12973         goto cleanup;
12974
12975  cleanup:
12976         g_slist_free (class_inits);
12977         mono_basic_block_free (original_bb);
12978         cfg->dont_inline = g_list_remove (cfg->dont_inline, method);
12979         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
12980         if (cfg->exception_type)
12981                 return -1;
12982         else
12983                 return inline_costs;
12984 }
12985
12986 static int
12987 store_membase_reg_to_store_membase_imm (int opcode)
12988 {
12989         switch (opcode) {
12990         case OP_STORE_MEMBASE_REG:
12991                 return OP_STORE_MEMBASE_IMM;
12992         case OP_STOREI1_MEMBASE_REG:
12993                 return OP_STOREI1_MEMBASE_IMM;
12994         case OP_STOREI2_MEMBASE_REG:
12995                 return OP_STOREI2_MEMBASE_IMM;
12996         case OP_STOREI4_MEMBASE_REG:
12997                 return OP_STOREI4_MEMBASE_IMM;
12998         case OP_STOREI8_MEMBASE_REG:
12999                 return OP_STOREI8_MEMBASE_IMM;
13000         default:
13001                 g_assert_not_reached ();
13002         }
13003
13004         return -1;
13005 }               
13006
13007 int
13008 mono_op_to_op_imm (int opcode)
13009 {
13010         switch (opcode) {
13011         case OP_IADD:
13012                 return OP_IADD_IMM;
13013         case OP_ISUB:
13014                 return OP_ISUB_IMM;
13015         case OP_IDIV:
13016                 return OP_IDIV_IMM;
13017         case OP_IDIV_UN:
13018                 return OP_IDIV_UN_IMM;
13019         case OP_IREM:
13020                 return OP_IREM_IMM;
13021         case OP_IREM_UN:
13022                 return OP_IREM_UN_IMM;
13023         case OP_IMUL:
13024                 return OP_IMUL_IMM;
13025         case OP_IAND:
13026                 return OP_IAND_IMM;
13027         case OP_IOR:
13028                 return OP_IOR_IMM;
13029         case OP_IXOR:
13030                 return OP_IXOR_IMM;
13031         case OP_ISHL:
13032                 return OP_ISHL_IMM;
13033         case OP_ISHR:
13034                 return OP_ISHR_IMM;
13035         case OP_ISHR_UN:
13036                 return OP_ISHR_UN_IMM;
13037
13038         case OP_LADD:
13039                 return OP_LADD_IMM;
13040         case OP_LSUB:
13041                 return OP_LSUB_IMM;
13042         case OP_LAND:
13043                 return OP_LAND_IMM;
13044         case OP_LOR:
13045                 return OP_LOR_IMM;
13046         case OP_LXOR:
13047                 return OP_LXOR_IMM;
13048         case OP_LSHL:
13049                 return OP_LSHL_IMM;
13050         case OP_LSHR:
13051                 return OP_LSHR_IMM;
13052         case OP_LSHR_UN:
13053                 return OP_LSHR_UN_IMM;
13054 #if SIZEOF_REGISTER == 8
13055         case OP_LREM:
13056                 return OP_LREM_IMM;
13057 #endif
13058
13059         case OP_COMPARE:
13060                 return OP_COMPARE_IMM;
13061         case OP_ICOMPARE:
13062                 return OP_ICOMPARE_IMM;
13063         case OP_LCOMPARE:
13064                 return OP_LCOMPARE_IMM;
13065
13066         case OP_STORE_MEMBASE_REG:
13067                 return OP_STORE_MEMBASE_IMM;
13068         case OP_STOREI1_MEMBASE_REG:
13069                 return OP_STOREI1_MEMBASE_IMM;
13070         case OP_STOREI2_MEMBASE_REG:
13071                 return OP_STOREI2_MEMBASE_IMM;
13072         case OP_STOREI4_MEMBASE_REG:
13073                 return OP_STOREI4_MEMBASE_IMM;
13074
13075 #if defined(TARGET_X86) || defined (TARGET_AMD64)
13076         case OP_X86_PUSH:
13077                 return OP_X86_PUSH_IMM;
13078         case OP_X86_COMPARE_MEMBASE_REG:
13079                 return OP_X86_COMPARE_MEMBASE_IMM;
13080 #endif
13081 #if defined(TARGET_AMD64)
13082         case OP_AMD64_ICOMPARE_MEMBASE_REG:
13083                 return OP_AMD64_ICOMPARE_MEMBASE_IMM;
13084 #endif
13085         case OP_VOIDCALL_REG:
13086                 return OP_VOIDCALL;
13087         case OP_CALL_REG:
13088                 return OP_CALL;
13089         case OP_LCALL_REG:
13090                 return OP_LCALL;
13091         case OP_FCALL_REG:
13092                 return OP_FCALL;
13093         case OP_LOCALLOC:
13094                 return OP_LOCALLOC_IMM;
13095         }
13096
13097         return -1;
13098 }
13099
13100 static int
13101 ldind_to_load_membase (int opcode)
13102 {
13103         switch (opcode) {
13104         case CEE_LDIND_I1:
13105                 return OP_LOADI1_MEMBASE;
13106         case CEE_LDIND_U1:
13107                 return OP_LOADU1_MEMBASE;
13108         case CEE_LDIND_I2:
13109                 return OP_LOADI2_MEMBASE;
13110         case CEE_LDIND_U2:
13111                 return OP_LOADU2_MEMBASE;
13112         case CEE_LDIND_I4:
13113                 return OP_LOADI4_MEMBASE;
13114         case CEE_LDIND_U4:
13115                 return OP_LOADU4_MEMBASE;
13116         case CEE_LDIND_I:
13117                 return OP_LOAD_MEMBASE;
13118         case CEE_LDIND_REF:
13119                 return OP_LOAD_MEMBASE;
13120         case CEE_LDIND_I8:
13121                 return OP_LOADI8_MEMBASE;
13122         case CEE_LDIND_R4:
13123                 return OP_LOADR4_MEMBASE;
13124         case CEE_LDIND_R8:
13125                 return OP_LOADR8_MEMBASE;
13126         default:
13127                 g_assert_not_reached ();
13128         }
13129
13130         return -1;
13131 }
13132
13133 static int
13134 stind_to_store_membase (int opcode)
13135 {
13136         switch (opcode) {
13137         case CEE_STIND_I1:
13138                 return OP_STOREI1_MEMBASE_REG;
13139         case CEE_STIND_I2:
13140                 return OP_STOREI2_MEMBASE_REG;
13141         case CEE_STIND_I4:
13142                 return OP_STOREI4_MEMBASE_REG;
13143         case CEE_STIND_I:
13144         case CEE_STIND_REF:
13145                 return OP_STORE_MEMBASE_REG;
13146         case CEE_STIND_I8:
13147                 return OP_STOREI8_MEMBASE_REG;
13148         case CEE_STIND_R4:
13149                 return OP_STORER4_MEMBASE_REG;
13150         case CEE_STIND_R8:
13151                 return OP_STORER8_MEMBASE_REG;
13152         default:
13153                 g_assert_not_reached ();
13154         }
13155
13156         return -1;
13157 }
13158
13159 int
13160 mono_load_membase_to_load_mem (int opcode)
13161 {
13162         // FIXME: Add a MONO_ARCH_HAVE_LOAD_MEM macro
13163 #if defined(TARGET_X86) || defined(TARGET_AMD64)
13164         switch (opcode) {
13165         case OP_LOAD_MEMBASE:
13166                 return OP_LOAD_MEM;
13167         case OP_LOADU1_MEMBASE:
13168                 return OP_LOADU1_MEM;
13169         case OP_LOADU2_MEMBASE:
13170                 return OP_LOADU2_MEM;
13171         case OP_LOADI4_MEMBASE:
13172                 return OP_LOADI4_MEM;
13173         case OP_LOADU4_MEMBASE:
13174                 return OP_LOADU4_MEM;
13175 #if SIZEOF_REGISTER == 8
13176         case OP_LOADI8_MEMBASE:
13177                 return OP_LOADI8_MEM;
13178 #endif
13179         }
13180 #endif
13181
13182         return -1;
13183 }
13184
13185 static inline int
13186 op_to_op_dest_membase (int store_opcode, int opcode)
13187 {
13188 #if defined(TARGET_X86)
13189         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG)))
13190                 return -1;
13191
13192         switch (opcode) {
13193         case OP_IADD:
13194                 return OP_X86_ADD_MEMBASE_REG;
13195         case OP_ISUB:
13196                 return OP_X86_SUB_MEMBASE_REG;
13197         case OP_IAND:
13198                 return OP_X86_AND_MEMBASE_REG;
13199         case OP_IOR:
13200                 return OP_X86_OR_MEMBASE_REG;
13201         case OP_IXOR:
13202                 return OP_X86_XOR_MEMBASE_REG;
13203         case OP_ADD_IMM:
13204         case OP_IADD_IMM:
13205                 return OP_X86_ADD_MEMBASE_IMM;
13206         case OP_SUB_IMM:
13207         case OP_ISUB_IMM:
13208                 return OP_X86_SUB_MEMBASE_IMM;
13209         case OP_AND_IMM:
13210         case OP_IAND_IMM:
13211                 return OP_X86_AND_MEMBASE_IMM;
13212         case OP_OR_IMM:
13213         case OP_IOR_IMM:
13214                 return OP_X86_OR_MEMBASE_IMM;
13215         case OP_XOR_IMM:
13216         case OP_IXOR_IMM:
13217                 return OP_X86_XOR_MEMBASE_IMM;
13218         case OP_MOVE:
13219                 return OP_NOP;
13220         }
13221 #endif
13222
13223 #if defined(TARGET_AMD64)
13224         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG) || (store_opcode == OP_STOREI8_MEMBASE_REG)))
13225                 return -1;
13226
13227         switch (opcode) {
13228         case OP_IADD:
13229                 return OP_X86_ADD_MEMBASE_REG;
13230         case OP_ISUB:
13231                 return OP_X86_SUB_MEMBASE_REG;
13232         case OP_IAND:
13233                 return OP_X86_AND_MEMBASE_REG;
13234         case OP_IOR:
13235                 return OP_X86_OR_MEMBASE_REG;
13236         case OP_IXOR:
13237                 return OP_X86_XOR_MEMBASE_REG;
13238         case OP_IADD_IMM:
13239                 return OP_X86_ADD_MEMBASE_IMM;
13240         case OP_ISUB_IMM:
13241                 return OP_X86_SUB_MEMBASE_IMM;
13242         case OP_IAND_IMM:
13243                 return OP_X86_AND_MEMBASE_IMM;
13244         case OP_IOR_IMM:
13245                 return OP_X86_OR_MEMBASE_IMM;
13246         case OP_IXOR_IMM:
13247                 return OP_X86_XOR_MEMBASE_IMM;
13248         case OP_LADD:
13249                 return OP_AMD64_ADD_MEMBASE_REG;
13250         case OP_LSUB:
13251                 return OP_AMD64_SUB_MEMBASE_REG;
13252         case OP_LAND:
13253                 return OP_AMD64_AND_MEMBASE_REG;
13254         case OP_LOR:
13255                 return OP_AMD64_OR_MEMBASE_REG;
13256         case OP_LXOR:
13257                 return OP_AMD64_XOR_MEMBASE_REG;
13258         case OP_ADD_IMM:
13259         case OP_LADD_IMM:
13260                 return OP_AMD64_ADD_MEMBASE_IMM;
13261         case OP_SUB_IMM:
13262         case OP_LSUB_IMM:
13263                 return OP_AMD64_SUB_MEMBASE_IMM;
13264         case OP_AND_IMM:
13265         case OP_LAND_IMM:
13266                 return OP_AMD64_AND_MEMBASE_IMM;
13267         case OP_OR_IMM:
13268         case OP_LOR_IMM:
13269                 return OP_AMD64_OR_MEMBASE_IMM;
13270         case OP_XOR_IMM:
13271         case OP_LXOR_IMM:
13272                 return OP_AMD64_XOR_MEMBASE_IMM;
13273         case OP_MOVE:
13274                 return OP_NOP;
13275         }
13276 #endif
13277
13278         return -1;
13279 }
13280
13281 static inline int
13282 op_to_op_store_membase (int store_opcode, int opcode)
13283 {
13284 #if defined(TARGET_X86) || defined(TARGET_AMD64)
13285         switch (opcode) {
13286         case OP_ICEQ:
13287                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
13288                         return OP_X86_SETEQ_MEMBASE;
13289         case OP_CNE:
13290                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
13291                         return OP_X86_SETNE_MEMBASE;
13292         }
13293 #endif
13294
13295         return -1;
13296 }
13297
13298 static inline int
13299 op_to_op_src1_membase (int load_opcode, int opcode)
13300 {
13301 #ifdef TARGET_X86
13302         /* FIXME: This has sign extension issues */
13303         /*
13304         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
13305                 return OP_X86_COMPARE_MEMBASE8_IMM;
13306         */
13307
13308         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
13309                 return -1;
13310
13311         switch (opcode) {
13312         case OP_X86_PUSH:
13313                 return OP_X86_PUSH_MEMBASE;
13314         case OP_COMPARE_IMM:
13315         case OP_ICOMPARE_IMM:
13316                 return OP_X86_COMPARE_MEMBASE_IMM;
13317         case OP_COMPARE:
13318         case OP_ICOMPARE:
13319                 return OP_X86_COMPARE_MEMBASE_REG;
13320         }
13321 #endif
13322
13323 #ifdef TARGET_AMD64
13324         /* FIXME: This has sign extension issues */
13325         /*
13326         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
13327                 return OP_X86_COMPARE_MEMBASE8_IMM;
13328         */
13329
13330         switch (opcode) {
13331         case OP_X86_PUSH:
13332 #ifdef __mono_ilp32__
13333                 if (load_opcode == OP_LOADI8_MEMBASE)
13334 #else
13335                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
13336 #endif
13337                         return OP_X86_PUSH_MEMBASE;
13338                 break;
13339                 /* FIXME: This only works for 32 bit immediates
13340         case OP_COMPARE_IMM:
13341         case OP_LCOMPARE_IMM:
13342                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
13343                         return OP_AMD64_COMPARE_MEMBASE_IMM;
13344                 */
13345         case OP_ICOMPARE_IMM:
13346                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
13347                         return OP_AMD64_ICOMPARE_MEMBASE_IMM;
13348                 break;
13349         case OP_COMPARE:
13350         case OP_LCOMPARE:
13351 #ifdef __mono_ilp32__
13352                 if (load_opcode == OP_LOAD_MEMBASE)
13353                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
13354                 if (load_opcode == OP_LOADI8_MEMBASE)
13355 #else
13356                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
13357 #endif
13358                         return OP_AMD64_COMPARE_MEMBASE_REG;
13359                 break;
13360         case OP_ICOMPARE:
13361                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
13362                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
13363                 break;
13364         }
13365 #endif
13366
13367         return -1;
13368 }
13369
13370 static inline int
13371 op_to_op_src2_membase (int load_opcode, int opcode)
13372 {
13373 #ifdef TARGET_X86
13374         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
13375                 return -1;
13376         
13377         switch (opcode) {
13378         case OP_COMPARE:
13379         case OP_ICOMPARE:
13380                 return OP_X86_COMPARE_REG_MEMBASE;
13381         case OP_IADD:
13382                 return OP_X86_ADD_REG_MEMBASE;
13383         case OP_ISUB:
13384                 return OP_X86_SUB_REG_MEMBASE;
13385         case OP_IAND:
13386                 return OP_X86_AND_REG_MEMBASE;
13387         case OP_IOR:
13388                 return OP_X86_OR_REG_MEMBASE;
13389         case OP_IXOR:
13390                 return OP_X86_XOR_REG_MEMBASE;
13391         }
13392 #endif
13393
13394 #ifdef TARGET_AMD64
13395 #ifdef __mono_ilp32__
13396         if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE) ) {
13397 #else
13398         if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)) {
13399 #endif
13400                 switch (opcode) {
13401                 case OP_ICOMPARE:
13402                         return OP_AMD64_ICOMPARE_REG_MEMBASE;
13403                 case OP_IADD:
13404                         return OP_X86_ADD_REG_MEMBASE;
13405                 case OP_ISUB:
13406                         return OP_X86_SUB_REG_MEMBASE;
13407                 case OP_IAND:
13408                         return OP_X86_AND_REG_MEMBASE;
13409                 case OP_IOR:
13410                         return OP_X86_OR_REG_MEMBASE;
13411                 case OP_IXOR:
13412                         return OP_X86_XOR_REG_MEMBASE;
13413                 }
13414 #ifdef __mono_ilp32__
13415         } else if (load_opcode == OP_LOADI8_MEMBASE) {
13416 #else
13417         } else if ((load_opcode == OP_LOADI8_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE)) {
13418 #endif
13419                 switch (opcode) {
13420                 case OP_COMPARE:
13421                 case OP_LCOMPARE:
13422                         return OP_AMD64_COMPARE_REG_MEMBASE;
13423                 case OP_LADD:
13424                         return OP_AMD64_ADD_REG_MEMBASE;
13425                 case OP_LSUB:
13426                         return OP_AMD64_SUB_REG_MEMBASE;
13427                 case OP_LAND:
13428                         return OP_AMD64_AND_REG_MEMBASE;
13429                 case OP_LOR:
13430                         return OP_AMD64_OR_REG_MEMBASE;
13431                 case OP_LXOR:
13432                         return OP_AMD64_XOR_REG_MEMBASE;
13433                 }
13434         }
13435 #endif
13436
13437         return -1;
13438 }
13439
13440 int
13441 mono_op_to_op_imm_noemul (int opcode)
13442 {
13443         switch (opcode) {
13444 #if SIZEOF_REGISTER == 4 && !defined(MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS)
13445         case OP_LSHR:
13446         case OP_LSHL:
13447         case OP_LSHR_UN:
13448                 return -1;
13449 #endif
13450 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
13451         case OP_IDIV:
13452         case OP_IDIV_UN:
13453         case OP_IREM:
13454         case OP_IREM_UN:
13455                 return -1;
13456 #endif
13457 #if defined(MONO_ARCH_EMULATE_MUL_DIV)
13458         case OP_IMUL:
13459                 return -1;
13460 #endif
13461         default:
13462                 return mono_op_to_op_imm (opcode);
13463         }
13464 }
13465
13466 /**
13467  * mono_handle_global_vregs:
13468  *
13469  *   Make vregs used in more than one bblock 'global', i.e. allocate a variable
13470  * for them.
13471  */
13472 void
13473 mono_handle_global_vregs (MonoCompile *cfg)
13474 {
13475         gint32 *vreg_to_bb;
13476         MonoBasicBlock *bb;
13477         int i, pos;
13478
13479         vreg_to_bb = mono_mempool_alloc0 (cfg->mempool, sizeof (gint32*) * cfg->next_vreg + 1);
13480
13481 #ifdef MONO_ARCH_SIMD_INTRINSICS
13482         if (cfg->uses_simd_intrinsics)
13483                 mono_simd_simplify_indirection (cfg);
13484 #endif
13485
13486         /* Find local vregs used in more than one bb */
13487         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
13488                 MonoInst *ins = bb->code;       
13489                 int block_num = bb->block_num;
13490
13491                 if (cfg->verbose_level > 2)
13492                         printf ("\nHANDLE-GLOBAL-VREGS BLOCK %d:\n", bb->block_num);
13493
13494                 cfg->cbb = bb;
13495                 for (; ins; ins = ins->next) {
13496                         const char *spec = INS_INFO (ins->opcode);
13497                         int regtype = 0, regindex;
13498                         gint32 prev_bb;
13499
13500                         if (G_UNLIKELY (cfg->verbose_level > 2))
13501                                 mono_print_ins (ins);
13502
13503                         g_assert (ins->opcode >= MONO_CEE_LAST);
13504
13505                         for (regindex = 0; regindex < 4; regindex ++) {
13506                                 int vreg = 0;
13507
13508                                 if (regindex == 0) {
13509                                         regtype = spec [MONO_INST_DEST];
13510                                         if (regtype == ' ')
13511                                                 continue;
13512                                         vreg = ins->dreg;
13513                                 } else if (regindex == 1) {
13514                                         regtype = spec [MONO_INST_SRC1];
13515                                         if (regtype == ' ')
13516                                                 continue;
13517                                         vreg = ins->sreg1;
13518                                 } else if (regindex == 2) {
13519                                         regtype = spec [MONO_INST_SRC2];
13520                                         if (regtype == ' ')
13521                                                 continue;
13522                                         vreg = ins->sreg2;
13523                                 } else if (regindex == 3) {
13524                                         regtype = spec [MONO_INST_SRC3];
13525                                         if (regtype == ' ')
13526                                                 continue;
13527                                         vreg = ins->sreg3;
13528                                 }
13529
13530 #if SIZEOF_REGISTER == 4
13531                                 /* In the LLVM case, the long opcodes are not decomposed */
13532                                 if (regtype == 'l' && !COMPILE_LLVM (cfg)) {
13533                                         /*
13534                                          * Since some instructions reference the original long vreg,
13535                                          * and some reference the two component vregs, it is quite hard
13536                                          * to determine when it needs to be global. So be conservative.
13537                                          */
13538                                         if (!get_vreg_to_inst (cfg, vreg)) {
13539                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
13540
13541                                                 if (cfg->verbose_level > 2)
13542                                                         printf ("LONG VREG R%d made global.\n", vreg);
13543                                         }
13544
13545                                         /*
13546                                          * Make the component vregs volatile since the optimizations can
13547                                          * get confused otherwise.
13548                                          */
13549                                         get_vreg_to_inst (cfg, vreg + 1)->flags |= MONO_INST_VOLATILE;
13550                                         get_vreg_to_inst (cfg, vreg + 2)->flags |= MONO_INST_VOLATILE;
13551                                 }
13552 #endif
13553
13554                                 g_assert (vreg != -1);
13555
13556                                 prev_bb = vreg_to_bb [vreg];
13557                                 if (prev_bb == 0) {
13558                                         /* 0 is a valid block num */
13559                                         vreg_to_bb [vreg] = block_num + 1;
13560                                 } else if ((prev_bb != block_num + 1) && (prev_bb != -1)) {
13561                                         if (((regtype == 'i' && (vreg < MONO_MAX_IREGS))) || (regtype == 'f' && (vreg < MONO_MAX_FREGS)))
13562                                                 continue;
13563
13564                                         if (!get_vreg_to_inst (cfg, vreg)) {
13565                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
13566                                                         printf ("VREG R%d used in BB%d and BB%d made global.\n", vreg, vreg_to_bb [vreg], block_num);
13567
13568                                                 switch (regtype) {
13569                                                 case 'i':
13570                                                         if (vreg_is_ref (cfg, vreg))
13571                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL, vreg);
13572                                                         else
13573                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL, vreg);
13574                                                         break;
13575                                                 case 'l':
13576                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
13577                                                         break;
13578                                                 case 'f':
13579                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.double_class->byval_arg, OP_LOCAL, vreg);
13580                                                         break;
13581                                                 case 'v':
13582                                                         mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, vreg);
13583                                                         break;
13584                                                 default:
13585                                                         g_assert_not_reached ();
13586                                                 }
13587                                         }
13588
13589                                         /* Flag as having been used in more than one bb */
13590                                         vreg_to_bb [vreg] = -1;
13591                                 }
13592                         }
13593                 }
13594         }
13595
13596         /* If a variable is used in only one bblock, convert it into a local vreg */
13597         for (i = 0; i < cfg->num_varinfo; i++) {
13598                 MonoInst *var = cfg->varinfo [i];
13599                 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
13600
13601                 switch (var->type) {
13602                 case STACK_I4:
13603                 case STACK_OBJ:
13604                 case STACK_PTR:
13605                 case STACK_MP:
13606                 case STACK_VTYPE:
13607 #if SIZEOF_REGISTER == 8
13608                 case STACK_I8:
13609 #endif
13610 #if !defined(TARGET_X86)
13611                 /* Enabling this screws up the fp stack on x86 */
13612                 case STACK_R8:
13613 #endif
13614                         if (mono_arch_is_soft_float ())
13615                                 break;
13616
13617                         /* Arguments are implicitly global */
13618                         /* Putting R4 vars into registers doesn't work currently */
13619                         /* The gsharedvt vars are implicitly referenced by ldaddr opcodes, but those opcodes are only generated later */
13620                         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 && var != cfg->gsharedvt_info_var && var != cfg->gsharedvt_locals_var && var != cfg->lmf_addr_var) {
13621                                 /* 
13622                                  * Make that the variable's liveness interval doesn't contain a call, since
13623                                  * that would cause the lvreg to be spilled, making the whole optimization
13624                                  * useless.
13625                                  */
13626                                 /* This is too slow for JIT compilation */
13627 #if 0
13628                                 if (cfg->compile_aot && vreg_to_bb [var->dreg]) {
13629                                         MonoInst *ins;
13630                                         int def_index, call_index, ins_index;
13631                                         gboolean spilled = FALSE;
13632
13633                                         def_index = -1;
13634                                         call_index = -1;
13635                                         ins_index = 0;
13636                                         for (ins = vreg_to_bb [var->dreg]->code; ins; ins = ins->next) {
13637                                                 const char *spec = INS_INFO (ins->opcode);
13638
13639                                                 if ((spec [MONO_INST_DEST] != ' ') && (ins->dreg == var->dreg))
13640                                                         def_index = ins_index;
13641
13642                                                 if (((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg)) ||
13643                                                         ((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg))) {
13644                                                         if (call_index > def_index) {
13645                                                                 spilled = TRUE;
13646                                                                 break;
13647                                                         }
13648                                                 }
13649
13650                                                 if (MONO_IS_CALL (ins))
13651                                                         call_index = ins_index;
13652
13653                                                 ins_index ++;
13654                                         }
13655
13656                                         if (spilled)
13657                                                 break;
13658                                 }
13659 #endif
13660
13661                                 if (G_UNLIKELY (cfg->verbose_level > 2))
13662                                         printf ("CONVERTED R%d(%d) TO VREG.\n", var->dreg, vmv->idx);
13663                                 var->flags |= MONO_INST_IS_DEAD;
13664                                 cfg->vreg_to_inst [var->dreg] = NULL;
13665                         }
13666                         break;
13667                 }
13668         }
13669
13670         /* 
13671          * Compress the varinfo and vars tables so the liveness computation is faster and
13672          * takes up less space.
13673          */
13674         pos = 0;
13675         for (i = 0; i < cfg->num_varinfo; ++i) {
13676                 MonoInst *var = cfg->varinfo [i];
13677                 if (pos < i && cfg->locals_start == i)
13678                         cfg->locals_start = pos;
13679                 if (!(var->flags & MONO_INST_IS_DEAD)) {
13680                         if (pos < i) {
13681                                 cfg->varinfo [pos] = cfg->varinfo [i];
13682                                 cfg->varinfo [pos]->inst_c0 = pos;
13683                                 memcpy (&cfg->vars [pos], &cfg->vars [i], sizeof (MonoMethodVar));
13684                                 cfg->vars [pos].idx = pos;
13685 #if SIZEOF_REGISTER == 4
13686                                 if (cfg->varinfo [pos]->type == STACK_I8) {
13687                                         /* Modify the two component vars too */
13688                                         MonoInst *var1;
13689
13690                                         var1 = get_vreg_to_inst (cfg, cfg->varinfo [pos]->dreg + 1);
13691                                         var1->inst_c0 = pos;
13692                                         var1 = get_vreg_to_inst (cfg, cfg->varinfo [pos]->dreg + 2);
13693                                         var1->inst_c0 = pos;
13694                                 }
13695 #endif
13696                         }
13697                         pos ++;
13698                 }
13699         }
13700         cfg->num_varinfo = pos;
13701         if (cfg->locals_start > cfg->num_varinfo)
13702                 cfg->locals_start = cfg->num_varinfo;
13703 }
13704
13705 /**
13706  * mono_spill_global_vars:
13707  *
13708  *   Generate spill code for variables which are not allocated to registers, 
13709  * and replace vregs with their allocated hregs. *need_local_opts is set to TRUE if
13710  * code is generated which could be optimized by the local optimization passes.
13711  */
13712 void
13713 mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
13714 {
13715         MonoBasicBlock *bb;
13716         char spec2 [16];
13717         int orig_next_vreg;
13718         guint32 *vreg_to_lvreg;
13719         guint32 *lvregs;
13720         guint32 i, lvregs_len;
13721         gboolean dest_has_lvreg = FALSE;
13722         guint32 stacktypes [128];
13723         MonoInst **live_range_start, **live_range_end;
13724         MonoBasicBlock **live_range_start_bb, **live_range_end_bb;
13725         int *gsharedvt_vreg_to_idx = NULL;
13726
13727         *need_local_opts = FALSE;
13728
13729         memset (spec2, 0, sizeof (spec2));
13730
13731         /* FIXME: Move this function to mini.c */
13732         stacktypes ['i'] = STACK_PTR;
13733         stacktypes ['l'] = STACK_I8;
13734         stacktypes ['f'] = STACK_R8;
13735 #ifdef MONO_ARCH_SIMD_INTRINSICS
13736         stacktypes ['x'] = STACK_VTYPE;
13737 #endif
13738
13739 #if SIZEOF_REGISTER == 4
13740         /* Create MonoInsts for longs */
13741         for (i = 0; i < cfg->num_varinfo; i++) {
13742                 MonoInst *ins = cfg->varinfo [i];
13743
13744                 if ((ins->opcode != OP_REGVAR) && !(ins->flags & MONO_INST_IS_DEAD)) {
13745                         switch (ins->type) {
13746                         case STACK_R8:
13747                         case STACK_I8: {
13748                                 MonoInst *tree;
13749
13750                                 if (ins->type == STACK_R8 && !COMPILE_SOFT_FLOAT (cfg))
13751                                         break;
13752
13753                                 g_assert (ins->opcode == OP_REGOFFSET);
13754
13755                                 tree = get_vreg_to_inst (cfg, ins->dreg + 1);
13756                                 g_assert (tree);
13757                                 tree->opcode = OP_REGOFFSET;
13758                                 tree->inst_basereg = ins->inst_basereg;
13759                                 tree->inst_offset = ins->inst_offset + MINI_LS_WORD_OFFSET;
13760
13761                                 tree = get_vreg_to_inst (cfg, ins->dreg + 2);
13762                                 g_assert (tree);
13763                                 tree->opcode = OP_REGOFFSET;
13764                                 tree->inst_basereg = ins->inst_basereg;
13765                                 tree->inst_offset = ins->inst_offset + MINI_MS_WORD_OFFSET;
13766                                 break;
13767                         }
13768                         default:
13769                                 break;
13770                         }
13771                 }
13772         }
13773 #endif
13774
13775         if (cfg->compute_gc_maps) {
13776                 /* registers need liveness info even for !non refs */
13777                 for (i = 0; i < cfg->num_varinfo; i++) {
13778                         MonoInst *ins = cfg->varinfo [i];
13779
13780                         if (ins->opcode == OP_REGVAR)
13781                                 ins->flags |= MONO_INST_GC_TRACK;
13782                 }
13783         }
13784
13785         if (cfg->gsharedvt) {
13786                 gsharedvt_vreg_to_idx = mono_mempool_alloc0 (cfg->mempool, sizeof (int) * cfg->next_vreg);
13787
13788                 for (i = 0; i < cfg->num_varinfo; ++i) {
13789                         MonoInst *ins = cfg->varinfo [i];
13790                         int idx;
13791
13792                         if (mini_is_gsharedvt_variable_type (ins->inst_vtype)) {
13793                                 if (i >= cfg->locals_start) {
13794                                         /* Local */
13795                                         idx = get_gsharedvt_info_slot (cfg, ins->inst_vtype, MONO_RGCTX_INFO_LOCAL_OFFSET);
13796                                         gsharedvt_vreg_to_idx [ins->dreg] = idx + 1;
13797                                         ins->opcode = OP_GSHAREDVT_LOCAL;
13798                                         ins->inst_imm = idx;
13799                                 } else {
13800                                         /* Arg */
13801                                         gsharedvt_vreg_to_idx [ins->dreg] = -1;
13802                                         ins->opcode = OP_GSHAREDVT_ARG_REGOFFSET;
13803                                 }
13804                         }
13805                 }
13806         }
13807                 
13808         /* FIXME: widening and truncation */
13809
13810         /*
13811          * As an optimization, when a variable allocated to the stack is first loaded into 
13812          * an lvreg, we will remember the lvreg and use it the next time instead of loading
13813          * the variable again.
13814          */
13815         orig_next_vreg = cfg->next_vreg;
13816         vreg_to_lvreg = mono_mempool_alloc0 (cfg->mempool, sizeof (guint32) * cfg->next_vreg);
13817         lvregs = mono_mempool_alloc (cfg->mempool, sizeof (guint32) * 1024);
13818         lvregs_len = 0;
13819
13820         /* 
13821          * These arrays contain the first and last instructions accessing a given
13822          * variable.
13823          * Since we emit bblocks in the same order we process them here, and we
13824          * don't split live ranges, these will precisely describe the live range of
13825          * the variable, i.e. the instruction range where a valid value can be found
13826          * in the variables location.
13827          * The live range is computed using the liveness info computed by the liveness pass.
13828          * We can't use vmv->range, since that is an abstract live range, and we need
13829          * one which is instruction precise.
13830          * FIXME: Variables used in out-of-line bblocks have a hole in their live range.
13831          */
13832         /* FIXME: Only do this if debugging info is requested */
13833         live_range_start = g_new0 (MonoInst*, cfg->next_vreg);
13834         live_range_end = g_new0 (MonoInst*, cfg->next_vreg);
13835         live_range_start_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
13836         live_range_end_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
13837         
13838         /* Add spill loads/stores */
13839         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
13840                 MonoInst *ins;
13841
13842                 if (cfg->verbose_level > 2)
13843                         printf ("\nSPILL BLOCK %d:\n", bb->block_num);
13844
13845                 /* Clear vreg_to_lvreg array */
13846                 for (i = 0; i < lvregs_len; i++)
13847                         vreg_to_lvreg [lvregs [i]] = 0;
13848                 lvregs_len = 0;
13849
13850                 cfg->cbb = bb;
13851                 MONO_BB_FOR_EACH_INS (bb, ins) {
13852                         const char *spec = INS_INFO (ins->opcode);
13853                         int regtype, srcindex, sreg, tmp_reg, prev_dreg, num_sregs;
13854                         gboolean store, no_lvreg;
13855                         int sregs [MONO_MAX_SRC_REGS];
13856
13857                         if (G_UNLIKELY (cfg->verbose_level > 2))
13858                                 mono_print_ins (ins);
13859
13860                         if (ins->opcode == OP_NOP)
13861                                 continue;
13862
13863                         /* 
13864                          * We handle LDADDR here as well, since it can only be decomposed
13865                          * when variable addresses are known.
13866                          */
13867                         if (ins->opcode == OP_LDADDR) {
13868                                 MonoInst *var = ins->inst_p0;
13869
13870                                 if (var->opcode == OP_VTARG_ADDR) {
13871                                         /* Happens on SPARC/S390 where vtypes are passed by reference */
13872                                         MonoInst *vtaddr = var->inst_left;
13873                                         if (vtaddr->opcode == OP_REGVAR) {
13874                                                 ins->opcode = OP_MOVE;
13875                                                 ins->sreg1 = vtaddr->dreg;
13876                                         }
13877                                         else if (var->inst_left->opcode == OP_REGOFFSET) {
13878                                                 ins->opcode = OP_LOAD_MEMBASE;
13879                                                 ins->inst_basereg = vtaddr->inst_basereg;
13880                                                 ins->inst_offset = vtaddr->inst_offset;
13881                                         } else
13882                                                 NOT_IMPLEMENTED;
13883                                 } else if (cfg->gsharedvt && gsharedvt_vreg_to_idx [var->dreg] < 0) {
13884                                         /* gsharedvt arg passed by ref */
13885                                         g_assert (var->opcode == OP_GSHAREDVT_ARG_REGOFFSET);
13886
13887                                         ins->opcode = OP_LOAD_MEMBASE;
13888                                         ins->inst_basereg = var->inst_basereg;
13889                                         ins->inst_offset = var->inst_offset;
13890                                 } else if (cfg->gsharedvt && gsharedvt_vreg_to_idx [var->dreg]) {
13891                                         MonoInst *load, *load2, *load3;
13892                                         int idx = gsharedvt_vreg_to_idx [var->dreg] - 1;
13893                                         int reg1, reg2, reg3;
13894                                         MonoInst *info_var = cfg->gsharedvt_info_var;
13895                                         MonoInst *locals_var = cfg->gsharedvt_locals_var;
13896
13897                                         /*
13898                                          * gsharedvt local.
13899                                          * Compute the address of the local as gsharedvt_locals_var + gsharedvt_info_var->locals_offsets [idx].
13900                                          */
13901
13902                                         g_assert (var->opcode == OP_GSHAREDVT_LOCAL);
13903
13904                                         g_assert (info_var);
13905                                         g_assert (locals_var);
13906
13907                                         /* Mark the instruction used to compute the locals var as used */
13908                                         cfg->gsharedvt_locals_var_ins = NULL;
13909
13910                                         /* Load the offset */
13911                                         if (info_var->opcode == OP_REGOFFSET) {
13912                                                 reg1 = alloc_ireg (cfg);
13913                                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, reg1, info_var->inst_basereg, info_var->inst_offset);
13914                                         } else if (info_var->opcode == OP_REGVAR) {
13915                                                 load = NULL;
13916                                                 reg1 = info_var->dreg;
13917                                         } else {
13918                                                 g_assert_not_reached ();
13919                                         }
13920                                         reg2 = alloc_ireg (cfg);
13921                                         NEW_LOAD_MEMBASE (cfg, load2, OP_LOADI4_MEMBASE, reg2, reg1, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, entries) + (idx * sizeof (gpointer)));
13922                                         /* Load the locals area address */
13923                                         reg3 = alloc_ireg (cfg);
13924                                         if (locals_var->opcode == OP_REGOFFSET) {
13925                                                 NEW_LOAD_MEMBASE (cfg, load3, OP_LOAD_MEMBASE, reg3, locals_var->inst_basereg, locals_var->inst_offset);
13926                                         } else if (locals_var->opcode == OP_REGVAR) {
13927                                                 NEW_UNALU (cfg, load3, OP_MOVE, reg3, locals_var->dreg);
13928                                         } else {
13929                                                 g_assert_not_reached ();
13930                                         }
13931                                         /* Compute the address */
13932                                         ins->opcode = OP_PADD;
13933                                         ins->sreg1 = reg3;
13934                                         ins->sreg2 = reg2;
13935
13936                                         mono_bblock_insert_before_ins (bb, ins, load3);
13937                                         mono_bblock_insert_before_ins (bb, load3, load2);
13938                                         if (load)
13939                                                 mono_bblock_insert_before_ins (bb, load2, load);
13940                                 } else {
13941                                         g_assert (var->opcode == OP_REGOFFSET);
13942
13943                                         ins->opcode = OP_ADD_IMM;
13944                                         ins->sreg1 = var->inst_basereg;
13945                                         ins->inst_imm = var->inst_offset;
13946                                 }
13947
13948                                 *need_local_opts = TRUE;
13949                                 spec = INS_INFO (ins->opcode);
13950                         }
13951
13952                         if (ins->opcode < MONO_CEE_LAST) {
13953                                 mono_print_ins (ins);
13954                                 g_assert_not_reached ();
13955                         }
13956
13957                         /*
13958                          * Store opcodes have destbasereg in the dreg, but in reality, it is an
13959                          * src register.
13960                          * FIXME:
13961                          */
13962                         if (MONO_IS_STORE_MEMBASE (ins)) {
13963                                 tmp_reg = ins->dreg;
13964                                 ins->dreg = ins->sreg2;
13965                                 ins->sreg2 = tmp_reg;
13966                                 store = TRUE;
13967
13968                                 spec2 [MONO_INST_DEST] = ' ';
13969                                 spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
13970                                 spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
13971                                 spec2 [MONO_INST_SRC3] = ' ';
13972                                 spec = spec2;
13973                         } else if (MONO_IS_STORE_MEMINDEX (ins))
13974                                 g_assert_not_reached ();
13975                         else
13976                                 store = FALSE;
13977                         no_lvreg = FALSE;
13978
13979                         if (G_UNLIKELY (cfg->verbose_level > 2)) {
13980                                 printf ("\t %.3s %d", spec, ins->dreg);
13981                                 num_sregs = mono_inst_get_src_registers (ins, sregs);
13982                                 for (srcindex = 0; srcindex < num_sregs; ++srcindex)
13983                                         printf (" %d", sregs [srcindex]);
13984                                 printf ("\n");
13985                         }
13986
13987                         /***************/
13988                         /*    DREG     */
13989                         /***************/
13990                         regtype = spec [MONO_INST_DEST];
13991                         g_assert (((ins->dreg == -1) && (regtype == ' ')) || ((ins->dreg != -1) && (regtype != ' ')));
13992                         prev_dreg = -1;
13993
13994                         if ((ins->dreg != -1) && get_vreg_to_inst (cfg, ins->dreg)) {
13995                                 MonoInst *var = get_vreg_to_inst (cfg, ins->dreg);
13996                                 MonoInst *store_ins;
13997                                 int store_opcode;
13998                                 MonoInst *def_ins = ins;
13999                                 int dreg = ins->dreg; /* The original vreg */
14000
14001                                 store_opcode = mono_type_to_store_membase (cfg, var->inst_vtype);
14002
14003                                 if (var->opcode == OP_REGVAR) {
14004                                         ins->dreg = var->dreg;
14005                                 } 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)) {
14006                                         /* 
14007                                          * Instead of emitting a load+store, use a _membase opcode.
14008                                          */
14009                                         g_assert (var->opcode == OP_REGOFFSET);
14010                                         if (ins->opcode == OP_MOVE) {
14011                                                 NULLIFY_INS (ins);
14012                                                 def_ins = NULL;
14013                                         } else {
14014                                                 ins->opcode = op_to_op_dest_membase (store_opcode, ins->opcode);
14015                                                 ins->inst_basereg = var->inst_basereg;
14016                                                 ins->inst_offset = var->inst_offset;
14017                                                 ins->dreg = -1;
14018                                         }
14019                                         spec = INS_INFO (ins->opcode);
14020                                 } else {
14021                                         guint32 lvreg;
14022
14023                                         g_assert (var->opcode == OP_REGOFFSET);
14024
14025                                         prev_dreg = ins->dreg;
14026
14027                                         /* Invalidate any previous lvreg for this vreg */
14028                                         vreg_to_lvreg [ins->dreg] = 0;
14029
14030                                         lvreg = 0;
14031
14032                                         if (COMPILE_SOFT_FLOAT (cfg) && store_opcode == OP_STORER8_MEMBASE_REG) {
14033                                                 regtype = 'l';
14034                                                 store_opcode = OP_STOREI8_MEMBASE_REG;
14035                                         }
14036
14037                                         ins->dreg = alloc_dreg (cfg, stacktypes [regtype]);
14038
14039 #if SIZEOF_REGISTER != 8
14040                                         if (regtype == 'l') {
14041                                                 NEW_STORE_MEMBASE (cfg, store_ins, OP_STOREI4_MEMBASE_REG, var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET, ins->dreg + 1);
14042                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
14043                                                 NEW_STORE_MEMBASE (cfg, store_ins, OP_STOREI4_MEMBASE_REG, var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET, ins->dreg + 2);
14044                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
14045                                                 def_ins = store_ins;
14046                                         }
14047                                         else
14048 #endif
14049                                         {
14050                                                 g_assert (store_opcode != OP_STOREV_MEMBASE);
14051
14052                                                 /* Try to fuse the store into the instruction itself */
14053                                                 /* FIXME: Add more instructions */
14054                                                 if (!lvreg && ((ins->opcode == OP_ICONST) || ((ins->opcode == OP_I8CONST) && (ins->inst_c0 == 0)))) {
14055                                                         ins->opcode = store_membase_reg_to_store_membase_imm (store_opcode);
14056                                                         ins->inst_imm = ins->inst_c0;
14057                                                         ins->inst_destbasereg = var->inst_basereg;
14058                                                         ins->inst_offset = var->inst_offset;
14059                                                         spec = INS_INFO (ins->opcode);
14060                                                 } else if (!lvreg && ((ins->opcode == OP_MOVE) || (ins->opcode == OP_FMOVE) || (ins->opcode == OP_LMOVE) || (ins->opcode == OP_RMOVE))) {
14061                                                         ins->opcode = store_opcode;
14062                                                         ins->inst_destbasereg = var->inst_basereg;
14063                                                         ins->inst_offset = var->inst_offset;
14064
14065                                                         no_lvreg = TRUE;
14066
14067                                                         tmp_reg = ins->dreg;
14068                                                         ins->dreg = ins->sreg2;
14069                                                         ins->sreg2 = tmp_reg;
14070                                                         store = TRUE;
14071
14072                                                         spec2 [MONO_INST_DEST] = ' ';
14073                                                         spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
14074                                                         spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
14075                                                         spec2 [MONO_INST_SRC3] = ' ';
14076                                                         spec = spec2;
14077                                                 } else if (!lvreg && (op_to_op_store_membase (store_opcode, ins->opcode) != -1)) {
14078                                                         // FIXME: The backends expect the base reg to be in inst_basereg
14079                                                         ins->opcode = op_to_op_store_membase (store_opcode, ins->opcode);
14080                                                         ins->dreg = -1;
14081                                                         ins->inst_basereg = var->inst_basereg;
14082                                                         ins->inst_offset = var->inst_offset;
14083                                                         spec = INS_INFO (ins->opcode);
14084                                                 } else {
14085                                                         /* printf ("INS: "); mono_print_ins (ins); */
14086                                                         /* Create a store instruction */
14087                                                         NEW_STORE_MEMBASE (cfg, store_ins, store_opcode, var->inst_basereg, var->inst_offset, ins->dreg);
14088
14089                                                         /* Insert it after the instruction */
14090                                                         mono_bblock_insert_after_ins (bb, ins, store_ins);
14091
14092                                                         def_ins = store_ins;
14093
14094                                                         /* 
14095                                                          * We can't assign ins->dreg to var->dreg here, since the
14096                                                          * sregs could use it. So set a flag, and do it after
14097                                                          * the sregs.
14098                                                          */
14099                                                         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)))
14100                                                                 dest_has_lvreg = TRUE;
14101                                                 }
14102                                         }
14103                                 }
14104
14105                                 if (def_ins && !live_range_start [dreg]) {
14106                                         live_range_start [dreg] = def_ins;
14107                                         live_range_start_bb [dreg] = bb;
14108                                 }
14109
14110                                 if (cfg->compute_gc_maps && def_ins && (var->flags & MONO_INST_GC_TRACK)) {
14111                                         MonoInst *tmp;
14112
14113                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_DEF);
14114                                         tmp->inst_c1 = dreg;
14115                                         mono_bblock_insert_after_ins (bb, def_ins, tmp);
14116                                 }
14117                         }
14118
14119                         /************/
14120                         /*  SREGS   */
14121                         /************/
14122                         num_sregs = mono_inst_get_src_registers (ins, sregs);
14123                         for (srcindex = 0; srcindex < 3; ++srcindex) {
14124                                 regtype = spec [MONO_INST_SRC1 + srcindex];
14125                                 sreg = sregs [srcindex];
14126
14127                                 g_assert (((sreg == -1) && (regtype == ' ')) || ((sreg != -1) && (regtype != ' ')));
14128                                 if ((sreg != -1) && get_vreg_to_inst (cfg, sreg)) {
14129                                         MonoInst *var = get_vreg_to_inst (cfg, sreg);
14130                                         MonoInst *use_ins = ins;
14131                                         MonoInst *load_ins;
14132                                         guint32 load_opcode;
14133
14134                                         if (var->opcode == OP_REGVAR) {
14135                                                 sregs [srcindex] = var->dreg;
14136                                                 //mono_inst_set_src_registers (ins, sregs);
14137                                                 live_range_end [sreg] = use_ins;
14138                                                 live_range_end_bb [sreg] = bb;
14139
14140                                                 if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
14141                                                         MonoInst *tmp;
14142
14143                                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
14144                                                         /* var->dreg is a hreg */
14145                                                         tmp->inst_c1 = sreg;
14146                                                         mono_bblock_insert_after_ins (bb, ins, tmp);
14147                                                 }
14148
14149                                                 continue;
14150                                         }
14151
14152                                         g_assert (var->opcode == OP_REGOFFSET);
14153                                                 
14154                                         load_opcode = mono_type_to_load_membase (cfg, var->inst_vtype);
14155
14156                                         g_assert (load_opcode != OP_LOADV_MEMBASE);
14157
14158                                         if (vreg_to_lvreg [sreg]) {
14159                                                 g_assert (vreg_to_lvreg [sreg] != -1);
14160
14161                                                 /* The variable is already loaded to an lvreg */
14162                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
14163                                                         printf ("\t\tUse lvreg R%d for R%d.\n", vreg_to_lvreg [sreg], sreg);
14164                                                 sregs [srcindex] = vreg_to_lvreg [sreg];
14165                                                 //mono_inst_set_src_registers (ins, sregs);
14166                                                 continue;
14167                                         }
14168
14169                                         /* Try to fuse the load into the instruction */
14170                                         if ((srcindex == 0) && (op_to_op_src1_membase (load_opcode, ins->opcode) != -1)) {
14171                                                 ins->opcode = op_to_op_src1_membase (load_opcode, ins->opcode);
14172                                                 sregs [0] = var->inst_basereg;
14173                                                 //mono_inst_set_src_registers (ins, sregs);
14174                                                 ins->inst_offset = var->inst_offset;
14175                                         } else if ((srcindex == 1) && (op_to_op_src2_membase (load_opcode, ins->opcode) != -1)) {
14176                                                 ins->opcode = op_to_op_src2_membase (load_opcode, ins->opcode);
14177                                                 sregs [1] = var->inst_basereg;
14178                                                 //mono_inst_set_src_registers (ins, sregs);
14179                                                 ins->inst_offset = var->inst_offset;
14180                                         } else {
14181                                                 if (MONO_IS_REAL_MOVE (ins)) {
14182                                                         ins->opcode = OP_NOP;
14183                                                         sreg = ins->dreg;
14184                                                 } else {
14185                                                         //printf ("%d ", srcindex); mono_print_ins (ins);
14186
14187                                                         sreg = alloc_dreg (cfg, stacktypes [regtype]);
14188
14189                                                         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) {
14190                                                                 if (var->dreg == prev_dreg) {
14191                                                                         /*
14192                                                                          * sreg refers to the value loaded by the load
14193                                                                          * emitted below, but we need to use ins->dreg
14194                                                                          * since it refers to the store emitted earlier.
14195                                                                          */
14196                                                                         sreg = ins->dreg;
14197                                                                 }
14198                                                                 g_assert (sreg != -1);
14199                                                                 vreg_to_lvreg [var->dreg] = sreg;
14200                                                                 g_assert (lvregs_len < 1024);
14201                                                                 lvregs [lvregs_len ++] = var->dreg;
14202                                                         }
14203                                                 }
14204
14205                                                 sregs [srcindex] = sreg;
14206                                                 //mono_inst_set_src_registers (ins, sregs);
14207
14208 #if SIZEOF_REGISTER != 8
14209                                                 if (regtype == 'l') {
14210                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, sreg + 2, var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET);
14211                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14212                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, sreg + 1, var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET);
14213                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14214                                                         use_ins = load_ins;
14215                                                 }
14216                                                 else
14217 #endif
14218                                                 {
14219 #if SIZEOF_REGISTER == 4
14220                                                         g_assert (load_opcode != OP_LOADI8_MEMBASE);
14221 #endif
14222                                                         NEW_LOAD_MEMBASE (cfg, load_ins, load_opcode, sreg, var->inst_basereg, var->inst_offset);
14223                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14224                                                         use_ins = load_ins;
14225                                                 }
14226                                         }
14227
14228                                         if (var->dreg < orig_next_vreg) {
14229                                                 live_range_end [var->dreg] = use_ins;
14230                                                 live_range_end_bb [var->dreg] = bb;
14231                                         }
14232
14233                                         if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
14234                                                 MonoInst *tmp;
14235
14236                                                 MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
14237                                                 tmp->inst_c1 = var->dreg;
14238                                                 mono_bblock_insert_after_ins (bb, ins, tmp);
14239                                         }
14240                                 }
14241                         }
14242                         mono_inst_set_src_registers (ins, sregs);
14243
14244                         if (dest_has_lvreg) {
14245                                 g_assert (ins->dreg != -1);
14246                                 vreg_to_lvreg [prev_dreg] = ins->dreg;
14247                                 g_assert (lvregs_len < 1024);
14248                                 lvregs [lvregs_len ++] = prev_dreg;
14249                                 dest_has_lvreg = FALSE;
14250                         }
14251
14252                         if (store) {
14253                                 tmp_reg = ins->dreg;
14254                                 ins->dreg = ins->sreg2;
14255                                 ins->sreg2 = tmp_reg;
14256                         }
14257
14258                         if (MONO_IS_CALL (ins)) {
14259                                 /* Clear vreg_to_lvreg array */
14260                                 for (i = 0; i < lvregs_len; i++)
14261                                         vreg_to_lvreg [lvregs [i]] = 0;
14262                                 lvregs_len = 0;
14263                         } else if (ins->opcode == OP_NOP) {
14264                                 ins->dreg = -1;
14265                                 MONO_INST_NULLIFY_SREGS (ins);
14266                         }
14267
14268                         if (cfg->verbose_level > 2)
14269                                 mono_print_ins_index (1, ins);
14270                 }
14271
14272                 /* Extend the live range based on the liveness info */
14273                 if (cfg->compute_precise_live_ranges && bb->live_out_set && bb->code) {
14274                         for (i = 0; i < cfg->num_varinfo; i ++) {
14275                                 MonoMethodVar *vi = MONO_VARINFO (cfg, i);
14276
14277                                 if (vreg_is_volatile (cfg, vi->vreg))
14278                                         /* The liveness info is incomplete */
14279                                         continue;
14280
14281                                 if (mono_bitset_test_fast (bb->live_in_set, i) && !live_range_start [vi->vreg]) {
14282                                         /* Live from at least the first ins of this bb */
14283                                         live_range_start [vi->vreg] = bb->code;
14284                                         live_range_start_bb [vi->vreg] = bb;
14285                                 }
14286
14287                                 if (mono_bitset_test_fast (bb->live_out_set, i)) {
14288                                         /* Live at least until the last ins of this bb */
14289                                         live_range_end [vi->vreg] = bb->last_ins;
14290                                         live_range_end_bb [vi->vreg] = bb;
14291                                 }
14292                         }
14293                 }
14294         }
14295         
14296 #ifdef MONO_ARCH_HAVE_LIVERANGE_OPS
14297         /*
14298          * Emit LIVERANGE_START/LIVERANGE_END opcodes, the backend will implement them
14299          * by storing the current native offset into MonoMethodVar->live_range_start/end.
14300          */
14301         if (cfg->compute_precise_live_ranges && cfg->comp_done & MONO_COMP_LIVENESS) {
14302                 for (i = 0; i < cfg->num_varinfo; ++i) {
14303                         int vreg = MONO_VARINFO (cfg, i)->vreg;
14304                         MonoInst *ins;
14305
14306                         if (live_range_start [vreg]) {
14307                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_START);
14308                                 ins->inst_c0 = i;
14309                                 ins->inst_c1 = vreg;
14310                                 mono_bblock_insert_after_ins (live_range_start_bb [vreg], live_range_start [vreg], ins);
14311                         }
14312                         if (live_range_end [vreg]) {
14313                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_END);
14314                                 ins->inst_c0 = i;
14315                                 ins->inst_c1 = vreg;
14316                                 if (live_range_end [vreg] == live_range_end_bb [vreg]->last_ins)
14317                                         mono_add_ins_to_end (live_range_end_bb [vreg], ins);
14318                                 else
14319                                         mono_bblock_insert_after_ins (live_range_end_bb [vreg], live_range_end [vreg], ins);
14320                         }
14321                 }
14322         }
14323 #endif
14324
14325         if (cfg->gsharedvt_locals_var_ins) {
14326                 /* Nullify if unused */
14327                 cfg->gsharedvt_locals_var_ins->opcode = OP_PCONST;
14328                 cfg->gsharedvt_locals_var_ins->inst_imm = 0;
14329         }
14330
14331         g_free (live_range_start);
14332         g_free (live_range_end);
14333         g_free (live_range_start_bb);
14334         g_free (live_range_end_bb);
14335 }
14336
14337 /**
14338  * FIXME:
14339  * - use 'iadd' instead of 'int_add'
14340  * - handling ovf opcodes: decompose in method_to_ir.
14341  * - unify iregs/fregs
14342  *   -> partly done, the missing parts are:
14343  *   - a more complete unification would involve unifying the hregs as well, so
14344  *     code wouldn't need if (fp) all over the place. but that would mean the hregs
14345  *     would no longer map to the machine hregs, so the code generators would need to
14346  *     be modified. Also, on ia64 for example, niregs + nfregs > 256 -> bitmasks
14347  *     wouldn't work any more. Duplicating the code in mono_local_regalloc () into
14348  *     fp/non-fp branches speeds it up by about 15%.
14349  * - use sext/zext opcodes instead of shifts
14350  * - add OP_ICALL
14351  * - get rid of TEMPLOADs if possible and use vregs instead
14352  * - clean up usage of OP_P/OP_ opcodes
14353  * - cleanup usage of DUMMY_USE
14354  * - cleanup the setting of ins->type for MonoInst's which are pushed on the 
14355  *   stack
14356  * - set the stack type and allocate a dreg in the EMIT_NEW macros
14357  * - get rid of all the <foo>2 stuff when the new JIT is ready.
14358  * - make sure handle_stack_args () is called before the branch is emitted
14359  * - when the new IR is done, get rid of all unused stuff
14360  * - COMPARE/BEQ as separate instructions or unify them ?
14361  *   - keeping them separate allows specialized compare instructions like
14362  *     compare_imm, compare_membase
14363  *   - most back ends unify fp compare+branch, fp compare+ceq
14364  * - integrate mono_save_args into inline_method
14365  * - get rid of the empty bblocks created by MONO_EMIT_NEW_BRACH_BLOCK2
14366  * - handle long shift opts on 32 bit platforms somehow: they require 
14367  *   3 sregs (2 for arg1 and 1 for arg2)
14368  * - make byref a 'normal' type.
14369  * - use vregs for bb->out_stacks if possible, handle_global_vreg will make them a
14370  *   variable if needed.
14371  * - do not start a new IL level bblock when cfg->cbb is changed by a function call
14372  *   like inline_method.
14373  * - remove inlining restrictions
14374  * - fix LNEG and enable cfold of INEG
14375  * - generalize x86 optimizations like ldelema as a peephole optimization
14376  * - add store_mem_imm for amd64
14377  * - optimize the loading of the interruption flag in the managed->native wrappers
14378  * - avoid special handling of OP_NOP in passes
14379  * - move code inserting instructions into one function/macro.
14380  * - try a coalescing phase after liveness analysis
14381  * - add float -> vreg conversion + local optimizations on !x86
14382  * - figure out how to handle decomposed branches during optimizations, ie.
14383  *   compare+branch, op_jump_table+op_br etc.
14384  * - promote RuntimeXHandles to vregs
14385  * - vtype cleanups:
14386  *   - add a NEW_VARLOADA_VREG macro
14387  * - the vtype optimizations are blocked by the LDADDR opcodes generated for 
14388  *   accessing vtype fields.
14389  * - get rid of I8CONST on 64 bit platforms
14390  * - dealing with the increase in code size due to branches created during opcode
14391  *   decomposition:
14392  *   - use extended basic blocks
14393  *     - all parts of the JIT
14394  *     - handle_global_vregs () && local regalloc
14395  *   - avoid introducing global vregs during decomposition, like 'vtable' in isinst
14396  * - sources of increase in code size:
14397  *   - vtypes
14398  *   - long compares
14399  *   - isinst and castclass
14400  *   - lvregs not allocated to global registers even if used multiple times
14401  * - call cctors outside the JIT, to make -v output more readable and JIT timings more
14402  *   meaningful.
14403  * - check for fp stack leakage in other opcodes too. (-> 'exceptions' optimization)
14404  * - add all micro optimizations from the old JIT
14405  * - put tree optimizations into the deadce pass
14406  * - decompose op_start_handler/op_endfilter/op_endfinally earlier using an arch
14407  *   specific function.
14408  * - unify the float comparison opcodes with the other comparison opcodes, i.e.
14409  *   fcompare + branchCC.
14410  * - create a helper function for allocating a stack slot, taking into account 
14411  *   MONO_CFG_HAS_SPILLUP.
14412  * - merge r68207.
14413  * - merge the ia64 switch changes.
14414  * - optimize mono_regstate2_alloc_int/float.
14415  * - fix the pessimistic handling of variables accessed in exception handler blocks.
14416  * - need to write a tree optimization pass, but the creation of trees is difficult, i.e.
14417  *   parts of the tree could be separated by other instructions, killing the tree
14418  *   arguments, or stores killing loads etc. Also, should we fold loads into other
14419  *   instructions if the result of the load is used multiple times ?
14420  * - make the REM_IMM optimization in mini-x86.c arch-independent.
14421  * - LAST MERGE: 108395.
14422  * - when returning vtypes in registers, generate IR and append it to the end of the
14423  *   last bb instead of doing it in the epilog.
14424  * - change the store opcodes so they use sreg1 instead of dreg to store the base register.
14425  */
14426
14427 /*
14428
14429 NOTES
14430 -----
14431
14432 - When to decompose opcodes:
14433   - earlier: this makes some optimizations hard to implement, since the low level IR
14434   no longer contains the neccessary information. But it is easier to do.
14435   - later: harder to implement, enables more optimizations.
14436 - Branches inside bblocks:
14437   - created when decomposing complex opcodes. 
14438     - branches to another bblock: harmless, but not tracked by the branch 
14439       optimizations, so need to branch to a label at the start of the bblock.
14440     - branches to inside the same bblock: very problematic, trips up the local
14441       reg allocator. Can be fixed by spitting the current bblock, but that is a
14442       complex operation, since some local vregs can become global vregs etc.
14443 - Local/global vregs:
14444   - local vregs: temporary vregs used inside one bblock. Assigned to hregs by the
14445     local register allocator.
14446   - global vregs: used in more than one bblock. Have an associated MonoMethodVar
14447     structure, created by mono_create_var (). Assigned to hregs or the stack by
14448     the global register allocator.
14449 - When to do optimizations like alu->alu_imm:
14450   - earlier -> saves work later on since the IR will be smaller/simpler
14451   - later -> can work on more instructions
14452 - Handling of valuetypes:
14453   - When a vtype is pushed on the stack, a new temporary is created, an 
14454     instruction computing its address (LDADDR) is emitted and pushed on
14455     the stack. Need to optimize cases when the vtype is used immediately as in
14456     argument passing, stloc etc.
14457 - Instead of the to_end stuff in the old JIT, simply call the function handling
14458   the values on the stack before emitting the last instruction of the bb.
14459 */
14460
14461 #endif /* DISABLE_JIT */