[sdb] Fix the aborting of multiple invocations.
[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 #ifdef MONO_ARCH_HAVE_LMF_OPS
5152         if (((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
5153                  (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) &&
5154             !MONO_TYPE_ISSTRUCT (signature->ret) && !mini_class_is_system_array (method->klass))
5155                 return TRUE;
5156 #endif
5157
5158
5159         if (!mono_method_get_header_summary (method, &header))
5160                 return FALSE;
5161
5162         /*runtime, icall and pinvoke are checked by summary call*/
5163         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_NOINLINING) ||
5164             (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) ||
5165             (mono_class_is_marshalbyref (method->klass)) ||
5166             header.has_clauses)
5167                 return FALSE;
5168
5169         /* also consider num_locals? */
5170         /* Do the size check early to avoid creating vtables */
5171         if (!inline_limit_inited) {
5172                 if (g_getenv ("MONO_INLINELIMIT"))
5173                         inline_limit = atoi (g_getenv ("MONO_INLINELIMIT"));
5174                 else
5175                         inline_limit = INLINE_LENGTH_LIMIT;
5176                 inline_limit_inited = TRUE;
5177         }
5178         if (header.code_size >= inline_limit && !(method->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING))
5179                 return FALSE;
5180
5181         /*
5182          * if we can initialize the class of the method right away, we do,
5183          * otherwise we don't allow inlining if the class needs initialization,
5184          * since it would mean inserting a call to mono_runtime_class_init()
5185          * inside the inlined code
5186          */
5187         if (!(cfg->opt & MONO_OPT_SHARED)) {
5188                 /* The AggressiveInlining hint is a good excuse to force that cctor to run. */
5189                 if (method->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING) {
5190                         vtable = mono_class_vtable (cfg->domain, method->klass);
5191                         if (!vtable)
5192                                 return FALSE;
5193                         if (!cfg->compile_aot)
5194                                 mono_runtime_class_init (vtable);
5195                 } else if (method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) {
5196                         if (cfg->run_cctors && method->klass->has_cctor) {
5197                                 /*FIXME it would easier and lazier to just use mono_class_try_get_vtable */
5198                                 if (!method->klass->runtime_info)
5199                                         /* No vtable created yet */
5200                                         return FALSE;
5201                                 vtable = mono_class_vtable (cfg->domain, method->klass);
5202                                 if (!vtable)
5203                                         return FALSE;
5204                                 /* This makes so that inline cannot trigger */
5205                                 /* .cctors: too many apps depend on them */
5206                                 /* running with a specific order... */
5207                                 if (! vtable->initialized)
5208                                         return FALSE;
5209                                 mono_runtime_class_init (vtable);
5210                         }
5211                 } else if (mono_class_needs_cctor_run (method->klass, NULL)) {
5212                         if (!method->klass->runtime_info)
5213                                 /* No vtable created yet */
5214                                 return FALSE;
5215                         vtable = mono_class_vtable (cfg->domain, method->klass);
5216                         if (!vtable)
5217                                 return FALSE;
5218                         if (!vtable->initialized)
5219                                 return FALSE;
5220                 }
5221         } else {
5222                 /* 
5223                  * If we're compiling for shared code
5224                  * the cctor will need to be run at aot method load time, for example,
5225                  * or at the end of the compilation of the inlining method.
5226                  */
5227                 if (mono_class_needs_cctor_run (method->klass, NULL) && !((method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT)))
5228                         return FALSE;
5229         }
5230
5231 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
5232         if (mono_arch_is_soft_float ()) {
5233                 /* FIXME: */
5234                 if (sig->ret && sig->ret->type == MONO_TYPE_R4)
5235                         return FALSE;
5236                 for (i = 0; i < sig->param_count; ++i)
5237                         if (!sig->params [i]->byref && sig->params [i]->type == MONO_TYPE_R4)
5238                                 return FALSE;
5239         }
5240 #endif
5241
5242         if (g_list_find (cfg->dont_inline, method))
5243                 return FALSE;
5244
5245         return TRUE;
5246 }
5247
5248 static gboolean
5249 mini_field_access_needs_cctor_run (MonoCompile *cfg, MonoMethod *method, MonoClass *klass, MonoVTable *vtable)
5250 {
5251         if (!cfg->compile_aot) {
5252                 g_assert (vtable);
5253                 if (vtable->initialized)
5254                         return FALSE;
5255         }
5256
5257         if (klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) {
5258                 if (cfg->method == method)
5259                         return FALSE;
5260         }
5261
5262         if (!mono_class_needs_cctor_run (klass, method))
5263                 return FALSE;
5264
5265         if (! (method->flags & METHOD_ATTRIBUTE_STATIC) && (klass == method->klass))
5266                 /* The initialization is already done before the method is called */
5267                 return FALSE;
5268
5269         return TRUE;
5270 }
5271
5272 static MonoInst*
5273 mini_emit_ldelema_1_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index, gboolean bcheck)
5274 {
5275         MonoInst *ins;
5276         guint32 size;
5277         int mult_reg, add_reg, array_reg, index_reg, index2_reg;
5278         int context_used;
5279
5280         if (mini_is_gsharedvt_variable_klass (klass)) {
5281                 size = -1;
5282         } else {
5283                 mono_class_init (klass);
5284                 size = mono_class_array_element_size (klass);
5285         }
5286
5287         mult_reg = alloc_preg (cfg);
5288         array_reg = arr->dreg;
5289         index_reg = index->dreg;
5290
5291 #if SIZEOF_REGISTER == 8
5292         /* The array reg is 64 bits but the index reg is only 32 */
5293         if (COMPILE_LLVM (cfg)) {
5294                 /* Not needed */
5295                 index2_reg = index_reg;
5296         } else {
5297                 index2_reg = alloc_preg (cfg);
5298                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index2_reg, index_reg);
5299         }
5300 #else
5301         if (index->type == STACK_I8) {
5302                 index2_reg = alloc_preg (cfg);
5303                 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I4, index2_reg, index_reg);
5304         } else {
5305                 index2_reg = index_reg;
5306         }
5307 #endif
5308
5309         if (bcheck)
5310                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index2_reg);
5311
5312 #if defined(TARGET_X86) || defined(TARGET_AMD64)
5313         if (size == 1 || size == 2 || size == 4 || size == 8) {
5314                 static const int fast_log2 [] = { 1, 0, 1, -1, 2, -1, -1, -1, 3 };
5315
5316                 EMIT_NEW_X86_LEA (cfg, ins, array_reg, index2_reg, fast_log2 [size], MONO_STRUCT_OFFSET (MonoArray, vector));
5317                 ins->klass = mono_class_get_element_class (klass);
5318                 ins->type = STACK_MP;
5319
5320                 return ins;
5321         }
5322 #endif          
5323
5324         add_reg = alloc_ireg_mp (cfg);
5325
5326         if (size == -1) {
5327                 MonoInst *rgctx_ins;
5328
5329                 /* gsharedvt */
5330                 g_assert (cfg->gshared);
5331                 context_used = mini_class_check_context_used (cfg, klass);
5332                 g_assert (context_used);
5333                 rgctx_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE);
5334                 MONO_EMIT_NEW_BIALU (cfg, OP_IMUL, mult_reg, index2_reg, rgctx_ins->dreg);
5335         } else {
5336                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MUL_IMM, mult_reg, index2_reg, size);
5337         }
5338         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, array_reg, mult_reg);
5339         NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, MONO_STRUCT_OFFSET (MonoArray, vector));
5340         ins->klass = mono_class_get_element_class (klass);
5341         ins->type = STACK_MP;
5342         MONO_ADD_INS (cfg->cbb, ins);
5343
5344         return ins;
5345 }
5346
5347 #ifndef MONO_ARCH_EMULATE_MUL_DIV
5348 static MonoInst*
5349 mini_emit_ldelema_2_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index_ins1, MonoInst *index_ins2)
5350 {
5351         int bounds_reg = alloc_preg (cfg);
5352         int add_reg = alloc_ireg_mp (cfg);
5353         int mult_reg = alloc_preg (cfg);
5354         int mult2_reg = alloc_preg (cfg);
5355         int low1_reg = alloc_preg (cfg);
5356         int low2_reg = alloc_preg (cfg);
5357         int high1_reg = alloc_preg (cfg);
5358         int high2_reg = alloc_preg (cfg);
5359         int realidx1_reg = alloc_preg (cfg);
5360         int realidx2_reg = alloc_preg (cfg);
5361         int sum_reg = alloc_preg (cfg);
5362         int index1, index2, tmpreg;
5363         MonoInst *ins;
5364         guint32 size;
5365
5366         mono_class_init (klass);
5367         size = mono_class_array_element_size (klass);
5368
5369         index1 = index_ins1->dreg;
5370         index2 = index_ins2->dreg;
5371
5372 #if SIZEOF_REGISTER == 8
5373         /* The array reg is 64 bits but the index reg is only 32 */
5374         if (COMPILE_LLVM (cfg)) {
5375                 /* Not needed */
5376         } else {
5377                 tmpreg = alloc_preg (cfg);
5378                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, tmpreg, index1);
5379                 index1 = tmpreg;
5380                 tmpreg = alloc_preg (cfg);
5381                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, tmpreg, index2);
5382                 index2 = tmpreg;
5383         }
5384 #else
5385         // FIXME: Do we need to do something here for i8 indexes, like in ldelema_1_ins ?
5386         tmpreg = -1;
5387 #endif
5388
5389         /* range checking */
5390         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, 
5391                                        arr->dreg, MONO_STRUCT_OFFSET (MonoArray, bounds));
5392
5393         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low1_reg, 
5394                                        bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
5395         MONO_EMIT_NEW_BIALU (cfg, OP_PSUB, realidx1_reg, index1, low1_reg);
5396         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high1_reg, 
5397                                        bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, length));
5398         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, high1_reg, realidx1_reg);
5399         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException");
5400
5401         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low2_reg, 
5402                                        bounds_reg, sizeof (MonoArrayBounds) + MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
5403         MONO_EMIT_NEW_BIALU (cfg, OP_PSUB, realidx2_reg, index2, low2_reg);
5404         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high2_reg, 
5405                                        bounds_reg, sizeof (MonoArrayBounds) + MONO_STRUCT_OFFSET (MonoArrayBounds, length));
5406         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, high2_reg, realidx2_reg);
5407         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException");
5408
5409         MONO_EMIT_NEW_BIALU (cfg, OP_PMUL, mult_reg, high2_reg, realidx1_reg);
5410         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, mult_reg, realidx2_reg);
5411         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PMUL_IMM, mult2_reg, sum_reg, size);
5412         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult2_reg, arr->dreg);
5413         NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, MONO_STRUCT_OFFSET (MonoArray, vector));
5414
5415         ins->type = STACK_MP;
5416         ins->klass = klass;
5417         MONO_ADD_INS (cfg->cbb, ins);
5418
5419         return ins;
5420 }
5421 #endif
5422
5423 static MonoInst*
5424 mini_emit_ldelema_ins (MonoCompile *cfg, MonoMethod *cmethod, MonoInst **sp, unsigned char *ip, gboolean is_set)
5425 {
5426         int rank;
5427         MonoInst *addr;
5428         MonoMethod *addr_method;
5429         int element_size;
5430         MonoClass *eclass = cmethod->klass->element_class;
5431
5432         rank = mono_method_signature (cmethod)->param_count - (is_set? 1: 0);
5433
5434         if (rank == 1)
5435                 return mini_emit_ldelema_1_ins (cfg, eclass, sp [0], sp [1], TRUE);
5436
5437 #ifndef MONO_ARCH_EMULATE_MUL_DIV
5438         /* emit_ldelema_2 depends on OP_LMUL */
5439         if (rank == 2 && (cfg->opt & MONO_OPT_INTRINS) && !mini_is_gsharedvt_variable_klass (eclass)) {
5440                 return mini_emit_ldelema_2_ins (cfg, eclass, sp [0], sp [1], sp [2]);
5441         }
5442 #endif
5443
5444         if (mini_is_gsharedvt_variable_klass (eclass))
5445                 element_size = 0;
5446         else
5447                 element_size = mono_class_array_element_size (eclass);
5448         addr_method = mono_marshal_get_array_address (rank, element_size);
5449         addr = mono_emit_method_call (cfg, addr_method, sp, NULL);
5450
5451         return addr;
5452 }
5453
5454 static MonoBreakPolicy
5455 always_insert_breakpoint (MonoMethod *method)
5456 {
5457         return MONO_BREAK_POLICY_ALWAYS;
5458 }
5459
5460 static MonoBreakPolicyFunc break_policy_func = always_insert_breakpoint;
5461
5462 /**
5463  * mono_set_break_policy:
5464  * policy_callback: the new callback function
5465  *
5466  * Allow embedders to decide wherther to actually obey breakpoint instructions
5467  * (both break IL instructions and Debugger.Break () method calls), for example
5468  * to not allow an app to be aborted by a perfectly valid IL opcode when executing
5469  * untrusted or semi-trusted code.
5470  *
5471  * @policy_callback will be called every time a break point instruction needs to
5472  * be inserted with the method argument being the method that calls Debugger.Break()
5473  * or has the IL break instruction. The callback should return #MONO_BREAK_POLICY_NEVER
5474  * if it wants the breakpoint to not be effective in the given method.
5475  * #MONO_BREAK_POLICY_ALWAYS is the default.
5476  */
5477 void
5478 mono_set_break_policy (MonoBreakPolicyFunc policy_callback)
5479 {
5480         if (policy_callback)
5481                 break_policy_func = policy_callback;
5482         else
5483                 break_policy_func = always_insert_breakpoint;
5484 }
5485
5486 static gboolean
5487 should_insert_brekpoint (MonoMethod *method) {
5488         switch (break_policy_func (method)) {
5489         case MONO_BREAK_POLICY_ALWAYS:
5490                 return TRUE;
5491         case MONO_BREAK_POLICY_NEVER:
5492                 return FALSE;
5493         case MONO_BREAK_POLICY_ON_DBG:
5494                 g_warning ("mdb no longer supported");
5495                 return FALSE;
5496         default:
5497                 g_warning ("Incorrect value returned from break policy callback");
5498                 return FALSE;
5499         }
5500 }
5501
5502 /* optimize the simple GetGenericValueImpl/SetGenericValueImpl generic icalls */
5503 static MonoInst*
5504 emit_array_generic_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set)
5505 {
5506         MonoInst *addr, *store, *load;
5507         MonoClass *eklass = mono_class_from_mono_type (fsig->params [2]);
5508
5509         /* the bounds check is already done by the callers */
5510         addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1], FALSE);
5511         if (is_set) {
5512                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, args [2]->dreg, 0);
5513                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, addr->dreg, 0, load->dreg);
5514                 if (mini_type_is_reference (fsig->params [2]))
5515                         emit_write_barrier (cfg, addr, load);
5516         } else {
5517                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, addr->dreg, 0);
5518                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, args [2]->dreg, 0, load->dreg);
5519         }
5520         return store;
5521 }
5522
5523
5524 static gboolean
5525 generic_class_is_reference_type (MonoCompile *cfg, MonoClass *klass)
5526 {
5527         return mini_type_is_reference (&klass->byval_arg);
5528 }
5529
5530 static MonoInst*
5531 emit_array_store (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, gboolean safety_checks)
5532 {
5533         if (safety_checks && generic_class_is_reference_type (cfg, klass) &&
5534                 !(sp [2]->opcode == OP_PCONST && sp [2]->inst_p0 == NULL)) {
5535                 MonoClass *obj_array = mono_array_class_get_cached (mono_defaults.object_class, 1);
5536                 MonoMethod *helper = mono_marshal_get_virtual_stelemref (obj_array);
5537                 MonoInst *iargs [3];
5538
5539                 if (!helper->slot)
5540                         mono_class_setup_vtable (obj_array);
5541                 g_assert (helper->slot);
5542
5543                 if (sp [0]->type != STACK_OBJ)
5544                         return NULL;
5545                 if (sp [2]->type != STACK_OBJ)
5546                         return NULL;
5547
5548                 iargs [2] = sp [2];
5549                 iargs [1] = sp [1];
5550                 iargs [0] = sp [0];
5551
5552                 return mono_emit_method_call (cfg, helper, iargs, sp [0]);
5553         } else {
5554                 MonoInst *ins;
5555
5556                 if (mini_is_gsharedvt_variable_klass (klass)) {
5557                         MonoInst *addr;
5558
5559                         // FIXME-VT: OP_ICONST optimization
5560                         addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
5561                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
5562                         ins->opcode = OP_STOREV_MEMBASE;
5563                 } else if (sp [1]->opcode == OP_ICONST) {
5564                         int array_reg = sp [0]->dreg;
5565                         int index_reg = sp [1]->dreg;
5566                         int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + MONO_STRUCT_OFFSET (MonoArray, vector);
5567
5568                         if (safety_checks)
5569                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
5570                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset, sp [2]->dreg);
5571                 } else {
5572                         MonoInst *addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], safety_checks);
5573                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
5574                         if (generic_class_is_reference_type (cfg, klass))
5575                                 emit_write_barrier (cfg, addr, sp [2]);
5576                 }
5577                 return ins;
5578         }
5579 }
5580
5581 static MonoInst*
5582 emit_array_unsafe_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set)
5583 {
5584         MonoClass *eklass;
5585         
5586         if (is_set)
5587                 eklass = mono_class_from_mono_type (fsig->params [2]);
5588         else
5589                 eklass = mono_class_from_mono_type (fsig->ret);
5590
5591         if (is_set) {
5592                 return emit_array_store (cfg, eklass, args, FALSE);
5593         } else {
5594                 MonoInst *ins, *addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1], FALSE);
5595                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &eklass->byval_arg, addr->dreg, 0);
5596                 return ins;
5597         }
5598 }
5599
5600 static gboolean
5601 is_unsafe_mov_compatible (MonoCompile *cfg, MonoClass *param_klass, MonoClass *return_klass)
5602 {
5603         uint32_t align;
5604
5605         param_klass = mono_class_from_mono_type (mini_get_underlying_type (&param_klass->byval_arg));
5606
5607         //Only allow for valuetypes
5608         if (!param_klass->valuetype || !return_klass->valuetype)
5609                 return FALSE;
5610
5611         //That are blitable
5612         if (param_klass->has_references || return_klass->has_references)
5613                 return FALSE;
5614
5615         /* Avoid mixing structs and primitive types/enums, they need to be handled differently in the JIT */
5616         if ((MONO_TYPE_ISSTRUCT (&param_klass->byval_arg) && !MONO_TYPE_ISSTRUCT (&return_klass->byval_arg)) ||
5617                 (!MONO_TYPE_ISSTRUCT (&param_klass->byval_arg) && MONO_TYPE_ISSTRUCT (&return_klass->byval_arg)))
5618                 return FALSE;
5619
5620         if (param_klass->byval_arg.type == MONO_TYPE_R4 || param_klass->byval_arg.type == MONO_TYPE_R8 ||
5621                 return_klass->byval_arg.type == MONO_TYPE_R4 || return_klass->byval_arg.type == MONO_TYPE_R8)
5622                 return FALSE;
5623
5624         //And have the same size
5625         if (mono_class_value_size (param_klass, &align) != mono_class_value_size (return_klass, &align))
5626                 return FALSE;
5627         return TRUE;
5628 }
5629
5630 static MonoInst*
5631 emit_array_unsafe_mov (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args)
5632 {
5633         MonoClass *param_klass = mono_class_from_mono_type (fsig->params [0]);
5634         MonoClass *return_klass = mono_class_from_mono_type (fsig->ret);
5635
5636         //Valuetypes that are semantically equivalent
5637         if (is_unsafe_mov_compatible (cfg, param_klass, return_klass))
5638                 return args [0];
5639
5640         //Arrays of valuetypes that are semantically equivalent
5641         if (param_klass->rank == 1 && return_klass->rank == 1 && is_unsafe_mov_compatible (cfg, param_klass->element_class, return_klass->element_class))
5642                 return args [0];
5643
5644         return NULL;
5645 }
5646
5647 static MonoInst*
5648 mini_emit_inst_for_ctor (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5649 {
5650 #ifdef MONO_ARCH_SIMD_INTRINSICS
5651         MonoInst *ins = NULL;
5652
5653         if (cfg->opt & MONO_OPT_SIMD) {
5654                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
5655                 if (ins)
5656                         return ins;
5657         }
5658 #endif
5659
5660         return mono_emit_native_types_intrinsics (cfg, cmethod, fsig, args);
5661 }
5662
5663 static MonoInst*
5664 emit_memory_barrier (MonoCompile *cfg, int kind)
5665 {
5666         MonoInst *ins = NULL;
5667         MONO_INST_NEW (cfg, ins, OP_MEMORY_BARRIER);
5668         MONO_ADD_INS (cfg->cbb, ins);
5669         ins->backend.memory_barrier_kind = kind;
5670
5671         return ins;
5672 }
5673
5674 static MonoInst*
5675 llvm_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5676 {
5677         MonoInst *ins = NULL;
5678         int opcode = 0;
5679
5680         /* The LLVM backend supports these intrinsics */
5681         if (cmethod->klass == mono_defaults.math_class) {
5682                 if (strcmp (cmethod->name, "Sin") == 0) {
5683                         opcode = OP_SIN;
5684                 } else if (strcmp (cmethod->name, "Cos") == 0) {
5685                         opcode = OP_COS;
5686                 } else if (strcmp (cmethod->name, "Sqrt") == 0) {
5687                         opcode = OP_SQRT;
5688                 } else if (strcmp (cmethod->name, "Abs") == 0 && fsig->params [0]->type == MONO_TYPE_R8) {
5689                         opcode = OP_ABS;
5690                 }
5691
5692                 if (opcode && fsig->param_count == 1) {
5693                         MONO_INST_NEW (cfg, ins, opcode);
5694                         ins->type = STACK_R8;
5695                         ins->dreg = mono_alloc_freg (cfg);
5696                         ins->sreg1 = args [0]->dreg;
5697                         MONO_ADD_INS (cfg->cbb, ins);
5698                 }
5699
5700                 opcode = 0;
5701                 if (cfg->opt & MONO_OPT_CMOV) {
5702                         if (strcmp (cmethod->name, "Min") == 0) {
5703                                 if (fsig->params [0]->type == MONO_TYPE_I4)
5704                                         opcode = OP_IMIN;
5705                                 if (fsig->params [0]->type == MONO_TYPE_U4)
5706                                         opcode = OP_IMIN_UN;
5707                                 else if (fsig->params [0]->type == MONO_TYPE_I8)
5708                                         opcode = OP_LMIN;
5709                                 else if (fsig->params [0]->type == MONO_TYPE_U8)
5710                                         opcode = OP_LMIN_UN;
5711                         } else if (strcmp (cmethod->name, "Max") == 0) {
5712                                 if (fsig->params [0]->type == MONO_TYPE_I4)
5713                                         opcode = OP_IMAX;
5714                                 if (fsig->params [0]->type == MONO_TYPE_U4)
5715                                         opcode = OP_IMAX_UN;
5716                                 else if (fsig->params [0]->type == MONO_TYPE_I8)
5717                                         opcode = OP_LMAX;
5718                                 else if (fsig->params [0]->type == MONO_TYPE_U8)
5719                                         opcode = OP_LMAX_UN;
5720                         }
5721                 }
5722
5723                 if (opcode && fsig->param_count == 2) {
5724                         MONO_INST_NEW (cfg, ins, opcode);
5725                         ins->type = fsig->params [0]->type == MONO_TYPE_I4 ? STACK_I4 : STACK_I8;
5726                         ins->dreg = mono_alloc_ireg (cfg);
5727                         ins->sreg1 = args [0]->dreg;
5728                         ins->sreg2 = args [1]->dreg;
5729                         MONO_ADD_INS (cfg->cbb, ins);
5730                 }
5731         }
5732
5733         return ins;
5734 }
5735
5736 static MonoInst*
5737 mini_emit_inst_for_sharable_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5738 {
5739         if (cmethod->klass == mono_defaults.array_class) {
5740                 if (strcmp (cmethod->name, "UnsafeStore") == 0)
5741                         return emit_array_unsafe_access (cfg, fsig, args, TRUE);
5742                 else if (strcmp (cmethod->name, "UnsafeLoad") == 0)
5743                         return emit_array_unsafe_access (cfg, fsig, args, FALSE);
5744                 else if (strcmp (cmethod->name, "UnsafeMov") == 0)
5745                         return emit_array_unsafe_mov (cfg, fsig, args);
5746         }
5747
5748         return NULL;
5749 }
5750
5751 static MonoInst*
5752 mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5753 {
5754         MonoInst *ins = NULL;
5755
5756         static MonoClass *runtime_helpers_class = NULL;
5757         if (! runtime_helpers_class)
5758                 runtime_helpers_class = mono_class_from_name (mono_defaults.corlib,
5759                         "System.Runtime.CompilerServices", "RuntimeHelpers");
5760
5761         if (cmethod->klass == mono_defaults.string_class) {
5762                 if (strcmp (cmethod->name, "get_Chars") == 0 && fsig->param_count + fsig->hasthis == 2) {
5763                         int dreg = alloc_ireg (cfg);
5764                         int index_reg = alloc_preg (cfg);
5765                         int add_reg = alloc_preg (cfg);
5766
5767 #if SIZEOF_REGISTER == 8
5768                         /* The array reg is 64 bits but the index reg is only 32 */
5769                         MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index_reg, args [1]->dreg);
5770 #else
5771                         index_reg = args [1]->dreg;
5772 #endif  
5773                         MONO_EMIT_BOUNDS_CHECK (cfg, args [0]->dreg, MonoString, length, index_reg);
5774
5775 #if defined(TARGET_X86) || defined(TARGET_AMD64)
5776                         EMIT_NEW_X86_LEA (cfg, ins, args [0]->dreg, index_reg, 1, MONO_STRUCT_OFFSET (MonoString, chars));
5777                         add_reg = ins->dreg;
5778                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
5779                                                                    add_reg, 0);
5780 #else
5781                         int mult_reg = alloc_preg (cfg);
5782                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, mult_reg, index_reg, 1);
5783                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult_reg, args [0]->dreg);
5784                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
5785                                                                    add_reg, MONO_STRUCT_OFFSET (MonoString, chars));
5786 #endif
5787                         type_from_op (cfg, ins, NULL, NULL);
5788                         return ins;
5789                 } else if (strcmp (cmethod->name, "get_Length") == 0 && fsig->param_count + fsig->hasthis == 1) {
5790                         int dreg = alloc_ireg (cfg);
5791                         /* Decompose later to allow more optimizations */
5792                         EMIT_NEW_UNALU (cfg, ins, OP_STRLEN, dreg, args [0]->dreg);
5793                         ins->type = STACK_I4;
5794                         ins->flags |= MONO_INST_FAULT;
5795                         cfg->cbb->has_array_access = TRUE;
5796                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
5797
5798                         return ins;
5799                 } else 
5800                         return NULL;
5801         } else if (cmethod->klass == mono_defaults.object_class) {
5802
5803                 if (strcmp (cmethod->name, "GetType") == 0 && fsig->param_count + fsig->hasthis == 1) {
5804                         int dreg = alloc_ireg_ref (cfg);
5805                         int vt_reg = alloc_preg (cfg);
5806                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vt_reg, args [0]->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
5807                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, vt_reg, MONO_STRUCT_OFFSET (MonoVTable, type));
5808                         type_from_op (cfg, ins, NULL, NULL);
5809
5810                         return ins;
5811 #if !defined(MONO_ARCH_EMULATE_MUL_DIV)
5812                 } else if (strcmp (cmethod->name, "InternalGetHashCode") == 0 && fsig->param_count == 1 && !mono_gc_is_moving ()) {
5813                         int dreg = alloc_ireg (cfg);
5814                         int t1 = alloc_ireg (cfg);
5815         
5816                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, t1, args [0]->dreg, 3);
5817                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_MUL_IMM, dreg, t1, 2654435761u);
5818                         ins->type = STACK_I4;
5819
5820                         return ins;
5821 #endif
5822                 } else if (strcmp (cmethod->name, ".ctor") == 0 && fsig->param_count == 0) {
5823                         MONO_INST_NEW (cfg, ins, OP_NOP);
5824                         MONO_ADD_INS (cfg->cbb, ins);
5825                         return ins;
5826                 } else
5827                         return NULL;
5828         } else if (cmethod->klass == mono_defaults.array_class) {
5829                 if (strcmp (cmethod->name, "GetGenericValueImpl") == 0 && fsig->param_count + fsig->hasthis == 3 && !cfg->gsharedvt)
5830                         return emit_array_generic_access (cfg, fsig, args, FALSE);
5831                 else if (strcmp (cmethod->name, "SetGenericValueImpl") == 0 && fsig->param_count + fsig->hasthis == 3 && !cfg->gsharedvt)
5832                         return emit_array_generic_access (cfg, fsig, args, TRUE);
5833
5834 #ifndef MONO_BIG_ARRAYS
5835                 /*
5836                  * This is an inline version of GetLength/GetLowerBound(0) used frequently in
5837                  * Array methods.
5838                  */
5839                 else if (((strcmp (cmethod->name, "GetLength") == 0 && fsig->param_count + fsig->hasthis == 2) ||
5840                          (strcmp (cmethod->name, "GetLowerBound") == 0 && fsig->param_count + fsig->hasthis == 2)) &&
5841                          args [1]->opcode == OP_ICONST && args [1]->inst_c0 == 0) {
5842                         int dreg = alloc_ireg (cfg);
5843                         int bounds_reg = alloc_ireg_mp (cfg);
5844                         MonoBasicBlock *end_bb, *szarray_bb;
5845                         gboolean get_length = strcmp (cmethod->name, "GetLength") == 0;
5846
5847                         NEW_BBLOCK (cfg, end_bb);
5848                         NEW_BBLOCK (cfg, szarray_bb);
5849
5850                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOAD_MEMBASE, bounds_reg,
5851                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, bounds));
5852                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
5853                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, szarray_bb);
5854                         /* Non-szarray case */
5855                         if (get_length)
5856                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5857                                                                            bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, length));
5858                         else
5859                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5860                                                                            bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
5861                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
5862                         MONO_START_BB (cfg, szarray_bb);
5863                         /* Szarray case */
5864                         if (get_length)
5865                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5866                                                                            args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, max_length));
5867                         else
5868                                 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
5869                         MONO_START_BB (cfg, end_bb);
5870
5871                         EMIT_NEW_UNALU (cfg, ins, OP_MOVE, dreg, dreg);
5872                         ins->type = STACK_I4;
5873                         
5874                         return ins;
5875                 }
5876 #endif
5877
5878                 if (cmethod->name [0] != 'g')
5879                         return NULL;
5880
5881                 if (strcmp (cmethod->name, "get_Rank") == 0 && fsig->param_count + fsig->hasthis == 1) {
5882                         int dreg = alloc_ireg (cfg);
5883                         int vtable_reg = alloc_preg (cfg);
5884                         MONO_EMIT_NEW_LOAD_MEMBASE_OP_FAULT (cfg, OP_LOAD_MEMBASE, vtable_reg, 
5885                                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
5886                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU1_MEMBASE, dreg,
5887                                                                    vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
5888                         type_from_op (cfg, ins, NULL, NULL);
5889
5890                         return ins;
5891                 } else if (strcmp (cmethod->name, "get_Length") == 0 && fsig->param_count + fsig->hasthis == 1) {
5892                         int dreg = alloc_ireg (cfg);
5893
5894                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOADI4_MEMBASE, dreg, 
5895                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, max_length));
5896                         type_from_op (cfg, ins, NULL, NULL);
5897
5898                         return ins;
5899                 } else
5900                         return NULL;
5901         } else if (cmethod->klass == runtime_helpers_class) {
5902
5903                 if (strcmp (cmethod->name, "get_OffsetToStringData") == 0 && fsig->param_count == 0) {
5904                         EMIT_NEW_ICONST (cfg, ins, MONO_STRUCT_OFFSET (MonoString, chars));
5905                         return ins;
5906                 } else
5907                         return NULL;
5908         } else if (cmethod->klass == mono_defaults.thread_class) {
5909                 if (strcmp (cmethod->name, "SpinWait_nop") == 0 && fsig->param_count == 0) {
5910                         MONO_INST_NEW (cfg, ins, OP_RELAXED_NOP);
5911                         MONO_ADD_INS (cfg->cbb, ins);
5912                         return ins;
5913                 } else if (strcmp (cmethod->name, "MemoryBarrier") == 0 && fsig->param_count == 0) {
5914                         return emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
5915                 } else if (!strcmp (cmethod->name, "VolatileRead") && fsig->param_count == 1) {
5916                         guint32 opcode = 0;
5917                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
5918
5919                         if (fsig->params [0]->type == MONO_TYPE_I1)
5920                                 opcode = OP_LOADI1_MEMBASE;
5921                         else if (fsig->params [0]->type == MONO_TYPE_U1)
5922                                 opcode = OP_LOADU1_MEMBASE;
5923                         else if (fsig->params [0]->type == MONO_TYPE_I2)
5924                                 opcode = OP_LOADI2_MEMBASE;
5925                         else if (fsig->params [0]->type == MONO_TYPE_U2)
5926                                 opcode = OP_LOADU2_MEMBASE;
5927                         else if (fsig->params [0]->type == MONO_TYPE_I4)
5928                                 opcode = OP_LOADI4_MEMBASE;
5929                         else if (fsig->params [0]->type == MONO_TYPE_U4)
5930                                 opcode = OP_LOADU4_MEMBASE;
5931                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_U8)
5932                                 opcode = OP_LOADI8_MEMBASE;
5933                         else if (fsig->params [0]->type == MONO_TYPE_R4)
5934                                 opcode = OP_LOADR4_MEMBASE;
5935                         else if (fsig->params [0]->type == MONO_TYPE_R8)
5936                                 opcode = OP_LOADR8_MEMBASE;
5937                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I || fsig->params [0]->type == MONO_TYPE_U)
5938                                 opcode = OP_LOAD_MEMBASE;
5939
5940                         if (opcode) {
5941                                 MONO_INST_NEW (cfg, ins, opcode);
5942                                 ins->inst_basereg = args [0]->dreg;
5943                                 ins->inst_offset = 0;
5944                                 MONO_ADD_INS (cfg->cbb, ins);
5945
5946                                 switch (fsig->params [0]->type) {
5947                                 case MONO_TYPE_I1:
5948                                 case MONO_TYPE_U1:
5949                                 case MONO_TYPE_I2:
5950                                 case MONO_TYPE_U2:
5951                                 case MONO_TYPE_I4:
5952                                 case MONO_TYPE_U4:
5953                                         ins->dreg = mono_alloc_ireg (cfg);
5954                                         ins->type = STACK_I4;
5955                                         break;
5956                                 case MONO_TYPE_I8:
5957                                 case MONO_TYPE_U8:
5958                                         ins->dreg = mono_alloc_lreg (cfg);
5959                                         ins->type = STACK_I8;
5960                                         break;
5961                                 case MONO_TYPE_I:
5962                                 case MONO_TYPE_U:
5963                                         ins->dreg = mono_alloc_ireg (cfg);
5964 #if SIZEOF_REGISTER == 8
5965                                         ins->type = STACK_I8;
5966 #else
5967                                         ins->type = STACK_I4;
5968 #endif
5969                                         break;
5970                                 case MONO_TYPE_R4:
5971                                 case MONO_TYPE_R8:
5972                                         ins->dreg = mono_alloc_freg (cfg);
5973                                         ins->type = STACK_R8;
5974                                         break;
5975                                 default:
5976                                         g_assert (mini_type_is_reference (fsig->params [0]));
5977                                         ins->dreg = mono_alloc_ireg_ref (cfg);
5978                                         ins->type = STACK_OBJ;
5979                                         break;
5980                                 }
5981
5982                                 if (opcode == OP_LOADI8_MEMBASE)
5983                                         ins = mono_decompose_opcode (cfg, ins);
5984
5985                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
5986
5987                                 return ins;
5988                         }
5989                 } else if (!strcmp (cmethod->name, "VolatileWrite") && fsig->param_count == 2) {
5990                         guint32 opcode = 0;
5991                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
5992
5993                         if (fsig->params [0]->type == MONO_TYPE_I1 || fsig->params [0]->type == MONO_TYPE_U1)
5994                                 opcode = OP_STOREI1_MEMBASE_REG;
5995                         else if (fsig->params [0]->type == MONO_TYPE_I2 || fsig->params [0]->type == MONO_TYPE_U2)
5996                                 opcode = OP_STOREI2_MEMBASE_REG;
5997                         else if (fsig->params [0]->type == MONO_TYPE_I4 || fsig->params [0]->type == MONO_TYPE_U4)
5998                                 opcode = OP_STOREI4_MEMBASE_REG;
5999                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_U8)
6000                                 opcode = OP_STOREI8_MEMBASE_REG;
6001                         else if (fsig->params [0]->type == MONO_TYPE_R4)
6002                                 opcode = OP_STORER4_MEMBASE_REG;
6003                         else if (fsig->params [0]->type == MONO_TYPE_R8)
6004                                 opcode = OP_STORER8_MEMBASE_REG;
6005                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I || fsig->params [0]->type == MONO_TYPE_U)
6006                                 opcode = OP_STORE_MEMBASE_REG;
6007
6008                         if (opcode) {
6009                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
6010
6011                                 MONO_INST_NEW (cfg, ins, opcode);
6012                                 ins->sreg1 = args [1]->dreg;
6013                                 ins->inst_destbasereg = args [0]->dreg;
6014                                 ins->inst_offset = 0;
6015                                 MONO_ADD_INS (cfg->cbb, ins);
6016
6017                                 if (opcode == OP_STOREI8_MEMBASE_REG)
6018                                         ins = mono_decompose_opcode (cfg, ins);
6019
6020                                 return ins;
6021                         }
6022                 }
6023         } else if (cmethod->klass->image == mono_defaults.corlib &&
6024                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
6025                            (strcmp (cmethod->klass->name, "Interlocked") == 0)) {
6026                 ins = NULL;
6027
6028 #if SIZEOF_REGISTER == 8
6029                 if (strcmp (cmethod->name, "Read") == 0 && fsig->param_count == 1 && (fsig->params [0]->type == MONO_TYPE_I8)) {
6030                         if (mono_arch_opcode_supported (OP_ATOMIC_LOAD_I8)) {
6031                                 MONO_INST_NEW (cfg, ins, OP_ATOMIC_LOAD_I8);
6032                                 ins->dreg = mono_alloc_preg (cfg);
6033                                 ins->sreg1 = args [0]->dreg;
6034                                 ins->type = STACK_I8;
6035                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_SEQ;
6036                                 MONO_ADD_INS (cfg->cbb, ins);
6037                         } else {
6038                                 MonoInst *load_ins;
6039
6040                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6041
6042                                 /* 64 bit reads are already atomic */
6043                                 MONO_INST_NEW (cfg, load_ins, OP_LOADI8_MEMBASE);
6044                                 load_ins->dreg = mono_alloc_preg (cfg);
6045                                 load_ins->inst_basereg = args [0]->dreg;
6046                                 load_ins->inst_offset = 0;
6047                                 load_ins->type = STACK_I8;
6048                                 MONO_ADD_INS (cfg->cbb, load_ins);
6049
6050                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6051
6052                                 ins = load_ins;
6053                         }
6054                 }
6055 #endif
6056
6057                 if (strcmp (cmethod->name, "Increment") == 0 && fsig->param_count == 1) {
6058                         MonoInst *ins_iconst;
6059                         guint32 opcode = 0;
6060
6061                         if (fsig->params [0]->type == MONO_TYPE_I4) {
6062                                 opcode = OP_ATOMIC_ADD_I4;
6063                                 cfg->has_atomic_add_i4 = TRUE;
6064                         }
6065 #if SIZEOF_REGISTER == 8
6066                         else if (fsig->params [0]->type == MONO_TYPE_I8)
6067                                 opcode = OP_ATOMIC_ADD_I8;
6068 #endif
6069                         if (opcode) {
6070                                 if (!mono_arch_opcode_supported (opcode))
6071                                         return NULL;
6072                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
6073                                 ins_iconst->inst_c0 = 1;
6074                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
6075                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
6076
6077                                 MONO_INST_NEW (cfg, ins, opcode);
6078                                 ins->dreg = mono_alloc_ireg (cfg);
6079                                 ins->inst_basereg = args [0]->dreg;
6080                                 ins->inst_offset = 0;
6081                                 ins->sreg2 = ins_iconst->dreg;
6082                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
6083                                 MONO_ADD_INS (cfg->cbb, ins);
6084                         }
6085                 } else if (strcmp (cmethod->name, "Decrement") == 0 && fsig->param_count == 1) {
6086                         MonoInst *ins_iconst;
6087                         guint32 opcode = 0;
6088
6089                         if (fsig->params [0]->type == MONO_TYPE_I4) {
6090                                 opcode = OP_ATOMIC_ADD_I4;
6091                                 cfg->has_atomic_add_i4 = TRUE;
6092                         }
6093 #if SIZEOF_REGISTER == 8
6094                         else if (fsig->params [0]->type == MONO_TYPE_I8)
6095                                 opcode = OP_ATOMIC_ADD_I8;
6096 #endif
6097                         if (opcode) {
6098                                 if (!mono_arch_opcode_supported (opcode))
6099                                         return NULL;
6100                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
6101                                 ins_iconst->inst_c0 = -1;
6102                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
6103                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
6104
6105                                 MONO_INST_NEW (cfg, ins, opcode);
6106                                 ins->dreg = mono_alloc_ireg (cfg);
6107                                 ins->inst_basereg = args [0]->dreg;
6108                                 ins->inst_offset = 0;
6109                                 ins->sreg2 = ins_iconst->dreg;
6110                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
6111                                 MONO_ADD_INS (cfg->cbb, ins);
6112                         }
6113                 } else if (strcmp (cmethod->name, "Add") == 0 && fsig->param_count == 2) {
6114                         guint32 opcode = 0;
6115
6116                         if (fsig->params [0]->type == MONO_TYPE_I4) {
6117                                 opcode = OP_ATOMIC_ADD_I4;
6118                                 cfg->has_atomic_add_i4 = TRUE;
6119                         }
6120 #if SIZEOF_REGISTER == 8
6121                         else if (fsig->params [0]->type == MONO_TYPE_I8)
6122                                 opcode = OP_ATOMIC_ADD_I8;
6123 #endif
6124                         if (opcode) {
6125                                 if (!mono_arch_opcode_supported (opcode))
6126                                         return NULL;
6127                                 MONO_INST_NEW (cfg, ins, opcode);
6128                                 ins->dreg = mono_alloc_ireg (cfg);
6129                                 ins->inst_basereg = args [0]->dreg;
6130                                 ins->inst_offset = 0;
6131                                 ins->sreg2 = args [1]->dreg;
6132                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
6133                                 MONO_ADD_INS (cfg->cbb, ins);
6134                         }
6135                 }
6136                 else if (strcmp (cmethod->name, "Exchange") == 0 && fsig->param_count == 2) {
6137                         MonoInst *f2i = NULL, *i2f;
6138                         guint32 opcode, f2i_opcode, i2f_opcode;
6139                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
6140                         gboolean is_float = fsig->params [0]->type == MONO_TYPE_R4 || fsig->params [0]->type == MONO_TYPE_R8;
6141
6142                         if (fsig->params [0]->type == MONO_TYPE_I4 ||
6143                             fsig->params [0]->type == MONO_TYPE_R4) {
6144                                 opcode = OP_ATOMIC_EXCHANGE_I4;
6145                                 f2i_opcode = OP_MOVE_F_TO_I4;
6146                                 i2f_opcode = OP_MOVE_I4_TO_F;
6147                                 cfg->has_atomic_exchange_i4 = TRUE;
6148                         }
6149 #if SIZEOF_REGISTER == 8
6150                         else if (is_ref ||
6151                                  fsig->params [0]->type == MONO_TYPE_I8 ||
6152                                  fsig->params [0]->type == MONO_TYPE_R8 ||
6153                                  fsig->params [0]->type == MONO_TYPE_I) {
6154                                 opcode = OP_ATOMIC_EXCHANGE_I8;
6155                                 f2i_opcode = OP_MOVE_F_TO_I8;
6156                                 i2f_opcode = OP_MOVE_I8_TO_F;
6157                         }
6158 #else
6159                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I) {
6160                                 opcode = OP_ATOMIC_EXCHANGE_I4;
6161                                 cfg->has_atomic_exchange_i4 = TRUE;
6162                         }
6163 #endif
6164                         else
6165                                 return NULL;
6166
6167                         if (!mono_arch_opcode_supported (opcode))
6168                                 return NULL;
6169
6170                         if (is_float) {
6171                                 /* TODO: Decompose these opcodes instead of bailing here. */
6172                                 if (COMPILE_SOFT_FLOAT (cfg))
6173                                         return NULL;
6174
6175                                 MONO_INST_NEW (cfg, f2i, f2i_opcode);
6176                                 f2i->dreg = mono_alloc_ireg (cfg);
6177                                 f2i->sreg1 = args [1]->dreg;
6178                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
6179                                         f2i->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6180                                 MONO_ADD_INS (cfg->cbb, f2i);
6181                         }
6182
6183                         MONO_INST_NEW (cfg, ins, opcode);
6184                         ins->dreg = is_ref ? mono_alloc_ireg_ref (cfg) : mono_alloc_ireg (cfg);
6185                         ins->inst_basereg = args [0]->dreg;
6186                         ins->inst_offset = 0;
6187                         ins->sreg2 = is_float ? f2i->dreg : args [1]->dreg;
6188                         MONO_ADD_INS (cfg->cbb, ins);
6189
6190                         switch (fsig->params [0]->type) {
6191                         case MONO_TYPE_I4:
6192                                 ins->type = STACK_I4;
6193                                 break;
6194                         case MONO_TYPE_I8:
6195                                 ins->type = STACK_I8;
6196                                 break;
6197                         case MONO_TYPE_I:
6198 #if SIZEOF_REGISTER == 8
6199                                 ins->type = STACK_I8;
6200 #else
6201                                 ins->type = STACK_I4;
6202 #endif
6203                                 break;
6204                         case MONO_TYPE_R4:
6205                         case MONO_TYPE_R8:
6206                                 ins->type = STACK_R8;
6207                                 break;
6208                         default:
6209                                 g_assert (mini_type_is_reference (fsig->params [0]));
6210                                 ins->type = STACK_OBJ;
6211                                 break;
6212                         }
6213
6214                         if (is_float) {
6215                                 MONO_INST_NEW (cfg, i2f, i2f_opcode);
6216                                 i2f->dreg = mono_alloc_freg (cfg);
6217                                 i2f->sreg1 = ins->dreg;
6218                                 i2f->type = STACK_R8;
6219                                 if (i2f_opcode == OP_MOVE_I4_TO_F)
6220                                         i2f->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6221                                 MONO_ADD_INS (cfg->cbb, i2f);
6222
6223                                 ins = i2f;
6224                         }
6225
6226                         if (cfg->gen_write_barriers && is_ref)
6227                                 emit_write_barrier (cfg, args [0], args [1]);
6228                 }
6229                 else if ((strcmp (cmethod->name, "CompareExchange") == 0) && fsig->param_count == 3) {
6230                         MonoInst *f2i_new = NULL, *f2i_cmp = NULL, *i2f;
6231                         guint32 opcode, f2i_opcode, i2f_opcode;
6232                         gboolean is_ref = mini_type_is_reference (fsig->params [1]);
6233                         gboolean is_float = fsig->params [1]->type == MONO_TYPE_R4 || fsig->params [1]->type == MONO_TYPE_R8;
6234
6235                         if (fsig->params [1]->type == MONO_TYPE_I4 ||
6236                             fsig->params [1]->type == MONO_TYPE_R4) {
6237                                 opcode = OP_ATOMIC_CAS_I4;
6238                                 f2i_opcode = OP_MOVE_F_TO_I4;
6239                                 i2f_opcode = OP_MOVE_I4_TO_F;
6240                                 cfg->has_atomic_cas_i4 = TRUE;
6241                         }
6242 #if SIZEOF_REGISTER == 8
6243                         else if (is_ref ||
6244                                  fsig->params [1]->type == MONO_TYPE_I8 ||
6245                                  fsig->params [1]->type == MONO_TYPE_R8 ||
6246                                  fsig->params [1]->type == MONO_TYPE_I) {
6247                                 opcode = OP_ATOMIC_CAS_I8;
6248                                 f2i_opcode = OP_MOVE_F_TO_I8;
6249                                 i2f_opcode = OP_MOVE_I8_TO_F;
6250                         }
6251 #else
6252                         else if (is_ref || fsig->params [1]->type == MONO_TYPE_I) {
6253                                 opcode = OP_ATOMIC_CAS_I4;
6254                                 cfg->has_atomic_cas_i4 = TRUE;
6255                         }
6256 #endif
6257                         else
6258                                 return NULL;
6259
6260                         if (!mono_arch_opcode_supported (opcode))
6261                                 return NULL;
6262
6263                         if (is_float) {
6264                                 /* TODO: Decompose these opcodes instead of bailing here. */
6265                                 if (COMPILE_SOFT_FLOAT (cfg))
6266                                         return NULL;
6267
6268                                 MONO_INST_NEW (cfg, f2i_new, f2i_opcode);
6269                                 f2i_new->dreg = mono_alloc_ireg (cfg);
6270                                 f2i_new->sreg1 = args [1]->dreg;
6271                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
6272                                         f2i_new->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6273                                 MONO_ADD_INS (cfg->cbb, f2i_new);
6274
6275                                 MONO_INST_NEW (cfg, f2i_cmp, f2i_opcode);
6276                                 f2i_cmp->dreg = mono_alloc_ireg (cfg);
6277                                 f2i_cmp->sreg1 = args [2]->dreg;
6278                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
6279                                         f2i_cmp->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6280                                 MONO_ADD_INS (cfg->cbb, f2i_cmp);
6281                         }
6282
6283                         MONO_INST_NEW (cfg, ins, opcode);
6284                         ins->dreg = is_ref ? alloc_ireg_ref (cfg) : alloc_ireg (cfg);
6285                         ins->sreg1 = args [0]->dreg;
6286                         ins->sreg2 = is_float ? f2i_new->dreg : args [1]->dreg;
6287                         ins->sreg3 = is_float ? f2i_cmp->dreg : args [2]->dreg;
6288                         MONO_ADD_INS (cfg->cbb, ins);
6289
6290                         switch (fsig->params [1]->type) {
6291                         case MONO_TYPE_I4:
6292                                 ins->type = STACK_I4;
6293                                 break;
6294                         case MONO_TYPE_I8:
6295                                 ins->type = STACK_I8;
6296                                 break;
6297                         case MONO_TYPE_I:
6298 #if SIZEOF_REGISTER == 8
6299                                 ins->type = STACK_I8;
6300 #else
6301                                 ins->type = STACK_I4;
6302 #endif
6303                                 break;
6304                         case MONO_TYPE_R4:
6305                                 ins->type = cfg->r4_stack_type;
6306                                 break;
6307                         case MONO_TYPE_R8:
6308                                 ins->type = STACK_R8;
6309                                 break;
6310                         default:
6311                                 g_assert (mini_type_is_reference (fsig->params [1]));
6312                                 ins->type = STACK_OBJ;
6313                                 break;
6314                         }
6315
6316                         if (is_float) {
6317                                 MONO_INST_NEW (cfg, i2f, i2f_opcode);
6318                                 i2f->dreg = mono_alloc_freg (cfg);
6319                                 i2f->sreg1 = ins->dreg;
6320                                 i2f->type = STACK_R8;
6321                                 if (i2f_opcode == OP_MOVE_I4_TO_F)
6322                                         i2f->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6323                                 MONO_ADD_INS (cfg->cbb, i2f);
6324
6325                                 ins = i2f;
6326                         }
6327
6328                         if (cfg->gen_write_barriers && is_ref)
6329                                 emit_write_barrier (cfg, args [0], args [1]);
6330                 }
6331                 else if ((strcmp (cmethod->name, "CompareExchange") == 0) && fsig->param_count == 4 &&
6332                          fsig->params [1]->type == MONO_TYPE_I4) {
6333                         MonoInst *cmp, *ceq;
6334
6335                         if (!mono_arch_opcode_supported (OP_ATOMIC_CAS_I4))
6336                                 return NULL;
6337
6338                         /* int32 r = CAS (location, value, comparand); */
6339                         MONO_INST_NEW (cfg, ins, OP_ATOMIC_CAS_I4);
6340                         ins->dreg = alloc_ireg (cfg);
6341                         ins->sreg1 = args [0]->dreg;
6342                         ins->sreg2 = args [1]->dreg;
6343                         ins->sreg3 = args [2]->dreg;
6344                         ins->type = STACK_I4;
6345                         MONO_ADD_INS (cfg->cbb, ins);
6346
6347                         /* bool result = r == comparand; */
6348                         MONO_INST_NEW (cfg, cmp, OP_ICOMPARE);
6349                         cmp->sreg1 = ins->dreg;
6350                         cmp->sreg2 = args [2]->dreg;
6351                         cmp->type = STACK_I4;
6352                         MONO_ADD_INS (cfg->cbb, cmp);
6353
6354                         MONO_INST_NEW (cfg, ceq, OP_ICEQ);
6355                         ceq->dreg = alloc_ireg (cfg);
6356                         ceq->type = STACK_I4;
6357                         MONO_ADD_INS (cfg->cbb, ceq);
6358
6359                         /* *success = result; */
6360                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, args [3]->dreg, 0, ceq->dreg);
6361
6362                         cfg->has_atomic_cas_i4 = TRUE;
6363                 }
6364                 else if (strcmp (cmethod->name, "MemoryBarrier") == 0 && fsig->param_count == 0)
6365                         ins = emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6366
6367                 if (ins)
6368                         return ins;
6369         } else if (cmethod->klass->image == mono_defaults.corlib &&
6370                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
6371                            (strcmp (cmethod->klass->name, "Volatile") == 0)) {
6372                 ins = NULL;
6373
6374                 if (!strcmp (cmethod->name, "Read") && fsig->param_count == 1) {
6375                         guint32 opcode = 0;
6376                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
6377                         gboolean is_float = fsig->params [0]->type == MONO_TYPE_R4 || fsig->params [0]->type == MONO_TYPE_R8;
6378
6379                         if (fsig->params [0]->type == MONO_TYPE_I1)
6380                                 opcode = OP_ATOMIC_LOAD_I1;
6381                         else if (fsig->params [0]->type == MONO_TYPE_U1 || fsig->params [0]->type == MONO_TYPE_BOOLEAN)
6382                                 opcode = OP_ATOMIC_LOAD_U1;
6383                         else if (fsig->params [0]->type == MONO_TYPE_I2)
6384                                 opcode = OP_ATOMIC_LOAD_I2;
6385                         else if (fsig->params [0]->type == MONO_TYPE_U2)
6386                                 opcode = OP_ATOMIC_LOAD_U2;
6387                         else if (fsig->params [0]->type == MONO_TYPE_I4)
6388                                 opcode = OP_ATOMIC_LOAD_I4;
6389                         else if (fsig->params [0]->type == MONO_TYPE_U4)
6390                                 opcode = OP_ATOMIC_LOAD_U4;
6391                         else if (fsig->params [0]->type == MONO_TYPE_R4)
6392                                 opcode = OP_ATOMIC_LOAD_R4;
6393                         else if (fsig->params [0]->type == MONO_TYPE_R8)
6394                                 opcode = OP_ATOMIC_LOAD_R8;
6395 #if SIZEOF_REGISTER == 8
6396                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_I)
6397                                 opcode = OP_ATOMIC_LOAD_I8;
6398                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_U8 || fsig->params [0]->type == MONO_TYPE_U)
6399                                 opcode = OP_ATOMIC_LOAD_U8;
6400 #else
6401                         else if (fsig->params [0]->type == MONO_TYPE_I)
6402                                 opcode = OP_ATOMIC_LOAD_I4;
6403                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_U)
6404                                 opcode = OP_ATOMIC_LOAD_U4;
6405 #endif
6406
6407                         if (opcode) {
6408                                 if (!mono_arch_opcode_supported (opcode))
6409                                         return NULL;
6410
6411                                 MONO_INST_NEW (cfg, ins, opcode);
6412                                 ins->dreg = is_ref ? mono_alloc_ireg_ref (cfg) : (is_float ? mono_alloc_freg (cfg) : mono_alloc_ireg (cfg));
6413                                 ins->sreg1 = args [0]->dreg;
6414                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_ACQ;
6415                                 MONO_ADD_INS (cfg->cbb, ins);
6416
6417                                 switch (fsig->params [0]->type) {
6418                                 case MONO_TYPE_BOOLEAN:
6419                                 case MONO_TYPE_I1:
6420                                 case MONO_TYPE_U1:
6421                                 case MONO_TYPE_I2:
6422                                 case MONO_TYPE_U2:
6423                                 case MONO_TYPE_I4:
6424                                 case MONO_TYPE_U4:
6425                                         ins->type = STACK_I4;
6426                                         break;
6427                                 case MONO_TYPE_I8:
6428                                 case MONO_TYPE_U8:
6429                                         ins->type = STACK_I8;
6430                                         break;
6431                                 case MONO_TYPE_I:
6432                                 case MONO_TYPE_U:
6433 #if SIZEOF_REGISTER == 8
6434                                         ins->type = STACK_I8;
6435 #else
6436                                         ins->type = STACK_I4;
6437 #endif
6438                                         break;
6439                                 case MONO_TYPE_R4:
6440                                         ins->type = cfg->r4_stack_type;
6441                                         break;
6442                                 case MONO_TYPE_R8:
6443                                         ins->type = STACK_R8;
6444                                         break;
6445                                 default:
6446                                         g_assert (mini_type_is_reference (fsig->params [0]));
6447                                         ins->type = STACK_OBJ;
6448                                         break;
6449                                 }
6450                         }
6451                 }
6452
6453                 if (!strcmp (cmethod->name, "Write") && fsig->param_count == 2) {
6454                         guint32 opcode = 0;
6455                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
6456
6457                         if (fsig->params [0]->type == MONO_TYPE_I1)
6458                                 opcode = OP_ATOMIC_STORE_I1;
6459                         else if (fsig->params [0]->type == MONO_TYPE_U1 || fsig->params [0]->type == MONO_TYPE_BOOLEAN)
6460                                 opcode = OP_ATOMIC_STORE_U1;
6461                         else if (fsig->params [0]->type == MONO_TYPE_I2)
6462                                 opcode = OP_ATOMIC_STORE_I2;
6463                         else if (fsig->params [0]->type == MONO_TYPE_U2)
6464                                 opcode = OP_ATOMIC_STORE_U2;
6465                         else if (fsig->params [0]->type == MONO_TYPE_I4)
6466                                 opcode = OP_ATOMIC_STORE_I4;
6467                         else if (fsig->params [0]->type == MONO_TYPE_U4)
6468                                 opcode = OP_ATOMIC_STORE_U4;
6469                         else if (fsig->params [0]->type == MONO_TYPE_R4)
6470                                 opcode = OP_ATOMIC_STORE_R4;
6471                         else if (fsig->params [0]->type == MONO_TYPE_R8)
6472                                 opcode = OP_ATOMIC_STORE_R8;
6473 #if SIZEOF_REGISTER == 8
6474                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_I)
6475                                 opcode = OP_ATOMIC_STORE_I8;
6476                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_U8 || fsig->params [0]->type == MONO_TYPE_U)
6477                                 opcode = OP_ATOMIC_STORE_U8;
6478 #else
6479                         else if (fsig->params [0]->type == MONO_TYPE_I)
6480                                 opcode = OP_ATOMIC_STORE_I4;
6481                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_U)
6482                                 opcode = OP_ATOMIC_STORE_U4;
6483 #endif
6484
6485                         if (opcode) {
6486                                 if (!mono_arch_opcode_supported (opcode))
6487                                         return NULL;
6488
6489                                 MONO_INST_NEW (cfg, ins, opcode);
6490                                 ins->dreg = args [0]->dreg;
6491                                 ins->sreg1 = args [1]->dreg;
6492                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_REL;
6493                                 MONO_ADD_INS (cfg->cbb, ins);
6494
6495                                 if (cfg->gen_write_barriers && is_ref)
6496                                         emit_write_barrier (cfg, args [0], args [1]);
6497                         }
6498                 }
6499
6500                 if (ins)
6501                         return ins;
6502         } else if (cmethod->klass->image == mono_defaults.corlib &&
6503                            (strcmp (cmethod->klass->name_space, "System.Diagnostics") == 0) &&
6504                            (strcmp (cmethod->klass->name, "Debugger") == 0)) {
6505                 if (!strcmp (cmethod->name, "Break") && fsig->param_count == 0) {
6506                         if (should_insert_brekpoint (cfg->method)) {
6507                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
6508                         } else {
6509                                 MONO_INST_NEW (cfg, ins, OP_NOP);
6510                                 MONO_ADD_INS (cfg->cbb, ins);
6511                         }
6512                         return ins;
6513                 }
6514         } else if (cmethod->klass->image == mono_defaults.corlib &&
6515                    (strcmp (cmethod->klass->name_space, "System") == 0) &&
6516                    (strcmp (cmethod->klass->name, "Environment") == 0)) {
6517                 if (!strcmp (cmethod->name, "get_IsRunningOnWindows") && fsig->param_count == 0) {
6518 #ifdef TARGET_WIN32
6519                         EMIT_NEW_ICONST (cfg, ins, 1);
6520 #else
6521                         EMIT_NEW_ICONST (cfg, ins, 0);
6522 #endif
6523                 }
6524         } else if (cmethod->klass == mono_defaults.math_class) {
6525                 /* 
6526                  * There is general branchless code for Min/Max, but it does not work for 
6527                  * all inputs:
6528                  * http://everything2.com/?node_id=1051618
6529                  */
6530         } else if (((!strcmp (cmethod->klass->image->assembly->aname.name, "MonoMac") ||
6531                     !strcmp (cmethod->klass->image->assembly->aname.name, "monotouch")) &&
6532                                 !strcmp (cmethod->klass->name_space, "XamCore.ObjCRuntime") &&
6533                                 !strcmp (cmethod->klass->name, "Selector")) ||
6534                            (!strcmp (cmethod->klass->image->assembly->aname.name, "Xamarin.iOS") &&
6535                                 !strcmp (cmethod->klass->name_space, "ObjCRuntime") &&
6536                                 !strcmp (cmethod->klass->name, "Selector"))
6537                            ) {
6538 #ifdef MONO_ARCH_HAVE_OBJC_GET_SELECTOR
6539                 if (!strcmp (cmethod->name, "GetHandle") && fsig->param_count == 1 &&
6540                     (args [0]->opcode == OP_GOT_ENTRY || args [0]->opcode == OP_AOTCONST) &&
6541                     cfg->compile_aot) {
6542                         MonoInst *pi;
6543                         MonoJumpInfoToken *ji;
6544                         MonoString *s;
6545
6546                         cfg->disable_llvm = TRUE;
6547
6548                         if (args [0]->opcode == OP_GOT_ENTRY) {
6549                                 pi = args [0]->inst_p1;
6550                                 g_assert (pi->opcode == OP_PATCH_INFO);
6551                                 g_assert (GPOINTER_TO_INT (pi->inst_p1) == MONO_PATCH_INFO_LDSTR);
6552                                 ji = pi->inst_p0;
6553                         } else {
6554                                 g_assert (GPOINTER_TO_INT (args [0]->inst_p1) == MONO_PATCH_INFO_LDSTR);
6555                                 ji = args [0]->inst_p0;
6556                         }
6557
6558                         NULLIFY_INS (args [0]);
6559
6560                         // FIXME: Ugly
6561                         s = mono_ldstr (cfg->domain, ji->image, mono_metadata_token_index (ji->token));
6562                         MONO_INST_NEW (cfg, ins, OP_OBJC_GET_SELECTOR);
6563                         ins->dreg = mono_alloc_ireg (cfg);
6564                         // FIXME: Leaks
6565                         ins->inst_p0 = mono_string_to_utf8 (s);
6566                         MONO_ADD_INS (cfg->cbb, ins);
6567                         return ins;
6568                 }
6569 #endif
6570         }
6571
6572 #ifdef MONO_ARCH_SIMD_INTRINSICS
6573         if (cfg->opt & MONO_OPT_SIMD) {
6574                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
6575                 if (ins)
6576                         return ins;
6577         }
6578 #endif
6579
6580         ins = mono_emit_native_types_intrinsics (cfg, cmethod, fsig, args);
6581         if (ins)
6582                 return ins;
6583
6584         if (COMPILE_LLVM (cfg)) {
6585                 ins = llvm_emit_inst_for_method (cfg, cmethod, fsig, args);
6586                 if (ins)
6587                         return ins;
6588         }
6589
6590         return mono_arch_emit_inst_for_method (cfg, cmethod, fsig, args);
6591 }
6592
6593 /*
6594  * This entry point could be used later for arbitrary method
6595  * redirection.
6596  */
6597 inline static MonoInst*
6598 mini_redirect_call (MonoCompile *cfg, MonoMethod *method,  
6599                                         MonoMethodSignature *signature, MonoInst **args, MonoInst *this_ins)
6600 {
6601         if (method->klass == mono_defaults.string_class) {
6602                 /* managed string allocation support */
6603                 if (strcmp (method->name, "InternalAllocateStr") == 0 && !(mono_profiler_events & MONO_PROFILE_ALLOCATIONS) && !(cfg->opt & MONO_OPT_SHARED)) {
6604                         MonoInst *iargs [2];
6605                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
6606                         MonoMethod *managed_alloc = NULL;
6607
6608                         g_assert (vtable); /*Should not fail since it System.String*/
6609 #ifndef MONO_CROSS_COMPILE
6610                         managed_alloc = mono_gc_get_managed_allocator (method->klass, FALSE, FALSE);
6611 #endif
6612                         if (!managed_alloc)
6613                                 return NULL;
6614                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
6615                         iargs [1] = args [0];
6616                         return mono_emit_method_call (cfg, managed_alloc, iargs, this_ins);
6617                 }
6618         }
6619         return NULL;
6620 }
6621
6622 static void
6623 mono_save_args (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **sp)
6624 {
6625         MonoInst *store, *temp;
6626         int i;
6627
6628         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
6629                 MonoType *argtype = (sig->hasthis && (i == 0)) ? type_from_stack_type (*sp) : sig->params [i - sig->hasthis];
6630
6631                 /*
6632                  * FIXME: We should use *args++ = sp [0], but that would mean the arg
6633                  * would be different than the MonoInst's used to represent arguments, and
6634                  * the ldelema implementation can't deal with that.
6635                  * Solution: When ldelema is used on an inline argument, create a var for 
6636                  * it, emit ldelema on that var, and emit the saving code below in
6637                  * inline_method () if needed.
6638                  */
6639                 temp = mono_compile_create_var (cfg, argtype, OP_LOCAL);
6640                 cfg->args [i] = temp;
6641                 /* This uses cfg->args [i] which is set by the preceeding line */
6642                 EMIT_NEW_ARGSTORE (cfg, store, i, *sp);
6643                 store->cil_code = sp [0]->cil_code;
6644                 sp++;
6645         }
6646 }
6647
6648 #define MONO_INLINE_CALLED_LIMITED_METHODS 1
6649 #define MONO_INLINE_CALLER_LIMITED_METHODS 1
6650
6651 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
6652 static gboolean
6653 check_inline_called_method_name_limit (MonoMethod *called_method)
6654 {
6655         int strncmp_result;
6656         static const char *limit = NULL;
6657         
6658         if (limit == NULL) {
6659                 const char *limit_string = g_getenv ("MONO_INLINE_CALLED_METHOD_NAME_LIMIT");
6660
6661                 if (limit_string != NULL)
6662                         limit = limit_string;
6663                 else
6664                         limit = "";
6665         }
6666
6667         if (limit [0] != '\0') {
6668                 char *called_method_name = mono_method_full_name (called_method, TRUE);
6669
6670                 strncmp_result = strncmp (called_method_name, limit, strlen (limit));
6671                 g_free (called_method_name);
6672         
6673                 //return (strncmp_result <= 0);
6674                 return (strncmp_result == 0);
6675         } else {
6676                 return TRUE;
6677         }
6678 }
6679 #endif
6680
6681 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
6682 static gboolean
6683 check_inline_caller_method_name_limit (MonoMethod *caller_method)
6684 {
6685         int strncmp_result;
6686         static const char *limit = NULL;
6687         
6688         if (limit == NULL) {
6689                 const char *limit_string = g_getenv ("MONO_INLINE_CALLER_METHOD_NAME_LIMIT");
6690                 if (limit_string != NULL) {
6691                         limit = limit_string;
6692                 } else {
6693                         limit = "";
6694                 }
6695         }
6696
6697         if (limit [0] != '\0') {
6698                 char *caller_method_name = mono_method_full_name (caller_method, TRUE);
6699
6700                 strncmp_result = strncmp (caller_method_name, limit, strlen (limit));
6701                 g_free (caller_method_name);
6702         
6703                 //return (strncmp_result <= 0);
6704                 return (strncmp_result == 0);
6705         } else {
6706                 return TRUE;
6707         }
6708 }
6709 #endif
6710
6711 static void
6712 emit_init_rvar (MonoCompile *cfg, int dreg, MonoType *rtype)
6713 {
6714         static double r8_0 = 0.0;
6715         static float r4_0 = 0.0;
6716         MonoInst *ins;
6717         int t;
6718
6719         rtype = mini_get_underlying_type (rtype);
6720         t = rtype->type;
6721
6722         if (rtype->byref) {
6723                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
6724         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
6725                 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
6726         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
6727                 MONO_EMIT_NEW_I8CONST (cfg, dreg, 0);
6728         } else if (cfg->r4fp && t == MONO_TYPE_R4) {
6729                 MONO_INST_NEW (cfg, ins, OP_R4CONST);
6730                 ins->type = STACK_R4;
6731                 ins->inst_p0 = (void*)&r4_0;
6732                 ins->dreg = dreg;
6733                 MONO_ADD_INS (cfg->cbb, ins);
6734         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
6735                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
6736                 ins->type = STACK_R8;
6737                 ins->inst_p0 = (void*)&r8_0;
6738                 ins->dreg = dreg;
6739                 MONO_ADD_INS (cfg->cbb, ins);
6740         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
6741                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (rtype))) {
6742                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (rtype));
6743         } else if (((t == MONO_TYPE_VAR) || (t == MONO_TYPE_MVAR)) && mini_type_var_is_vt (rtype)) {
6744                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (rtype));
6745         } else {
6746                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
6747         }
6748 }
6749
6750 static void
6751 emit_dummy_init_rvar (MonoCompile *cfg, int dreg, MonoType *rtype)
6752 {
6753         int t;
6754
6755         rtype = mini_get_underlying_type (rtype);
6756         t = rtype->type;
6757
6758         if (rtype->byref) {
6759                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_PCONST);
6760         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
6761                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_ICONST);
6762         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
6763                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_I8CONST);
6764         } else if (cfg->r4fp && t == MONO_TYPE_R4) {
6765                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_R4CONST);
6766         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
6767                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_R8CONST);
6768         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
6769                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (rtype))) {
6770                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_VZERO);
6771         } else if (((t == MONO_TYPE_VAR) || (t == MONO_TYPE_MVAR)) && mini_type_var_is_vt (rtype)) {
6772                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_VZERO);
6773         } else {
6774                 emit_init_rvar (cfg, dreg, rtype);
6775         }
6776 }
6777
6778 /* If INIT is FALSE, emit dummy initialization statements to keep the IR valid */
6779 static void
6780 emit_init_local (MonoCompile *cfg, int local, MonoType *type, gboolean init)
6781 {
6782         MonoInst *var = cfg->locals [local];
6783         if (COMPILE_SOFT_FLOAT (cfg)) {
6784                 MonoInst *store;
6785                 int reg = alloc_dreg (cfg, var->type);
6786                 emit_init_rvar (cfg, reg, type);
6787                 EMIT_NEW_LOCSTORE (cfg, store, local, cfg->cbb->last_ins);
6788         } else {
6789                 if (init)
6790                         emit_init_rvar (cfg, var->dreg, type);
6791                 else
6792                         emit_dummy_init_rvar (cfg, var->dreg, type);
6793         }
6794 }
6795
6796 /*
6797  * inline_method:
6798  *
6799  *   Return the cost of inlining CMETHOD.
6800  */
6801 static int
6802 inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp,
6803                            guchar *ip, guint real_offset, gboolean inline_always)
6804 {
6805         MonoInst *ins, *rvar = NULL;
6806         MonoMethodHeader *cheader;
6807         MonoBasicBlock *ebblock, *sbblock;
6808         int i, costs;
6809         MonoMethod *prev_inlined_method;
6810         MonoInst **prev_locals, **prev_args;
6811         MonoType **prev_arg_types;
6812         guint prev_real_offset;
6813         GHashTable *prev_cbb_hash;
6814         MonoBasicBlock **prev_cil_offset_to_bb;
6815         MonoBasicBlock *prev_cbb;
6816         unsigned char* prev_cil_start;
6817         guint32 prev_cil_offset_to_bb_len;
6818         MonoMethod *prev_current_method;
6819         MonoGenericContext *prev_generic_context;
6820         gboolean ret_var_set, prev_ret_var_set, prev_disable_inline, virtual = FALSE;
6821
6822         g_assert (cfg->exception_type == MONO_EXCEPTION_NONE);
6823
6824 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
6825         if ((! inline_always) && ! check_inline_called_method_name_limit (cmethod))
6826                 return 0;
6827 #endif
6828 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
6829         if ((! inline_always) && ! check_inline_caller_method_name_limit (cfg->method))
6830                 return 0;
6831 #endif
6832
6833         if (!fsig)
6834                 fsig = mono_method_signature (cmethod);
6835
6836         if (cfg->verbose_level > 2)
6837                 printf ("INLINE START %p %s -> %s\n", cmethod,  mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
6838
6839         if (!cmethod->inline_info) {
6840                 cfg->stat_inlineable_methods++;
6841                 cmethod->inline_info = 1;
6842         }
6843
6844         /* allocate local variables */
6845         cheader = mono_method_get_header (cmethod);
6846
6847         if (cheader == NULL || mono_loader_get_last_error ()) {
6848                 MonoLoaderError *error = mono_loader_get_last_error ();
6849
6850                 if (cheader)
6851                         mono_metadata_free_mh (cheader);
6852                 if (inline_always && error)
6853                         mono_cfg_set_exception (cfg, error->exception_type);
6854
6855                 mono_loader_clear_error ();
6856                 return 0;
6857         }
6858
6859         /*Must verify before creating locals as it can cause the JIT to assert.*/
6860         if (mono_compile_is_broken (cfg, cmethod, FALSE)) {
6861                 mono_metadata_free_mh (cheader);
6862                 return 0;
6863         }
6864
6865         /* allocate space to store the return value */
6866         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
6867                 rvar = mono_compile_create_var (cfg, fsig->ret, OP_LOCAL);
6868         }
6869
6870         prev_locals = cfg->locals;
6871         cfg->locals = mono_mempool_alloc0 (cfg->mempool, cheader->num_locals * sizeof (MonoInst*));     
6872         for (i = 0; i < cheader->num_locals; ++i)
6873                 cfg->locals [i] = mono_compile_create_var (cfg, cheader->locals [i], OP_LOCAL);
6874
6875         /* allocate start and end blocks */
6876         /* This is needed so if the inline is aborted, we can clean up */
6877         NEW_BBLOCK (cfg, sbblock);
6878         sbblock->real_offset = real_offset;
6879
6880         NEW_BBLOCK (cfg, ebblock);
6881         ebblock->block_num = cfg->num_bblocks++;
6882         ebblock->real_offset = real_offset;
6883
6884         prev_args = cfg->args;
6885         prev_arg_types = cfg->arg_types;
6886         prev_inlined_method = cfg->inlined_method;
6887         cfg->inlined_method = cmethod;
6888         cfg->ret_var_set = FALSE;
6889         cfg->inline_depth ++;
6890         prev_real_offset = cfg->real_offset;
6891         prev_cbb_hash = cfg->cbb_hash;
6892         prev_cil_offset_to_bb = cfg->cil_offset_to_bb;
6893         prev_cil_offset_to_bb_len = cfg->cil_offset_to_bb_len;
6894         prev_cil_start = cfg->cil_start;
6895         prev_cbb = cfg->cbb;
6896         prev_current_method = cfg->current_method;
6897         prev_generic_context = cfg->generic_context;
6898         prev_ret_var_set = cfg->ret_var_set;
6899         prev_disable_inline = cfg->disable_inline;
6900
6901         if (ip && *ip == CEE_CALLVIRT && !(cmethod->flags & METHOD_ATTRIBUTE_STATIC))
6902                 virtual = TRUE;
6903
6904         costs = mono_method_to_ir (cfg, cmethod, sbblock, ebblock, rvar, sp, real_offset, virtual);
6905
6906         ret_var_set = cfg->ret_var_set;
6907
6908         cfg->inlined_method = prev_inlined_method;
6909         cfg->real_offset = prev_real_offset;
6910         cfg->cbb_hash = prev_cbb_hash;
6911         cfg->cil_offset_to_bb = prev_cil_offset_to_bb;
6912         cfg->cil_offset_to_bb_len = prev_cil_offset_to_bb_len;
6913         cfg->cil_start = prev_cil_start;
6914         cfg->locals = prev_locals;
6915         cfg->args = prev_args;
6916         cfg->arg_types = prev_arg_types;
6917         cfg->current_method = prev_current_method;
6918         cfg->generic_context = prev_generic_context;
6919         cfg->ret_var_set = prev_ret_var_set;
6920         cfg->disable_inline = prev_disable_inline;
6921         cfg->inline_depth --;
6922
6923         if ((costs >= 0 && costs < 60) || inline_always || (costs >= 0 && (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING))) {
6924                 if (cfg->verbose_level > 2)
6925                         printf ("INLINE END %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
6926                 
6927                 cfg->stat_inlined_methods++;
6928
6929                 /* always add some code to avoid block split failures */
6930                 MONO_INST_NEW (cfg, ins, OP_NOP);
6931                 MONO_ADD_INS (prev_cbb, ins);
6932
6933                 prev_cbb->next_bb = sbblock;
6934                 link_bblock (cfg, prev_cbb, sbblock);
6935
6936                 /* 
6937                  * Get rid of the begin and end bblocks if possible to aid local
6938                  * optimizations.
6939                  */
6940                 mono_merge_basic_blocks (cfg, prev_cbb, sbblock);
6941
6942                 if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] != ebblock))
6943                         mono_merge_basic_blocks (cfg, prev_cbb, prev_cbb->out_bb [0]);
6944
6945                 if ((ebblock->in_count == 1) && ebblock->in_bb [0]->out_count == 1) {
6946                         MonoBasicBlock *prev = ebblock->in_bb [0];
6947                         mono_merge_basic_blocks (cfg, prev, ebblock);
6948                         cfg->cbb = prev;
6949                         if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] == prev)) {
6950                                 mono_merge_basic_blocks (cfg, prev_cbb, prev);
6951                                 cfg->cbb = prev_cbb;
6952                         }
6953                 } else {
6954                         /* 
6955                          * Its possible that the rvar is set in some prev bblock, but not in others.
6956                          * (#1835).
6957                          */
6958                         if (rvar) {
6959                                 MonoBasicBlock *bb;
6960
6961                                 for (i = 0; i < ebblock->in_count; ++i) {
6962                                         bb = ebblock->in_bb [i];
6963
6964                                         if (bb->last_ins && bb->last_ins->opcode == OP_NOT_REACHED) {
6965                                                 cfg->cbb = bb;
6966
6967                                                 emit_init_rvar (cfg, rvar->dreg, fsig->ret);
6968                                         }
6969                                 }
6970                         }
6971
6972                         cfg->cbb = ebblock;
6973                 }
6974
6975                 if (rvar) {
6976                         /*
6977                          * If the inlined method contains only a throw, then the ret var is not 
6978                          * set, so set it to a dummy value.
6979                          */
6980                         if (!ret_var_set)
6981                                 emit_init_rvar (cfg, rvar->dreg, fsig->ret);
6982
6983                         EMIT_NEW_TEMPLOAD (cfg, ins, rvar->inst_c0);
6984                         *sp++ = ins;
6985                 }
6986                 cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
6987                 return costs + 1;
6988         } else {
6989                 if (cfg->verbose_level > 2)
6990                         printf ("INLINE ABORTED %s (cost %d)\n", mono_method_full_name (cmethod, TRUE), costs);
6991                 cfg->exception_type = MONO_EXCEPTION_NONE;
6992                 mono_loader_clear_error ();
6993
6994                 /* This gets rid of the newly added bblocks */
6995                 cfg->cbb = prev_cbb;
6996         }
6997         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
6998         return 0;
6999 }
7000
7001 /*
7002  * Some of these comments may well be out-of-date.
7003  * Design decisions: we do a single pass over the IL code (and we do bblock 
7004  * splitting/merging in the few cases when it's required: a back jump to an IL
7005  * address that was not already seen as bblock starting point).
7006  * Code is validated as we go (full verification is still better left to metadata/verify.c).
7007  * Complex operations are decomposed in simpler ones right away. We need to let the 
7008  * arch-specific code peek and poke inside this process somehow (except when the 
7009  * optimizations can take advantage of the full semantic info of coarse opcodes).
7010  * All the opcodes of the form opcode.s are 'normalized' to opcode.
7011  * MonoInst->opcode initially is the IL opcode or some simplification of that 
7012  * (OP_LOAD, OP_STORE). The arch-specific code may rearrange it to an arch-specific 
7013  * opcode with value bigger than OP_LAST.
7014  * At this point the IR can be handed over to an interpreter, a dumb code generator
7015  * or to the optimizing code generator that will translate it to SSA form.
7016  *
7017  * Profiling directed optimizations.
7018  * We may compile by default with few or no optimizations and instrument the code
7019  * or the user may indicate what methods to optimize the most either in a config file
7020  * or through repeated runs where the compiler applies offline the optimizations to 
7021  * each method and then decides if it was worth it.
7022  */
7023
7024 #define CHECK_TYPE(ins) if (!(ins)->type) UNVERIFIED
7025 #define CHECK_STACK(num) if ((sp - stack_start) < (num)) UNVERIFIED
7026 #define CHECK_STACK_OVF(num) if (((sp - stack_start) + (num)) > header->max_stack) UNVERIFIED
7027 #define CHECK_ARG(num) if ((unsigned)(num) >= (unsigned)num_args) UNVERIFIED
7028 #define CHECK_LOCAL(num) if ((unsigned)(num) >= (unsigned)header->num_locals) UNVERIFIED
7029 #define CHECK_OPSIZE(size) if (ip + size > end) UNVERIFIED
7030 #define CHECK_UNVERIFIABLE(cfg) if (cfg->unverifiable) UNVERIFIED
7031 #define CHECK_TYPELOAD(klass) if (!(klass) || (klass)->exception_type) TYPE_LOAD_ERROR ((klass))
7032
7033 /* offset from br.s -> br like opcodes */
7034 #define BIG_BRANCH_OFFSET 13
7035
7036 static gboolean
7037 ip_in_bb (MonoCompile *cfg, MonoBasicBlock *bb, const guint8* ip)
7038 {
7039         MonoBasicBlock *b = cfg->cil_offset_to_bb [ip - cfg->cil_start];
7040
7041         return b == NULL || b == bb;
7042 }
7043
7044 static int
7045 get_basic_blocks (MonoCompile *cfg, MonoMethodHeader* header, guint real_offset, unsigned char *start, unsigned char *end, unsigned char **pos)
7046 {
7047         unsigned char *ip = start;
7048         unsigned char *target;
7049         int i;
7050         guint cli_addr;
7051         MonoBasicBlock *bblock;
7052         const MonoOpcode *opcode;
7053
7054         while (ip < end) {
7055                 cli_addr = ip - start;
7056                 i = mono_opcode_value ((const guint8 **)&ip, end);
7057                 if (i < 0)
7058                         UNVERIFIED;
7059                 opcode = &mono_opcodes [i];
7060                 switch (opcode->argument) {
7061                 case MonoInlineNone:
7062                         ip++; 
7063                         break;
7064                 case MonoInlineString:
7065                 case MonoInlineType:
7066                 case MonoInlineField:
7067                 case MonoInlineMethod:
7068                 case MonoInlineTok:
7069                 case MonoInlineSig:
7070                 case MonoShortInlineR:
7071                 case MonoInlineI:
7072                         ip += 5;
7073                         break;
7074                 case MonoInlineVar:
7075                         ip += 3;
7076                         break;
7077                 case MonoShortInlineVar:
7078                 case MonoShortInlineI:
7079                         ip += 2;
7080                         break;
7081                 case MonoShortInlineBrTarget:
7082                         target = start + cli_addr + 2 + (signed char)ip [1];
7083                         GET_BBLOCK (cfg, bblock, target);
7084                         ip += 2;
7085                         if (ip < end)
7086                                 GET_BBLOCK (cfg, bblock, ip);
7087                         break;
7088                 case MonoInlineBrTarget:
7089                         target = start + cli_addr + 5 + (gint32)read32 (ip + 1);
7090                         GET_BBLOCK (cfg, bblock, target);
7091                         ip += 5;
7092                         if (ip < end)
7093                                 GET_BBLOCK (cfg, bblock, ip);
7094                         break;
7095                 case MonoInlineSwitch: {
7096                         guint32 n = read32 (ip + 1);
7097                         guint32 j;
7098                         ip += 5;
7099                         cli_addr += 5 + 4 * n;
7100                         target = start + cli_addr;
7101                         GET_BBLOCK (cfg, bblock, target);
7102                         
7103                         for (j = 0; j < n; ++j) {
7104                                 target = start + cli_addr + (gint32)read32 (ip);
7105                                 GET_BBLOCK (cfg, bblock, target);
7106                                 ip += 4;
7107                         }
7108                         break;
7109                 }
7110                 case MonoInlineR:
7111                 case MonoInlineI8:
7112                         ip += 9;
7113                         break;
7114                 default:
7115                         g_assert_not_reached ();
7116                 }
7117
7118                 if (i == CEE_THROW) {
7119                         unsigned char *bb_start = ip - 1;
7120                         
7121                         /* Find the start of the bblock containing the throw */
7122                         bblock = NULL;
7123                         while ((bb_start >= start) && !bblock) {
7124                                 bblock = cfg->cil_offset_to_bb [(bb_start) - start];
7125                                 bb_start --;
7126                         }
7127                         if (bblock)
7128                                 bblock->out_of_line = 1;
7129                 }
7130         }
7131         return 0;
7132 unverified:
7133 exception_exit:
7134         *pos = ip;
7135         return 1;
7136 }
7137
7138 static inline MonoMethod *
7139 mini_get_method_allow_open (MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
7140 {
7141         MonoMethod *method;
7142
7143         if (m->wrapper_type != MONO_WRAPPER_NONE) {
7144                 method = mono_method_get_wrapper_data (m, token);
7145                 if (context) {
7146                         MonoError error;
7147                         method = mono_class_inflate_generic_method_checked (method, context, &error);
7148                         g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
7149                 }
7150         } else {
7151                 method = mono_get_method_full (m->klass->image, token, klass, context);
7152         }
7153
7154         return method;
7155 }
7156
7157 static inline MonoMethod *
7158 mini_get_method (MonoCompile *cfg, MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
7159 {
7160         MonoMethod *method = mini_get_method_allow_open (m, token, klass, context);
7161
7162         if (method && cfg && !cfg->gshared && mono_class_is_open_constructed_type (&method->klass->byval_arg))
7163                 return NULL;
7164
7165         return method;
7166 }
7167
7168 static inline MonoClass*
7169 mini_get_class (MonoMethod *method, guint32 token, MonoGenericContext *context)
7170 {
7171         MonoError error;
7172         MonoClass *klass;
7173
7174         if (method->wrapper_type != MONO_WRAPPER_NONE) {
7175                 klass = mono_method_get_wrapper_data (method, token);
7176                 if (context)
7177                         klass = mono_class_inflate_generic_class (klass, context);
7178         } else {
7179                 klass = mono_class_get_and_inflate_typespec_checked (method->klass->image, token, context, &error);
7180                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
7181         }
7182         if (klass)
7183                 mono_class_init (klass);
7184         return klass;
7185 }
7186
7187 static inline MonoMethodSignature*
7188 mini_get_signature (MonoMethod *method, guint32 token, MonoGenericContext *context)
7189 {
7190         MonoMethodSignature *fsig;
7191
7192         if (method->wrapper_type != MONO_WRAPPER_NONE) {
7193                 MonoError error;
7194
7195                 fsig = (MonoMethodSignature *)mono_method_get_wrapper_data (method, token);
7196                 if (context) {
7197                         fsig = mono_inflate_generic_signature (fsig, context, &error);
7198                         // FIXME:
7199                         g_assert (mono_error_ok (&error));
7200                 }
7201         } else {
7202                 fsig = mono_metadata_parse_signature (method->klass->image, token);
7203         }
7204         return fsig;
7205 }
7206
7207 static MonoMethod*
7208 throw_exception (void)
7209 {
7210         static MonoMethod *method = NULL;
7211
7212         if (!method) {
7213                 MonoSecurityManager *secman = mono_security_manager_get_methods ();
7214                 method = mono_class_get_method_from_name (secman->securitymanager, "ThrowException", 1);
7215         }
7216         g_assert (method);
7217         return method;
7218 }
7219
7220 static void
7221 emit_throw_exception (MonoCompile *cfg, MonoException *ex)
7222 {
7223         MonoMethod *thrower = throw_exception ();
7224         MonoInst *args [1];
7225
7226         EMIT_NEW_PCONST (cfg, args [0], ex);
7227         mono_emit_method_call (cfg, thrower, args, NULL);
7228 }
7229
7230 /*
7231  * Return the original method is a wrapper is specified. We can only access 
7232  * the custom attributes from the original method.
7233  */
7234 static MonoMethod*
7235 get_original_method (MonoMethod *method)
7236 {
7237         if (method->wrapper_type == MONO_WRAPPER_NONE)
7238                 return method;
7239
7240         /* native code (which is like Critical) can call any managed method XXX FIXME XXX to validate all usages */
7241         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED)
7242                 return NULL;
7243
7244         /* in other cases we need to find the original method */
7245         return mono_marshal_method_from_wrapper (method);
7246 }
7247
7248 static void
7249 ensure_method_is_allowed_to_access_field (MonoCompile *cfg, MonoMethod *caller, MonoClassField *field)
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_field_access_allowed (get_original_method (caller), field);
7253         if (ex)
7254                 emit_throw_exception (cfg, ex);
7255 }
7256
7257 static void
7258 ensure_method_is_allowed_to_call_method (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee)
7259 {
7260         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
7261         MonoException *ex = mono_security_core_clr_is_call_allowed (get_original_method (caller), callee);
7262         if (ex)
7263                 emit_throw_exception (cfg, ex);
7264 }
7265
7266 /*
7267  * Check that the IL instructions at ip are the array initialization
7268  * sequence and return the pointer to the data and the size.
7269  */
7270 static const char*
7271 initialize_array_data (MonoMethod *method, gboolean aot, unsigned char *ip, MonoClass *klass, guint32 len, int *out_size, guint32 *out_field_token)
7272 {
7273         /*
7274          * newarr[System.Int32]
7275          * dup
7276          * ldtoken field valuetype ...
7277          * call void class [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype [mscorlib]System.RuntimeFieldHandle)
7278          */
7279         if (ip [0] == CEE_DUP && ip [1] == CEE_LDTOKEN && ip [5] == 0x4 && ip [6] == CEE_CALL) {
7280                 MonoError error;
7281                 guint32 token = read32 (ip + 7);
7282                 guint32 field_token = read32 (ip + 2);
7283                 guint32 field_index = field_token & 0xffffff;
7284                 guint32 rva;
7285                 const char *data_ptr;
7286                 int size = 0;
7287                 MonoMethod *cmethod;
7288                 MonoClass *dummy_class;
7289                 MonoClassField *field = mono_field_from_token_checked (method->klass->image, field_token, &dummy_class, NULL, &error);
7290                 int dummy_align;
7291
7292                 if (!field) {
7293                         mono_error_cleanup (&error); /* FIXME don't swallow the error */
7294                         return NULL;
7295                 }
7296
7297                 *out_field_token = field_token;
7298
7299                 cmethod = mini_get_method (NULL, method, token, NULL, NULL);
7300                 if (!cmethod)
7301                         return NULL;
7302                 if (strcmp (cmethod->name, "InitializeArray") || strcmp (cmethod->klass->name, "RuntimeHelpers") || cmethod->klass->image != mono_defaults.corlib)
7303                         return NULL;
7304                 switch (mono_type_get_underlying_type (&klass->byval_arg)->type) {
7305                 case MONO_TYPE_BOOLEAN:
7306                 case MONO_TYPE_I1:
7307                 case MONO_TYPE_U1:
7308                         size = 1; break;
7309                 /* we need to swap on big endian, so punt. Should we handle R4 and R8 as well? */
7310 #if TARGET_BYTE_ORDER == G_LITTLE_ENDIAN
7311                 case MONO_TYPE_CHAR:
7312                 case MONO_TYPE_I2:
7313                 case MONO_TYPE_U2:
7314                         size = 2; break;
7315                 case MONO_TYPE_I4:
7316                 case MONO_TYPE_U4:
7317                 case MONO_TYPE_R4:
7318                         size = 4; break;
7319                 case MONO_TYPE_R8:
7320                 case MONO_TYPE_I8:
7321                 case MONO_TYPE_U8:
7322                         size = 8; break;
7323 #endif
7324                 default:
7325                         return NULL;
7326                 }
7327                 size *= len;
7328                 if (size > mono_type_size (field->type, &dummy_align))
7329                     return NULL;
7330                 *out_size = size;
7331                 /*g_print ("optimized in %s: size: %d, numelems: %d\n", method->name, size, newarr->inst_newa_len->inst_c0);*/
7332                 if (!image_is_dynamic (method->klass->image)) {
7333                         field_index = read32 (ip + 2) & 0xffffff;
7334                         mono_metadata_field_info (method->klass->image, field_index - 1, NULL, &rva, NULL);
7335                         data_ptr = mono_image_rva_map (method->klass->image, rva);
7336                         /*g_print ("field: 0x%08x, rva: %d, rva_ptr: %p\n", read32 (ip + 2), rva, data_ptr);*/
7337                         /* for aot code we do the lookup on load */
7338                         if (aot && data_ptr)
7339                                 return GUINT_TO_POINTER (rva);
7340                 } else {
7341                         /*FIXME is it possible to AOT a SRE assembly not meant to be saved? */ 
7342                         g_assert (!aot);
7343                         data_ptr = mono_field_get_data (field);
7344                 }
7345                 return data_ptr;
7346         }
7347         return NULL;
7348 }
7349
7350 static void
7351 set_exception_type_from_invalid_il (MonoCompile *cfg, MonoMethod *method, unsigned char *ip)
7352 {
7353         char *method_fname = mono_method_full_name (method, TRUE);
7354         char *method_code;
7355         MonoMethodHeader *header = mono_method_get_header (method);
7356
7357         if (header->code_size == 0)
7358                 method_code = g_strdup ("method body is empty.");
7359         else
7360                 method_code = mono_disasm_code_one (NULL, method, ip, NULL);
7361         mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
7362         cfg->exception_message = g_strdup_printf ("Invalid IL code in %s: %s\n", method_fname, method_code);
7363         g_free (method_fname);
7364         g_free (method_code);
7365         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
7366 }
7367
7368 static void
7369 set_exception_object (MonoCompile *cfg, MonoException *exception)
7370 {
7371         mono_cfg_set_exception (cfg, MONO_EXCEPTION_OBJECT_SUPPLIED);
7372         MONO_GC_REGISTER_ROOT_SINGLE (cfg->exception_ptr, MONO_ROOT_SOURCE_JIT, "jit exception");
7373         cfg->exception_ptr = exception;
7374 }
7375
7376 static void
7377 emit_stloc_ir (MonoCompile *cfg, MonoInst **sp, MonoMethodHeader *header, int n)
7378 {
7379         MonoInst *ins;
7380         guint32 opcode = mono_type_to_regmove (cfg, header->locals [n]);
7381         if ((opcode == OP_MOVE) && cfg->cbb->last_ins == sp [0]  &&
7382                         ((sp [0]->opcode == OP_ICONST) || (sp [0]->opcode == OP_I8CONST))) {
7383                 /* Optimize reg-reg moves away */
7384                 /* 
7385                  * Can't optimize other opcodes, since sp[0] might point to
7386                  * the last ins of a decomposed opcode.
7387                  */
7388                 sp [0]->dreg = (cfg)->locals [n]->dreg;
7389         } else {
7390                 EMIT_NEW_LOCSTORE (cfg, ins, n, *sp);
7391         }
7392 }
7393
7394 /*
7395  * ldloca inhibits many optimizations so try to get rid of it in common
7396  * cases.
7397  */
7398 static inline unsigned char *
7399 emit_optimized_ldloca_ir (MonoCompile *cfg, unsigned char *ip, unsigned char *end, int size)
7400 {
7401         int local, token;
7402         MonoClass *klass;
7403         MonoType *type;
7404
7405         if (size == 1) {
7406                 local = ip [1];
7407                 ip += 2;
7408         } else {
7409                 local = read16 (ip + 2);
7410                 ip += 4;
7411         }
7412         
7413         if (ip + 6 < end && (ip [0] == CEE_PREFIX1) && (ip [1] == CEE_INITOBJ) && ip_in_bb (cfg, cfg->cbb, ip + 1)) {
7414                 /* From the INITOBJ case */
7415                 token = read32 (ip + 2);
7416                 klass = mini_get_class (cfg->current_method, token, cfg->generic_context);
7417                 CHECK_TYPELOAD (klass);
7418                 type = mini_get_underlying_type (&klass->byval_arg);
7419                 emit_init_local (cfg, local, type, TRUE);
7420                 return ip + 6;
7421         }
7422  exception_exit:
7423         return NULL;
7424 }
7425
7426 static gboolean
7427 is_exception_class (MonoClass *klass)
7428 {
7429         while (klass) {
7430                 if (klass == mono_defaults.exception_class)
7431                         return TRUE;
7432                 klass = klass->parent;
7433         }
7434         return FALSE;
7435 }
7436
7437 /*
7438  * is_jit_optimizer_disabled:
7439  *
7440  *   Determine whenever M's assembly has a DebuggableAttribute with the
7441  * IsJITOptimizerDisabled flag set.
7442  */
7443 static gboolean
7444 is_jit_optimizer_disabled (MonoMethod *m)
7445 {
7446         MonoAssembly *ass = m->klass->image->assembly;
7447         MonoCustomAttrInfo* attrs;
7448         static MonoClass *klass;
7449         int i;
7450         gboolean val = FALSE;
7451
7452         g_assert (ass);
7453         if (ass->jit_optimizer_disabled_inited)
7454                 return ass->jit_optimizer_disabled;
7455
7456         if (!klass)
7457                 klass = mono_class_from_name (mono_defaults.corlib, "System.Diagnostics", "DebuggableAttribute");
7458         if (!klass) {
7459                 /* Linked away */
7460                 ass->jit_optimizer_disabled = FALSE;
7461                 mono_memory_barrier ();
7462                 ass->jit_optimizer_disabled_inited = TRUE;
7463                 return FALSE;
7464         }
7465
7466         attrs = mono_custom_attrs_from_assembly (ass);
7467         if (attrs) {
7468                 for (i = 0; i < attrs->num_attrs; ++i) {
7469                         MonoCustomAttrEntry *attr = &attrs->attrs [i];
7470                         const gchar *p;
7471                         MonoMethodSignature *sig;
7472
7473                         if (!attr->ctor || attr->ctor->klass != klass)
7474                                 continue;
7475                         /* Decode the attribute. See reflection.c */
7476                         p = (const char*)attr->data;
7477                         g_assert (read16 (p) == 0x0001);
7478                         p += 2;
7479
7480                         // FIXME: Support named parameters
7481                         sig = mono_method_signature (attr->ctor);
7482                         if (sig->param_count != 2 || sig->params [0]->type != MONO_TYPE_BOOLEAN || sig->params [1]->type != MONO_TYPE_BOOLEAN)
7483                                 continue;
7484                         /* Two boolean arguments */
7485                         p ++;
7486                         val = *p;
7487                 }
7488                 mono_custom_attrs_free (attrs);
7489         }
7490
7491         ass->jit_optimizer_disabled = val;
7492         mono_memory_barrier ();
7493         ass->jit_optimizer_disabled_inited = TRUE;
7494
7495         return val;
7496 }
7497
7498 static gboolean
7499 is_supported_tail_call (MonoCompile *cfg, MonoMethod *method, MonoMethod *cmethod, MonoMethodSignature *fsig, int call_opcode)
7500 {
7501         gboolean supported_tail_call;
7502         int i;
7503
7504 #ifdef MONO_ARCH_HAVE_OP_TAIL_CALL
7505         supported_tail_call = mono_arch_tail_call_supported (cfg, mono_method_signature (method), mono_method_signature (cmethod));
7506 #else
7507         supported_tail_call = mono_metadata_signature_equal (mono_method_signature (method), mono_method_signature (cmethod)) && !MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->ret);
7508 #endif
7509
7510         for (i = 0; i < fsig->param_count; ++i) {
7511                 if (fsig->params [i]->byref || fsig->params [i]->type == MONO_TYPE_PTR || fsig->params [i]->type == MONO_TYPE_FNPTR)
7512                         /* These can point to the current method's stack */
7513                         supported_tail_call = FALSE;
7514         }
7515         if (fsig->hasthis && cmethod->klass->valuetype)
7516                 /* this might point to the current method's stack */
7517                 supported_tail_call = FALSE;
7518         if (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
7519                 supported_tail_call = FALSE;
7520         if (cfg->method->save_lmf)
7521                 supported_tail_call = FALSE;
7522         if (cmethod->wrapper_type && cmethod->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD)
7523                 supported_tail_call = FALSE;
7524         if (call_opcode != CEE_CALL)
7525                 supported_tail_call = FALSE;
7526
7527         /* Debugging support */
7528 #if 0
7529         if (supported_tail_call) {
7530                 if (!mono_debug_count ())
7531                         supported_tail_call = FALSE;
7532         }
7533 #endif
7534
7535         return supported_tail_call;
7536 }
7537
7538 /*
7539  * handle_ctor_call:
7540  *
7541  *   Handle calls made to ctors from NEWOBJ opcodes.
7542  */
7543 static void
7544 handle_ctor_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, int context_used,
7545                                   MonoInst **sp, guint8 *ip, int *inline_costs)
7546 {
7547         MonoInst *vtable_arg = NULL, *callvirt_this_arg = NULL, *ins;
7548
7549         if (cmethod->klass->valuetype && mono_class_generic_sharing_enabled (cmethod->klass) &&
7550                                         mono_method_is_generic_sharable (cmethod, TRUE)) {
7551                 if (cmethod->is_inflated && mono_method_get_context (cmethod)->method_inst) {
7552                         mono_class_vtable (cfg->domain, cmethod->klass);
7553                         CHECK_TYPELOAD (cmethod->klass);
7554
7555                         vtable_arg = emit_get_rgctx_method (cfg, context_used,
7556                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
7557                 } else {
7558                         if (context_used) {
7559                                 vtable_arg = emit_get_rgctx_klass (cfg, context_used,
7560                                                                                                    cmethod->klass, MONO_RGCTX_INFO_VTABLE);
7561                         } else {
7562                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
7563
7564                                 CHECK_TYPELOAD (cmethod->klass);
7565                                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
7566                         }
7567                 }
7568         }
7569
7570         /* Avoid virtual calls to ctors if possible */
7571         if (mono_class_is_marshalbyref (cmethod->klass))
7572                 callvirt_this_arg = sp [0];
7573
7574         if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_ctor (cfg, cmethod, fsig, sp))) {
7575                 g_assert (MONO_TYPE_IS_VOID (fsig->ret));
7576                 CHECK_CFG_EXCEPTION;
7577         } else if ((cfg->opt & MONO_OPT_INLINE) && cmethod && !context_used && !vtable_arg &&
7578                            mono_method_check_inlining (cfg, cmethod) &&
7579                            !mono_class_is_subclass_of (cmethod->klass, mono_defaults.exception_class, FALSE)) {
7580                 int costs;
7581
7582                 if ((costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, FALSE))) {
7583                         cfg->real_offset += 5;
7584
7585                         *inline_costs += costs - 5;
7586                 } else {
7587                         INLINE_FAILURE ("inline failure");
7588                         // FIXME-VT: Clean this up
7589                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig))
7590                                 GSHAREDVT_FAILURE(*ip);
7591                         mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, callvirt_this_arg, NULL, NULL);
7592                 }
7593         } else if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) {
7594                 MonoInst *addr;
7595
7596                 addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE);
7597                 mono_emit_calli (cfg, fsig, sp, addr, NULL, vtable_arg);
7598         } else if (context_used &&
7599                            ((!mono_method_is_generic_sharable_full (cmethod, TRUE, FALSE, FALSE) ||
7600                                  !mono_class_generic_sharing_enabled (cmethod->klass)) || cfg->gsharedvt)) {
7601                 MonoInst *cmethod_addr;
7602
7603                 /* Generic calls made out of gsharedvt methods cannot be patched, so use an indirect call */
7604
7605                 cmethod_addr = emit_get_rgctx_method (cfg, context_used,
7606                                                                                           cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
7607
7608                 mono_emit_calli (cfg, fsig, sp, cmethod_addr, NULL, vtable_arg);
7609         } else {
7610                 INLINE_FAILURE ("ctor call");
7611                 ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp,
7612                                                                                   callvirt_this_arg, NULL, vtable_arg);
7613         }
7614  exception_exit:
7615         return;
7616 }
7617
7618 /*
7619  * mono_method_to_ir:
7620  *
7621  *   Translate the .net IL into linear IR.
7622  */
7623 int
7624 mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock, 
7625                    MonoInst *return_var, MonoInst **inline_args, 
7626                    guint inline_offset, gboolean is_virtual_call)
7627 {
7628         MonoError error;
7629         MonoInst *ins, **sp, **stack_start;
7630         MonoBasicBlock *tblock = NULL, *init_localsbb = NULL;
7631         MonoSimpleBasicBlock *bb = NULL, *original_bb = NULL;
7632         MonoMethod *cmethod, *method_definition;
7633         MonoInst **arg_array;
7634         MonoMethodHeader *header;
7635         MonoImage *image;
7636         guint32 token, ins_flag;
7637         MonoClass *klass;
7638         MonoClass *constrained_class = NULL;
7639         unsigned char *ip, *end, *target, *err_pos;
7640         MonoMethodSignature *sig;
7641         MonoGenericContext *generic_context = NULL;
7642         MonoGenericContainer *generic_container = NULL;
7643         MonoType **param_types;
7644         int i, n, start_new_bblock, dreg;
7645         int num_calls = 0, inline_costs = 0;
7646         int breakpoint_id = 0;
7647         guint num_args;
7648         GSList *class_inits = NULL;
7649         gboolean dont_verify, dont_verify_stloc, readonly = FALSE;
7650         int context_used;
7651         gboolean init_locals, seq_points, skip_dead_blocks;
7652         gboolean sym_seq_points = FALSE;
7653         MonoDebugMethodInfo *minfo;
7654         MonoBitSet *seq_point_locs = NULL;
7655         MonoBitSet *seq_point_set_locs = NULL;
7656
7657         cfg->disable_inline = is_jit_optimizer_disabled (method);
7658
7659         /* serialization and xdomain stuff may need access to private fields and methods */
7660         dont_verify = method->klass->image->assembly->corlib_internal? TRUE: FALSE;
7661         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE;
7662         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH;
7663         dont_verify |= method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE; /* bug #77896 */
7664         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP;
7665         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP_INVOKE;
7666
7667         /* still some type unsafety issues in marshal wrappers... (unknown is PtrToStructure) */
7668         dont_verify_stloc = method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE;
7669         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_UNKNOWN;
7670         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED;
7671         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_STELEMREF;
7672
7673         image = method->klass->image;
7674         header = mono_method_get_header (method);
7675         if (!header) {
7676                 MonoLoaderError *error;
7677
7678                 if ((error = mono_loader_get_last_error ())) {
7679                         mono_cfg_set_exception (cfg, error->exception_type);
7680                 } else {
7681                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
7682                         cfg->exception_message = g_strdup_printf ("Missing or incorrect header for method %s", cfg->method->name);
7683                 }
7684                 goto exception_exit;
7685         }
7686         generic_container = mono_method_get_generic_container (method);
7687         sig = mono_method_signature (method);
7688         num_args = sig->hasthis + sig->param_count;
7689         ip = (unsigned char*)header->code;
7690         cfg->cil_start = ip;
7691         end = ip + header->code_size;
7692         cfg->stat_cil_code_size += header->code_size;
7693
7694         seq_points = cfg->gen_seq_points && cfg->method == method;
7695
7696         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
7697                 /* We could hit a seq point before attaching to the JIT (#8338) */
7698                 seq_points = FALSE;
7699         }
7700
7701         if (cfg->gen_sdb_seq_points && cfg->method == method) {
7702                 minfo = mono_debug_lookup_method (method);
7703                 if (minfo) {
7704                         MonoSymSeqPoint *sps;
7705                         int i, n_il_offsets;
7706
7707                         mono_debug_get_seq_points (minfo, NULL, NULL, NULL, &sps, &n_il_offsets);
7708                         seq_point_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
7709                         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);
7710                         sym_seq_points = TRUE;
7711                         for (i = 0; i < n_il_offsets; ++i) {
7712                                 if (sps [i].il_offset < header->code_size)
7713                                         mono_bitset_set_fast (seq_point_locs, sps [i].il_offset);
7714                         }
7715                         g_free (sps);
7716                 } else if (!method->wrapper_type && !method->dynamic && mono_debug_image_has_debug_info (method->klass->image)) {
7717                         /* Methods without line number info like auto-generated property accessors */
7718                         seq_point_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
7719                         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);
7720                         sym_seq_points = TRUE;
7721                 }
7722         }
7723
7724         /* 
7725          * Methods without init_locals set could cause asserts in various passes
7726          * (#497220). To work around this, we emit dummy initialization opcodes
7727          * (OP_DUMMY_ICONST etc.) which generate no code. These are only supported
7728          * on some platforms.
7729          */
7730         if ((cfg->opt & MONO_OPT_UNSAFE) && ARCH_HAVE_DUMMY_INIT)
7731                 init_locals = header->init_locals;
7732         else
7733                 init_locals = TRUE;
7734
7735         method_definition = method;
7736         while (method_definition->is_inflated) {
7737                 MonoMethodInflated *imethod = (MonoMethodInflated *) method_definition;
7738                 method_definition = imethod->declaring;
7739         }
7740
7741         /* SkipVerification is not allowed if core-clr is enabled */
7742         if (!dont_verify && mini_assembly_can_skip_verification (cfg->domain, method)) {
7743                 dont_verify = TRUE;
7744                 dont_verify_stloc = TRUE;
7745         }
7746
7747         if (sig->is_inflated)
7748                 generic_context = mono_method_get_context (method);
7749         else if (generic_container)
7750                 generic_context = &generic_container->context;
7751         cfg->generic_context = generic_context;
7752
7753         if (!cfg->gshared)
7754                 g_assert (!sig->has_type_parameters);
7755
7756         if (sig->generic_param_count && method->wrapper_type == MONO_WRAPPER_NONE) {
7757                 g_assert (method->is_inflated);
7758                 g_assert (mono_method_get_context (method)->method_inst);
7759         }
7760         if (method->is_inflated && mono_method_get_context (method)->method_inst)
7761                 g_assert (sig->generic_param_count);
7762
7763         if (cfg->method == method) {
7764                 cfg->real_offset = 0;
7765         } else {
7766                 cfg->real_offset = inline_offset;
7767         }
7768
7769         cfg->cil_offset_to_bb = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoBasicBlock*) * header->code_size);
7770         cfg->cil_offset_to_bb_len = header->code_size;
7771
7772         cfg->current_method = method;
7773
7774         if (cfg->verbose_level > 2)
7775                 printf ("method to IR %s\n", mono_method_full_name (method, TRUE));
7776
7777         param_types = mono_mempool_alloc (cfg->mempool, sizeof (MonoType*) * num_args);
7778         if (sig->hasthis)
7779                 param_types [0] = method->klass->valuetype?&method->klass->this_arg:&method->klass->byval_arg;
7780         for (n = 0; n < sig->param_count; ++n)
7781                 param_types [n + sig->hasthis] = sig->params [n];
7782         cfg->arg_types = param_types;
7783
7784         cfg->dont_inline = g_list_prepend (cfg->dont_inline, method);
7785         if (cfg->method == method) {
7786
7787                 if (cfg->prof_options & MONO_PROFILE_INS_COVERAGE)
7788                         cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, header->code_size);
7789
7790                 /* ENTRY BLOCK */
7791                 NEW_BBLOCK (cfg, start_bblock);
7792                 cfg->bb_entry = start_bblock;
7793                 start_bblock->cil_code = NULL;
7794                 start_bblock->cil_length = 0;
7795
7796                 /* EXIT BLOCK */
7797                 NEW_BBLOCK (cfg, end_bblock);
7798                 cfg->bb_exit = end_bblock;
7799                 end_bblock->cil_code = NULL;
7800                 end_bblock->cil_length = 0;
7801                 end_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
7802                 g_assert (cfg->num_bblocks == 2);
7803
7804                 arg_array = cfg->args;
7805
7806                 if (header->num_clauses) {
7807                         cfg->spvars = g_hash_table_new (NULL, NULL);
7808                         cfg->exvars = g_hash_table_new (NULL, NULL);
7809                 }
7810                 /* handle exception clauses */
7811                 for (i = 0; i < header->num_clauses; ++i) {
7812                         MonoBasicBlock *try_bb;
7813                         MonoExceptionClause *clause = &header->clauses [i];
7814                         GET_BBLOCK (cfg, try_bb, ip + clause->try_offset);
7815                         try_bb->real_offset = clause->try_offset;
7816                         try_bb->try_start = TRUE;
7817                         try_bb->region = ((i + 1) << 8) | clause->flags;
7818                         GET_BBLOCK (cfg, tblock, ip + clause->handler_offset);
7819                         tblock->real_offset = clause->handler_offset;
7820                         tblock->flags |= BB_EXCEPTION_HANDLER;
7821
7822                         /*
7823                          * Linking the try block with the EH block hinders inlining as we won't be able to 
7824                          * merge the bblocks from inlining and produce an artificial hole for no good reason.
7825                          */
7826                         if (COMPILE_LLVM (cfg))
7827                                 link_bblock (cfg, try_bb, tblock);
7828
7829                         if (*(ip + clause->handler_offset) == CEE_POP)
7830                                 tblock->flags |= BB_EXCEPTION_DEAD_OBJ;
7831
7832                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY ||
7833                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER ||
7834                             clause->flags == MONO_EXCEPTION_CLAUSE_FAULT) {
7835                                 MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
7836                                 MONO_ADD_INS (tblock, ins);
7837
7838                                 if (seq_points && clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY && clause->flags != MONO_EXCEPTION_CLAUSE_FILTER) {
7839                                         /* finally clauses already have a seq point */
7840                                         /* seq points for filter clauses are emitted below */
7841                                         NEW_SEQ_POINT (cfg, ins, clause->handler_offset, TRUE);
7842                                         MONO_ADD_INS (tblock, ins);
7843                                 }
7844
7845                                 /* todo: is a fault block unsafe to optimize? */
7846                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
7847                                         tblock->flags |= BB_EXCEPTION_UNSAFE;
7848                         }
7849
7850                         /*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);
7851                           while (p < end) {
7852                           printf ("%s", mono_disasm_code_one (NULL, method, p, &p));
7853                           }*/
7854                         /* catch and filter blocks get the exception object on the stack */
7855                         if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE ||
7856                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
7857
7858                                 /* mostly like handle_stack_args (), but just sets the input args */
7859                                 /* printf ("handling clause at IL_%04x\n", clause->handler_offset); */
7860                                 tblock->in_scount = 1;
7861                                 tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
7862                                 tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
7863
7864                                 cfg->cbb = tblock;
7865
7866 #ifdef MONO_CONTEXT_SET_LLVM_EXC_REG
7867                                 /* The EH code passes in the exception in a register to both JITted and LLVM compiled code */
7868                                 if (!cfg->compile_llvm) {
7869                                         MONO_INST_NEW (cfg, ins, OP_GET_EX_OBJ);
7870                                         ins->dreg = tblock->in_stack [0]->dreg;
7871                                         MONO_ADD_INS (tblock, ins);
7872                                 }
7873 #else
7874                                 MonoInst *dummy_use;
7875
7876                                 /* 
7877                                  * Add a dummy use for the exvar so its liveness info will be
7878                                  * correct.
7879                                  */
7880                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, tblock->in_stack [0]);
7881 #endif
7882
7883                                 if (seq_points && clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
7884                                         NEW_SEQ_POINT (cfg, ins, clause->handler_offset, TRUE);
7885                                         MONO_ADD_INS (tblock, ins);
7886                                 }
7887                                 
7888                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
7889                                         GET_BBLOCK (cfg, tblock, ip + clause->data.filter_offset);
7890                                         tblock->flags |= BB_EXCEPTION_HANDLER;
7891                                         tblock->real_offset = clause->data.filter_offset;
7892                                         tblock->in_scount = 1;
7893                                         tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
7894                                         /* The filter block shares the exvar with the handler block */
7895                                         tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
7896                                         MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
7897                                         MONO_ADD_INS (tblock, ins);
7898                                 }
7899                         }
7900
7901                         if (clause->flags != MONO_EXCEPTION_CLAUSE_FILTER &&
7902                                         clause->data.catch_class &&
7903                                         cfg->gshared &&
7904                                         mono_class_check_context_used (clause->data.catch_class)) {
7905                                 /*
7906                                  * In shared generic code with catch
7907                                  * clauses containing type variables
7908                                  * the exception handling code has to
7909                                  * be able to get to the rgctx.
7910                                  * Therefore we have to make sure that
7911                                  * the vtable/mrgctx argument (for
7912                                  * static or generic methods) or the
7913                                  * "this" argument (for non-static
7914                                  * methods) are live.
7915                                  */
7916                                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
7917                                                 mini_method_get_context (method)->method_inst ||
7918                                                 method->klass->valuetype) {
7919                                         mono_get_vtable_var (cfg);
7920                                 } else {
7921                                         MonoInst *dummy_use;
7922
7923                                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, arg_array [0]);
7924                                 }
7925                         }
7926                 }
7927         } else {
7928                 arg_array = (MonoInst **) alloca (sizeof (MonoInst *) * num_args);
7929                 cfg->cbb = start_bblock;
7930                 cfg->args = arg_array;
7931                 mono_save_args (cfg, sig, inline_args);
7932         }
7933
7934         /* FIRST CODE BLOCK */
7935         NEW_BBLOCK (cfg, tblock);
7936         tblock->cil_code = ip;
7937         cfg->cbb = tblock;
7938         cfg->ip = ip;
7939
7940         ADD_BBLOCK (cfg, tblock);
7941
7942         if (cfg->method == method) {
7943                 breakpoint_id = mono_debugger_method_has_breakpoint (method);
7944                 if (breakpoint_id) {
7945                         MONO_INST_NEW (cfg, ins, OP_BREAK);
7946                         MONO_ADD_INS (cfg->cbb, ins);
7947                 }
7948         }
7949
7950         /* we use a separate basic block for the initialization code */
7951         NEW_BBLOCK (cfg, init_localsbb);
7952         cfg->bb_init = init_localsbb;
7953         init_localsbb->real_offset = cfg->real_offset;
7954         start_bblock->next_bb = init_localsbb;
7955         init_localsbb->next_bb = cfg->cbb;
7956         link_bblock (cfg, start_bblock, init_localsbb);
7957         link_bblock (cfg, init_localsbb, cfg->cbb);
7958                 
7959         cfg->cbb = init_localsbb;
7960
7961         if (cfg->gsharedvt && cfg->method == method) {
7962                 MonoGSharedVtMethodInfo *info;
7963                 MonoInst *var, *locals_var;
7964                 int dreg;
7965
7966                 info = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoGSharedVtMethodInfo));
7967                 info->method = cfg->method;
7968                 info->count_entries = 16;
7969                 info->entries = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
7970                 cfg->gsharedvt_info = info;
7971
7972                 var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
7973                 /* prevent it from being register allocated */
7974                 //var->flags |= MONO_INST_VOLATILE;
7975                 cfg->gsharedvt_info_var = var;
7976
7977                 ins = emit_get_rgctx_gsharedvt_method (cfg, mini_method_check_context_used (cfg, method), method, info);
7978                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, var->dreg, ins->dreg);
7979
7980                 /* Allocate locals */
7981                 locals_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
7982                 /* prevent it from being register allocated */
7983                 //locals_var->flags |= MONO_INST_VOLATILE;
7984                 cfg->gsharedvt_locals_var = locals_var;
7985
7986                 dreg = alloc_ireg (cfg);
7987                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, dreg, var->dreg, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, locals_size));
7988
7989                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
7990                 ins->dreg = locals_var->dreg;
7991                 ins->sreg1 = dreg;
7992                 MONO_ADD_INS (cfg->cbb, ins);
7993                 cfg->gsharedvt_locals_var_ins = ins;
7994                 
7995                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
7996                 /*
7997                 if (init_locals)
7998                         ins->flags |= MONO_INST_INIT;
7999                 */
8000         }
8001
8002         if (mono_security_core_clr_enabled ()) {
8003                 /* check if this is native code, e.g. an icall or a p/invoke */
8004                 if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
8005                         MonoMethod *wrapped = mono_marshal_method_from_wrapper (method);
8006                         if (wrapped) {
8007                                 gboolean pinvk = (wrapped->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL);
8008                                 gboolean icall = (wrapped->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL);
8009
8010                                 /* if this ia a native call then it can only be JITted from platform code */
8011                                 if ((icall || pinvk) && method->klass && method->klass->image) {
8012                                         if (!mono_security_core_clr_is_platform_image (method->klass->image)) {
8013                                                 MonoException *ex = icall ? mono_get_exception_security () : 
8014                                                         mono_get_exception_method_access ();
8015                                                 emit_throw_exception (cfg, ex);
8016                                         }
8017                                 }
8018                         }
8019                 }
8020         }
8021
8022         CHECK_CFG_EXCEPTION;
8023
8024         if (header->code_size == 0)
8025                 UNVERIFIED;
8026
8027         if (get_basic_blocks (cfg, header, cfg->real_offset, ip, end, &err_pos)) {
8028                 ip = err_pos;
8029                 UNVERIFIED;
8030         }
8031
8032         if (cfg->method == method)
8033                 mono_debug_init_method (cfg, cfg->cbb, breakpoint_id);
8034
8035         for (n = 0; n < header->num_locals; ++n) {
8036                 if (header->locals [n]->type == MONO_TYPE_VOID && !header->locals [n]->byref)
8037                         UNVERIFIED;
8038         }
8039         class_inits = NULL;
8040
8041         /* We force the vtable variable here for all shared methods
8042            for the possibility that they might show up in a stack
8043            trace where their exact instantiation is needed. */
8044         if (cfg->gshared && method == cfg->method) {
8045                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
8046                                 mini_method_get_context (method)->method_inst ||
8047                                 method->klass->valuetype) {
8048                         mono_get_vtable_var (cfg);
8049                 } else {
8050                         /* FIXME: Is there a better way to do this?
8051                            We need the variable live for the duration
8052                            of the whole method. */
8053                         cfg->args [0]->flags |= MONO_INST_VOLATILE;
8054                 }
8055         }
8056
8057         /* add a check for this != NULL to inlined methods */
8058         if (is_virtual_call) {
8059                 MonoInst *arg_ins;
8060
8061                 NEW_ARGLOAD (cfg, arg_ins, 0);
8062                 MONO_ADD_INS (cfg->cbb, arg_ins);
8063                 MONO_EMIT_NEW_CHECK_THIS (cfg, arg_ins->dreg);
8064         }
8065
8066         skip_dead_blocks = !dont_verify;
8067         if (skip_dead_blocks) {
8068                 original_bb = bb = mono_basic_block_split (method, &cfg->error);
8069                 CHECK_CFG_ERROR;
8070                 g_assert (bb);
8071         }
8072
8073         /* we use a spare stack slot in SWITCH and NEWOBJ and others */
8074         stack_start = sp = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (header->max_stack + 1));
8075
8076         ins_flag = 0;
8077         start_new_bblock = 0;
8078         while (ip < end) {
8079                 if (cfg->method == method)
8080                         cfg->real_offset = ip - header->code;
8081                 else
8082                         cfg->real_offset = inline_offset;
8083                 cfg->ip = ip;
8084
8085                 context_used = 0;
8086
8087                 if (start_new_bblock) {
8088                         cfg->cbb->cil_length = ip - cfg->cbb->cil_code;
8089                         if (start_new_bblock == 2) {
8090                                 g_assert (ip == tblock->cil_code);
8091                         } else {
8092                                 GET_BBLOCK (cfg, tblock, ip);
8093                         }
8094                         cfg->cbb->next_bb = tblock;
8095                         cfg->cbb = tblock;
8096                         start_new_bblock = 0;
8097                         for (i = 0; i < cfg->cbb->in_scount; ++i) {
8098                                 if (cfg->verbose_level > 3)
8099                                         printf ("loading %d from temp %d\n", i, (int)cfg->cbb->in_stack [i]->inst_c0);
8100                                 EMIT_NEW_TEMPLOAD (cfg, ins, cfg->cbb->in_stack [i]->inst_c0);
8101                                 *sp++ = ins;
8102                         }
8103                         if (class_inits)
8104                                 g_slist_free (class_inits);
8105                         class_inits = NULL;
8106                 } else {
8107                         if ((tblock = cfg->cil_offset_to_bb [ip - cfg->cil_start]) && (tblock != cfg->cbb)) {
8108                                 link_bblock (cfg, cfg->cbb, tblock);
8109                                 if (sp != stack_start) {
8110                                         handle_stack_args (cfg, stack_start, sp - stack_start);
8111                                         sp = stack_start;
8112                                         CHECK_UNVERIFIABLE (cfg);
8113                                 }
8114                                 cfg->cbb->next_bb = tblock;
8115                                 cfg->cbb = tblock;
8116                                 for (i = 0; i < cfg->cbb->in_scount; ++i) {
8117                                         if (cfg->verbose_level > 3)
8118                                                 printf ("loading %d from temp %d\n", i, (int)cfg->cbb->in_stack [i]->inst_c0);
8119                                         EMIT_NEW_TEMPLOAD (cfg, ins, cfg->cbb->in_stack [i]->inst_c0);
8120                                         *sp++ = ins;
8121                                 }
8122                                 g_slist_free (class_inits);
8123                                 class_inits = NULL;
8124                         }
8125                 }
8126
8127                 if (skip_dead_blocks) {
8128                         int ip_offset = ip - header->code;
8129
8130                         if (ip_offset == bb->end)
8131                                 bb = bb->next;
8132
8133                         if (bb->dead) {
8134                                 int op_size = mono_opcode_size (ip, end);
8135                                 g_assert (op_size > 0); /*The BB formation pass must catch all bad ops*/
8136
8137                                 if (cfg->verbose_level > 3) printf ("SKIPPING DEAD OP at %x\n", ip_offset);
8138
8139                                 if (ip_offset + op_size == bb->end) {
8140                                         MONO_INST_NEW (cfg, ins, OP_NOP);
8141                                         MONO_ADD_INS (cfg->cbb, ins);
8142                                         start_new_bblock = 1;
8143                                 }
8144
8145                                 ip += op_size;
8146                                 continue;
8147                         }
8148                 }
8149                 /*
8150                  * Sequence points are points where the debugger can place a breakpoint.
8151                  * Currently, we generate these automatically at points where the IL
8152                  * stack is empty.
8153                  */
8154                 if (seq_points && ((!sym_seq_points && (sp == stack_start)) || (sym_seq_points && mono_bitset_test_fast (seq_point_locs, ip - header->code)))) {
8155                         /*
8156                          * Make methods interruptable at the beginning, and at the targets of
8157                          * backward branches.
8158                          * Also, do this at the start of every bblock in methods with clauses too,
8159                          * to be able to handle instructions with inprecise control flow like
8160                          * throw/endfinally.
8161                          * Backward branches are handled at the end of method-to-ir ().
8162                          */
8163                         gboolean intr_loc = ip == header->code || (!cfg->cbb->last_ins && cfg->header->num_clauses);
8164                         gboolean sym_seq_point = sym_seq_points && mono_bitset_test_fast (seq_point_locs, ip - header->code);
8165
8166                         /* Avoid sequence points on empty IL like .volatile */
8167                         // FIXME: Enable this
8168                         //if (!(cfg->cbb->last_ins && cfg->cbb->last_ins->opcode == OP_SEQ_POINT)) {
8169                         NEW_SEQ_POINT (cfg, ins, ip - header->code, intr_loc);
8170                         if ((sp != stack_start) && !sym_seq_point)
8171                                 ins->flags |= MONO_INST_NONEMPTY_STACK;
8172                         MONO_ADD_INS (cfg->cbb, ins);
8173
8174                         if (sym_seq_points)
8175                                 mono_bitset_set_fast (seq_point_set_locs, ip - header->code);
8176                 }
8177
8178                 cfg->cbb->real_offset = cfg->real_offset;
8179
8180                 if ((cfg->method == method) && cfg->coverage_info) {
8181                         guint32 cil_offset = ip - header->code;
8182                         cfg->coverage_info->data [cil_offset].cil_code = ip;
8183
8184                         /* TODO: Use an increment here */
8185 #if defined(TARGET_X86)
8186                         MONO_INST_NEW (cfg, ins, OP_STORE_MEM_IMM);
8187                         ins->inst_p0 = &(cfg->coverage_info->data [cil_offset].count);
8188                         ins->inst_imm = 1;
8189                         MONO_ADD_INS (cfg->cbb, ins);
8190 #else
8191                         EMIT_NEW_PCONST (cfg, ins, &(cfg->coverage_info->data [cil_offset].count));
8192                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, ins->dreg, 0, 1);
8193 #endif
8194                 }
8195
8196                 if (cfg->verbose_level > 3)
8197                         printf ("converting (in B%d: stack: %d) %s", cfg->cbb->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
8198
8199                 switch (*ip) {
8200                 case CEE_NOP:
8201                         if (seq_points && !sym_seq_points && sp != stack_start) {
8202                                 /*
8203                                  * The C# compiler uses these nops to notify the JIT that it should
8204                                  * insert seq points.
8205                                  */
8206                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, FALSE);
8207                                 MONO_ADD_INS (cfg->cbb, ins);
8208                         }
8209                         if (cfg->keep_cil_nops)
8210                                 MONO_INST_NEW (cfg, ins, OP_HARD_NOP);
8211                         else
8212                                 MONO_INST_NEW (cfg, ins, OP_NOP);
8213                         ip++;
8214                         MONO_ADD_INS (cfg->cbb, ins);
8215                         break;
8216                 case CEE_BREAK:
8217                         if (should_insert_brekpoint (cfg->method)) {
8218                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
8219                         } else {
8220                                 MONO_INST_NEW (cfg, ins, OP_NOP);
8221                         }
8222                         ip++;
8223                         MONO_ADD_INS (cfg->cbb, ins);
8224                         break;
8225                 case CEE_LDARG_0:
8226                 case CEE_LDARG_1:
8227                 case CEE_LDARG_2:
8228                 case CEE_LDARG_3:
8229                         CHECK_STACK_OVF (1);
8230                         n = (*ip)-CEE_LDARG_0;
8231                         CHECK_ARG (n);
8232                         EMIT_NEW_ARGLOAD (cfg, ins, n);
8233                         ip++;
8234                         *sp++ = ins;
8235                         break;
8236                 case CEE_LDLOC_0:
8237                 case CEE_LDLOC_1:
8238                 case CEE_LDLOC_2:
8239                 case CEE_LDLOC_3:
8240                         CHECK_STACK_OVF (1);
8241                         n = (*ip)-CEE_LDLOC_0;
8242                         CHECK_LOCAL (n);
8243                         EMIT_NEW_LOCLOAD (cfg, ins, n);
8244                         ip++;
8245                         *sp++ = ins;
8246                         break;
8247                 case CEE_STLOC_0:
8248                 case CEE_STLOC_1:
8249                 case CEE_STLOC_2:
8250                 case CEE_STLOC_3: {
8251                         CHECK_STACK (1);
8252                         n = (*ip)-CEE_STLOC_0;
8253                         CHECK_LOCAL (n);
8254                         --sp;
8255                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
8256                                 UNVERIFIED;
8257                         emit_stloc_ir (cfg, sp, header, n);
8258                         ++ip;
8259                         inline_costs += 1;
8260                         break;
8261                         }
8262                 case CEE_LDARG_S:
8263                         CHECK_OPSIZE (2);
8264                         CHECK_STACK_OVF (1);
8265                         n = ip [1];
8266                         CHECK_ARG (n);
8267                         EMIT_NEW_ARGLOAD (cfg, ins, n);
8268                         *sp++ = ins;
8269                         ip += 2;
8270                         break;
8271                 case CEE_LDARGA_S:
8272                         CHECK_OPSIZE (2);
8273                         CHECK_STACK_OVF (1);
8274                         n = ip [1];
8275                         CHECK_ARG (n);
8276                         NEW_ARGLOADA (cfg, ins, n);
8277                         MONO_ADD_INS (cfg->cbb, ins);
8278                         *sp++ = ins;
8279                         ip += 2;
8280                         break;
8281                 case CEE_STARG_S:
8282                         CHECK_OPSIZE (2);
8283                         CHECK_STACK (1);
8284                         --sp;
8285                         n = ip [1];
8286                         CHECK_ARG (n);
8287                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [ip [1]], *sp))
8288                                 UNVERIFIED;
8289                         EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
8290                         ip += 2;
8291                         break;
8292                 case CEE_LDLOC_S:
8293                         CHECK_OPSIZE (2);
8294                         CHECK_STACK_OVF (1);
8295                         n = ip [1];
8296                         CHECK_LOCAL (n);
8297                         EMIT_NEW_LOCLOAD (cfg, ins, n);
8298                         *sp++ = ins;
8299                         ip += 2;
8300                         break;
8301                 case CEE_LDLOCA_S: {
8302                         unsigned char *tmp_ip;
8303                         CHECK_OPSIZE (2);
8304                         CHECK_STACK_OVF (1);
8305                         CHECK_LOCAL (ip [1]);
8306
8307                         if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 1))) {
8308                                 ip = tmp_ip;
8309                                 inline_costs += 1;
8310                                 break;
8311                         }
8312
8313                         EMIT_NEW_LOCLOADA (cfg, ins, ip [1]);
8314                         *sp++ = ins;
8315                         ip += 2;
8316                         break;
8317                 }
8318                 case CEE_STLOC_S:
8319                         CHECK_OPSIZE (2);
8320                         CHECK_STACK (1);
8321                         --sp;
8322                         CHECK_LOCAL (ip [1]);
8323                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [ip [1]], *sp))
8324                                 UNVERIFIED;
8325                         emit_stloc_ir (cfg, sp, header, ip [1]);
8326                         ip += 2;
8327                         inline_costs += 1;
8328                         break;
8329                 case CEE_LDNULL:
8330                         CHECK_STACK_OVF (1);
8331                         EMIT_NEW_PCONST (cfg, ins, NULL);
8332                         ins->type = STACK_OBJ;
8333                         ++ip;
8334                         *sp++ = ins;
8335                         break;
8336                 case CEE_LDC_I4_M1:
8337                         CHECK_STACK_OVF (1);
8338                         EMIT_NEW_ICONST (cfg, ins, -1);
8339                         ++ip;
8340                         *sp++ = ins;
8341                         break;
8342                 case CEE_LDC_I4_0:
8343                 case CEE_LDC_I4_1:
8344                 case CEE_LDC_I4_2:
8345                 case CEE_LDC_I4_3:
8346                 case CEE_LDC_I4_4:
8347                 case CEE_LDC_I4_5:
8348                 case CEE_LDC_I4_6:
8349                 case CEE_LDC_I4_7:
8350                 case CEE_LDC_I4_8:
8351                         CHECK_STACK_OVF (1);
8352                         EMIT_NEW_ICONST (cfg, ins, (*ip) - CEE_LDC_I4_0);
8353                         ++ip;
8354                         *sp++ = ins;
8355                         break;
8356                 case CEE_LDC_I4_S:
8357                         CHECK_OPSIZE (2);
8358                         CHECK_STACK_OVF (1);
8359                         ++ip;
8360                         EMIT_NEW_ICONST (cfg, ins, *((signed char*)ip));
8361                         ++ip;
8362                         *sp++ = ins;
8363                         break;
8364                 case CEE_LDC_I4:
8365                         CHECK_OPSIZE (5);
8366                         CHECK_STACK_OVF (1);
8367                         EMIT_NEW_ICONST (cfg, ins, (gint32)read32 (ip + 1));
8368                         ip += 5;
8369                         *sp++ = ins;
8370                         break;
8371                 case CEE_LDC_I8:
8372                         CHECK_OPSIZE (9);
8373                         CHECK_STACK_OVF (1);
8374                         MONO_INST_NEW (cfg, ins, OP_I8CONST);
8375                         ins->type = STACK_I8;
8376                         ins->dreg = alloc_dreg (cfg, STACK_I8);
8377                         ++ip;
8378                         ins->inst_l = (gint64)read64 (ip);
8379                         MONO_ADD_INS (cfg->cbb, ins);
8380                         ip += 8;
8381                         *sp++ = ins;
8382                         break;
8383                 case CEE_LDC_R4: {
8384                         float *f;
8385                         gboolean use_aotconst = FALSE;
8386
8387 #ifdef TARGET_POWERPC
8388                         /* FIXME: Clean this up */
8389                         if (cfg->compile_aot)
8390                                 use_aotconst = TRUE;
8391 #endif
8392
8393                         /* FIXME: we should really allocate this only late in the compilation process */
8394                         f = mono_domain_alloc (cfg->domain, sizeof (float));
8395                         CHECK_OPSIZE (5);
8396                         CHECK_STACK_OVF (1);
8397
8398                         if (use_aotconst) {
8399                                 MonoInst *cons;
8400                                 int dreg;
8401
8402                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R4, f);
8403
8404                                 dreg = alloc_freg (cfg);
8405                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR4_MEMBASE, dreg, cons->dreg, 0);
8406                                 ins->type = cfg->r4_stack_type;
8407                         } else {
8408                                 MONO_INST_NEW (cfg, ins, OP_R4CONST);
8409                                 ins->type = cfg->r4_stack_type;
8410                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
8411                                 ins->inst_p0 = f;
8412                                 MONO_ADD_INS (cfg->cbb, ins);
8413                         }
8414                         ++ip;
8415                         readr4 (ip, f);
8416                         ip += 4;
8417                         *sp++ = ins;                    
8418                         break;
8419                 }
8420                 case CEE_LDC_R8: {
8421                         double *d;
8422                         gboolean use_aotconst = FALSE;
8423
8424 #ifdef TARGET_POWERPC
8425                         /* FIXME: Clean this up */
8426                         if (cfg->compile_aot)
8427                                 use_aotconst = TRUE;
8428 #endif
8429
8430                         /* FIXME: we should really allocate this only late in the compilation process */
8431                         d = mono_domain_alloc (cfg->domain, sizeof (double));
8432                         CHECK_OPSIZE (9);
8433                         CHECK_STACK_OVF (1);
8434
8435                         if (use_aotconst) {
8436                                 MonoInst *cons;
8437                                 int dreg;
8438
8439                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R8, d);
8440
8441                                 dreg = alloc_freg (cfg);
8442                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR8_MEMBASE, dreg, cons->dreg, 0);
8443                                 ins->type = STACK_R8;
8444                         } else {
8445                                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
8446                                 ins->type = STACK_R8;
8447                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
8448                                 ins->inst_p0 = d;
8449                                 MONO_ADD_INS (cfg->cbb, ins);
8450                         }
8451                         ++ip;
8452                         readr8 (ip, d);
8453                         ip += 8;
8454                         *sp++ = ins;
8455                         break;
8456                 }
8457                 case CEE_DUP: {
8458                         MonoInst *temp, *store;
8459                         CHECK_STACK (1);
8460                         CHECK_STACK_OVF (1);
8461                         sp--;
8462                         ins = *sp;
8463
8464                         temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
8465                         EMIT_NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
8466
8467                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
8468                         *sp++ = ins;
8469
8470                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
8471                         *sp++ = ins;
8472
8473                         ++ip;
8474                         inline_costs += 2;
8475                         break;
8476                 }
8477                 case CEE_POP:
8478                         CHECK_STACK (1);
8479                         ip++;
8480                         --sp;
8481
8482 #ifdef TARGET_X86
8483                         if (sp [0]->type == STACK_R8)
8484                                 /* we need to pop the value from the x86 FP stack */
8485                                 MONO_EMIT_NEW_UNALU (cfg, OP_X86_FPOP, -1, sp [0]->dreg);
8486 #endif
8487                         break;
8488                 case CEE_JMP: {
8489                         MonoCallInst *call;
8490
8491                         INLINE_FAILURE ("jmp");
8492                         GSHAREDVT_FAILURE (*ip);
8493
8494                         CHECK_OPSIZE (5);
8495                         if (stack_start != sp)
8496                                 UNVERIFIED;
8497                         token = read32 (ip + 1);
8498                         /* FIXME: check the signature matches */
8499                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
8500
8501                         if (!cmethod || mono_loader_get_last_error ())
8502                                 LOAD_ERROR;
8503  
8504                         if (cfg->gshared && mono_method_check_context_used (cmethod))
8505                                 GENERIC_SHARING_FAILURE (CEE_JMP);
8506
8507                         emit_instrumentation_call (cfg, mono_profiler_method_leave);
8508
8509                         if (ARCH_HAVE_OP_TAIL_CALL) {
8510                                 MonoMethodSignature *fsig = mono_method_signature (cmethod);
8511                                 int i, n;
8512
8513                                 /* Handle tail calls similarly to calls */
8514                                 n = fsig->param_count + fsig->hasthis;
8515
8516                                 DISABLE_AOT (cfg);
8517
8518                                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
8519                                 call->method = cmethod;
8520                                 call->tail_call = TRUE;
8521                                 call->signature = mono_method_signature (cmethod);
8522                                 call->args = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * n);
8523                                 call->inst.inst_p0 = cmethod;
8524                                 for (i = 0; i < n; ++i)
8525                                         EMIT_NEW_ARGLOAD (cfg, call->args [i], i);
8526
8527                                 mono_arch_emit_call (cfg, call);
8528                                 cfg->param_area = MAX(cfg->param_area, call->stack_usage);
8529                                 MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
8530                         } else {
8531                                 for (i = 0; i < num_args; ++i)
8532                                         /* Prevent arguments from being optimized away */
8533                                         arg_array [i]->flags |= MONO_INST_VOLATILE;
8534
8535                                 MONO_INST_NEW_CALL (cfg, call, OP_JMP);
8536                                 ins = (MonoInst*)call;
8537                                 ins->inst_p0 = cmethod;
8538                                 MONO_ADD_INS (cfg->cbb, ins);
8539                         }
8540
8541                         ip += 5;
8542                         start_new_bblock = 1;
8543                         break;
8544                 }
8545                 case CEE_CALLI: {
8546                         MonoInst *addr;
8547                         MonoMethodSignature *fsig;
8548
8549                         CHECK_OPSIZE (5);
8550                         token = read32 (ip + 1);
8551
8552                         ins = NULL;
8553
8554                         //GSHAREDVT_FAILURE (*ip);
8555                         cmethod = NULL;
8556                         CHECK_STACK (1);
8557                         --sp;
8558                         addr = *sp;
8559                         fsig = mini_get_signature (method, token, generic_context);
8560
8561                         if (method->dynamic && fsig->pinvoke) {
8562                                 MonoInst *args [3];
8563
8564                                 /*
8565                                  * This is a call through a function pointer using a pinvoke
8566                                  * signature. Have to create a wrapper and call that instead.
8567                                  * FIXME: This is very slow, need to create a wrapper at JIT time
8568                                  * instead based on the signature.
8569                                  */
8570                                 EMIT_NEW_IMAGECONST (cfg, args [0], method->klass->image);
8571                                 EMIT_NEW_PCONST (cfg, args [1], fsig);
8572                                 args [2] = addr;
8573                                 addr = mono_emit_jit_icall (cfg, mono_get_native_calli_wrapper, args);
8574                         }
8575
8576                         n = fsig->param_count + fsig->hasthis;
8577
8578                         CHECK_STACK (n);
8579
8580                         //g_assert (!virtual || fsig->hasthis);
8581
8582                         sp -= n;
8583
8584                         inline_costs += 10 * num_calls++;
8585
8586                         /*
8587                          * Making generic calls out of gsharedvt methods.
8588                          * This needs to be used for all generic calls, not just ones with a gsharedvt signature, to avoid
8589                          * patching gshared method addresses into a gsharedvt method.
8590                          */
8591                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) {
8592                                 /*
8593                                  * We pass the address to the gsharedvt trampoline in the rgctx reg
8594                                  */
8595                                 MonoInst *callee = addr;
8596
8597                                 if (method->wrapper_type != MONO_WRAPPER_DELEGATE_INVOKE)
8598                                         /* Not tested */
8599                                         GSHAREDVT_FAILURE (*ip);
8600
8601                                 addr = emit_get_rgctx_sig (cfg, context_used,
8602                                                                                           fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
8603                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, callee);
8604                                 goto calli_end;
8605                         }
8606
8607                         /* Prevent inlining of methods with indirect calls */
8608                         INLINE_FAILURE ("indirect call");
8609
8610                         if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST || addr->opcode == OP_GOT_ENTRY) {
8611                                 int info_type;
8612                                 gpointer info_data;
8613
8614                                 /*
8615                                  * Instead of emitting an indirect call, emit a direct call
8616                                  * with the contents of the aotconst as the patch info.
8617                                  */
8618                                 if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST) {
8619                                         info_type = addr->inst_c1;
8620                                         info_data = addr->inst_p0;
8621                                 } else {
8622                                         info_type = addr->inst_right->inst_c1;
8623                                         info_data = addr->inst_right->inst_left;
8624                                 }
8625
8626                                 if (info_type == MONO_PATCH_INFO_ICALL_ADDR || info_type == MONO_PATCH_INFO_JIT_ICALL_ADDR) {
8627                                         ins = (MonoInst*)mono_emit_abs_call (cfg, info_type, info_data, fsig, sp);
8628                                         NULLIFY_INS (addr);
8629                                         goto calli_end;
8630                                 }
8631                         }
8632                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
8633
8634                         calli_end:
8635
8636                         /* End of call, INS should contain the result of the call, if any */
8637
8638                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
8639                                 g_assert (ins);
8640                                 *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
8641                         }
8642
8643                         CHECK_CFG_EXCEPTION;
8644
8645                         ip += 5;
8646                         ins_flag = 0;
8647                         constrained_class = NULL;
8648                         break;
8649                 }
8650                 case CEE_CALL:
8651                 case CEE_CALLVIRT: {
8652                         MonoInst *addr = NULL;
8653                         MonoMethodSignature *fsig = NULL;
8654                         int array_rank = 0;
8655                         int virtual = *ip == CEE_CALLVIRT;
8656                         gboolean pass_imt_from_rgctx = FALSE;
8657                         MonoInst *imt_arg = NULL;
8658                         MonoInst *keep_this_alive = NULL;
8659                         gboolean pass_vtable = FALSE;
8660                         gboolean pass_mrgctx = FALSE;
8661                         MonoInst *vtable_arg = NULL;
8662                         gboolean check_this = FALSE;
8663                         gboolean supported_tail_call = FALSE;
8664                         gboolean tail_call = FALSE;
8665                         gboolean need_seq_point = FALSE;
8666                         guint32 call_opcode = *ip;
8667                         gboolean emit_widen = TRUE;
8668                         gboolean push_res = TRUE;
8669                         gboolean skip_ret = FALSE;
8670                         gboolean delegate_invoke = FALSE;
8671                         gboolean direct_icall = FALSE;
8672                         gboolean constrained_partial_call = FALSE;
8673                         MonoMethod *cil_method;
8674
8675                         CHECK_OPSIZE (5);
8676                         token = read32 (ip + 1);
8677
8678                         ins = NULL;
8679
8680                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
8681                         cil_method = cmethod;
8682                                 
8683                         if (constrained_class) {
8684                                 if ((constrained_class->byval_arg.type == MONO_TYPE_VAR || constrained_class->byval_arg.type == MONO_TYPE_MVAR) && cfg->gshared) {
8685                                         if (!mini_is_gsharedvt_klass (constrained_class)) {
8686                                                 g_assert (!cmethod->klass->valuetype);
8687                                                 if (!mini_type_is_reference (&constrained_class->byval_arg))
8688                                                         constrained_partial_call = TRUE;
8689                                         }
8690                                 }
8691
8692                                 if (method->wrapper_type != MONO_WRAPPER_NONE) {
8693                                         if (cfg->verbose_level > 2)
8694                                                 printf ("DM Constrained call to %s\n", mono_type_get_full_name (constrained_class));
8695                                         if (!((constrained_class->byval_arg.type == MONO_TYPE_VAR ||
8696                                                    constrained_class->byval_arg.type == MONO_TYPE_MVAR) &&
8697                                                   cfg->gshared)) {
8698                                                 cmethod = mono_get_method_constrained_with_method (image, cil_method, constrained_class, generic_context, &cfg->error);
8699                                                 CHECK_CFG_ERROR;
8700                                         }
8701                                 } else {
8702                                         if (cfg->verbose_level > 2)
8703                                                 printf ("Constrained call to %s\n", mono_type_get_full_name (constrained_class));
8704
8705                                         if ((constrained_class->byval_arg.type == MONO_TYPE_VAR || constrained_class->byval_arg.type == MONO_TYPE_MVAR) && cfg->gshared) {
8706                                                 /* 
8707                                                  * This is needed since get_method_constrained can't find 
8708                                                  * the method in klass representing a type var.
8709                                                  * The type var is guaranteed to be a reference type in this
8710                                                  * case.
8711                                                  */
8712                                                 if (!mini_is_gsharedvt_klass (constrained_class))
8713                                                         g_assert (!cmethod->klass->valuetype);
8714                                         } else {
8715                                                 cmethod = mono_get_method_constrained_checked (image, token, constrained_class, generic_context, &cil_method, &cfg->error);
8716                                                 CHECK_CFG_ERROR;
8717                                         }
8718                                 }
8719                         }
8720                                         
8721                         if (!cmethod || mono_loader_get_last_error ())
8722                                 LOAD_ERROR;
8723                         if (!dont_verify && !cfg->skip_visibility) {
8724                                 MonoMethod *target_method = cil_method;
8725                                 if (method->is_inflated) {
8726                                         target_method = mini_get_method_allow_open (method, token, NULL, &(mono_method_get_generic_container (method_definition)->context));
8727                                 }
8728                                 if (!mono_method_can_access_method (method_definition, target_method) &&
8729                                         !mono_method_can_access_method (method, cil_method))
8730                                         METHOD_ACCESS_FAILURE (method, cil_method);
8731                         }
8732
8733                         if (mono_security_core_clr_enabled ())
8734                                 ensure_method_is_allowed_to_call_method (cfg, method, cil_method);
8735
8736                         if (!virtual && (cmethod->flags & METHOD_ATTRIBUTE_ABSTRACT))
8737                                 /* MS.NET seems to silently convert this to a callvirt */
8738                                 virtual = 1;
8739
8740                         {
8741                                 /*
8742                                  * MS.NET accepts non virtual calls to virtual final methods of transparent proxy classes and
8743                                  * converts to a callvirt.
8744                                  *
8745                                  * tests/bug-515884.il is an example of this behavior
8746                                  */
8747                                 const int test_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_STATIC;
8748                                 const int expected_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL;
8749                                 if (!virtual && mono_class_is_marshalbyref (cmethod->klass) && (cmethod->flags & test_flags) == expected_flags && cfg->method->wrapper_type == MONO_WRAPPER_NONE)
8750                                         virtual = 1;
8751                         }
8752
8753                         if (!cmethod->klass->inited)
8754                                 if (!mono_class_init (cmethod->klass))
8755                                         TYPE_LOAD_ERROR (cmethod->klass);
8756
8757                         fsig = mono_method_signature (cmethod);
8758                         if (!fsig)
8759                                 LOAD_ERROR;
8760                         if (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL &&
8761                                 mini_class_is_system_array (cmethod->klass)) {
8762                                 array_rank = cmethod->klass->rank;
8763                         } else if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && icall_is_direct_callable (cfg, cmethod)) {
8764                                 direct_icall = TRUE;
8765                         } else if (fsig->pinvoke) {
8766                                 MonoMethod *wrapper = mono_marshal_get_native_wrapper (cmethod, TRUE, cfg->compile_aot);
8767                                 fsig = mono_method_signature (wrapper);
8768                         } else if (constrained_class) {
8769                         } else {
8770                                 fsig = mono_method_get_signature_checked (cmethod, image, token, generic_context, &cfg->error);
8771                                 CHECK_CFG_ERROR;
8772                         }
8773
8774                         /* See code below */
8775                         if (cmethod->klass == mono_defaults.monitor_class && !strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1) {
8776                                 MonoBasicBlock *tbb;
8777
8778                                 GET_BBLOCK (cfg, tbb, ip + 5);
8779                                 if (tbb->try_start && MONO_REGION_FLAGS(tbb->region) == MONO_EXCEPTION_CLAUSE_FINALLY) {
8780                                         /*
8781                                          * We want to extend the try block to cover the call, but we can't do it if the
8782                                          * call is made directly since its followed by an exception check.
8783                                          */
8784                                         direct_icall = FALSE;
8785                                 }
8786                         }
8787
8788                         mono_save_token_info (cfg, image, token, cil_method);
8789
8790                         if (!(seq_point_locs && mono_bitset_test_fast (seq_point_locs, ip + 5 - header->code)))
8791                                 need_seq_point = TRUE;
8792
8793                         /* Don't support calls made using type arguments for now */
8794                         /*
8795                           if (cfg->gsharedvt) {
8796                           if (mini_is_gsharedvt_signature (fsig))
8797                           GSHAREDVT_FAILURE (*ip);
8798                           }
8799                         */
8800
8801                         if (cmethod->string_ctor && method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE)
8802                                 g_assert_not_reached ();
8803
8804                         n = fsig->param_count + fsig->hasthis;
8805
8806                         if (!cfg->gshared && cmethod->klass->generic_container)
8807                                 UNVERIFIED;
8808
8809                         if (!cfg->gshared)
8810                                 g_assert (!mono_method_check_context_used (cmethod));
8811
8812                         CHECK_STACK (n);
8813
8814                         //g_assert (!virtual || fsig->hasthis);
8815
8816                         sp -= n;
8817
8818                         if (constrained_class) {
8819                                 if (mini_is_gsharedvt_klass (constrained_class)) {
8820                                         if ((cmethod->klass != mono_defaults.object_class) && constrained_class->valuetype && cmethod->klass->valuetype) {
8821                                                 /* The 'Own method' case below */
8822                                         } else if (cmethod->klass->image != mono_defaults.corlib && !(cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) && !cmethod->klass->valuetype) {
8823                                                 /* 'The type parameter is instantiated as a reference type' case below. */
8824                                         } else {
8825                                                 ins = handle_constrained_gsharedvt_call (cfg, cmethod, fsig, sp, constrained_class, &emit_widen);
8826                                                 CHECK_CFG_EXCEPTION;
8827                                                 g_assert (ins);
8828                                                 goto call_end;
8829                                         }
8830                                 }
8831
8832                                 /*
8833                                  * We have the `constrained.' prefix opcode.
8834                                  */
8835                                 if (constrained_partial_call) {
8836                                         gboolean need_box = TRUE;
8837
8838                                         /*
8839                                          * The receiver is a valuetype, but the exact type is not known at compile time. This means the
8840                                          * called method is not known at compile time either. The called method could end up being
8841                                          * one of the methods on the parent classes (object/valuetype/enum), in which case we need
8842                                          * to box the receiver.
8843                                          * A simple solution would be to box always and make a normal virtual call, but that would
8844                                          * be bad performance wise.
8845                                          */
8846                                         if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE && cmethod->klass->generic_class) {
8847                                                 /*
8848                                                  * The parent classes implement no generic interfaces, so the called method will be a vtype method, so no boxing neccessary.
8849                                                  */
8850                                                 need_box = FALSE;
8851                                         }
8852
8853                                         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)) {
8854                                                 /* The called method is not virtual, i.e. Object:GetType (), the receiver is a vtype, has to box */
8855                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
8856                                                 ins->klass = constrained_class;
8857                                                 sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
8858                                                 CHECK_CFG_EXCEPTION;
8859                                         } else if (need_box) {
8860                                                 MonoInst *box_type;
8861                                                 MonoBasicBlock *is_ref_bb, *end_bb;
8862                                                 MonoInst *nonbox_call;
8863
8864                                                 /*
8865                                                  * Determine at runtime whenever the called method is defined on object/valuetype/enum, and emit a boxing call
8866                                                  * if needed.
8867                                                  * FIXME: It is possible to inline the called method in a lot of cases, i.e. for T_INT,
8868                                                  * the no-box case goes to a method in Int32, while the box case goes to a method in Enum.
8869                                                  */
8870                                                 addr = emit_get_rgctx_virt_method (cfg, mono_class_check_context_used (constrained_class), constrained_class, cmethod, MONO_RGCTX_INFO_VIRT_METHOD_CODE);
8871
8872                                                 NEW_BBLOCK (cfg, is_ref_bb);
8873                                                 NEW_BBLOCK (cfg, end_bb);
8874
8875                                                 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);
8876                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, box_type->dreg, 1);
8877                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
8878
8879                                                 /* Non-ref case */
8880                                                 nonbox_call = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
8881
8882                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
8883
8884                                                 /* Ref case */
8885                                                 MONO_START_BB (cfg, is_ref_bb);
8886                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
8887                                                 ins->klass = constrained_class;
8888                                                 sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
8889                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
8890
8891                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
8892
8893                                                 MONO_START_BB (cfg, end_bb);
8894                                                 cfg->cbb = end_bb;
8895
8896                                                 nonbox_call->dreg = ins->dreg;
8897                                                 goto call_end;
8898                                         } else {
8899                                                 g_assert (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE);
8900                                                 addr = emit_get_rgctx_virt_method (cfg, mono_class_check_context_used (constrained_class), constrained_class, cmethod, MONO_RGCTX_INFO_VIRT_METHOD_CODE);
8901                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
8902                                                 goto call_end;
8903                                         }
8904                                 } else if (constrained_class->valuetype && (cmethod->klass == mono_defaults.object_class || cmethod->klass == mono_defaults.enum_class->parent || cmethod->klass == mono_defaults.enum_class)) {
8905                                         /*
8906                                          * The type parameter is instantiated as a valuetype,
8907                                          * but that type doesn't override the method we're
8908                                          * calling, so we need to box `this'.
8909                                          */
8910                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
8911                                         ins->klass = constrained_class;
8912                                         sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
8913                                         CHECK_CFG_EXCEPTION;
8914                                 } else if (!constrained_class->valuetype) {
8915                                         int dreg = alloc_ireg_ref (cfg);
8916
8917                                         /*
8918                                          * The type parameter is instantiated as a reference
8919                                          * type.  We have a managed pointer on the stack, so
8920                                          * we need to dereference it here.
8921                                          */
8922                                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, sp [0]->dreg, 0);
8923                                         ins->type = STACK_OBJ;
8924                                         sp [0] = ins;
8925                                 } else {
8926                                         if (cmethod->klass->valuetype) {
8927                                                 /* Own method */
8928                                         } else {
8929                                                 /* Interface method */
8930                                                 int ioffset, slot;
8931
8932                                                 mono_class_setup_vtable (constrained_class);
8933                                                 CHECK_TYPELOAD (constrained_class);
8934                                                 ioffset = mono_class_interface_offset (constrained_class, cmethod->klass);
8935                                                 if (ioffset == -1)
8936                                                         TYPE_LOAD_ERROR (constrained_class);
8937                                                 slot = mono_method_get_vtable_slot (cmethod);
8938                                                 if (slot == -1)
8939                                                         TYPE_LOAD_ERROR (cmethod->klass);
8940                                                 cmethod = constrained_class->vtable [ioffset + slot];
8941
8942                                                 if (cmethod->klass == mono_defaults.enum_class) {
8943                                                         /* Enum implements some interfaces, so treat this as the first case */
8944                                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
8945                                                         ins->klass = constrained_class;
8946                                                         sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
8947                                                         CHECK_CFG_EXCEPTION;
8948                                                 }
8949                                         }
8950                                         virtual = 0;
8951                                 }
8952                                 constrained_class = NULL;
8953                         }
8954
8955                         if (check_call_signature (cfg, fsig, sp))
8956                                 UNVERIFIED;
8957
8958                         if ((cmethod->klass->parent == mono_defaults.multicastdelegate_class) && !strcmp (cmethod->name, "Invoke"))
8959                                 delegate_invoke = TRUE;
8960
8961                         if ((cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_sharable_method (cfg, cmethod, fsig, sp))) {
8962                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
8963                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
8964                                         emit_widen = FALSE;
8965                                 }
8966
8967                                 goto call_end;
8968                         }
8969
8970                         /* 
8971                          * If the callee is a shared method, then its static cctor
8972                          * might not get called after the call was patched.
8973                          */
8974                         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)) {
8975                                 emit_class_init (cfg, cmethod->klass);
8976                                 CHECK_TYPELOAD (cmethod->klass);
8977                         }
8978
8979                         check_method_sharing (cfg, cmethod, &pass_vtable, &pass_mrgctx);
8980
8981                         if (cfg->gshared) {
8982                                 MonoGenericContext *cmethod_context = mono_method_get_context (cmethod);
8983
8984                                 context_used = mini_method_check_context_used (cfg, cmethod);
8985
8986                                 if (context_used && (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
8987                                         /* Generic method interface
8988                                            calls are resolved via a
8989                                            helper function and don't
8990                                            need an imt. */
8991                                         if (!cmethod_context || !cmethod_context->method_inst)
8992                                                 pass_imt_from_rgctx = TRUE;
8993                                 }
8994
8995                                 /*
8996                                  * If a shared method calls another
8997                                  * shared method then the caller must
8998                                  * have a generic sharing context
8999                                  * because the magic trampoline
9000                                  * requires it.  FIXME: We shouldn't
9001                                  * have to force the vtable/mrgctx
9002                                  * variable here.  Instead there
9003                                  * should be a flag in the cfg to
9004                                  * request a generic sharing context.
9005                                  */
9006                                 if (context_used &&
9007                                                 ((method->flags & METHOD_ATTRIBUTE_STATIC) || method->klass->valuetype))
9008                                         mono_get_vtable_var (cfg);
9009                         }
9010
9011                         if (pass_vtable) {
9012                                 if (context_used) {
9013                                         vtable_arg = emit_get_rgctx_klass (cfg, context_used, cmethod->klass, MONO_RGCTX_INFO_VTABLE);
9014                                 } else {
9015                                         MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
9016
9017                                         CHECK_TYPELOAD (cmethod->klass);
9018                                         EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
9019                                 }
9020                         }
9021
9022                         if (pass_mrgctx) {
9023                                 g_assert (!vtable_arg);
9024
9025                                 if (!cfg->compile_aot) {
9026                                         /* 
9027                                          * emit_get_rgctx_method () calls mono_class_vtable () so check 
9028                                          * for type load errors before.
9029                                          */
9030                                         mono_class_setup_vtable (cmethod->klass);
9031                                         CHECK_TYPELOAD (cmethod->klass);
9032                                 }
9033
9034                                 vtable_arg = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
9035
9036                                 /* !marshalbyref is needed to properly handle generic methods + remoting */
9037                                 if ((!(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
9038                                          MONO_METHOD_IS_FINAL (cmethod)) &&
9039                                         !mono_class_is_marshalbyref (cmethod->klass)) {
9040                                         if (virtual)
9041                                                 check_this = TRUE;
9042                                         virtual = 0;
9043                                 }
9044                         }
9045
9046                         if (pass_imt_from_rgctx) {
9047                                 g_assert (!pass_vtable);
9048
9049                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9050                                         cmethod, MONO_RGCTX_INFO_METHOD);
9051                         }
9052
9053                         if (check_this)
9054                                 MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
9055
9056                         /* Calling virtual generic methods */
9057                         if (virtual && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) && 
9058                             !(MONO_METHOD_IS_FINAL (cmethod) && 
9059                               cmethod->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK) &&
9060                             fsig->generic_param_count && 
9061                                 !(cfg->gsharedvt && mini_is_gsharedvt_signature (fsig))) {
9062                                 MonoInst *this_temp, *this_arg_temp, *store;
9063                                 MonoInst *iargs [4];
9064                                 gboolean use_imt = FALSE;
9065
9066                                 g_assert (fsig->is_inflated);
9067
9068                                 /* Prevent inlining of methods that contain indirect calls */
9069                                 INLINE_FAILURE ("virtual generic call");
9070
9071                                 if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig))
9072                                         GSHAREDVT_FAILURE (*ip);
9073
9074 #if MONO_ARCH_HAVE_GENERALIZED_IMT_THUNK && defined(MONO_ARCH_GSHARED_SUPPORTED)
9075                                 if (cmethod->wrapper_type == MONO_WRAPPER_NONE)
9076                                         use_imt = TRUE;
9077 #endif
9078
9079                                 if (use_imt) {
9080                                         g_assert (!imt_arg);
9081                                         if (!context_used)
9082                                                 g_assert (cmethod->is_inflated);
9083                                         imt_arg = emit_get_rgctx_method (cfg, context_used,
9084                                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
9085                                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, sp [0], imt_arg, NULL);
9086                                 } else {
9087                                         this_temp = mono_compile_create_var (cfg, type_from_stack_type (sp [0]), OP_LOCAL);
9088                                         NEW_TEMPSTORE (cfg, store, this_temp->inst_c0, sp [0]);
9089                                         MONO_ADD_INS (cfg->cbb, store);
9090
9091                                         /* FIXME: This should be a managed pointer */
9092                                         this_arg_temp = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
9093
9094                                         EMIT_NEW_TEMPLOAD (cfg, iargs [0], this_temp->inst_c0);
9095                                         iargs [1] = emit_get_rgctx_method (cfg, context_used,
9096                                                                                                            cmethod, MONO_RGCTX_INFO_METHOD);
9097                                         EMIT_NEW_TEMPLOADA (cfg, iargs [2], this_arg_temp->inst_c0);
9098                                         addr = mono_emit_jit_icall (cfg,
9099                                                                                                 mono_helper_compile_generic_method, iargs);
9100
9101                                         EMIT_NEW_TEMPLOAD (cfg, sp [0], this_arg_temp->inst_c0);
9102
9103                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9104                                 }
9105
9106                                 goto call_end;
9107                         }
9108
9109                         /*
9110                          * Implement a workaround for the inherent races involved in locking:
9111                          * Monitor.Enter ()
9112                          * try {
9113                          * } finally {
9114                          *    Monitor.Exit ()
9115                          * }
9116                          * If a thread abort happens between the call to Monitor.Enter () and the start of the
9117                          * try block, the Exit () won't be executed, see:
9118                          * http://www.bluebytesoftware.com/blog/2007/01/30/MonitorEnterThreadAbortsAndOrphanedLocks.aspx
9119                          * To work around this, we extend such try blocks to include the last x bytes
9120                          * of the Monitor.Enter () call.
9121                          */
9122                         if (cmethod->klass == mono_defaults.monitor_class && !strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1) {
9123                                 MonoBasicBlock *tbb;
9124
9125                                 GET_BBLOCK (cfg, tbb, ip + 5);
9126                                 /* 
9127                                  * Only extend try blocks with a finally, to avoid catching exceptions thrown
9128                                  * from Monitor.Enter like ArgumentNullException.
9129                                  */
9130                                 if (tbb->try_start && MONO_REGION_FLAGS(tbb->region) == MONO_EXCEPTION_CLAUSE_FINALLY) {
9131                                         /* Mark this bblock as needing to be extended */
9132                                         tbb->extend_try_block = TRUE;
9133                                 }
9134                         }
9135
9136                         /* Conversion to a JIT intrinsic */
9137                         if ((cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_method (cfg, cmethod, fsig, sp))) {
9138                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9139                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
9140                                         emit_widen = FALSE;
9141                                 }
9142                                 goto call_end;
9143                         }
9144
9145                         /* Inlining */
9146                         if ((cfg->opt & MONO_OPT_INLINE) &&
9147                                 (!virtual || !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) || MONO_METHOD_IS_FINAL (cmethod)) &&
9148                             mono_method_check_inlining (cfg, cmethod)) {
9149                                 int costs;
9150                                 gboolean always = FALSE;
9151
9152                                 if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
9153                                         (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
9154                                         /* Prevent inlining of methods that call wrappers */
9155                                         INLINE_FAILURE ("wrapper call");
9156                                         cmethod = mono_marshal_get_native_wrapper (cmethod, TRUE, FALSE);
9157                                         always = TRUE;
9158                                 }
9159
9160                                 costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, always);
9161                                 if (costs) {
9162                                         cfg->real_offset += 5;
9163
9164                                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9165                                                 /* *sp is already set by inline_method */
9166                                                 sp++;
9167                                                 push_res = FALSE;
9168                                         }
9169
9170                                         inline_costs += costs;
9171
9172                                         goto call_end;
9173                                 }
9174                         }
9175
9176                         /* Tail recursion elimination */
9177                         if ((cfg->opt & MONO_OPT_TAILC) && call_opcode == CEE_CALL && cmethod == method && ip [5] == CEE_RET && !vtable_arg) {
9178                                 gboolean has_vtargs = FALSE;
9179                                 int i;
9180
9181                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
9182                                 INLINE_FAILURE ("tail call");
9183
9184                                 /* keep it simple */
9185                                 for (i =  fsig->param_count - 1; i >= 0; i--) {
9186                                         if (MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->params [i])) 
9187                                                 has_vtargs = TRUE;
9188                                 }
9189
9190                                 if (!has_vtargs) {
9191                                         for (i = 0; i < n; ++i)
9192                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
9193                                         MONO_INST_NEW (cfg, ins, OP_BR);
9194                                         MONO_ADD_INS (cfg->cbb, ins);
9195                                         tblock = start_bblock->out_bb [0];
9196                                         link_bblock (cfg, cfg->cbb, tblock);
9197                                         ins->inst_target_bb = tblock;
9198                                         start_new_bblock = 1;
9199
9200                                         /* skip the CEE_RET, too */
9201                                         if (ip_in_bb (cfg, cfg->cbb, ip + 5))
9202                                                 skip_ret = TRUE;
9203                                         push_res = FALSE;
9204                                         goto call_end;
9205                                 }
9206                         }
9207
9208                         inline_costs += 10 * num_calls++;
9209
9210                         /*
9211                          * Making generic calls out of gsharedvt methods.
9212                          * This needs to be used for all generic calls, not just ones with a gsharedvt signature, to avoid
9213                          * patching gshared method addresses into a gsharedvt method.
9214                          */
9215                         if (cfg->gsharedvt && (mini_is_gsharedvt_signature (fsig) || cmethod->is_inflated || cmethod->klass->generic_class) &&
9216                                 !(cmethod->klass->rank && cmethod->klass->byval_arg.type != MONO_TYPE_SZARRAY)) {
9217                                 MonoRgctxInfoType info_type;
9218
9219                                 if (virtual) {
9220                                         //if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)
9221                                                 //GSHAREDVT_FAILURE (*ip);
9222                                         // disable for possible remoting calls
9223                                         if (fsig->hasthis && (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class))
9224                                                 GSHAREDVT_FAILURE (*ip);
9225                                         if (fsig->generic_param_count) {
9226                                                 /* virtual generic call */
9227                                                 g_assert (!imt_arg);
9228                                                 /* Same as the virtual generic case above */
9229                                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9230                                                                                                                  cmethod, MONO_RGCTX_INFO_METHOD);
9231                                                 /* This is not needed, as the trampoline code will pass one, and it might be passed in the same reg as the imt arg */
9232                                                 vtable_arg = NULL;
9233                                         } else if ((cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) && !imt_arg) {
9234                                                 /* This can happen when we call a fully instantiated iface method */
9235                                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9236                                                                                                                  cmethod, MONO_RGCTX_INFO_METHOD);
9237                                                 vtable_arg = NULL;
9238                                         }
9239                                 }
9240
9241                                 if ((cmethod->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (cmethod->name, "Invoke")))
9242                                         keep_this_alive = sp [0];
9243
9244                                 if (virtual && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))
9245                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
9246                                 else
9247                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE;
9248                                 addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, info_type);
9249
9250                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
9251                                 goto call_end;
9252                         }
9253
9254                         /* Generic sharing */
9255
9256                         /*
9257                          * Use this if the callee is gsharedvt sharable too, since
9258                          * at runtime we might find an instantiation so the call cannot
9259                          * be patched (the 'no_patch' code path in mini-trampolines.c).
9260                          */
9261                         if (context_used && !imt_arg && !array_rank && !delegate_invoke &&
9262                                 (!mono_method_is_generic_sharable_full (cmethod, TRUE, FALSE, FALSE) ||
9263                                  !mono_class_generic_sharing_enabled (cmethod->klass)) &&
9264                                 (!virtual || MONO_METHOD_IS_FINAL (cmethod) ||
9265                                  !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))) {
9266                                 INLINE_FAILURE ("gshared");
9267
9268                                 g_assert (cfg->gshared && cmethod);
9269                                 g_assert (!addr);
9270
9271                                 /*
9272                                  * We are compiling a call to a
9273                                  * generic method from shared code,
9274                                  * which means that we have to look up
9275                                  * the method in the rgctx and do an
9276                                  * indirect call.
9277                                  */
9278                                 if (fsig->hasthis)
9279                                         MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
9280
9281                                 addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
9282                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
9283                                 goto call_end;
9284                         }
9285
9286                         /* Direct calls to icalls */
9287                         if (direct_icall) {
9288                                 MonoMethod *wrapper;
9289                                 int costs;
9290
9291                                 /* Inline the wrapper */
9292                                 wrapper = mono_marshal_get_native_wrapper (cmethod, TRUE, cfg->compile_aot);
9293
9294                                 costs = inline_method (cfg, wrapper, fsig, sp, ip, cfg->real_offset, TRUE);
9295                                 g_assert (costs > 0);
9296                                 cfg->real_offset += 5;
9297
9298                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9299                                         /* *sp is already set by inline_method */
9300                                         sp++;
9301                                         push_res = FALSE;
9302                                 }
9303
9304                                 inline_costs += costs;
9305
9306                                 goto call_end;
9307                         }
9308                                         
9309                         /* Array methods */
9310                         if (array_rank) {
9311                                 MonoInst *addr;
9312
9313                                 if (strcmp (cmethod->name, "Set") == 0) { /* array Set */ 
9314                                         MonoInst *val = sp [fsig->param_count];
9315
9316                                         if (val->type == STACK_OBJ) {
9317                                                 MonoInst *iargs [2];
9318
9319                                                 iargs [0] = sp [0];
9320                                                 iargs [1] = val;
9321                                                 
9322                                                 mono_emit_jit_icall (cfg, mono_helper_stelem_ref_check, iargs);
9323                                         }
9324                                         
9325                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, TRUE);
9326                                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, fsig->params [fsig->param_count - 1], addr->dreg, 0, val->dreg);
9327                                         if (cfg->gen_write_barriers && val->type == STACK_OBJ && !(val->opcode == OP_PCONST && val->inst_c0 == 0))
9328                                                 emit_write_barrier (cfg, addr, val);
9329                                         if (cfg->gen_write_barriers && mini_is_gsharedvt_klass (cmethod->klass))
9330                                                 GSHAREDVT_FAILURE (*ip);
9331                                 } else if (strcmp (cmethod->name, "Get") == 0) { /* array Get */
9332                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
9333
9334                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, addr->dreg, 0);
9335                                 } else if (strcmp (cmethod->name, "Address") == 0) { /* array Address */
9336                                         if (!cmethod->klass->element_class->valuetype && !readonly)
9337                                                 mini_emit_check_array_type (cfg, sp [0], cmethod->klass);
9338                                         CHECK_TYPELOAD (cmethod->klass);
9339                                         
9340                                         readonly = FALSE;
9341                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
9342                                         ins = addr;
9343                                 } else {
9344                                         g_assert_not_reached ();
9345                                 }
9346
9347                                 emit_widen = FALSE;
9348                                 goto call_end;
9349                         }
9350
9351                         ins = mini_redirect_call (cfg, cmethod, fsig, sp, virtual ? sp [0] : NULL);
9352                         if (ins)
9353                                 goto call_end;
9354
9355                         /* Tail prefix / tail call optimization */
9356
9357                         /* FIXME: Enabling TAILC breaks some inlining/stack trace/etc tests */
9358                         /* FIXME: runtime generic context pointer for jumps? */
9359                         /* FIXME: handle this for generic sharing eventually */
9360                         if ((ins_flag & MONO_INST_TAILCALL) &&
9361                                 !vtable_arg && !cfg->gshared && is_supported_tail_call (cfg, method, cmethod, fsig, call_opcode))
9362                                 supported_tail_call = TRUE;
9363
9364                         if (supported_tail_call) {
9365                                 MonoCallInst *call;
9366
9367                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
9368                                 INLINE_FAILURE ("tail call");
9369
9370                                 //printf ("HIT: %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
9371
9372                                 if (ARCH_HAVE_OP_TAIL_CALL) {
9373                                         /* Handle tail calls similarly to normal calls */
9374                                         tail_call = TRUE;
9375                                 } else {
9376                                         emit_instrumentation_call (cfg, mono_profiler_method_leave);
9377
9378                                         MONO_INST_NEW_CALL (cfg, call, OP_JMP);
9379                                         call->tail_call = TRUE;
9380                                         call->method = cmethod;
9381                                         call->signature = mono_method_signature (cmethod);
9382
9383                                         /*
9384                                          * We implement tail calls by storing the actual arguments into the 
9385                                          * argument variables, then emitting a CEE_JMP.
9386                                          */
9387                                         for (i = 0; i < n; ++i) {
9388                                                 /* Prevent argument from being register allocated */
9389                                                 arg_array [i]->flags |= MONO_INST_VOLATILE;
9390                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
9391                                         }
9392                                         ins = (MonoInst*)call;
9393                                         ins->inst_p0 = cmethod;
9394                                         ins->inst_p1 = arg_array [0];
9395                                         MONO_ADD_INS (cfg->cbb, ins);
9396                                         link_bblock (cfg, cfg->cbb, end_bblock);
9397                                         start_new_bblock = 1;
9398
9399                                         // FIXME: Eliminate unreachable epilogs
9400
9401                                         /*
9402                                          * OP_TAILCALL has no return value, so skip the CEE_RET if it is
9403                                          * only reachable from this call.
9404                                          */
9405                                         GET_BBLOCK (cfg, tblock, ip + 5);
9406                                         if (tblock == cfg->cbb || tblock->in_count == 0)
9407                                                 skip_ret = TRUE;
9408                                         push_res = FALSE;
9409
9410                                         goto call_end;
9411                                 }
9412                         }
9413
9414                         /* 
9415                          * Synchronized wrappers.
9416                          * Its hard to determine where to replace a method with its synchronized
9417                          * wrapper without causing an infinite recursion. The current solution is
9418                          * to add the synchronized wrapper in the trampolines, and to
9419                          * change the called method to a dummy wrapper, and resolve that wrapper
9420                          * to the real method in mono_jit_compile_method ().
9421                          */
9422                         if (cfg->method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
9423                                 MonoMethod *orig = mono_marshal_method_from_wrapper (cfg->method);
9424                                 if (cmethod == orig || (cmethod->is_inflated && mono_method_get_declaring_generic_method (cmethod) == orig))
9425                                         cmethod = mono_marshal_get_synchronized_inner_wrapper (cmethod);
9426                         }
9427
9428                         /* Common call */
9429                         INLINE_FAILURE ("call");
9430                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, tail_call, sp, virtual ? sp [0] : NULL,
9431                                                                                           imt_arg, vtable_arg);
9432
9433                         if (tail_call) {
9434                                 link_bblock (cfg, cfg->cbb, end_bblock);
9435                                 start_new_bblock = 1;
9436
9437                                 // FIXME: Eliminate unreachable epilogs
9438
9439                                 /*
9440                                  * OP_TAILCALL has no return value, so skip the CEE_RET if it is
9441                                  * only reachable from this call.
9442                                  */
9443                                 GET_BBLOCK (cfg, tblock, ip + 5);
9444                                 if (tblock == cfg->cbb || tblock->in_count == 0)
9445                                         skip_ret = TRUE;
9446                                 push_res = FALSE;
9447                         }
9448
9449                         call_end:
9450
9451                         /* End of call, INS should contain the result of the call, if any */
9452
9453                         if (push_res && !MONO_TYPE_IS_VOID (fsig->ret)) {
9454                                 g_assert (ins);
9455                                 if (emit_widen)
9456                                         *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
9457                                 else
9458                                         *sp++ = ins;
9459                         }
9460
9461                         if (keep_this_alive) {
9462                                 MonoInst *dummy_use;
9463
9464                                 /* See mono_emit_method_call_full () */
9465                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, keep_this_alive);
9466                         }
9467
9468                         CHECK_CFG_EXCEPTION;
9469
9470                         ip += 5;
9471                         if (skip_ret) {
9472                                 g_assert (*ip == CEE_RET);
9473                                 ip += 1;
9474                         }
9475                         ins_flag = 0;
9476                         constrained_class = NULL;
9477                         if (need_seq_point)
9478                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
9479                         break;
9480                 }
9481                 case CEE_RET:
9482                         if (cfg->method != method) {
9483                                 /* return from inlined method */
9484                                 /* 
9485                                  * If in_count == 0, that means the ret is unreachable due to
9486                                  * being preceeded by a throw. In that case, inline_method () will
9487                                  * handle setting the return value 
9488                                  * (test case: test_0_inline_throw ()).
9489                                  */
9490                                 if (return_var && cfg->cbb->in_count) {
9491                                         MonoType *ret_type = mono_method_signature (method)->ret;
9492
9493                                         MonoInst *store;
9494                                         CHECK_STACK (1);
9495                                         --sp;
9496
9497                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
9498                                                 UNVERIFIED;
9499
9500                                         //g_assert (returnvar != -1);
9501                                         EMIT_NEW_TEMPSTORE (cfg, store, return_var->inst_c0, *sp);
9502                                         cfg->ret_var_set = TRUE;
9503                                 } 
9504                         } else {
9505                                 emit_instrumentation_call (cfg, mono_profiler_method_leave);
9506
9507                                 if (cfg->lmf_var && cfg->cbb->in_count)
9508                                         emit_pop_lmf (cfg);
9509
9510                                 if (cfg->ret) {
9511                                         MonoType *ret_type = mini_get_underlying_type (mono_method_signature (method)->ret);
9512
9513                                         if (seq_points && !sym_seq_points) {
9514                                                 /* 
9515                                                  * Place a seq point here too even through the IL stack is not
9516                                                  * empty, so a step over on
9517                                                  * call <FOO>
9518                                                  * ret
9519                                                  * will work correctly.
9520                                                  */
9521                                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, TRUE);
9522                                                 MONO_ADD_INS (cfg->cbb, ins);
9523                                         }
9524
9525                                         g_assert (!return_var);
9526                                         CHECK_STACK (1);
9527                                         --sp;
9528
9529                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
9530                                                 UNVERIFIED;
9531
9532                                         if (mini_type_to_stind (cfg, ret_type) == CEE_STOBJ) {
9533                                                 MonoInst *ret_addr;
9534
9535                                                 if (!cfg->vret_addr) {
9536                                                         MonoInst *ins;
9537
9538                                                         EMIT_NEW_VARSTORE (cfg, ins, cfg->ret, ret_type, (*sp));
9539                                                 } else {
9540                                                         EMIT_NEW_RETLOADA (cfg, ret_addr);
9541
9542                                                         EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STOREV_MEMBASE, ret_addr->dreg, 0, (*sp)->dreg);
9543                                                         ins->klass = mono_class_from_mono_type (ret_type);
9544                                                 }
9545                                         } else {
9546 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
9547                                                 if (COMPILE_SOFT_FLOAT (cfg) && !ret_type->byref && ret_type->type == MONO_TYPE_R4) {
9548                                                         MonoInst *iargs [1];
9549                                                         MonoInst *conv;
9550
9551                                                         iargs [0] = *sp;
9552                                                         conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
9553                                                         mono_arch_emit_setret (cfg, method, conv);
9554                                                 } else {
9555                                                         mono_arch_emit_setret (cfg, method, *sp);
9556                                                 }
9557 #else
9558                                                 mono_arch_emit_setret (cfg, method, *sp);
9559 #endif
9560                                         }
9561                                 }
9562                         }
9563                         if (sp != stack_start)
9564                                 UNVERIFIED;
9565                         MONO_INST_NEW (cfg, ins, OP_BR);
9566                         ip++;
9567                         ins->inst_target_bb = end_bblock;
9568                         MONO_ADD_INS (cfg->cbb, ins);
9569                         link_bblock (cfg, cfg->cbb, end_bblock);
9570                         start_new_bblock = 1;
9571                         break;
9572                 case CEE_BR_S:
9573                         CHECK_OPSIZE (2);
9574                         MONO_INST_NEW (cfg, ins, OP_BR);
9575                         ip++;
9576                         target = ip + 1 + (signed char)(*ip);
9577                         ++ip;
9578                         GET_BBLOCK (cfg, tblock, target);
9579                         link_bblock (cfg, cfg->cbb, tblock);
9580                         ins->inst_target_bb = tblock;
9581                         if (sp != stack_start) {
9582                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9583                                 sp = stack_start;
9584                                 CHECK_UNVERIFIABLE (cfg);
9585                         }
9586                         MONO_ADD_INS (cfg->cbb, ins);
9587                         start_new_bblock = 1;
9588                         inline_costs += BRANCH_COST;
9589                         break;
9590                 case CEE_BEQ_S:
9591                 case CEE_BGE_S:
9592                 case CEE_BGT_S:
9593                 case CEE_BLE_S:
9594                 case CEE_BLT_S:
9595                 case CEE_BNE_UN_S:
9596                 case CEE_BGE_UN_S:
9597                 case CEE_BGT_UN_S:
9598                 case CEE_BLE_UN_S:
9599                 case CEE_BLT_UN_S:
9600                         CHECK_OPSIZE (2);
9601                         CHECK_STACK (2);
9602                         MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
9603                         ip++;
9604                         target = ip + 1 + *(signed char*)ip;
9605                         ip++;
9606
9607                         ADD_BINCOND (NULL);
9608
9609                         sp = stack_start;
9610                         inline_costs += BRANCH_COST;
9611                         break;
9612                 case CEE_BR:
9613                         CHECK_OPSIZE (5);
9614                         MONO_INST_NEW (cfg, ins, OP_BR);
9615                         ip++;
9616
9617                         target = ip + 4 + (gint32)read32(ip);
9618                         ip += 4;
9619                         GET_BBLOCK (cfg, tblock, target);
9620                         link_bblock (cfg, cfg->cbb, tblock);
9621                         ins->inst_target_bb = tblock;
9622                         if (sp != stack_start) {
9623                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9624                                 sp = stack_start;
9625                                 CHECK_UNVERIFIABLE (cfg);
9626                         }
9627
9628                         MONO_ADD_INS (cfg->cbb, ins);
9629
9630                         start_new_bblock = 1;
9631                         inline_costs += BRANCH_COST;
9632                         break;
9633                 case CEE_BRFALSE_S:
9634                 case CEE_BRTRUE_S:
9635                 case CEE_BRFALSE:
9636                 case CEE_BRTRUE: {
9637                         MonoInst *cmp;
9638                         gboolean is_short = ((*ip) == CEE_BRFALSE_S) || ((*ip) == CEE_BRTRUE_S);
9639                         gboolean is_true = ((*ip) == CEE_BRTRUE_S) || ((*ip) == CEE_BRTRUE);
9640                         guint32 opsize = is_short ? 1 : 4;
9641
9642                         CHECK_OPSIZE (opsize);
9643                         CHECK_STACK (1);
9644                         if (sp [-1]->type == STACK_VTYPE || sp [-1]->type == STACK_R8)
9645                                 UNVERIFIED;
9646                         ip ++;
9647                         target = ip + opsize + (is_short ? *(signed char*)ip : (gint32)read32(ip));
9648                         ip += opsize;
9649
9650                         sp--;
9651
9652                         GET_BBLOCK (cfg, tblock, target);
9653                         link_bblock (cfg, cfg->cbb, tblock);
9654                         GET_BBLOCK (cfg, tblock, ip);
9655                         link_bblock (cfg, cfg->cbb, tblock);
9656
9657                         if (sp != stack_start) {
9658                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9659                                 CHECK_UNVERIFIABLE (cfg);
9660                         }
9661
9662                         MONO_INST_NEW(cfg, cmp, OP_ICOMPARE_IMM);
9663                         cmp->sreg1 = sp [0]->dreg;
9664                         type_from_op (cfg, cmp, sp [0], NULL);
9665                         CHECK_TYPE (cmp);
9666
9667 #if SIZEOF_REGISTER == 4
9668                         if (cmp->opcode == OP_LCOMPARE_IMM) {
9669                                 /* Convert it to OP_LCOMPARE */
9670                                 MONO_INST_NEW (cfg, ins, OP_I8CONST);
9671                                 ins->type = STACK_I8;
9672                                 ins->dreg = alloc_dreg (cfg, STACK_I8);
9673                                 ins->inst_l = 0;
9674                                 MONO_ADD_INS (cfg->cbb, ins);
9675                                 cmp->opcode = OP_LCOMPARE;
9676                                 cmp->sreg2 = ins->dreg;
9677                         }
9678 #endif
9679                         MONO_ADD_INS (cfg->cbb, cmp);
9680
9681                         MONO_INST_NEW (cfg, ins, is_true ? CEE_BNE_UN : CEE_BEQ);
9682                         type_from_op (cfg, ins, sp [0], NULL);
9683                         MONO_ADD_INS (cfg->cbb, ins);
9684                         ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);
9685                         GET_BBLOCK (cfg, tblock, target);
9686                         ins->inst_true_bb = tblock;
9687                         GET_BBLOCK (cfg, tblock, ip);
9688                         ins->inst_false_bb = tblock;
9689                         start_new_bblock = 2;
9690
9691                         sp = stack_start;
9692                         inline_costs += BRANCH_COST;
9693                         break;
9694                 }
9695                 case CEE_BEQ:
9696                 case CEE_BGE:
9697                 case CEE_BGT:
9698                 case CEE_BLE:
9699                 case CEE_BLT:
9700                 case CEE_BNE_UN:
9701                 case CEE_BGE_UN:
9702                 case CEE_BGT_UN:
9703                 case CEE_BLE_UN:
9704                 case CEE_BLT_UN:
9705                         CHECK_OPSIZE (5);
9706                         CHECK_STACK (2);
9707                         MONO_INST_NEW (cfg, ins, *ip);
9708                         ip++;
9709                         target = ip + 4 + (gint32)read32(ip);
9710                         ip += 4;
9711
9712                         ADD_BINCOND (NULL);
9713
9714                         sp = stack_start;
9715                         inline_costs += BRANCH_COST;
9716                         break;
9717                 case CEE_SWITCH: {
9718                         MonoInst *src1;
9719                         MonoBasicBlock **targets;
9720                         MonoBasicBlock *default_bblock;
9721                         MonoJumpInfoBBTable *table;
9722                         int offset_reg = alloc_preg (cfg);
9723                         int target_reg = alloc_preg (cfg);
9724                         int table_reg = alloc_preg (cfg);
9725                         int sum_reg = alloc_preg (cfg);
9726                         gboolean use_op_switch;
9727
9728                         CHECK_OPSIZE (5);
9729                         CHECK_STACK (1);
9730                         n = read32 (ip + 1);
9731                         --sp;
9732                         src1 = sp [0];
9733                         if ((src1->type != STACK_I4) && (src1->type != STACK_PTR)) 
9734                                 UNVERIFIED;
9735
9736                         ip += 5;
9737                         CHECK_OPSIZE (n * sizeof (guint32));
9738                         target = ip + n * sizeof (guint32);
9739
9740                         GET_BBLOCK (cfg, default_bblock, target);
9741                         default_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
9742
9743                         targets = mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * n);
9744                         for (i = 0; i < n; ++i) {
9745                                 GET_BBLOCK (cfg, tblock, target + (gint32)read32(ip));
9746                                 targets [i] = tblock;
9747                                 targets [i]->flags |= BB_INDIRECT_JUMP_TARGET;
9748                                 ip += 4;
9749                         }
9750
9751                         if (sp != stack_start) {
9752                                 /* 
9753                                  * Link the current bb with the targets as well, so handle_stack_args
9754                                  * will set their in_stack correctly.
9755                                  */
9756                                 link_bblock (cfg, cfg->cbb, default_bblock);
9757                                 for (i = 0; i < n; ++i)
9758                                         link_bblock (cfg, cfg->cbb, targets [i]);
9759
9760                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9761                                 sp = stack_start;
9762                                 CHECK_UNVERIFIABLE (cfg);
9763                         }
9764
9765                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, src1->dreg, n);
9766                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBGE_UN, default_bblock);
9767
9768                         for (i = 0; i < n; ++i)
9769                                 link_bblock (cfg, cfg->cbb, targets [i]);
9770
9771                         table = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfoBBTable));
9772                         table->table = targets;
9773                         table->table_size = n;
9774
9775                         use_op_switch = FALSE;
9776 #ifdef TARGET_ARM
9777                         /* ARM implements SWITCH statements differently */
9778                         /* FIXME: Make it use the generic implementation */
9779                         if (!cfg->compile_aot)
9780                                 use_op_switch = TRUE;
9781 #endif
9782
9783                         if (COMPILE_LLVM (cfg))
9784                                 use_op_switch = TRUE;
9785
9786                         cfg->cbb->has_jump_table = 1;
9787
9788                         if (use_op_switch) {
9789                                 MONO_INST_NEW (cfg, ins, OP_SWITCH);
9790                                 ins->sreg1 = src1->dreg;
9791                                 ins->inst_p0 = table;
9792                                 ins->inst_many_bb = targets;
9793                                 ins->klass = GUINT_TO_POINTER (n);
9794                                 MONO_ADD_INS (cfg->cbb, ins);
9795                         } else {
9796                                 if (sizeof (gpointer) == 8)
9797                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 3);
9798                                 else
9799                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 2);
9800
9801 #if SIZEOF_REGISTER == 8
9802                                 /* The upper word might not be zero, and we add it to a 64 bit address later */
9803                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, offset_reg, offset_reg);
9804 #endif
9805
9806                                 if (cfg->compile_aot) {
9807                                         MONO_EMIT_NEW_AOTCONST (cfg, table_reg, table, MONO_PATCH_INFO_SWITCH);
9808                                 } else {
9809                                         MONO_INST_NEW (cfg, ins, OP_JUMP_TABLE);
9810                                         ins->inst_c1 = MONO_PATCH_INFO_SWITCH;
9811                                         ins->inst_p0 = table;
9812                                         ins->dreg = table_reg;
9813                                         MONO_ADD_INS (cfg->cbb, ins);
9814                                 }
9815
9816                                 /* FIXME: Use load_memindex */
9817                                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, table_reg, offset_reg);
9818                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, target_reg, sum_reg, 0);
9819                                 MONO_EMIT_NEW_UNALU (cfg, OP_BR_REG, -1, target_reg);
9820                         }
9821                         start_new_bblock = 1;
9822                         inline_costs += (BRANCH_COST * 2);
9823                         break;
9824                 }
9825                 case CEE_LDIND_I1:
9826                 case CEE_LDIND_U1:
9827                 case CEE_LDIND_I2:
9828                 case CEE_LDIND_U2:
9829                 case CEE_LDIND_I4:
9830                 case CEE_LDIND_U4:
9831                 case CEE_LDIND_I8:
9832                 case CEE_LDIND_I:
9833                 case CEE_LDIND_R4:
9834                 case CEE_LDIND_R8:
9835                 case CEE_LDIND_REF:
9836                         CHECK_STACK (1);
9837                         --sp;
9838
9839                         switch (*ip) {
9840                         case CEE_LDIND_R4:
9841                         case CEE_LDIND_R8:
9842                                 dreg = alloc_freg (cfg);
9843                                 break;
9844                         case CEE_LDIND_I8:
9845                                 dreg = alloc_lreg (cfg);
9846                                 break;
9847                         case CEE_LDIND_REF:
9848                                 dreg = alloc_ireg_ref (cfg);
9849                                 break;
9850                         default:
9851                                 dreg = alloc_preg (cfg);
9852                         }
9853
9854                         NEW_LOAD_MEMBASE (cfg, ins, ldind_to_load_membase (*ip), dreg, sp [0]->dreg, 0);
9855                         ins->type = ldind_type [*ip - CEE_LDIND_I1];
9856                         if (*ip == CEE_LDIND_R4)
9857                                 ins->type = cfg->r4_stack_type;
9858                         ins->flags |= ins_flag;
9859                         MONO_ADD_INS (cfg->cbb, ins);
9860                         *sp++ = ins;
9861                         if (ins_flag & MONO_INST_VOLATILE) {
9862                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
9863                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
9864                         }
9865                         ins_flag = 0;
9866                         ++ip;
9867                         break;
9868                 case CEE_STIND_REF:
9869                 case CEE_STIND_I1:
9870                 case CEE_STIND_I2:
9871                 case CEE_STIND_I4:
9872                 case CEE_STIND_I8:
9873                 case CEE_STIND_R4:
9874                 case CEE_STIND_R8:
9875                 case CEE_STIND_I:
9876                         CHECK_STACK (2);
9877                         sp -= 2;
9878
9879                         if (ins_flag & MONO_INST_VOLATILE) {
9880                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
9881                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
9882                         }
9883
9884                         NEW_STORE_MEMBASE (cfg, ins, stind_to_store_membase (*ip), sp [0]->dreg, 0, sp [1]->dreg);
9885                         ins->flags |= ins_flag;
9886                         ins_flag = 0;
9887
9888                         MONO_ADD_INS (cfg->cbb, ins);
9889
9890                         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)))
9891                                 emit_write_barrier (cfg, sp [0], sp [1]);
9892
9893                         inline_costs += 1;
9894                         ++ip;
9895                         break;
9896
9897                 case CEE_MUL:
9898                         CHECK_STACK (2);
9899
9900                         MONO_INST_NEW (cfg, ins, (*ip));
9901                         sp -= 2;
9902                         ins->sreg1 = sp [0]->dreg;
9903                         ins->sreg2 = sp [1]->dreg;
9904                         type_from_op (cfg, ins, sp [0], sp [1]);
9905                         CHECK_TYPE (ins);
9906                         ins->dreg = alloc_dreg ((cfg), (ins)->type);
9907
9908                         /* Use the immediate opcodes if possible */
9909                         if ((sp [1]->opcode == OP_ICONST) && mono_arch_is_inst_imm (sp [1]->inst_c0)) {
9910                                 int imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
9911                                 if (imm_opcode != -1) {
9912                                         ins->opcode = imm_opcode;
9913                                         ins->inst_p1 = (gpointer)(gssize)(sp [1]->inst_c0);
9914                                         ins->sreg2 = -1;
9915
9916                                         NULLIFY_INS (sp [1]);
9917                                 }
9918                         }
9919
9920                         MONO_ADD_INS ((cfg)->cbb, (ins));
9921
9922                         *sp++ = mono_decompose_opcode (cfg, ins);
9923                         ip++;
9924                         break;
9925                 case CEE_ADD:
9926                 case CEE_SUB:
9927                 case CEE_DIV:
9928                 case CEE_DIV_UN:
9929                 case CEE_REM:
9930                 case CEE_REM_UN:
9931                 case CEE_AND:
9932                 case CEE_OR:
9933                 case CEE_XOR:
9934                 case CEE_SHL:
9935                 case CEE_SHR:
9936                 case CEE_SHR_UN:
9937                         CHECK_STACK (2);
9938
9939                         MONO_INST_NEW (cfg, ins, (*ip));
9940                         sp -= 2;
9941                         ins->sreg1 = sp [0]->dreg;
9942                         ins->sreg2 = sp [1]->dreg;
9943                         type_from_op (cfg, ins, sp [0], sp [1]);
9944                         CHECK_TYPE (ins);
9945                         add_widen_op (cfg, ins, &sp [0], &sp [1]);
9946                         ins->dreg = alloc_dreg ((cfg), (ins)->type);
9947
9948                         /* FIXME: Pass opcode to is_inst_imm */
9949
9950                         /* Use the immediate opcodes if possible */
9951                         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)) {
9952                                 int imm_opcode;
9953
9954                                 imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
9955 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
9956                                 /* Keep emulated opcodes which are optimized away later */
9957                                 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) {
9958                                         imm_opcode = mono_op_to_op_imm (ins->opcode);
9959                                 }
9960 #endif
9961                                 if (imm_opcode != -1) {
9962                                         ins->opcode = imm_opcode;
9963                                         if (sp [1]->opcode == OP_I8CONST) {
9964 #if SIZEOF_REGISTER == 8
9965                                                 ins->inst_imm = sp [1]->inst_l;
9966 #else
9967                                                 ins->inst_ls_word = sp [1]->inst_ls_word;
9968                                                 ins->inst_ms_word = sp [1]->inst_ms_word;
9969 #endif
9970                                         }
9971                                         else
9972                                                 ins->inst_imm = (gssize)(sp [1]->inst_c0);
9973                                         ins->sreg2 = -1;
9974
9975                                         /* Might be followed by an instruction added by add_widen_op */
9976                                         if (sp [1]->next == NULL)
9977                                                 NULLIFY_INS (sp [1]);
9978                                 }
9979                         }
9980                         MONO_ADD_INS ((cfg)->cbb, (ins));
9981
9982                         *sp++ = mono_decompose_opcode (cfg, ins);
9983                         ip++;
9984                         break;
9985                 case CEE_NEG:
9986                 case CEE_NOT:
9987                 case CEE_CONV_I1:
9988                 case CEE_CONV_I2:
9989                 case CEE_CONV_I4:
9990                 case CEE_CONV_R4:
9991                 case CEE_CONV_R8:
9992                 case CEE_CONV_U4:
9993                 case CEE_CONV_I8:
9994                 case CEE_CONV_U8:
9995                 case CEE_CONV_OVF_I8:
9996                 case CEE_CONV_OVF_U8:
9997                 case CEE_CONV_R_UN:
9998                         CHECK_STACK (1);
9999
10000                         /* Special case this earlier so we have long constants in the IR */
10001                         if ((((*ip) == CEE_CONV_I8) || ((*ip) == CEE_CONV_U8)) && (sp [-1]->opcode == OP_ICONST)) {
10002                                 int data = sp [-1]->inst_c0;
10003                                 sp [-1]->opcode = OP_I8CONST;
10004                                 sp [-1]->type = STACK_I8;
10005 #if SIZEOF_REGISTER == 8
10006                                 if ((*ip) == CEE_CONV_U8)
10007                                         sp [-1]->inst_c0 = (guint32)data;
10008                                 else
10009                                         sp [-1]->inst_c0 = data;
10010 #else
10011                                 sp [-1]->inst_ls_word = data;
10012                                 if ((*ip) == CEE_CONV_U8)
10013                                         sp [-1]->inst_ms_word = 0;
10014                                 else
10015                                         sp [-1]->inst_ms_word = (data < 0) ? -1 : 0;
10016 #endif
10017                                 sp [-1]->dreg = alloc_dreg (cfg, STACK_I8);
10018                         }
10019                         else {
10020                                 ADD_UNOP (*ip);
10021                         }
10022                         ip++;
10023                         break;
10024                 case CEE_CONV_OVF_I4:
10025                 case CEE_CONV_OVF_I1:
10026                 case CEE_CONV_OVF_I2:
10027                 case CEE_CONV_OVF_I:
10028                 case CEE_CONV_OVF_U:
10029                         CHECK_STACK (1);
10030
10031                         if (sp [-1]->type == STACK_R8 || sp [-1]->type == STACK_R4) {
10032                                 ADD_UNOP (CEE_CONV_OVF_I8);
10033                                 ADD_UNOP (*ip);
10034                         } else {
10035                                 ADD_UNOP (*ip);
10036                         }
10037                         ip++;
10038                         break;
10039                 case CEE_CONV_OVF_U1:
10040                 case CEE_CONV_OVF_U2:
10041                 case CEE_CONV_OVF_U4:
10042                         CHECK_STACK (1);
10043
10044                         if (sp [-1]->type == STACK_R8 || sp [-1]->type == STACK_R4) {
10045                                 ADD_UNOP (CEE_CONV_OVF_U8);
10046                                 ADD_UNOP (*ip);
10047                         } else {
10048                                 ADD_UNOP (*ip);
10049                         }
10050                         ip++;
10051                         break;
10052                 case CEE_CONV_OVF_I1_UN:
10053                 case CEE_CONV_OVF_I2_UN:
10054                 case CEE_CONV_OVF_I4_UN:
10055                 case CEE_CONV_OVF_I8_UN:
10056                 case CEE_CONV_OVF_U1_UN:
10057                 case CEE_CONV_OVF_U2_UN:
10058                 case CEE_CONV_OVF_U4_UN:
10059                 case CEE_CONV_OVF_U8_UN:
10060                 case CEE_CONV_OVF_I_UN:
10061                 case CEE_CONV_OVF_U_UN:
10062                 case CEE_CONV_U2:
10063                 case CEE_CONV_U1:
10064                 case CEE_CONV_I:
10065                 case CEE_CONV_U:
10066                         CHECK_STACK (1);
10067                         ADD_UNOP (*ip);
10068                         CHECK_CFG_EXCEPTION;
10069                         ip++;
10070                         break;
10071                 case CEE_ADD_OVF:
10072                 case CEE_ADD_OVF_UN:
10073                 case CEE_MUL_OVF:
10074                 case CEE_MUL_OVF_UN:
10075                 case CEE_SUB_OVF:
10076                 case CEE_SUB_OVF_UN:
10077                         CHECK_STACK (2);
10078                         ADD_BINOP (*ip);
10079                         ip++;
10080                         break;
10081                 case CEE_CPOBJ:
10082                         GSHAREDVT_FAILURE (*ip);
10083                         CHECK_OPSIZE (5);
10084                         CHECK_STACK (2);
10085                         token = read32 (ip + 1);
10086                         klass = mini_get_class (method, token, generic_context);
10087                         CHECK_TYPELOAD (klass);
10088                         sp -= 2;
10089                         if (generic_class_is_reference_type (cfg, klass)) {
10090                                 MonoInst *store, *load;
10091                                 int dreg = alloc_ireg_ref (cfg);
10092
10093                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, dreg, sp [1]->dreg, 0);
10094                                 load->flags |= ins_flag;
10095                                 MONO_ADD_INS (cfg->cbb, load);
10096
10097                                 NEW_STORE_MEMBASE (cfg, store, OP_STORE_MEMBASE_REG, sp [0]->dreg, 0, dreg);
10098                                 store->flags |= ins_flag;
10099                                 MONO_ADD_INS (cfg->cbb, store);
10100
10101                                 if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER)
10102                                         emit_write_barrier (cfg, sp [0], sp [1]);
10103                         } else {
10104                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
10105                         }
10106                         ins_flag = 0;
10107                         ip += 5;
10108                         break;
10109                 case CEE_LDOBJ: {
10110                         int loc_index = -1;
10111                         int stloc_len = 0;
10112
10113                         CHECK_OPSIZE (5);
10114                         CHECK_STACK (1);
10115                         --sp;
10116                         token = read32 (ip + 1);
10117                         klass = mini_get_class (method, token, generic_context);
10118                         CHECK_TYPELOAD (klass);
10119
10120                         /* Optimize the common ldobj+stloc combination */
10121                         switch (ip [5]) {
10122                         case CEE_STLOC_S:
10123                                 loc_index = ip [6];
10124                                 stloc_len = 2;
10125                                 break;
10126                         case CEE_STLOC_0:
10127                         case CEE_STLOC_1:
10128                         case CEE_STLOC_2:
10129                         case CEE_STLOC_3:
10130                                 loc_index = ip [5] - CEE_STLOC_0;
10131                                 stloc_len = 1;
10132                                 break;
10133                         default:
10134                                 break;
10135                         }
10136
10137                         if ((loc_index != -1) && ip_in_bb (cfg, cfg->cbb, ip + 5)) {
10138                                 CHECK_LOCAL (loc_index);
10139
10140                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
10141                                 ins->dreg = cfg->locals [loc_index]->dreg;
10142                                 ins->flags |= ins_flag;
10143                                 ip += 5;
10144                                 ip += stloc_len;
10145                                 if (ins_flag & MONO_INST_VOLATILE) {
10146                                         /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10147                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10148                                 }
10149                                 ins_flag = 0;
10150                                 break;
10151                         }
10152
10153                         /* Optimize the ldobj+stobj combination */
10154                         /* The reference case ends up being a load+store anyway */
10155                         /* Skip this if the operation is volatile. */
10156                         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)) {
10157                                 CHECK_STACK (1);
10158
10159                                 sp --;
10160
10161                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
10162
10163                                 ip += 5 + 5;
10164                                 ins_flag = 0;
10165                                 break;
10166                         }
10167
10168                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
10169                         ins->flags |= ins_flag;
10170                         *sp++ = ins;
10171
10172                         if (ins_flag & MONO_INST_VOLATILE) {
10173                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10174                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10175                         }
10176
10177                         ip += 5;
10178                         ins_flag = 0;
10179                         inline_costs += 1;
10180                         break;
10181                 }
10182                 case CEE_LDSTR:
10183                         CHECK_STACK_OVF (1);
10184                         CHECK_OPSIZE (5);
10185                         n = read32 (ip + 1);
10186
10187                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
10188                                 EMIT_NEW_PCONST (cfg, ins, mono_method_get_wrapper_data (method, n));
10189                                 ins->type = STACK_OBJ;
10190                                 *sp = ins;
10191                         }
10192                         else if (method->wrapper_type != MONO_WRAPPER_NONE) {
10193                                 MonoInst *iargs [1];
10194                                 char *str = mono_method_get_wrapper_data (method, n);
10195
10196                                 if (cfg->compile_aot)
10197                                         EMIT_NEW_LDSTRLITCONST (cfg, iargs [0], str);
10198                                 else
10199                                         EMIT_NEW_PCONST (cfg, iargs [0], str);
10200                                 *sp = mono_emit_jit_icall (cfg, mono_string_new_wrapper, iargs);
10201                         } else {
10202                                 if (cfg->opt & MONO_OPT_SHARED) {
10203                                         MonoInst *iargs [3];
10204
10205                                         if (cfg->compile_aot) {
10206                                                 cfg->ldstr_list = g_list_prepend (cfg->ldstr_list, GINT_TO_POINTER (n));
10207                                         }
10208                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
10209                                         EMIT_NEW_IMAGECONST (cfg, iargs [1], image);
10210                                         EMIT_NEW_ICONST (cfg, iargs [2], mono_metadata_token_index (n));
10211                                         *sp = mono_emit_jit_icall (cfg, mono_ldstr, iargs);
10212                                         mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
10213                                 } else {
10214                                         if (cfg->cbb->out_of_line) {
10215                                                 MonoInst *iargs [2];
10216
10217                                                 if (image == mono_defaults.corlib) {
10218                                                         /* 
10219                                                          * Avoid relocations in AOT and save some space by using a 
10220                                                          * version of helper_ldstr specialized to mscorlib.
10221                                                          */
10222                                                         EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (n));
10223                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr_mscorlib, iargs);
10224                                                 } else {
10225                                                         /* Avoid creating the string object */
10226                                                         EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
10227                                                         EMIT_NEW_ICONST (cfg, iargs [1], mono_metadata_token_index (n));
10228                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr, iargs);
10229                                                 }
10230                                         } 
10231                                         else
10232                                         if (cfg->compile_aot) {
10233                                                 NEW_LDSTRCONST (cfg, ins, image, n);
10234                                                 *sp = ins;
10235                                                 MONO_ADD_INS (cfg->cbb, ins);
10236                                         } 
10237                                         else {
10238                                                 NEW_PCONST (cfg, ins, NULL);
10239                                                 ins->type = STACK_OBJ;
10240                                                 ins->inst_p0 = mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
10241                                                 if (!ins->inst_p0)
10242                                                         OUT_OF_MEMORY_FAILURE;
10243
10244                                                 *sp = ins;
10245                                                 MONO_ADD_INS (cfg->cbb, ins);
10246                                         }
10247                                 }
10248                         }
10249
10250                         sp++;
10251                         ip += 5;
10252                         break;
10253                 case CEE_NEWOBJ: {
10254                         MonoInst *iargs [2];
10255                         MonoMethodSignature *fsig;
10256                         MonoInst this_ins;
10257                         MonoInst *alloc;
10258                         MonoInst *vtable_arg = NULL;
10259
10260                         CHECK_OPSIZE (5);
10261                         token = read32 (ip + 1);
10262                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
10263                         if (!cmethod || mono_loader_get_last_error ())
10264                                 LOAD_ERROR;
10265                         fsig = mono_method_get_signature_checked (cmethod, image, token, generic_context, &cfg->error);
10266                         CHECK_CFG_ERROR;
10267
10268                         mono_save_token_info (cfg, image, token, cmethod);
10269
10270                         if (!mono_class_init (cmethod->klass))
10271                                 TYPE_LOAD_ERROR (cmethod->klass);
10272
10273                         context_used = mini_method_check_context_used (cfg, cmethod);
10274
10275                         if (mono_security_core_clr_enabled ())
10276                                 ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
10277
10278                         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)) {
10279                                 emit_class_init (cfg, cmethod->klass);
10280                                 CHECK_TYPELOAD (cmethod->klass);
10281                         }
10282
10283                         /*
10284                         if (cfg->gsharedvt) {
10285                                 if (mini_is_gsharedvt_variable_signature (sig))
10286                                         GSHAREDVT_FAILURE (*ip);
10287                         }
10288                         */
10289
10290                         n = fsig->param_count;
10291                         CHECK_STACK (n);
10292
10293                         /* 
10294                          * Generate smaller code for the common newobj <exception> instruction in
10295                          * argument checking code.
10296                          */
10297                         if (cfg->cbb->out_of_line && cmethod->klass->image == mono_defaults.corlib &&
10298                                 is_exception_class (cmethod->klass) && n <= 2 &&
10299                                 ((n < 1) || (!fsig->params [0]->byref && fsig->params [0]->type == MONO_TYPE_STRING)) && 
10300                                 ((n < 2) || (!fsig->params [1]->byref && fsig->params [1]->type == MONO_TYPE_STRING))) {
10301                                 MonoInst *iargs [3];
10302
10303                                 sp -= n;
10304
10305                                 EMIT_NEW_ICONST (cfg, iargs [0], cmethod->klass->type_token);
10306                                 switch (n) {
10307                                 case 0:
10308                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_0, iargs);
10309                                         break;
10310                                 case 1:
10311                                         iargs [1] = sp [0];
10312                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_1, iargs);
10313                                         break;
10314                                 case 2:
10315                                         iargs [1] = sp [0];
10316                                         iargs [2] = sp [1];
10317                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_2, iargs);
10318                                         break;
10319                                 default:
10320                                         g_assert_not_reached ();
10321                                 }
10322
10323                                 ip += 5;
10324                                 inline_costs += 5;
10325                                 break;
10326                         }
10327
10328                         /* move the args to allow room for 'this' in the first position */
10329                         while (n--) {
10330                                 --sp;
10331                                 sp [1] = sp [0];
10332                         }
10333
10334                         /* check_call_signature () requires sp[0] to be set */
10335                         this_ins.type = STACK_OBJ;
10336                         sp [0] = &this_ins;
10337                         if (check_call_signature (cfg, fsig, sp))
10338                                 UNVERIFIED;
10339
10340                         iargs [0] = NULL;
10341
10342                         if (mini_class_is_system_array (cmethod->klass)) {
10343                                 *sp = emit_get_rgctx_method (cfg, context_used,
10344                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
10345
10346                                 /* Avoid varargs in the common case */
10347                                 if (fsig->param_count == 1)
10348                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_1, sp);
10349                                 else if (fsig->param_count == 2)
10350                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_2, sp);
10351                                 else if (fsig->param_count == 3)
10352                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_3, sp);
10353                                 else if (fsig->param_count == 4)
10354                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_4, sp);
10355                                 else
10356                                         alloc = handle_array_new (cfg, fsig->param_count, sp, ip);
10357                         } else if (cmethod->string_ctor) {
10358                                 g_assert (!context_used);
10359                                 g_assert (!vtable_arg);
10360                                 /* we simply pass a null pointer */
10361                                 EMIT_NEW_PCONST (cfg, *sp, NULL); 
10362                                 /* now call the string ctor */
10363                                 alloc = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, NULL, NULL, NULL);
10364                         } else {
10365                                 if (cmethod->klass->valuetype) {
10366                                         iargs [0] = mono_compile_create_var (cfg, &cmethod->klass->byval_arg, OP_LOCAL);
10367                                         emit_init_rvar (cfg, iargs [0]->dreg, &cmethod->klass->byval_arg);
10368                                         EMIT_NEW_TEMPLOADA (cfg, *sp, iargs [0]->inst_c0);
10369
10370                                         alloc = NULL;
10371
10372                                         /* 
10373                                          * The code generated by mini_emit_virtual_call () expects
10374                                          * iargs [0] to be a boxed instance, but luckily the vcall
10375                                          * will be transformed into a normal call there.
10376                                          */
10377                                 } else if (context_used) {
10378                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, context_used);
10379                                         *sp = alloc;
10380                                 } else {
10381                                         MonoVTable *vtable = NULL;
10382
10383                                         if (!cfg->compile_aot)
10384                                                 vtable = mono_class_vtable (cfg->domain, cmethod->klass);
10385                                         CHECK_TYPELOAD (cmethod->klass);
10386
10387                                         /*
10388                                          * TypeInitializationExceptions thrown from the mono_runtime_class_init
10389                                          * call in mono_jit_runtime_invoke () can abort the finalizer thread.
10390                                          * As a workaround, we call class cctors before allocating objects.
10391                                          */
10392                                         if (mini_field_access_needs_cctor_run (cfg, method, cmethod->klass, vtable) && !(g_slist_find (class_inits, cmethod->klass))) {
10393                                                 emit_class_init (cfg, cmethod->klass);
10394                                                 if (cfg->verbose_level > 2)
10395                                                         printf ("class %s.%s needs init call for ctor\n", cmethod->klass->name_space, cmethod->klass->name);
10396                                                 class_inits = g_slist_prepend (class_inits, cmethod->klass);
10397                                         }
10398
10399                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, 0);
10400                                         *sp = alloc;
10401                                 }
10402                                 CHECK_CFG_EXCEPTION; /*for handle_alloc*/
10403
10404                                 if (alloc)
10405                                         MONO_EMIT_NEW_UNALU (cfg, OP_NOT_NULL, -1, alloc->dreg);
10406
10407                                 /* Now call the actual ctor */
10408                                 handle_ctor_call (cfg, cmethod, fsig, context_used, sp, ip, &inline_costs);
10409                                 CHECK_CFG_EXCEPTION;
10410                         }
10411
10412                         if (alloc == NULL) {
10413                                 /* Valuetype */
10414                                 EMIT_NEW_TEMPLOAD (cfg, ins, iargs [0]->inst_c0);
10415                                 type_to_eval_stack_type (cfg, &ins->klass->byval_arg, ins);
10416                                 *sp++= ins;
10417                         } else {
10418                                 *sp++ = alloc;
10419                         }
10420                         
10421                         ip += 5;
10422                         inline_costs += 5;
10423                         if (!(seq_point_locs && mono_bitset_test_fast (seq_point_locs, ip - header->code)))
10424                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
10425                         break;
10426                 }
10427                 case CEE_CASTCLASS:
10428                         CHECK_STACK (1);
10429                         --sp;
10430                         CHECK_OPSIZE (5);
10431                         token = read32 (ip + 1);
10432                         klass = mini_get_class (method, token, generic_context);
10433                         CHECK_TYPELOAD (klass);
10434                         if (sp [0]->type != STACK_OBJ)
10435                                 UNVERIFIED;
10436
10437                         ins = handle_castclass (cfg, klass, *sp, ip, &inline_costs);
10438                         CHECK_CFG_EXCEPTION;
10439
10440                         *sp ++ = ins;
10441                         ip += 5;
10442                         break;
10443                 case CEE_ISINST: {
10444                         CHECK_STACK (1);
10445                         --sp;
10446                         CHECK_OPSIZE (5);
10447                         token = read32 (ip + 1);
10448                         klass = mini_get_class (method, token, generic_context);
10449                         CHECK_TYPELOAD (klass);
10450                         if (sp [0]->type != STACK_OBJ)
10451                                 UNVERIFIED;
10452  
10453                         context_used = mini_class_check_context_used (cfg, klass);
10454
10455                         if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
10456                                 MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
10457                                 MonoInst *args [3];
10458                                 int idx;
10459
10460                                 /* obj */
10461                                 args [0] = *sp;
10462
10463                                 /* klass */
10464                                 EMIT_NEW_CLASSCONST (cfg, args [1], klass);
10465
10466                                 /* inline cache*/
10467                                 if (cfg->compile_aot) {
10468                                         idx = get_castclass_cache_idx (cfg);
10469                                         EMIT_NEW_AOTCONST (cfg, args [2], MONO_PATCH_INFO_CASTCLASS_CACHE, GINT_TO_POINTER (idx));
10470                                 } else {
10471                                         EMIT_NEW_PCONST (cfg, args [2], mono_domain_alloc0 (cfg->domain, sizeof (gpointer)));
10472                                 }
10473
10474                                 *sp++ = mono_emit_method_call (cfg, mono_isinst, args, NULL);
10475                                 ip += 5;
10476                                 inline_costs += 2;
10477                         } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
10478                                 MonoMethod *mono_isinst;
10479                                 MonoInst *iargs [1];
10480                                 int costs;
10481
10482                                 mono_isinst = mono_marshal_get_isinst (klass); 
10483                                 iargs [0] = sp [0];
10484
10485                                 costs = inline_method (cfg, mono_isinst, mono_method_signature (mono_isinst), 
10486                                                                            iargs, ip, cfg->real_offset, TRUE);
10487                                 CHECK_CFG_EXCEPTION;
10488                                 g_assert (costs > 0);
10489                                 
10490                                 ip += 5;
10491                                 cfg->real_offset += 5;
10492
10493                                 *sp++= iargs [0];
10494
10495                                 inline_costs += costs;
10496                         }
10497                         else {
10498                                 ins = handle_isinst (cfg, klass, *sp, context_used);
10499                                 CHECK_CFG_EXCEPTION;
10500                                 *sp ++ = ins;
10501                                 ip += 5;
10502                         }
10503                         break;
10504                 }
10505                 case CEE_UNBOX_ANY: {
10506                         MonoInst *res, *addr;
10507
10508                         CHECK_STACK (1);
10509                         --sp;
10510                         CHECK_OPSIZE (5);
10511                         token = read32 (ip + 1);
10512                         klass = mini_get_class (method, token, generic_context);
10513                         CHECK_TYPELOAD (klass);
10514
10515                         mono_save_token_info (cfg, image, token, klass);
10516
10517                         context_used = mini_class_check_context_used (cfg, klass);
10518
10519                         if (mini_is_gsharedvt_klass (klass)) {
10520                                 res = handle_unbox_gsharedvt (cfg, klass, *sp);
10521                                 inline_costs += 2;
10522                         } else if (generic_class_is_reference_type (cfg, klass)) {
10523                                 res = handle_castclass (cfg, klass, *sp, ip, &inline_costs);
10524                                 CHECK_CFG_EXCEPTION;
10525                         } else if (mono_class_is_nullable (klass)) {
10526                                 res = handle_unbox_nullable (cfg, *sp, klass, context_used);
10527                         } else {
10528                                 addr = handle_unbox (cfg, klass, sp, context_used);
10529                                 /* LDOBJ */
10530                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
10531                                 res = ins;
10532                                 inline_costs += 2;
10533                         }
10534
10535                         *sp ++ = res;
10536                         ip += 5;
10537                         break;
10538                 }
10539                 case CEE_BOX: {
10540                         MonoInst *val;
10541                         MonoClass *enum_class;
10542                         MonoMethod *has_flag;
10543
10544                         CHECK_STACK (1);
10545                         --sp;
10546                         val = *sp;
10547                         CHECK_OPSIZE (5);
10548                         token = read32 (ip + 1);
10549                         klass = mini_get_class (method, token, generic_context);
10550                         CHECK_TYPELOAD (klass);
10551
10552                         mono_save_token_info (cfg, image, token, klass);
10553
10554                         context_used = mini_class_check_context_used (cfg, klass);
10555
10556                         if (generic_class_is_reference_type (cfg, klass)) {
10557                                 *sp++ = val;
10558                                 ip += 5;
10559                                 break;
10560                         }
10561
10562                         if (klass == mono_defaults.void_class)
10563                                 UNVERIFIED;
10564                         if (target_type_is_incompatible (cfg, &klass->byval_arg, *sp))
10565                                 UNVERIFIED;
10566                         /* frequent check in generic code: box (struct), brtrue */
10567
10568                         /*
10569                          * Look for:
10570                          *
10571                          *   <push int/long ptr>
10572                          *   <push int/long>
10573                          *   box MyFlags
10574                          *   constrained. MyFlags
10575                          *   callvirt instace bool class [mscorlib] System.Enum::HasFlag (class [mscorlib] System.Enum)
10576                          *
10577                          * If we find this sequence and the operand types on box and constrained
10578                          * are equal, we can emit a specialized instruction sequence instead of
10579                          * the very slow HasFlag () call.
10580                          */
10581                         if ((cfg->opt & MONO_OPT_INTRINS) &&
10582                             /* Cheap checks first. */
10583                             ip + 5 + 6 + 5 < end &&
10584                             ip [5] == CEE_PREFIX1 &&
10585                             ip [6] == CEE_CONSTRAINED_ &&
10586                             ip [11] == CEE_CALLVIRT &&
10587                             ip_in_bb (cfg, cfg->cbb, ip + 5 + 6 + 5) &&
10588                             mono_class_is_enum (klass) &&
10589                             (enum_class = mini_get_class (method, read32 (ip + 7), generic_context)) &&
10590                             (has_flag = mini_get_method (cfg, method, read32 (ip + 12), NULL, generic_context)) &&
10591                             has_flag->klass == mono_defaults.enum_class &&
10592                             !strcmp (has_flag->name, "HasFlag") &&
10593                             has_flag->signature->hasthis &&
10594                             has_flag->signature->param_count == 1) {
10595                                 CHECK_TYPELOAD (enum_class);
10596
10597                                 if (enum_class == klass) {
10598                                         MonoInst *enum_this, *enum_flag;
10599
10600                                         ip += 5 + 6 + 5;
10601                                         --sp;
10602
10603                                         enum_this = sp [0];
10604                                         enum_flag = sp [1];
10605
10606                                         *sp++ = handle_enum_has_flag (cfg, klass, enum_this, enum_flag);
10607                                         break;
10608                                 }
10609                         }
10610
10611                         // FIXME: LLVM can't handle the inconsistent bb linking
10612                         if (!mono_class_is_nullable (klass) &&
10613                                 !mini_is_gsharedvt_klass (klass) &&
10614                                 ip + 5 < end && ip_in_bb (cfg, cfg->cbb, ip + 5) &&
10615                                 (ip [5] == CEE_BRTRUE || 
10616                                  ip [5] == CEE_BRTRUE_S ||
10617                                  ip [5] == CEE_BRFALSE ||
10618                                  ip [5] == CEE_BRFALSE_S)) {
10619                                 gboolean is_true = ip [5] == CEE_BRTRUE || ip [5] == CEE_BRTRUE_S;
10620                                 int dreg;
10621                                 MonoBasicBlock *true_bb, *false_bb;
10622
10623                                 ip += 5;
10624
10625                                 if (cfg->verbose_level > 3) {
10626                                         printf ("converting (in B%d: stack: %d) %s", cfg->cbb->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
10627                                         printf ("<box+brtrue opt>\n");
10628                                 }
10629
10630                                 switch (*ip) {
10631                                 case CEE_BRTRUE_S:
10632                                 case CEE_BRFALSE_S:
10633                                         CHECK_OPSIZE (2);
10634                                         ip++;
10635                                         target = ip + 1 + (signed char)(*ip);
10636                                         ip++;
10637                                         break;
10638                                 case CEE_BRTRUE:
10639                                 case CEE_BRFALSE:
10640                                         CHECK_OPSIZE (5);
10641                                         ip++;
10642                                         target = ip + 4 + (gint)(read32 (ip));
10643                                         ip += 4;
10644                                         break;
10645                                 default:
10646                                         g_assert_not_reached ();
10647                                 }
10648
10649                                 /* 
10650                                  * We need to link both bblocks, since it is needed for handling stack
10651                                  * arguments correctly (See test_0_box_brtrue_opt_regress_81102).
10652                                  * Branching to only one of them would lead to inconsistencies, so
10653                                  * generate an ICONST+BRTRUE, the branch opts will get rid of them.
10654                                  */
10655                                 GET_BBLOCK (cfg, true_bb, target);
10656                                 GET_BBLOCK (cfg, false_bb, ip);
10657
10658                                 mono_link_bblock (cfg, cfg->cbb, true_bb);
10659                                 mono_link_bblock (cfg, cfg->cbb, false_bb);
10660
10661                                 if (sp != stack_start) {
10662                                         handle_stack_args (cfg, stack_start, sp - stack_start);
10663                                         sp = stack_start;
10664                                         CHECK_UNVERIFIABLE (cfg);
10665                                 }
10666
10667                                 if (COMPILE_LLVM (cfg)) {
10668                                         dreg = alloc_ireg (cfg);
10669                                         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
10670                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, dreg, is_true ? 0 : 1);
10671
10672                                         MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, OP_IBEQ, true_bb, false_bb);
10673                                 } else {
10674                                         /* The JIT can't eliminate the iconst+compare */
10675                                         MONO_INST_NEW (cfg, ins, OP_BR);
10676                                         ins->inst_target_bb = is_true ? true_bb : false_bb;
10677                                         MONO_ADD_INS (cfg->cbb, ins);
10678                                 }
10679
10680                                 start_new_bblock = 1;
10681                                 break;
10682                         }
10683
10684                         *sp++ = handle_box (cfg, val, klass, context_used);
10685
10686                         CHECK_CFG_EXCEPTION;
10687                         ip += 5;
10688                         inline_costs += 1;
10689                         break;
10690                 }
10691                 case CEE_UNBOX: {
10692                         CHECK_STACK (1);
10693                         --sp;
10694                         CHECK_OPSIZE (5);
10695                         token = read32 (ip + 1);
10696                         klass = mini_get_class (method, token, generic_context);
10697                         CHECK_TYPELOAD (klass);
10698
10699                         mono_save_token_info (cfg, image, token, klass);
10700
10701                         context_used = mini_class_check_context_used (cfg, klass);
10702
10703                         if (mono_class_is_nullable (klass)) {
10704                                 MonoInst *val;
10705
10706                                 val = handle_unbox_nullable (cfg, *sp, klass, context_used);
10707                                 EMIT_NEW_VARLOADA (cfg, ins, get_vreg_to_inst (cfg, val->dreg), &val->klass->byval_arg);
10708
10709                                 *sp++= ins;
10710                         } else {
10711                                 ins = handle_unbox (cfg, klass, sp, context_used);
10712                                 *sp++ = ins;
10713                         }
10714                         ip += 5;
10715                         inline_costs += 2;
10716                         break;
10717                 }
10718                 case CEE_LDFLD:
10719                 case CEE_LDFLDA:
10720                 case CEE_STFLD:
10721                 case CEE_LDSFLD:
10722                 case CEE_LDSFLDA:
10723                 case CEE_STSFLD: {
10724                         MonoClassField *field;
10725 #ifndef DISABLE_REMOTING
10726                         int costs;
10727 #endif
10728                         guint foffset;
10729                         gboolean is_instance;
10730                         int op;
10731                         gpointer addr = NULL;
10732                         gboolean is_special_static;
10733                         MonoType *ftype;
10734                         MonoInst *store_val = NULL;
10735                         MonoInst *thread_ins;
10736
10737                         op = *ip;
10738                         is_instance = (op == CEE_LDFLD || op == CEE_LDFLDA || op == CEE_STFLD);
10739                         if (is_instance) {
10740                                 if (op == CEE_STFLD) {
10741                                         CHECK_STACK (2);
10742                                         sp -= 2;
10743                                         store_val = sp [1];
10744                                 } else {
10745                                         CHECK_STACK (1);
10746                                         --sp;
10747                                 }
10748                                 if (sp [0]->type == STACK_I4 || sp [0]->type == STACK_I8 || sp [0]->type == STACK_R8)
10749                                         UNVERIFIED;
10750                                 if (*ip != CEE_LDFLD && sp [0]->type == STACK_VTYPE)
10751                                         UNVERIFIED;
10752                         } else {
10753                                 if (op == CEE_STSFLD) {
10754                                         CHECK_STACK (1);
10755                                         sp--;
10756                                         store_val = sp [0];
10757                                 }
10758                         }
10759
10760                         CHECK_OPSIZE (5);
10761                         token = read32 (ip + 1);
10762                         if (method->wrapper_type != MONO_WRAPPER_NONE) {
10763                                 field = mono_method_get_wrapper_data (method, token);
10764                                 klass = field->parent;
10765                         }
10766                         else {
10767                                 field = mono_field_from_token_checked (image, token, &klass, generic_context, &cfg->error);
10768                                 CHECK_CFG_ERROR;
10769                         }
10770                         if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_field (method, field))
10771                                 FIELD_ACCESS_FAILURE (method, field);
10772                         mono_class_init (klass);
10773
10774                         /* if the class is Critical then transparent code cannot access it's fields */
10775                         if (!is_instance && mono_security_core_clr_enabled ())
10776                                 ensure_method_is_allowed_to_access_field (cfg, method, field);
10777
10778                         /* XXX this is technically required but, so far (SL2), no [SecurityCritical] types (not many exists) have
10779                            any visible *instance* field  (in fact there's a single case for a static field in Marshal) XXX
10780                         if (mono_security_core_clr_enabled ())
10781                                 ensure_method_is_allowed_to_access_field (cfg, method, field);
10782                         */
10783
10784                         ftype = mono_field_get_type (field);
10785
10786                         /*
10787                          * LDFLD etc. is usable on static fields as well, so convert those cases to
10788                          * the static case.
10789                          */
10790                         if (is_instance && ftype->attrs & FIELD_ATTRIBUTE_STATIC) {
10791                                 switch (op) {
10792                                 case CEE_LDFLD:
10793                                         op = CEE_LDSFLD;
10794                                         break;
10795                                 case CEE_STFLD:
10796                                         op = CEE_STSFLD;
10797                                         break;
10798                                 case CEE_LDFLDA:
10799                                         op = CEE_LDSFLDA;
10800                                         break;
10801                                 default:
10802                                         g_assert_not_reached ();
10803                                 }
10804                                 is_instance = FALSE;
10805                         }
10806
10807                         context_used = mini_class_check_context_used (cfg, klass);
10808
10809                         /* INSTANCE CASE */
10810
10811                         foffset = klass->valuetype? field->offset - sizeof (MonoObject): field->offset;
10812                         if (op == CEE_STFLD) {
10813                                 if (target_type_is_incompatible (cfg, field->type, sp [1]))
10814                                         UNVERIFIED;
10815 #ifndef DISABLE_REMOTING
10816                                 if ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class) {
10817                                         MonoMethod *stfld_wrapper = mono_marshal_get_stfld_wrapper (field->type); 
10818                                         MonoInst *iargs [5];
10819
10820                                         GSHAREDVT_FAILURE (op);
10821
10822                                         iargs [0] = sp [0];
10823                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
10824                                         EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
10825                                         EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : 
10826                                                     field->offset);
10827                                         iargs [4] = sp [1];
10828
10829                                         if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
10830                                                 costs = inline_method (cfg, stfld_wrapper, mono_method_signature (stfld_wrapper), 
10831                                                                                            iargs, ip, cfg->real_offset, TRUE);
10832                                                 CHECK_CFG_EXCEPTION;
10833                                                 g_assert (costs > 0);
10834                                                       
10835                                                 cfg->real_offset += 5;
10836
10837                                                 inline_costs += costs;
10838                                         } else {
10839                                                 mono_emit_method_call (cfg, stfld_wrapper, iargs, NULL);
10840                                         }
10841                                 } else
10842 #endif
10843                                 {
10844                                         MonoInst *store;
10845
10846                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
10847
10848                                         if (mini_is_gsharedvt_klass (klass)) {
10849                                                 MonoInst *offset_ins;
10850
10851                                                 context_used = mini_class_check_context_used (cfg, klass);
10852
10853                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
10854                                                 dreg = alloc_ireg_mp (cfg);
10855                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
10856                                                 /* The decomposition will call mini_emit_stobj () which will emit a wbarrier if needed */
10857                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, dreg, 0, sp [1]->dreg);
10858                                         } else {
10859                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, sp [0]->dreg, foffset, sp [1]->dreg);
10860                                         }
10861                                         if (sp [0]->opcode != OP_LDADDR)
10862                                                 store->flags |= MONO_INST_FAULT;
10863
10864                                 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)) {
10865                                         /* insert call to write barrier */
10866                                         MonoInst *ptr;
10867                                         int dreg;
10868
10869                                         dreg = alloc_ireg_mp (cfg);
10870                                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
10871                                         emit_write_barrier (cfg, ptr, sp [1]);
10872                                 }
10873
10874                                         store->flags |= ins_flag;
10875                                 }
10876                                 ins_flag = 0;
10877                                 ip += 5;
10878                                 break;
10879                         }
10880
10881 #ifndef DISABLE_REMOTING
10882                         if (is_instance && ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class)) {
10883                                 MonoMethod *wrapper = (op == CEE_LDFLDA) ? mono_marshal_get_ldflda_wrapper (field->type) : mono_marshal_get_ldfld_wrapper (field->type); 
10884                                 MonoInst *iargs [4];
10885
10886                                 GSHAREDVT_FAILURE (op);
10887
10888                                 iargs [0] = sp [0];
10889                                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
10890                                 EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
10891                                 EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset);
10892                                 if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
10893                                         costs = inline_method (cfg, wrapper, mono_method_signature (wrapper), 
10894                                                                                    iargs, ip, cfg->real_offset, TRUE);
10895                                         CHECK_CFG_EXCEPTION;
10896                                         g_assert (costs > 0);
10897                                                       
10898                                         cfg->real_offset += 5;
10899
10900                                         *sp++ = iargs [0];
10901
10902                                         inline_costs += costs;
10903                                 } else {
10904                                         ins = mono_emit_method_call (cfg, wrapper, iargs, NULL);
10905                                         *sp++ = ins;
10906                                 }
10907                         } else 
10908 #endif
10909                         if (is_instance) {
10910                                 if (sp [0]->type == STACK_VTYPE) {
10911                                         MonoInst *var;
10912
10913                                         /* Have to compute the address of the variable */
10914
10915                                         var = get_vreg_to_inst (cfg, sp [0]->dreg);
10916                                         if (!var)
10917                                                 var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, sp [0]->dreg);
10918                                         else
10919                                                 g_assert (var->klass == klass);
10920                                         
10921                                         EMIT_NEW_VARLOADA (cfg, ins, var, &var->klass->byval_arg);
10922                                         sp [0] = ins;
10923                                 }
10924
10925                                 if (op == CEE_LDFLDA) {
10926                                         if (sp [0]->type == STACK_OBJ) {
10927                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, sp [0]->dreg, 0);
10928                                                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "NullReferenceException");
10929                                         }
10930
10931                                         dreg = alloc_ireg_mp (cfg);
10932
10933                                         if (mini_is_gsharedvt_klass (klass)) {
10934                                                 MonoInst *offset_ins;
10935
10936                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
10937                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
10938                                         } else {
10939                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
10940                                         }
10941                                         ins->klass = mono_class_from_mono_type (field->type);
10942                                         ins->type = STACK_MP;
10943                                         *sp++ = ins;
10944                                 } else {
10945                                         MonoInst *load;
10946
10947                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
10948
10949                                         if (mini_is_gsharedvt_klass (klass)) {
10950                                                 MonoInst *offset_ins;
10951
10952                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
10953                                                 dreg = alloc_ireg_mp (cfg);
10954                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
10955                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, dreg, 0);
10956                                         } else {
10957                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, sp [0]->dreg, foffset);
10958                                         }
10959                                         load->flags |= ins_flag;
10960                                         if (sp [0]->opcode != OP_LDADDR)
10961                                                 load->flags |= MONO_INST_FAULT;
10962                                         *sp++ = load;
10963                                 }
10964                         }
10965
10966                         if (is_instance) {
10967                                 ins_flag = 0;
10968                                 ip += 5;
10969                                 break;
10970                         }
10971
10972                         /* STATIC CASE */
10973                         context_used = mini_class_check_context_used (cfg, klass);
10974
10975                         if (ftype->attrs & FIELD_ATTRIBUTE_LITERAL)
10976                                 UNVERIFIED;
10977
10978                         /* The special_static_fields field is init'd in mono_class_vtable, so it needs
10979                          * to be called here.
10980                          */
10981                         if (!context_used && !(cfg->opt & MONO_OPT_SHARED)) {
10982                                 mono_class_vtable (cfg->domain, klass);
10983                                 CHECK_TYPELOAD (klass);
10984                         }
10985                         mono_domain_lock (cfg->domain);
10986                         if (cfg->domain->special_static_fields)
10987                                 addr = g_hash_table_lookup (cfg->domain->special_static_fields, field);
10988                         mono_domain_unlock (cfg->domain);
10989
10990                         is_special_static = mono_class_field_is_special_static (field);
10991
10992                         if (is_special_static && ((gsize)addr & 0x80000000) == 0)
10993                                 thread_ins = mono_get_thread_intrinsic (cfg);
10994                         else
10995                                 thread_ins = NULL;
10996
10997                         /* Generate IR to compute the field address */
10998                         if (is_special_static && ((gsize)addr & 0x80000000) == 0 && thread_ins && !(cfg->opt & MONO_OPT_SHARED) && !context_used) {
10999                                 /*
11000                                  * Fast access to TLS data
11001                                  * Inline version of get_thread_static_data () in
11002                                  * threads.c.
11003                                  */
11004                                 guint32 offset;
11005                                 int idx, static_data_reg, array_reg, dreg;
11006
11007                                 GSHAREDVT_FAILURE (op);
11008
11009                                 MONO_ADD_INS (cfg->cbb, thread_ins);
11010                                 static_data_reg = alloc_ireg (cfg);
11011                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, static_data_reg, thread_ins->dreg, MONO_STRUCT_OFFSET (MonoInternalThread, static_data));
11012
11013                                 if (cfg->compile_aot) {
11014                                         int offset_reg, offset2_reg, idx_reg;
11015
11016                                         /* For TLS variables, this will return the TLS offset */
11017                                         EMIT_NEW_SFLDACONST (cfg, ins, field);
11018                                         offset_reg = ins->dreg;
11019                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset_reg, offset_reg, 0x7fffffff);
11020                                         idx_reg = alloc_ireg (cfg);
11021                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, idx_reg, offset_reg, 0x3f);
11022                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHL_IMM, idx_reg, idx_reg, sizeof (gpointer) == 8 ? 3 : 2);
11023                                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, static_data_reg, static_data_reg, idx_reg);
11024                                         array_reg = alloc_ireg (cfg);
11025                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, 0);
11026                                         offset2_reg = alloc_ireg (cfg);
11027                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, offset2_reg, offset_reg, 6);
11028                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset2_reg, offset2_reg, 0x1ffffff);
11029                                         dreg = alloc_ireg (cfg);
11030                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, array_reg, offset2_reg);
11031                                 } else {
11032                                         offset = (gsize)addr & 0x7fffffff;
11033                                         idx = offset & 0x3f;
11034
11035                                         array_reg = alloc_ireg (cfg);
11036                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, idx * sizeof (gpointer));
11037                                         dreg = alloc_ireg (cfg);
11038                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_ADD_IMM, dreg, array_reg, ((offset >> 6) & 0x1ffffff));
11039                                 }
11040                         } else if ((cfg->opt & MONO_OPT_SHARED) ||
11041                                         (cfg->compile_aot && is_special_static) ||
11042                                         (context_used && is_special_static)) {
11043                                 MonoInst *iargs [2];
11044
11045                                 g_assert (field->parent);
11046                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11047                                 if (context_used) {
11048                                         iargs [1] = emit_get_rgctx_field (cfg, context_used,
11049                                                 field, MONO_RGCTX_INFO_CLASS_FIELD);
11050                                 } else {
11051                                         EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
11052                                 }
11053                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
11054                         } else if (context_used) {
11055                                 MonoInst *static_data;
11056
11057                                 /*
11058                                 g_print ("sharing static field access in %s.%s.%s - depth %d offset %d\n",
11059                                         method->klass->name_space, method->klass->name, method->name,
11060                                         depth, field->offset);
11061                                 */
11062
11063                                 if (mono_class_needs_cctor_run (klass, method))
11064                                         emit_class_init (cfg, klass);
11065
11066                                 /*
11067                                  * The pointer we're computing here is
11068                                  *
11069                                  *   super_info.static_data + field->offset
11070                                  */
11071                                 static_data = emit_get_rgctx_klass (cfg, context_used,
11072                                         klass, MONO_RGCTX_INFO_STATIC_DATA);
11073
11074                                 if (mini_is_gsharedvt_klass (klass)) {
11075                                         MonoInst *offset_ins;
11076
11077                                         offset_ins = emit_get_rgctx_field (cfg, context_used, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11078                                         dreg = alloc_ireg_mp (cfg);
11079                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, static_data->dreg, offset_ins->dreg);
11080                                 } else if (field->offset == 0) {
11081                                         ins = static_data;
11082                                 } else {
11083                                         int addr_reg = mono_alloc_preg (cfg);
11084                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, addr_reg, static_data->dreg, field->offset);
11085                                 }
11086                                 } else if ((cfg->opt & MONO_OPT_SHARED) || (cfg->compile_aot && addr)) {
11087                                 MonoInst *iargs [2];
11088
11089                                 g_assert (field->parent);
11090                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11091                                 EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
11092                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
11093                         } else {
11094                                 MonoVTable *vtable = NULL;
11095
11096                                 if (!cfg->compile_aot)
11097                                         vtable = mono_class_vtable (cfg->domain, klass);
11098                                 CHECK_TYPELOAD (klass);
11099
11100                                 if (!addr) {
11101                                         if (mini_field_access_needs_cctor_run (cfg, method, klass, vtable)) {
11102                                                 if (!(g_slist_find (class_inits, klass))) {
11103                                                         emit_class_init (cfg, klass);
11104                                                         if (cfg->verbose_level > 2)
11105                                                                 printf ("class %s.%s needs init call for %s\n", klass->name_space, klass->name, mono_field_get_name (field));
11106                                                         class_inits = g_slist_prepend (class_inits, klass);
11107                                                 }
11108                                         } else {
11109                                                 if (cfg->run_cctors) {
11110                                                         MonoException *ex;
11111                                                         /* This makes so that inline cannot trigger */
11112                                                         /* .cctors: too many apps depend on them */
11113                                                         /* running with a specific order... */
11114                                                         g_assert (vtable);
11115                                                         if (! vtable->initialized)
11116                                                                 INLINE_FAILURE ("class init");
11117                                                         ex = mono_runtime_class_init_full (vtable, FALSE);
11118                                                         if (ex) {
11119                                                                 set_exception_object (cfg, ex);
11120                                                                 goto exception_exit;
11121                                                         }
11122                                                 }
11123                                         }
11124                                         if (cfg->compile_aot)
11125                                                 EMIT_NEW_SFLDACONST (cfg, ins, field);
11126                                         else {
11127                                                 g_assert (vtable);
11128                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
11129                                                 g_assert (addr);
11130                                                 EMIT_NEW_PCONST (cfg, ins, addr);
11131                                         }
11132                                 } else {
11133                                         MonoInst *iargs [1];
11134                                         EMIT_NEW_ICONST (cfg, iargs [0], GPOINTER_TO_UINT (addr));
11135                                         ins = mono_emit_jit_icall (cfg, mono_get_special_static_data, iargs);
11136                                 }
11137                         }
11138
11139                         /* Generate IR to do the actual load/store operation */
11140
11141                         if ((op == CEE_STFLD || op == CEE_STSFLD) && (ins_flag & MONO_INST_VOLATILE)) {
11142                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
11143                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
11144                         }
11145
11146                         if (op == CEE_LDSFLDA) {
11147                                 ins->klass = mono_class_from_mono_type (ftype);
11148                                 ins->type = STACK_PTR;
11149                                 *sp++ = ins;
11150                         } else if (op == CEE_STSFLD) {
11151                                 MonoInst *store;
11152
11153                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, ftype, ins->dreg, 0, store_val->dreg);
11154                                 store->flags |= ins_flag;
11155                         } else {
11156                                 gboolean is_const = FALSE;
11157                                 MonoVTable *vtable = NULL;
11158                                 gpointer addr = NULL;
11159
11160                                 if (!context_used) {
11161                                         vtable = mono_class_vtable (cfg->domain, klass);
11162                                         CHECK_TYPELOAD (klass);
11163                                 }
11164                                 if ((ftype->attrs & FIELD_ATTRIBUTE_INIT_ONLY) && (((addr = mono_aot_readonly_field_override (field)) != NULL) ||
11165                                                 (!context_used && !((cfg->opt & MONO_OPT_SHARED) || cfg->compile_aot) && vtable->initialized))) {
11166                                         int ro_type = ftype->type;
11167                                         if (!addr)
11168                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
11169                                         if (ro_type == MONO_TYPE_VALUETYPE && ftype->data.klass->enumtype) {
11170                                                 ro_type = mono_class_enum_basetype (ftype->data.klass)->type;
11171                                         }
11172
11173                                         GSHAREDVT_FAILURE (op);
11174
11175                                         /* printf ("RO-FIELD %s.%s:%s\n", klass->name_space, klass->name, mono_field_get_name (field));*/
11176                                         is_const = TRUE;
11177                                         switch (ro_type) {
11178                                         case MONO_TYPE_BOOLEAN:
11179                                         case MONO_TYPE_U1:
11180                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint8 *)addr));
11181                                                 sp++;
11182                                                 break;
11183                                         case MONO_TYPE_I1:
11184                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint8 *)addr));
11185                                                 sp++;
11186                                                 break;                                          
11187                                         case MONO_TYPE_CHAR:
11188                                         case MONO_TYPE_U2:
11189                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint16 *)addr));
11190                                                 sp++;
11191                                                 break;
11192                                         case MONO_TYPE_I2:
11193                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint16 *)addr));
11194                                                 sp++;
11195                                                 break;
11196                                                 break;
11197                                         case MONO_TYPE_I4:
11198                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint32 *)addr));
11199                                                 sp++;
11200                                                 break;                                          
11201                                         case MONO_TYPE_U4:
11202                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint32 *)addr));
11203                                                 sp++;
11204                                                 break;
11205                                         case MONO_TYPE_I:
11206                                         case MONO_TYPE_U:
11207                                         case MONO_TYPE_PTR:
11208                                         case MONO_TYPE_FNPTR:
11209                                                 EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
11210                                                 type_to_eval_stack_type ((cfg), field->type, *sp);
11211                                                 sp++;
11212                                                 break;
11213                                         case MONO_TYPE_STRING:
11214                                         case MONO_TYPE_OBJECT:
11215                                         case MONO_TYPE_CLASS:
11216                                         case MONO_TYPE_SZARRAY:
11217                                         case MONO_TYPE_ARRAY:
11218                                                 if (!mono_gc_is_moving ()) {
11219                                                         EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
11220                                                         type_to_eval_stack_type ((cfg), field->type, *sp);
11221                                                         sp++;
11222                                                 } else {
11223                                                         is_const = FALSE;
11224                                                 }
11225                                                 break;
11226                                         case MONO_TYPE_I8:
11227                                         case MONO_TYPE_U8:
11228                                                 EMIT_NEW_I8CONST (cfg, *sp, *((gint64 *)addr));
11229                                                 sp++;
11230                                                 break;
11231                                         case MONO_TYPE_R4:
11232                                         case MONO_TYPE_R8:
11233                                         case MONO_TYPE_VALUETYPE:
11234                                         default:
11235                                                 is_const = FALSE;
11236                                                 break;
11237                                         }
11238                                 }
11239
11240                                 if (!is_const) {
11241                                         MonoInst *load;
11242
11243                                         CHECK_STACK_OVF (1);
11244
11245                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, ins->dreg, 0);
11246                                         load->flags |= ins_flag;
11247                                         ins_flag = 0;
11248                                         *sp++ = load;
11249                                 }
11250                         }
11251
11252                         if ((op == CEE_LDFLD || op == CEE_LDSFLD) && (ins_flag & MONO_INST_VOLATILE)) {
11253                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
11254                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
11255                         }
11256
11257                         ins_flag = 0;
11258                         ip += 5;
11259                         break;
11260                 }
11261                 case CEE_STOBJ:
11262                         CHECK_STACK (2);
11263                         sp -= 2;
11264                         CHECK_OPSIZE (5);
11265                         token = read32 (ip + 1);
11266                         klass = mini_get_class (method, token, generic_context);
11267                         CHECK_TYPELOAD (klass);
11268                         if (ins_flag & MONO_INST_VOLATILE) {
11269                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
11270                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
11271                         }
11272                         /* FIXME: should check item at sp [1] is compatible with the type of the store. */
11273                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0, sp [1]->dreg);
11274                         ins->flags |= ins_flag;
11275                         if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER &&
11276                                         generic_class_is_reference_type (cfg, klass)) {
11277                                 /* insert call to write barrier */
11278                                 emit_write_barrier (cfg, sp [0], sp [1]);
11279                         }
11280                         ins_flag = 0;
11281                         ip += 5;
11282                         inline_costs += 1;
11283                         break;
11284
11285                         /*
11286                          * Array opcodes
11287                          */
11288                 case CEE_NEWARR: {
11289                         MonoInst *len_ins;
11290                         const char *data_ptr;
11291                         int data_size = 0;
11292                         guint32 field_token;
11293
11294                         CHECK_STACK (1);
11295                         --sp;
11296
11297                         CHECK_OPSIZE (5);
11298                         token = read32 (ip + 1);
11299
11300                         klass = mini_get_class (method, token, generic_context);
11301                         CHECK_TYPELOAD (klass);
11302
11303                         context_used = mini_class_check_context_used (cfg, klass);
11304
11305                         if (sp [0]->type == STACK_I8 || (SIZEOF_VOID_P == 8 && sp [0]->type == STACK_PTR)) {
11306                                 MONO_INST_NEW (cfg, ins, OP_LCONV_TO_OVF_U4);
11307                                 ins->sreg1 = sp [0]->dreg;
11308                                 ins->type = STACK_I4;
11309                                 ins->dreg = alloc_ireg (cfg);
11310                                 MONO_ADD_INS (cfg->cbb, ins);
11311                                 *sp = mono_decompose_opcode (cfg, ins);
11312                         }
11313
11314                         if (context_used) {
11315                                 MonoInst *args [3];
11316                                 MonoClass *array_class = mono_array_class_get (klass, 1);
11317                                 MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (array_class);
11318
11319                                 /* FIXME: Use OP_NEWARR and decompose later to help abcrem */
11320
11321                                 /* vtable */
11322                                 args [0] = emit_get_rgctx_klass (cfg, context_used,
11323                                         array_class, MONO_RGCTX_INFO_VTABLE);
11324                                 /* array len */
11325                                 args [1] = sp [0];
11326
11327                                 if (managed_alloc)
11328                                         ins = mono_emit_method_call (cfg, managed_alloc, args, NULL);
11329                                 else
11330                                         ins = mono_emit_jit_icall (cfg, mono_array_new_specific, args);
11331                         } else {
11332                                 if (cfg->opt & MONO_OPT_SHARED) {
11333                                         /* Decompose now to avoid problems with references to the domainvar */
11334                                         MonoInst *iargs [3];
11335
11336                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11337                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
11338                                         iargs [2] = sp [0];
11339
11340                                         ins = mono_emit_jit_icall (cfg, mono_array_new, iargs);
11341                                 } else {
11342                                         /* Decompose later since it is needed by abcrem */
11343                                         MonoClass *array_type = mono_array_class_get (klass, 1);
11344                                         mono_class_vtable (cfg->domain, array_type);
11345                                         CHECK_TYPELOAD (array_type);
11346
11347                                         MONO_INST_NEW (cfg, ins, OP_NEWARR);
11348                                         ins->dreg = alloc_ireg_ref (cfg);
11349                                         ins->sreg1 = sp [0]->dreg;
11350                                         ins->inst_newa_class = klass;
11351                                         ins->type = STACK_OBJ;
11352                                         ins->klass = array_type;
11353                                         MONO_ADD_INS (cfg->cbb, ins);
11354                                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
11355                                         cfg->cbb->has_array_access = TRUE;
11356
11357                                         /* Needed so mono_emit_load_get_addr () gets called */
11358                                         mono_get_got_var (cfg);
11359                                 }
11360                         }
11361
11362                         len_ins = sp [0];
11363                         ip += 5;
11364                         *sp++ = ins;
11365                         inline_costs += 1;
11366
11367                         /* 
11368                          * we inline/optimize the initialization sequence if possible.
11369                          * we should also allocate the array as not cleared, since we spend as much time clearing to 0 as initializing
11370                          * for small sizes open code the memcpy
11371                          * ensure the rva field is big enough
11372                          */
11373                         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))) {
11374                                 MonoMethod *memcpy_method = get_memcpy_method ();
11375                                 MonoInst *iargs [3];
11376                                 int add_reg = alloc_ireg_mp (cfg);
11377
11378                                 EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, add_reg, ins->dreg, MONO_STRUCT_OFFSET (MonoArray, vector));
11379                                 if (cfg->compile_aot) {
11380                                         EMIT_NEW_AOTCONST_TOKEN (cfg, iargs [1], MONO_PATCH_INFO_RVA, method->klass->image, GPOINTER_TO_UINT(field_token), STACK_PTR, NULL);
11381                                 } else {
11382                                         EMIT_NEW_PCONST (cfg, iargs [1], (char*)data_ptr);
11383                                 }
11384                                 EMIT_NEW_ICONST (cfg, iargs [2], data_size);
11385                                 mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
11386                                 ip += 11;
11387                         }
11388
11389                         break;
11390                 }
11391                 case CEE_LDLEN:
11392                         CHECK_STACK (1);
11393                         --sp;
11394                         if (sp [0]->type != STACK_OBJ)
11395                                 UNVERIFIED;
11396
11397                         MONO_INST_NEW (cfg, ins, OP_LDLEN);
11398                         ins->dreg = alloc_preg (cfg);
11399                         ins->sreg1 = sp [0]->dreg;
11400                         ins->type = STACK_I4;
11401                         /* This flag will be inherited by the decomposition */
11402                         ins->flags |= MONO_INST_FAULT;
11403                         MONO_ADD_INS (cfg->cbb, ins);
11404                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
11405                         cfg->cbb->has_array_access = TRUE;
11406                         ip ++;
11407                         *sp++ = ins;
11408                         break;
11409                 case CEE_LDELEMA:
11410                         CHECK_STACK (2);
11411                         sp -= 2;
11412                         CHECK_OPSIZE (5);
11413                         if (sp [0]->type != STACK_OBJ)
11414                                 UNVERIFIED;
11415
11416                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11417
11418                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
11419                         CHECK_TYPELOAD (klass);
11420                         /* we need to make sure that this array is exactly the type it needs
11421                          * to be for correctness. the wrappers are lax with their usage
11422                          * so we need to ignore them here
11423                          */
11424                         if (!klass->valuetype && method->wrapper_type == MONO_WRAPPER_NONE && !readonly) {
11425                                 MonoClass *array_class = mono_array_class_get (klass, 1);
11426                                 mini_emit_check_array_type (cfg, sp [0], array_class);
11427                                 CHECK_TYPELOAD (array_class);
11428                         }
11429
11430                         readonly = FALSE;
11431                         ins = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11432                         *sp++ = ins;
11433                         ip += 5;
11434                         break;
11435                 case CEE_LDELEM:
11436                 case CEE_LDELEM_I1:
11437                 case CEE_LDELEM_U1:
11438                 case CEE_LDELEM_I2:
11439                 case CEE_LDELEM_U2:
11440                 case CEE_LDELEM_I4:
11441                 case CEE_LDELEM_U4:
11442                 case CEE_LDELEM_I8:
11443                 case CEE_LDELEM_I:
11444                 case CEE_LDELEM_R4:
11445                 case CEE_LDELEM_R8:
11446                 case CEE_LDELEM_REF: {
11447                         MonoInst *addr;
11448
11449                         CHECK_STACK (2);
11450                         sp -= 2;
11451
11452                         if (*ip == CEE_LDELEM) {
11453                                 CHECK_OPSIZE (5);
11454                                 token = read32 (ip + 1);
11455                                 klass = mini_get_class (method, token, generic_context);
11456                                 CHECK_TYPELOAD (klass);
11457                                 mono_class_init (klass);
11458                         }
11459                         else
11460                                 klass = array_access_to_klass (*ip);
11461
11462                         if (sp [0]->type != STACK_OBJ)
11463                                 UNVERIFIED;
11464
11465                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11466
11467                         if (mini_is_gsharedvt_variable_klass (klass)) {
11468                                 // FIXME-VT: OP_ICONST optimization
11469                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11470                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
11471                                 ins->opcode = OP_LOADV_MEMBASE;
11472                         } else if (sp [1]->opcode == OP_ICONST) {
11473                                 int array_reg = sp [0]->dreg;
11474                                 int index_reg = sp [1]->dreg;
11475                                 int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + MONO_STRUCT_OFFSET (MonoArray, vector);
11476
11477                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
11478                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset);
11479                         } else {
11480                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11481                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
11482                         }
11483                         *sp++ = ins;
11484                         if (*ip == CEE_LDELEM)
11485                                 ip += 5;
11486                         else
11487                                 ++ip;
11488                         break;
11489                 }
11490                 case CEE_STELEM_I:
11491                 case CEE_STELEM_I1:
11492                 case CEE_STELEM_I2:
11493                 case CEE_STELEM_I4:
11494                 case CEE_STELEM_I8:
11495                 case CEE_STELEM_R4:
11496                 case CEE_STELEM_R8:
11497                 case CEE_STELEM_REF:
11498                 case CEE_STELEM: {
11499                         CHECK_STACK (3);
11500                         sp -= 3;
11501
11502                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11503
11504                         if (*ip == CEE_STELEM) {
11505                                 CHECK_OPSIZE (5);
11506                                 token = read32 (ip + 1);
11507                                 klass = mini_get_class (method, token, generic_context);
11508                                 CHECK_TYPELOAD (klass);
11509                                 mono_class_init (klass);
11510                         }
11511                         else
11512                                 klass = array_access_to_klass (*ip);
11513
11514                         if (sp [0]->type != STACK_OBJ)
11515                                 UNVERIFIED;
11516
11517                         emit_array_store (cfg, klass, sp, TRUE);
11518
11519                         if (*ip == CEE_STELEM)
11520                                 ip += 5;
11521                         else
11522                                 ++ip;
11523                         inline_costs += 1;
11524                         break;
11525                 }
11526                 case CEE_CKFINITE: {
11527                         CHECK_STACK (1);
11528                         --sp;
11529
11530                         MONO_INST_NEW (cfg, ins, OP_CKFINITE);
11531                         ins->sreg1 = sp [0]->dreg;
11532                         ins->dreg = alloc_freg (cfg);
11533                         ins->type = STACK_R8;
11534                         MONO_ADD_INS (cfg->cbb, ins);
11535
11536                         *sp++ = mono_decompose_opcode (cfg, ins);
11537
11538                         ++ip;
11539                         break;
11540                 }
11541                 case CEE_REFANYVAL: {
11542                         MonoInst *src_var, *src;
11543
11544                         int klass_reg = alloc_preg (cfg);
11545                         int dreg = alloc_preg (cfg);
11546
11547                         GSHAREDVT_FAILURE (*ip);
11548
11549                         CHECK_STACK (1);
11550                         MONO_INST_NEW (cfg, ins, *ip);
11551                         --sp;
11552                         CHECK_OPSIZE (5);
11553                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
11554                         CHECK_TYPELOAD (klass);
11555
11556                         context_used = mini_class_check_context_used (cfg, klass);
11557
11558                         // FIXME:
11559                         src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
11560                         if (!src_var)
11561                                 src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
11562                         EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
11563                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass));
11564
11565                         if (context_used) {
11566                                 MonoInst *klass_ins;
11567
11568                                 klass_ins = emit_get_rgctx_klass (cfg, context_used,
11569                                                 klass, MONO_RGCTX_INFO_KLASS);
11570
11571                                 // FIXME:
11572                                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_ins->dreg);
11573                                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
11574                         } else {
11575                                 mini_emit_class_check (cfg, klass_reg, klass);
11576                         }
11577                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, value));
11578                         ins->type = STACK_MP;
11579                         ins->klass = klass;
11580                         *sp++ = ins;
11581                         ip += 5;
11582                         break;
11583                 }
11584                 case CEE_MKREFANY: {
11585                         MonoInst *loc, *addr;
11586
11587                         GSHAREDVT_FAILURE (*ip);
11588
11589                         CHECK_STACK (1);
11590                         MONO_INST_NEW (cfg, ins, *ip);
11591                         --sp;
11592                         CHECK_OPSIZE (5);
11593                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
11594                         CHECK_TYPELOAD (klass);
11595
11596                         context_used = mini_class_check_context_used (cfg, klass);
11597
11598                         loc = mono_compile_create_var (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL);
11599                         EMIT_NEW_TEMPLOADA (cfg, addr, loc->inst_c0);
11600
11601                         if (context_used) {
11602                                 MonoInst *const_ins;
11603                                 int type_reg = alloc_preg (cfg);
11604
11605                                 const_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
11606                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), const_ins->dreg);
11607                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_ins->dreg, MONO_STRUCT_OFFSET (MonoClass, byval_arg));
11608                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
11609                         } else if (cfg->compile_aot) {
11610                                 int const_reg = alloc_preg (cfg);
11611                                 int type_reg = alloc_preg (cfg);
11612
11613                                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
11614                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), const_reg);
11615                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_reg, MONO_STRUCT_OFFSET (MonoClass, byval_arg));
11616                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
11617                         } else {
11618                                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), &klass->byval_arg);
11619                                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), klass);
11620                         }
11621                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, value), sp [0]->dreg);
11622
11623                         EMIT_NEW_TEMPLOAD (cfg, ins, loc->inst_c0);
11624                         ins->type = STACK_VTYPE;
11625                         ins->klass = mono_defaults.typed_reference_class;
11626                         *sp++ = ins;
11627                         ip += 5;
11628                         break;
11629                 }
11630                 case CEE_LDTOKEN: {
11631                         gpointer handle;
11632                         MonoClass *handle_class;
11633
11634                         CHECK_STACK_OVF (1);
11635
11636                         CHECK_OPSIZE (5);
11637                         n = read32 (ip + 1);
11638
11639                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD ||
11640                                         method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
11641                                 handle = mono_method_get_wrapper_data (method, n);
11642                                 handle_class = mono_method_get_wrapper_data (method, n + 1);
11643                                 if (handle_class == mono_defaults.typehandle_class)
11644                                         handle = &((MonoClass*)handle)->byval_arg;
11645                         }
11646                         else {
11647                                 handle = mono_ldtoken_checked (image, n, &handle_class, generic_context, &cfg->error);
11648                                 CHECK_CFG_ERROR;
11649                         }
11650                         if (!handle)
11651                                 LOAD_ERROR;
11652                         mono_class_init (handle_class);
11653                         if (cfg->gshared) {
11654                                 if (mono_metadata_token_table (n) == MONO_TABLE_TYPEDEF ||
11655                                                 mono_metadata_token_table (n) == MONO_TABLE_TYPEREF) {
11656                                         /* This case handles ldtoken
11657                                            of an open type, like for
11658                                            typeof(Gen<>). */
11659                                         context_used = 0;
11660                                 } else if (handle_class == mono_defaults.typehandle_class) {
11661                                         context_used = mini_class_check_context_used (cfg, mono_class_from_mono_type (handle));
11662                                 } else if (handle_class == mono_defaults.fieldhandle_class)
11663                                         context_used = mini_class_check_context_used (cfg, ((MonoClassField*)handle)->parent);
11664                                 else if (handle_class == mono_defaults.methodhandle_class)
11665                                         context_used = mini_method_check_context_used (cfg, handle);
11666                                 else
11667                                         g_assert_not_reached ();
11668                         }
11669
11670                         if ((cfg->opt & MONO_OPT_SHARED) &&
11671                                         method->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD &&
11672                                         method->wrapper_type != MONO_WRAPPER_SYNCHRONIZED) {
11673                                 MonoInst *addr, *vtvar, *iargs [3];
11674                                 int method_context_used;
11675
11676                                 method_context_used = mini_method_check_context_used (cfg, method);
11677
11678                                 vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL); 
11679
11680                                 EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
11681                                 EMIT_NEW_ICONST (cfg, iargs [1], n);
11682                                 if (method_context_used) {
11683                                         iargs [2] = emit_get_rgctx_method (cfg, method_context_used,
11684                                                 method, MONO_RGCTX_INFO_METHOD);
11685                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper_generic_shared, iargs);
11686                                 } else {
11687                                         EMIT_NEW_PCONST (cfg, iargs [2], generic_context);
11688                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper, iargs);
11689                                 }
11690                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
11691
11692                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
11693
11694                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
11695                         } else {
11696                                 if ((ip + 5 < end) && ip_in_bb (cfg, cfg->cbb, ip + 5) && 
11697                                         ((ip [5] == CEE_CALL) || (ip [5] == CEE_CALLVIRT)) && 
11698                                         (cmethod = mini_get_method (cfg, method, read32 (ip + 6), NULL, generic_context)) &&
11699                                         (cmethod->klass == mono_defaults.systemtype_class) &&
11700                                         (strcmp (cmethod->name, "GetTypeFromHandle") == 0)) {
11701                                         MonoClass *tclass = mono_class_from_mono_type (handle);
11702
11703                                         mono_class_init (tclass);
11704                                         if (context_used) {
11705                                                 ins = emit_get_rgctx_klass (cfg, context_used,
11706                                                         tclass, MONO_RGCTX_INFO_REFLECTION_TYPE);
11707                                         } else if (cfg->compile_aot) {
11708                                                 if (method->wrapper_type) {
11709                                                         mono_error_init (&error); //got to do it since there are multiple conditionals below
11710                                                         if (mono_class_get_checked (tclass->image, tclass->type_token, &error) == tclass && !generic_context) {
11711                                                                 /* Special case for static synchronized wrappers */
11712                                                                 EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, tclass->image, tclass->type_token, generic_context);
11713                                                         } else {
11714                                                                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
11715                                                                 /* FIXME: n is not a normal token */
11716                                                                 DISABLE_AOT (cfg);
11717                                                                 EMIT_NEW_PCONST (cfg, ins, NULL);
11718                                                         }
11719                                                 } else {
11720                                                         EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, image, n, generic_context);
11721                                                 }
11722                                         } else {
11723                                                 EMIT_NEW_PCONST (cfg, ins, mono_type_get_object (cfg->domain, handle));
11724                                         }
11725                                         ins->type = STACK_OBJ;
11726                                         ins->klass = cmethod->klass;
11727                                         ip += 5;
11728                                 } else {
11729                                         MonoInst *addr, *vtvar;
11730
11731                                         vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL);
11732
11733                                         if (context_used) {
11734                                                 if (handle_class == mono_defaults.typehandle_class) {
11735                                                         ins = emit_get_rgctx_klass (cfg, context_used,
11736                                                                         mono_class_from_mono_type (handle),
11737                                                                         MONO_RGCTX_INFO_TYPE);
11738                                                 } else if (handle_class == mono_defaults.methodhandle_class) {
11739                                                         ins = emit_get_rgctx_method (cfg, context_used,
11740                                                                         handle, MONO_RGCTX_INFO_METHOD);
11741                                                 } else if (handle_class == mono_defaults.fieldhandle_class) {
11742                                                         ins = emit_get_rgctx_field (cfg, context_used,
11743                                                                         handle, MONO_RGCTX_INFO_CLASS_FIELD);
11744                                                 } else {
11745                                                         g_assert_not_reached ();
11746                                                 }
11747                                         } else if (cfg->compile_aot) {
11748                                                 EMIT_NEW_LDTOKENCONST (cfg, ins, image, n, generic_context);
11749                                         } else {
11750                                                 EMIT_NEW_PCONST (cfg, ins, handle);
11751                                         }
11752                                         EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
11753                                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
11754                                         EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
11755                                 }
11756                         }
11757
11758                         *sp++ = ins;
11759                         ip += 5;
11760                         break;
11761                 }
11762                 case CEE_THROW:
11763                         CHECK_STACK (1);
11764                         MONO_INST_NEW (cfg, ins, OP_THROW);
11765                         --sp;
11766                         ins->sreg1 = sp [0]->dreg;
11767                         ip++;
11768                         cfg->cbb->out_of_line = TRUE;
11769                         MONO_ADD_INS (cfg->cbb, ins);
11770                         MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
11771                         MONO_ADD_INS (cfg->cbb, ins);
11772                         sp = stack_start;
11773                         
11774                         link_bblock (cfg, cfg->cbb, end_bblock);
11775                         start_new_bblock = 1;
11776                         break;
11777                 case CEE_ENDFINALLY:
11778                         /* mono_save_seq_point_info () depends on this */
11779                         if (sp != stack_start)
11780                                 emit_seq_point (cfg, method, ip, FALSE, FALSE);
11781                         MONO_INST_NEW (cfg, ins, OP_ENDFINALLY);
11782                         MONO_ADD_INS (cfg->cbb, ins);
11783                         ip++;
11784                         start_new_bblock = 1;
11785
11786                         /*
11787                          * Control will leave the method so empty the stack, otherwise
11788                          * the next basic block will start with a nonempty stack.
11789                          */
11790                         while (sp != stack_start) {
11791                                 sp--;
11792                         }
11793                         break;
11794                 case CEE_LEAVE:
11795                 case CEE_LEAVE_S: {
11796                         GList *handlers;
11797
11798                         if (*ip == CEE_LEAVE) {
11799                                 CHECK_OPSIZE (5);
11800                                 target = ip + 5 + (gint32)read32(ip + 1);
11801                         } else {
11802                                 CHECK_OPSIZE (2);
11803                                 target = ip + 2 + (signed char)(ip [1]);
11804                         }
11805
11806                         /* empty the stack */
11807                         while (sp != stack_start) {
11808                                 sp--;
11809                         }
11810
11811                         /* 
11812                          * If this leave statement is in a catch block, check for a
11813                          * pending exception, and rethrow it if necessary.
11814                          * We avoid doing this in runtime invoke wrappers, since those are called
11815                          * by native code which excepts the wrapper to catch all exceptions.
11816                          */
11817                         for (i = 0; i < header->num_clauses; ++i) {
11818                                 MonoExceptionClause *clause = &header->clauses [i];
11819
11820                                 /* 
11821                                  * Use <= in the final comparison to handle clauses with multiple
11822                                  * leave statements, like in bug #78024.
11823                                  * The ordering of the exception clauses guarantees that we find the
11824                                  * innermost clause.
11825                                  */
11826                                 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) {
11827                                         MonoInst *exc_ins;
11828                                         MonoBasicBlock *dont_throw;
11829
11830                                         /*
11831                                           MonoInst *load;
11832
11833                                           NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, clause->handler_offset)->inst_c0);
11834                                         */
11835
11836                                         exc_ins = mono_emit_jit_icall (cfg, mono_thread_get_undeniable_exception, NULL);
11837
11838                                         NEW_BBLOCK (cfg, dont_throw);
11839
11840                                         /*
11841                                          * Currently, we always rethrow the abort exception, despite the 
11842                                          * fact that this is not correct. See thread6.cs for an example. 
11843                                          * But propagating the abort exception is more important than 
11844                                          * getting the sematics right.
11845                                          */
11846                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, exc_ins->dreg, 0);
11847                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, dont_throw);
11848                                         MONO_EMIT_NEW_UNALU (cfg, OP_THROW, -1, exc_ins->dreg);
11849
11850                                         MONO_START_BB (cfg, dont_throw);
11851                                 }
11852                         }
11853
11854                         if ((handlers = mono_find_final_block (cfg, ip, target, MONO_EXCEPTION_CLAUSE_FINALLY))) {
11855                                 GList *tmp;
11856                                 MonoExceptionClause *clause;
11857
11858                                 for (tmp = handlers; tmp; tmp = tmp->next) {
11859                                         clause = tmp->data;
11860                                         tblock = cfg->cil_offset_to_bb [clause->handler_offset];
11861                                         g_assert (tblock);
11862                                         link_bblock (cfg, cfg->cbb, tblock);
11863                                         MONO_INST_NEW (cfg, ins, OP_CALL_HANDLER);
11864                                         ins->inst_target_bb = tblock;
11865                                         ins->inst_eh_block = clause;
11866                                         MONO_ADD_INS (cfg->cbb, ins);
11867                                         cfg->cbb->has_call_handler = 1;
11868                                         if (COMPILE_LLVM (cfg)) {
11869                                                 MonoBasicBlock *target_bb;
11870
11871                                                 /* 
11872                                                  * Link the finally bblock with the target, since it will
11873                                                  * conceptually branch there.
11874                                                  * FIXME: Have to link the bblock containing the endfinally.
11875                                                  */
11876                                                 GET_BBLOCK (cfg, target_bb, target);
11877                                                 link_bblock (cfg, tblock, target_bb);
11878                                         }
11879                                 }
11880                                 g_list_free (handlers);
11881                         } 
11882
11883                         MONO_INST_NEW (cfg, ins, OP_BR);
11884                         MONO_ADD_INS (cfg->cbb, ins);
11885                         GET_BBLOCK (cfg, tblock, target);
11886                         link_bblock (cfg, cfg->cbb, tblock);
11887                         ins->inst_target_bb = tblock;
11888                         start_new_bblock = 1;
11889
11890                         if (*ip == CEE_LEAVE)
11891                                 ip += 5;
11892                         else
11893                                 ip += 2;
11894
11895                         break;
11896                 }
11897
11898                         /*
11899                          * Mono specific opcodes
11900                          */
11901                 case MONO_CUSTOM_PREFIX: {
11902
11903                         g_assert (method->wrapper_type != MONO_WRAPPER_NONE);
11904
11905                         CHECK_OPSIZE (2);
11906                         switch (ip [1]) {
11907                         case CEE_MONO_ICALL: {
11908                                 gpointer func;
11909                                 MonoJitICallInfo *info;
11910
11911                                 token = read32 (ip + 2);
11912                                 func = mono_method_get_wrapper_data (method, token);
11913                                 info = mono_find_jit_icall_by_addr (func);
11914                                 if (!info)
11915                                         g_error ("Could not find icall address in wrapper %s", mono_method_full_name (method, 1));
11916                                 g_assert (info);
11917
11918                                 CHECK_STACK (info->sig->param_count);
11919                                 sp -= info->sig->param_count;
11920
11921                                 ins = mono_emit_jit_icall (cfg, info->func, sp);
11922                                 if (!MONO_TYPE_IS_VOID (info->sig->ret))
11923                                         *sp++ = ins;
11924
11925                                 ip += 6;
11926                                 inline_costs += 10 * num_calls++;
11927
11928                                 break;
11929                         }
11930                         case CEE_MONO_LDPTR_CARD_TABLE: {
11931                                 int shift_bits;
11932                                 gpointer card_mask;
11933                                 CHECK_STACK_OVF (1);
11934
11935                                 if (cfg->compile_aot)
11936                                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_GC_CARD_TABLE_ADDR, NULL);
11937                                 else
11938                                         EMIT_NEW_PCONST (cfg, ins, mono_gc_get_card_table (&shift_bits, &card_mask));
11939
11940                                 *sp++ = ins;
11941                                 ip += 2;
11942                                 inline_costs += 10 * num_calls++;
11943                                 break;
11944                         }
11945                         case CEE_MONO_LDPTR_NURSERY_START: {
11946                                 int shift_bits;
11947                                 size_t size;
11948                                 CHECK_STACK_OVF (1);
11949
11950                                 if (cfg->compile_aot)
11951                                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_GC_NURSERY_START, NULL);
11952                                 else
11953                                         EMIT_NEW_PCONST (cfg, ins, mono_gc_get_nursery (&shift_bits, &size));
11954
11955                                 *sp++ = ins;
11956                                 ip += 2;
11957                                 inline_costs += 10 * num_calls++;
11958                                 break;
11959                         }
11960                         case CEE_MONO_LDPTR_INT_REQ_FLAG: {
11961                                 CHECK_STACK_OVF (1);
11962
11963                                 if (cfg->compile_aot)
11964                                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG, NULL);
11965                                 else
11966                                         EMIT_NEW_PCONST (cfg, ins, mono_thread_interruption_request_flag ());
11967
11968                                 *sp++ = ins;
11969                                 ip += 2;
11970                                 inline_costs += 10 * num_calls++;
11971                                 break;
11972                         }
11973                         case CEE_MONO_LDPTR: {
11974                                 gpointer ptr;
11975
11976                                 CHECK_STACK_OVF (1);
11977                                 CHECK_OPSIZE (6);
11978                                 token = read32 (ip + 2);
11979
11980                                 ptr = mono_method_get_wrapper_data (method, token);
11981                                 EMIT_NEW_PCONST (cfg, ins, ptr);
11982                                 *sp++ = ins;
11983                                 ip += 6;
11984                                 inline_costs += 10 * num_calls++;
11985                                 /* Can't embed random pointers into AOT code */
11986                                 DISABLE_AOT (cfg);
11987                                 break;
11988                         }
11989                         case CEE_MONO_JIT_ICALL_ADDR: {
11990                                 MonoJitICallInfo *callinfo;
11991                                 gpointer ptr;
11992
11993                                 CHECK_STACK_OVF (1);
11994                                 CHECK_OPSIZE (6);
11995                                 token = read32 (ip + 2);
11996
11997                                 ptr = mono_method_get_wrapper_data (method, token);
11998                                 callinfo = mono_find_jit_icall_by_addr (ptr);
11999                                 g_assert (callinfo);
12000                                 EMIT_NEW_JIT_ICALL_ADDRCONST (cfg, ins, (char*)callinfo->name);
12001                                 *sp++ = ins;
12002                                 ip += 6;
12003                                 inline_costs += 10 * num_calls++;
12004                                 break;
12005                         }
12006                         case CEE_MONO_ICALL_ADDR: {
12007                                 MonoMethod *cmethod;
12008                                 gpointer ptr;
12009
12010                                 CHECK_STACK_OVF (1);
12011                                 CHECK_OPSIZE (6);
12012                                 token = read32 (ip + 2);
12013
12014                                 cmethod = mono_method_get_wrapper_data (method, token);
12015
12016                                 if (cfg->compile_aot) {
12017                                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_ICALL_ADDR, cmethod);
12018                                 } else {
12019                                         ptr = mono_lookup_internal_call (cmethod);
12020                                         g_assert (ptr);
12021                                         EMIT_NEW_PCONST (cfg, ins, ptr);
12022                                 }
12023                                 *sp++ = ins;
12024                                 ip += 6;
12025                                 break;
12026                         }
12027                         case CEE_MONO_VTADDR: {
12028                                 MonoInst *src_var, *src;
12029
12030                                 CHECK_STACK (1);
12031                                 --sp;
12032
12033                                 // FIXME:
12034                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
12035                                 EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
12036                                 *sp++ = src;
12037                                 ip += 2;
12038                                 break;
12039                         }
12040                         case CEE_MONO_NEWOBJ: {
12041                                 MonoInst *iargs [2];
12042
12043                                 CHECK_STACK_OVF (1);
12044                                 CHECK_OPSIZE (6);
12045                                 token = read32 (ip + 2);
12046                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12047                                 mono_class_init (klass);
12048                                 NEW_DOMAINCONST (cfg, iargs [0]);
12049                                 MONO_ADD_INS (cfg->cbb, iargs [0]);
12050                                 NEW_CLASSCONST (cfg, iargs [1], klass);
12051                                 MONO_ADD_INS (cfg->cbb, iargs [1]);
12052                                 *sp++ = mono_emit_jit_icall (cfg, mono_object_new, iargs);
12053                                 ip += 6;
12054                                 inline_costs += 10 * num_calls++;
12055                                 break;
12056                         }
12057                         case CEE_MONO_OBJADDR:
12058                                 CHECK_STACK (1);
12059                                 --sp;
12060                                 MONO_INST_NEW (cfg, ins, OP_MOVE);
12061                                 ins->dreg = alloc_ireg_mp (cfg);
12062                                 ins->sreg1 = sp [0]->dreg;
12063                                 ins->type = STACK_MP;
12064                                 MONO_ADD_INS (cfg->cbb, ins);
12065                                 *sp++ = ins;
12066                                 ip += 2;
12067                                 break;
12068                         case CEE_MONO_LDNATIVEOBJ:
12069                                 /*
12070                                  * Similar to LDOBJ, but instead load the unmanaged 
12071                                  * representation of the vtype to the stack.
12072                                  */
12073                                 CHECK_STACK (1);
12074                                 CHECK_OPSIZE (6);
12075                                 --sp;
12076                                 token = read32 (ip + 2);
12077                                 klass = mono_method_get_wrapper_data (method, token);
12078                                 g_assert (klass->valuetype);
12079                                 mono_class_init (klass);
12080
12081                                 {
12082                                         MonoInst *src, *dest, *temp;
12083
12084                                         src = sp [0];
12085                                         temp = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
12086                                         temp->backend.is_pinvoke = 1;
12087                                         EMIT_NEW_TEMPLOADA (cfg, dest, temp->inst_c0);
12088                                         mini_emit_stobj (cfg, dest, src, klass, TRUE);
12089
12090                                         EMIT_NEW_TEMPLOAD (cfg, dest, temp->inst_c0);
12091                                         dest->type = STACK_VTYPE;
12092                                         dest->klass = klass;
12093
12094                                         *sp ++ = dest;
12095                                         ip += 6;
12096                                 }
12097                                 break;
12098                         case CEE_MONO_RETOBJ: {
12099                                 /*
12100                                  * Same as RET, but return the native representation of a vtype
12101                                  * to the caller.
12102                                  */
12103                                 g_assert (cfg->ret);
12104                                 g_assert (mono_method_signature (method)->pinvoke); 
12105                                 CHECK_STACK (1);
12106                                 --sp;
12107                                 
12108                                 CHECK_OPSIZE (6);
12109                                 token = read32 (ip + 2);    
12110                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12111
12112                                 if (!cfg->vret_addr) {
12113                                         g_assert (cfg->ret_var_is_local);
12114
12115                                         EMIT_NEW_VARLOADA (cfg, ins, cfg->ret, cfg->ret->inst_vtype);
12116                                 } else {
12117                                         EMIT_NEW_RETLOADA (cfg, ins);
12118                                 }
12119                                 mini_emit_stobj (cfg, ins, sp [0], klass, TRUE);
12120                                 
12121                                 if (sp != stack_start)
12122                                         UNVERIFIED;
12123                                 
12124                                 MONO_INST_NEW (cfg, ins, OP_BR);
12125                                 ins->inst_target_bb = end_bblock;
12126                                 MONO_ADD_INS (cfg->cbb, ins);
12127                                 link_bblock (cfg, cfg->cbb, end_bblock);
12128                                 start_new_bblock = 1;
12129                                 ip += 6;
12130                                 break;
12131                         }
12132                         case CEE_MONO_CISINST:
12133                         case CEE_MONO_CCASTCLASS: {
12134                                 int token;
12135                                 CHECK_STACK (1);
12136                                 --sp;
12137                                 CHECK_OPSIZE (6);
12138                                 token = read32 (ip + 2);
12139                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12140                                 if (ip [1] == CEE_MONO_CISINST)
12141                                         ins = handle_cisinst (cfg, klass, sp [0]);
12142                                 else
12143                                         ins = handle_ccastclass (cfg, klass, sp [0]);
12144                                 *sp++ = ins;
12145                                 ip += 6;
12146                                 break;
12147                         }
12148                         case CEE_MONO_SAVE_LMF:
12149                         case CEE_MONO_RESTORE_LMF:
12150 #ifdef MONO_ARCH_HAVE_LMF_OPS
12151                                 MONO_INST_NEW (cfg, ins, (ip [1] == CEE_MONO_SAVE_LMF) ? OP_SAVE_LMF : OP_RESTORE_LMF);
12152                                 MONO_ADD_INS (cfg->cbb, ins);
12153                                 cfg->need_lmf_area = TRUE;
12154 #endif
12155                                 ip += 2;
12156                                 break;
12157                         case CEE_MONO_CLASSCONST:
12158                                 CHECK_STACK_OVF (1);
12159                                 CHECK_OPSIZE (6);
12160                                 token = read32 (ip + 2);
12161                                 EMIT_NEW_CLASSCONST (cfg, ins, mono_method_get_wrapper_data (method, token));
12162                                 *sp++ = ins;
12163                                 ip += 6;
12164                                 inline_costs += 10 * num_calls++;
12165                                 break;
12166                         case CEE_MONO_NOT_TAKEN:
12167                                 cfg->cbb->out_of_line = TRUE;
12168                                 ip += 2;
12169                                 break;
12170                         case CEE_MONO_TLS: {
12171                                 int key;
12172
12173                                 CHECK_STACK_OVF (1);
12174                                 CHECK_OPSIZE (6);
12175                                 key = (gint32)read32 (ip + 2);
12176                                 g_assert (key < TLS_KEY_NUM);
12177
12178                                 ins = mono_create_tls_get (cfg, key);
12179                                 if (!ins) {
12180                                         if (cfg->compile_aot) {
12181                                                 DISABLE_AOT (cfg);
12182                                                 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
12183                                                 ins->dreg = alloc_preg (cfg);
12184                                                 ins->type = STACK_PTR;
12185                                         } else {
12186                                                 g_assert_not_reached ();
12187                                         }
12188                                 }
12189                                 ins->type = STACK_PTR;
12190                                 MONO_ADD_INS (cfg->cbb, ins);
12191                                 *sp++ = ins;
12192                                 ip += 6;
12193                                 break;
12194                         }
12195                         case CEE_MONO_DYN_CALL: {
12196                                 MonoCallInst *call;
12197
12198                                 /* It would be easier to call a trampoline, but that would put an
12199                                  * extra frame on the stack, confusing exception handling. So
12200                                  * implement it inline using an opcode for now.
12201                                  */
12202
12203                                 if (!cfg->dyn_call_var) {
12204                                         cfg->dyn_call_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
12205                                         /* prevent it from being register allocated */
12206                                         cfg->dyn_call_var->flags |= MONO_INST_VOLATILE;
12207                                 }
12208
12209                                 /* Has to use a call inst since it local regalloc expects it */
12210                                 MONO_INST_NEW_CALL (cfg, call, OP_DYN_CALL);
12211                                 ins = (MonoInst*)call;
12212                                 sp -= 2;
12213                                 ins->sreg1 = sp [0]->dreg;
12214                                 ins->sreg2 = sp [1]->dreg;
12215                                 MONO_ADD_INS (cfg->cbb, ins);
12216
12217                                 cfg->param_area = MAX (cfg->param_area, MONO_ARCH_DYN_CALL_PARAM_AREA);
12218
12219                                 ip += 2;
12220                                 inline_costs += 10 * num_calls++;
12221
12222                                 break;
12223                         }
12224                         case CEE_MONO_MEMORY_BARRIER: {
12225                                 CHECK_OPSIZE (6);
12226                                 emit_memory_barrier (cfg, (int)read32 (ip + 2));
12227                                 ip += 6;
12228                                 break;
12229                         }
12230                         case CEE_MONO_JIT_ATTACH: {
12231                                 MonoInst *args [16], *domain_ins;
12232                                 MonoInst *ad_ins, *jit_tls_ins;
12233                                 MonoBasicBlock *next_bb = NULL, *call_bb = NULL;
12234
12235                                 cfg->orig_domain_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
12236
12237                                 EMIT_NEW_PCONST (cfg, ins, NULL);
12238                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
12239
12240                                 ad_ins = mono_get_domain_intrinsic (cfg);
12241                                 jit_tls_ins = mono_get_jit_tls_intrinsic (cfg);
12242
12243                                 if (MONO_ARCH_HAVE_TLS_GET && ad_ins && jit_tls_ins) {
12244                                         NEW_BBLOCK (cfg, next_bb);
12245                                         NEW_BBLOCK (cfg, call_bb);
12246
12247                                         if (cfg->compile_aot) {
12248                                                 /* AOT code is only used in the root domain */
12249                                                 EMIT_NEW_PCONST (cfg, domain_ins, NULL);
12250                                         } else {
12251                                                 EMIT_NEW_PCONST (cfg, domain_ins, cfg->domain);
12252                                         }
12253                                         MONO_ADD_INS (cfg->cbb, ad_ins);
12254                                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, ad_ins->dreg, domain_ins->dreg);
12255                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, call_bb);
12256
12257                                         MONO_ADD_INS (cfg->cbb, jit_tls_ins);
12258                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, jit_tls_ins->dreg, 0);
12259                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, call_bb);
12260
12261                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, next_bb);
12262                                         MONO_START_BB (cfg, call_bb);
12263                                 }
12264
12265                                 if (cfg->compile_aot) {
12266                                         /* AOT code is only used in the root domain */
12267                                         EMIT_NEW_PCONST (cfg, args [0], NULL);
12268                                 } else {
12269                                         EMIT_NEW_PCONST (cfg, args [0], cfg->domain);
12270                                 }
12271                                 ins = mono_emit_jit_icall (cfg, mono_jit_thread_attach, args);
12272                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
12273
12274                                 if (next_bb)
12275                                         MONO_START_BB (cfg, next_bb);
12276                                 ip += 2;
12277                                 break;
12278                         }
12279                         case CEE_MONO_JIT_DETACH: {
12280                                 MonoInst *args [16];
12281
12282                                 /* Restore the original domain */
12283                                 dreg = alloc_ireg (cfg);
12284                                 EMIT_NEW_UNALU (cfg, args [0], OP_MOVE, dreg, cfg->orig_domain_var->dreg);
12285                                 mono_emit_jit_icall (cfg, mono_jit_set_domain, args);
12286                                 ip += 2;
12287                                 break;
12288                         }
12289                         default:
12290                                 g_error ("opcode 0x%02x 0x%02x not handled", MONO_CUSTOM_PREFIX, ip [1]);
12291                                 break;
12292                         }
12293                         break;
12294                 }
12295
12296                 case CEE_PREFIX1: {
12297                         CHECK_OPSIZE (2);
12298                         switch (ip [1]) {
12299                         case CEE_ARGLIST: {
12300                                 /* somewhat similar to LDTOKEN */
12301                                 MonoInst *addr, *vtvar;
12302                                 CHECK_STACK_OVF (1);
12303                                 vtvar = mono_compile_create_var (cfg, &mono_defaults.argumenthandle_class->byval_arg, OP_LOCAL); 
12304
12305                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
12306                                 EMIT_NEW_UNALU (cfg, ins, OP_ARGLIST, -1, addr->dreg);
12307
12308                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
12309                                 ins->type = STACK_VTYPE;
12310                                 ins->klass = mono_defaults.argumenthandle_class;
12311                                 *sp++ = ins;
12312                                 ip += 2;
12313                                 break;
12314                         }
12315                         case CEE_CEQ:
12316                         case CEE_CGT:
12317                         case CEE_CGT_UN:
12318                         case CEE_CLT:
12319                         case CEE_CLT_UN: {
12320                                 MonoInst *cmp, *arg1, *arg2;
12321
12322                                 CHECK_STACK (2);
12323                                 sp -= 2;
12324                                 arg1 = sp [0];
12325                                 arg2 = sp [1];
12326
12327                                 /*
12328                                  * The following transforms:
12329                                  *    CEE_CEQ    into OP_CEQ
12330                                  *    CEE_CGT    into OP_CGT
12331                                  *    CEE_CGT_UN into OP_CGT_UN
12332                                  *    CEE_CLT    into OP_CLT
12333                                  *    CEE_CLT_UN into OP_CLT_UN
12334                                  */
12335                                 MONO_INST_NEW (cfg, cmp, (OP_CEQ - CEE_CEQ) + ip [1]);
12336
12337                                 MONO_INST_NEW (cfg, ins, cmp->opcode);
12338                                 cmp->sreg1 = arg1->dreg;
12339                                 cmp->sreg2 = arg2->dreg;
12340                                 type_from_op (cfg, cmp, arg1, arg2);
12341                                 CHECK_TYPE (cmp);
12342                                 add_widen_op (cfg, cmp, &arg1, &arg2);
12343                                 if ((arg1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((arg1->type == STACK_PTR) || (arg1->type == STACK_OBJ) || (arg1->type == STACK_MP))))
12344                                         cmp->opcode = OP_LCOMPARE;
12345                                 else if (arg1->type == STACK_R4)
12346                                         cmp->opcode = OP_RCOMPARE;
12347                                 else if (arg1->type == STACK_R8)
12348                                         cmp->opcode = OP_FCOMPARE;
12349                                 else
12350                                         cmp->opcode = OP_ICOMPARE;
12351                                 MONO_ADD_INS (cfg->cbb, cmp);
12352                                 ins->type = STACK_I4;
12353                                 ins->dreg = alloc_dreg (cfg, ins->type);
12354                                 type_from_op (cfg, ins, arg1, arg2);
12355
12356                                 if (cmp->opcode == OP_FCOMPARE || cmp->opcode == OP_RCOMPARE) {
12357                                         /*
12358                                          * The backends expect the fceq opcodes to do the
12359                                          * comparison too.
12360                                          */
12361                                         ins->sreg1 = cmp->sreg1;
12362                                         ins->sreg2 = cmp->sreg2;
12363                                         NULLIFY_INS (cmp);
12364                                 }
12365                                 MONO_ADD_INS (cfg->cbb, ins);
12366                                 *sp++ = ins;
12367                                 ip += 2;
12368                                 break;
12369                         }
12370                         case CEE_LDFTN: {
12371                                 MonoInst *argconst;
12372                                 MonoMethod *cil_method;
12373
12374                                 CHECK_STACK_OVF (1);
12375                                 CHECK_OPSIZE (6);
12376                                 n = read32 (ip + 2);
12377                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
12378                                 if (!cmethod || mono_loader_get_last_error ())
12379                                         LOAD_ERROR;
12380                                 mono_class_init (cmethod->klass);
12381
12382                                 mono_save_token_info (cfg, image, n, cmethod);
12383
12384                                 context_used = mini_method_check_context_used (cfg, cmethod);
12385
12386                                 cil_method = cmethod;
12387                                 if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_method (method, cmethod))
12388                                         METHOD_ACCESS_FAILURE (method, cil_method);
12389
12390                                 if (mono_security_core_clr_enabled ())
12391                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
12392
12393                                 /* 
12394                                  * Optimize the common case of ldftn+delegate creation
12395                                  */
12396                                 if ((sp > stack_start) && (ip + 6 + 5 < end) && ip_in_bb (cfg, cfg->cbb, ip + 6) && (ip [6] == CEE_NEWOBJ)) {
12397                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
12398                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
12399                                                 MonoInst *target_ins, *handle_ins;
12400                                                 MonoMethod *invoke;
12401                                                 int invoke_context_used;
12402
12403                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
12404                                                 if (!invoke || !mono_method_signature (invoke))
12405                                                         LOAD_ERROR;
12406
12407                                                 invoke_context_used = mini_method_check_context_used (cfg, invoke);
12408
12409                                                 target_ins = sp [-1];
12410
12411                                                 if (mono_security_core_clr_enabled ())
12412                                                         ensure_method_is_allowed_to_call_method (cfg, method, ctor_method);
12413
12414                                                 if (!(cmethod->flags & METHOD_ATTRIBUTE_STATIC)) {
12415                                                         /*LAME IMPL: We must not add a null check for virtual invoke delegates.*/
12416                                                         if (mono_method_signature (invoke)->param_count == mono_method_signature (cmethod)->param_count) {
12417                                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, target_ins->dreg, 0);
12418                                                                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "ArgumentException");
12419                                                         }
12420                                                 }
12421
12422                                                 /* FIXME: SGEN support */
12423                                                 if (invoke_context_used == 0) {
12424                                                         ip += 6;
12425                                                         if (cfg->verbose_level > 3)
12426                                                                 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));
12427                                                         if ((handle_ins = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used, FALSE))) {
12428                                                                 sp --;
12429                                                                 *sp = handle_ins;
12430                                                                 CHECK_CFG_EXCEPTION;
12431                                                                 ip += 5;
12432                                                                 sp ++;
12433                                                                 break;
12434                                                         }
12435                                                         ip -= 6;
12436                                                 }
12437                                         }
12438                                 }
12439
12440                                 argconst = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD);
12441                                 ins = mono_emit_jit_icall (cfg, mono_ldftn, &argconst);
12442                                 *sp++ = ins;
12443                                 
12444                                 ip += 6;
12445                                 inline_costs += 10 * num_calls++;
12446                                 break;
12447                         }
12448                         case CEE_LDVIRTFTN: {
12449                                 MonoInst *args [2];
12450
12451                                 CHECK_STACK (1);
12452                                 CHECK_OPSIZE (6);
12453                                 n = read32 (ip + 2);
12454                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
12455                                 if (!cmethod || mono_loader_get_last_error ())
12456                                         LOAD_ERROR;
12457                                 mono_class_init (cmethod->klass);
12458  
12459                                 context_used = mini_method_check_context_used (cfg, cmethod);
12460
12461                                 if (mono_security_core_clr_enabled ())
12462                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
12463
12464                                 /*
12465                                  * Optimize the common case of ldvirtftn+delegate creation
12466                                  */
12467                                 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)) {
12468                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
12469                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
12470                                                 MonoInst *target_ins, *handle_ins;
12471                                                 MonoMethod *invoke;
12472                                                 int invoke_context_used;
12473                                                 gboolean is_virtual = cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL;
12474
12475                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
12476                                                 if (!invoke || !mono_method_signature (invoke))
12477                                                         LOAD_ERROR;
12478
12479                                                 invoke_context_used = mini_method_check_context_used (cfg, invoke);
12480
12481                                                 target_ins = sp [-1];
12482
12483                                                 if (mono_security_core_clr_enabled ())
12484                                                         ensure_method_is_allowed_to_call_method (cfg, method, ctor_method);
12485
12486                                                 /* FIXME: SGEN support */
12487                                                 if (invoke_context_used == 0) {
12488                                                         ip += 6;
12489                                                         if (cfg->verbose_level > 3)
12490                                                                 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));
12491                                                         if ((handle_ins = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used, is_virtual))) {
12492                                                                 sp -= 2;
12493                                                                 *sp = handle_ins;
12494                                                                 CHECK_CFG_EXCEPTION;
12495                                                                 ip += 5;
12496                                                                 sp ++;
12497                                                                 break;
12498                                                         }
12499                                                         ip -= 6;
12500                                                 }
12501                                         }
12502                                 }
12503
12504                                 --sp;
12505                                 args [0] = *sp;
12506
12507                                 args [1] = emit_get_rgctx_method (cfg, context_used,
12508                                                                                                   cmethod, MONO_RGCTX_INFO_METHOD);
12509
12510                                 if (context_used)
12511                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn_gshared, args);
12512                                 else
12513                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn, args);
12514
12515                                 ip += 6;
12516                                 inline_costs += 10 * num_calls++;
12517                                 break;
12518                         }
12519                         case CEE_LDARG:
12520                                 CHECK_STACK_OVF (1);
12521                                 CHECK_OPSIZE (4);
12522                                 n = read16 (ip + 2);
12523                                 CHECK_ARG (n);
12524                                 EMIT_NEW_ARGLOAD (cfg, ins, n);
12525                                 *sp++ = ins;
12526                                 ip += 4;
12527                                 break;
12528                         case CEE_LDARGA:
12529                                 CHECK_STACK_OVF (1);
12530                                 CHECK_OPSIZE (4);
12531                                 n = read16 (ip + 2);
12532                                 CHECK_ARG (n);
12533                                 NEW_ARGLOADA (cfg, ins, n);
12534                                 MONO_ADD_INS (cfg->cbb, ins);
12535                                 *sp++ = ins;
12536                                 ip += 4;
12537                                 break;
12538                         case CEE_STARG:
12539                                 CHECK_STACK (1);
12540                                 --sp;
12541                                 CHECK_OPSIZE (4);
12542                                 n = read16 (ip + 2);
12543                                 CHECK_ARG (n);
12544                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [n], *sp))
12545                                         UNVERIFIED;
12546                                 EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
12547                                 ip += 4;
12548                                 break;
12549                         case CEE_LDLOC:
12550                                 CHECK_STACK_OVF (1);
12551                                 CHECK_OPSIZE (4);
12552                                 n = read16 (ip + 2);
12553                                 CHECK_LOCAL (n);
12554                                 EMIT_NEW_LOCLOAD (cfg, ins, n);
12555                                 *sp++ = ins;
12556                                 ip += 4;
12557                                 break;
12558                         case CEE_LDLOCA: {
12559                                 unsigned char *tmp_ip;
12560                                 CHECK_STACK_OVF (1);
12561                                 CHECK_OPSIZE (4);
12562                                 n = read16 (ip + 2);
12563                                 CHECK_LOCAL (n);
12564
12565                                 if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 2))) {
12566                                         ip = tmp_ip;
12567                                         inline_costs += 1;
12568                                         break;
12569                                 }                       
12570                                 
12571                                 EMIT_NEW_LOCLOADA (cfg, ins, n);
12572                                 *sp++ = ins;
12573                                 ip += 4;
12574                                 break;
12575                         }
12576                         case CEE_STLOC:
12577                                 CHECK_STACK (1);
12578                                 --sp;
12579                                 CHECK_OPSIZE (4);
12580                                 n = read16 (ip + 2);
12581                                 CHECK_LOCAL (n);
12582                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
12583                                         UNVERIFIED;
12584                                 emit_stloc_ir (cfg, sp, header, n);
12585                                 ip += 4;
12586                                 inline_costs += 1;
12587                                 break;
12588                         case CEE_LOCALLOC:
12589                                 CHECK_STACK (1);
12590                                 --sp;
12591                                 if (sp != stack_start) 
12592                                         UNVERIFIED;
12593                                 if (cfg->method != method) 
12594                                         /* 
12595                                          * Inlining this into a loop in a parent could lead to 
12596                                          * stack overflows which is different behavior than the
12597                                          * non-inlined case, thus disable inlining in this case.
12598                                          */
12599                                         INLINE_FAILURE("localloc");
12600
12601                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
12602                                 ins->dreg = alloc_preg (cfg);
12603                                 ins->sreg1 = sp [0]->dreg;
12604                                 ins->type = STACK_PTR;
12605                                 MONO_ADD_INS (cfg->cbb, ins);
12606
12607                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
12608                                 if (init_locals)
12609                                         ins->flags |= MONO_INST_INIT;
12610
12611                                 *sp++ = ins;
12612                                 ip += 2;
12613                                 break;
12614                         case CEE_ENDFILTER: {
12615                                 MonoExceptionClause *clause, *nearest;
12616                                 int cc;
12617
12618                                 CHECK_STACK (1);
12619                                 --sp;
12620                                 if ((sp != stack_start) || (sp [0]->type != STACK_I4)) 
12621                                         UNVERIFIED;
12622                                 MONO_INST_NEW (cfg, ins, OP_ENDFILTER);
12623                                 ins->sreg1 = (*sp)->dreg;
12624                                 MONO_ADD_INS (cfg->cbb, ins);
12625                                 start_new_bblock = 1;
12626                                 ip += 2;
12627
12628                                 nearest = NULL;
12629                                 for (cc = 0; cc < header->num_clauses; ++cc) {
12630                                         clause = &header->clauses [cc];
12631                                         if ((clause->flags & MONO_EXCEPTION_CLAUSE_FILTER) &&
12632                                                 ((ip - header->code) > clause->data.filter_offset && (ip - header->code) <= clause->handler_offset) &&
12633                                             (!nearest || (clause->data.filter_offset < nearest->data.filter_offset)))
12634                                                 nearest = clause;
12635                                 }
12636                                 g_assert (nearest);
12637                                 if ((ip - header->code) != nearest->handler_offset)
12638                                         UNVERIFIED;
12639
12640                                 break;
12641                         }
12642                         case CEE_UNALIGNED_:
12643                                 ins_flag |= MONO_INST_UNALIGNED;
12644                                 /* FIXME: record alignment? we can assume 1 for now */
12645                                 CHECK_OPSIZE (3);
12646                                 ip += 3;
12647                                 break;
12648                         case CEE_VOLATILE_:
12649                                 ins_flag |= MONO_INST_VOLATILE;
12650                                 ip += 2;
12651                                 break;
12652                         case CEE_TAIL_:
12653                                 ins_flag   |= MONO_INST_TAILCALL;
12654                                 cfg->flags |= MONO_CFG_HAS_TAIL;
12655                                 /* Can't inline tail calls at this time */
12656                                 inline_costs += 100000;
12657                                 ip += 2;
12658                                 break;
12659                         case CEE_INITOBJ:
12660                                 CHECK_STACK (1);
12661                                 --sp;
12662                                 CHECK_OPSIZE (6);
12663                                 token = read32 (ip + 2);
12664                                 klass = mini_get_class (method, token, generic_context);
12665                                 CHECK_TYPELOAD (klass);
12666                                 if (generic_class_is_reference_type (cfg, klass))
12667                                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, sp [0]->dreg, 0, 0);
12668                                 else
12669                                         mini_emit_initobj (cfg, *sp, NULL, klass);
12670                                 ip += 6;
12671                                 inline_costs += 1;
12672                                 break;
12673                         case CEE_CONSTRAINED_:
12674                                 CHECK_OPSIZE (6);
12675                                 token = read32 (ip + 2);
12676                                 constrained_class = mini_get_class (method, token, generic_context);
12677                                 CHECK_TYPELOAD (constrained_class);
12678                                 ip += 6;
12679                                 break;
12680                         case CEE_CPBLK:
12681                         case CEE_INITBLK: {
12682                                 MonoInst *iargs [3];
12683                                 CHECK_STACK (3);
12684                                 sp -= 3;
12685
12686                                 /* Skip optimized paths for volatile operations. */
12687                                 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)) {
12688                                         mini_emit_memcpy (cfg, sp [0]->dreg, 0, sp [1]->dreg, 0, sp [2]->inst_c0, 0);
12689                                 } 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)) {
12690                                         /* emit_memset only works when val == 0 */
12691                                         mini_emit_memset (cfg, sp [0]->dreg, 0, sp [2]->inst_c0, sp [1]->inst_c0, 0);
12692                                 } else {
12693                                         MonoInst *call;
12694                                         iargs [0] = sp [0];
12695                                         iargs [1] = sp [1];
12696                                         iargs [2] = sp [2];
12697                                         if (ip [1] == CEE_CPBLK) {
12698                                                 /*
12699                                                  * FIXME: It's unclear whether we should be emitting both the acquire
12700                                                  * and release barriers for cpblk. It is technically both a load and
12701                                                  * store operation, so it seems like that's the sensible thing to do.
12702                                                  *
12703                                                  * FIXME: We emit full barriers on both sides of the operation for
12704                                                  * simplicity. We should have a separate atomic memcpy method instead.
12705                                                  */
12706                                                 MonoMethod *memcpy_method = get_memcpy_method ();
12707
12708                                                 if (ins_flag & MONO_INST_VOLATILE)
12709                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
12710
12711                                                 call = mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
12712                                                 call->flags |= ins_flag;
12713
12714                                                 if (ins_flag & MONO_INST_VOLATILE)
12715                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
12716                                         } else {
12717                                                 MonoMethod *memset_method = get_memset_method ();
12718                                                 if (ins_flag & MONO_INST_VOLATILE) {
12719                                                         /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
12720                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
12721                                                 }
12722                                                 call = mono_emit_method_call (cfg, memset_method, iargs, NULL);
12723                                                 call->flags |= ins_flag;
12724                                         }
12725                                 }
12726                                 ip += 2;
12727                                 ins_flag = 0;
12728                                 inline_costs += 1;
12729                                 break;
12730                         }
12731                         case CEE_NO_:
12732                                 CHECK_OPSIZE (3);
12733                                 if (ip [2] & 0x1)
12734                                         ins_flag |= MONO_INST_NOTYPECHECK;
12735                                 if (ip [2] & 0x2)
12736                                         ins_flag |= MONO_INST_NORANGECHECK;
12737                                 /* we ignore the no-nullcheck for now since we
12738                                  * really do it explicitly only when doing callvirt->call
12739                                  */
12740                                 ip += 3;
12741                                 break;
12742                         case CEE_RETHROW: {
12743                                 MonoInst *load;
12744                                 int handler_offset = -1;
12745
12746                                 for (i = 0; i < header->num_clauses; ++i) {
12747                                         MonoExceptionClause *clause = &header->clauses [i];
12748                                         if (MONO_OFFSET_IN_HANDLER (clause, ip - header->code) && !(clause->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
12749                                                 handler_offset = clause->handler_offset;
12750                                                 break;
12751                                         }
12752                                 }
12753
12754                                 cfg->cbb->flags |= BB_EXCEPTION_UNSAFE;
12755
12756                                 if (handler_offset == -1)
12757                                         UNVERIFIED;
12758
12759                                 EMIT_NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, handler_offset)->inst_c0);
12760                                 MONO_INST_NEW (cfg, ins, OP_RETHROW);
12761                                 ins->sreg1 = load->dreg;
12762                                 MONO_ADD_INS (cfg->cbb, ins);
12763
12764                                 MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
12765                                 MONO_ADD_INS (cfg->cbb, ins);
12766
12767                                 sp = stack_start;
12768                                 link_bblock (cfg, cfg->cbb, end_bblock);
12769                                 start_new_bblock = 1;
12770                                 ip += 2;
12771                                 break;
12772                         }
12773                         case CEE_SIZEOF: {
12774                                 guint32 val;
12775                                 int ialign;
12776
12777                                 CHECK_STACK_OVF (1);
12778                                 CHECK_OPSIZE (6);
12779                                 token = read32 (ip + 2);
12780                                 if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC && !image_is_dynamic (method->klass->image) && !generic_context) {
12781                                         MonoType *type = mono_type_create_from_typespec_checked (image, token, &cfg->error);
12782                                         CHECK_CFG_ERROR;
12783
12784                                         val = mono_type_size (type, &ialign);
12785                                 } else {
12786                                         MonoClass *klass = mini_get_class (method, token, generic_context);
12787                                         CHECK_TYPELOAD (klass);
12788
12789                                         val = mono_type_size (&klass->byval_arg, &ialign);
12790
12791                                         if (mini_is_gsharedvt_klass (klass))
12792                                                 GSHAREDVT_FAILURE (*ip);
12793                                 }
12794                                 EMIT_NEW_ICONST (cfg, ins, val);
12795                                 *sp++= ins;
12796                                 ip += 6;
12797                                 break;
12798                         }
12799                         case CEE_REFANYTYPE: {
12800                                 MonoInst *src_var, *src;
12801
12802                                 GSHAREDVT_FAILURE (*ip);
12803
12804                                 CHECK_STACK (1);
12805                                 --sp;
12806
12807                                 // FIXME:
12808                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
12809                                 if (!src_var)
12810                                         src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
12811                                 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
12812                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &mono_defaults.typehandle_class->byval_arg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type));
12813                                 *sp++ = ins;
12814                                 ip += 2;
12815                                 break;
12816                         }
12817                         case CEE_READONLY_:
12818                                 readonly = TRUE;
12819                                 ip += 2;
12820                                 break;
12821
12822                         case CEE_UNUSED56:
12823                         case CEE_UNUSED57:
12824                         case CEE_UNUSED70:
12825                         case CEE_UNUSED:
12826                         case CEE_UNUSED99:
12827                                 UNVERIFIED;
12828                                 
12829                         default:
12830                                 g_warning ("opcode 0xfe 0x%02x not handled", ip [1]);
12831                                 UNVERIFIED;
12832                         }
12833                         break;
12834                 }
12835                 case CEE_UNUSED58:
12836                 case CEE_UNUSED1:
12837                         UNVERIFIED;
12838
12839                 default:
12840                         g_warning ("opcode 0x%02x not handled", *ip);
12841                         UNVERIFIED;
12842                 }
12843         }
12844         if (start_new_bblock != 1)
12845                 UNVERIFIED;
12846
12847         cfg->cbb->cil_length = ip - cfg->cbb->cil_code;
12848         if (cfg->cbb->next_bb) {
12849                 /* This could already be set because of inlining, #693905 */
12850                 MonoBasicBlock *bb = cfg->cbb;
12851
12852                 while (bb->next_bb)
12853                         bb = bb->next_bb;
12854                 bb->next_bb = end_bblock;
12855         } else {
12856                 cfg->cbb->next_bb = end_bblock;
12857         }
12858
12859         if (cfg->method == method && cfg->domainvar) {
12860                 MonoInst *store;
12861                 MonoInst *get_domain;
12862
12863                 cfg->cbb = init_localsbb;
12864
12865                 if ((get_domain = mono_get_domain_intrinsic (cfg))) {
12866                         MONO_ADD_INS (cfg->cbb, get_domain);
12867                 } else {
12868                         get_domain = mono_emit_jit_icall (cfg, mono_domain_get, NULL);
12869                 }
12870                 NEW_TEMPSTORE (cfg, store, cfg->domainvar->inst_c0, get_domain);
12871                 MONO_ADD_INS (cfg->cbb, store);
12872         }
12873
12874 #if defined(TARGET_POWERPC) || defined(TARGET_X86)
12875         if (cfg->compile_aot)
12876                 /* FIXME: The plt slots require a GOT var even if the method doesn't use it */
12877                 mono_get_got_var (cfg);
12878 #endif
12879
12880         if (cfg->method == method && cfg->got_var)
12881                 mono_emit_load_got_addr (cfg);
12882
12883         if (init_localsbb) {
12884                 cfg->cbb = init_localsbb;
12885                 cfg->ip = NULL;
12886                 for (i = 0; i < header->num_locals; ++i) {
12887                         emit_init_local (cfg, i, header->locals [i], init_locals);
12888                 }
12889         }
12890
12891         if (cfg->init_ref_vars && cfg->method == method) {
12892                 /* Emit initialization for ref vars */
12893                 // FIXME: Avoid duplication initialization for IL locals.
12894                 for (i = 0; i < cfg->num_varinfo; ++i) {
12895                         MonoInst *ins = cfg->varinfo [i];
12896
12897                         if (ins->opcode == OP_LOCAL && ins->type == STACK_OBJ)
12898                                 MONO_EMIT_NEW_PCONST (cfg, ins->dreg, NULL);
12899                 }
12900         }
12901
12902         if (cfg->lmf_var && cfg->method == method) {
12903                 cfg->cbb = init_localsbb;
12904                 emit_push_lmf (cfg);
12905         }
12906
12907         cfg->cbb = init_localsbb;
12908         emit_instrumentation_call (cfg, mono_profiler_method_enter);
12909
12910         if (seq_points) {
12911                 MonoBasicBlock *bb;
12912
12913                 /*
12914                  * Make seq points at backward branch targets interruptable.
12915                  */
12916                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
12917                         if (bb->code && bb->in_count > 1 && bb->code->opcode == OP_SEQ_POINT)
12918                                 bb->code->flags |= MONO_INST_SINGLE_STEP_LOC;
12919         }
12920
12921         /* Add a sequence point for method entry/exit events */
12922         if (seq_points && cfg->gen_sdb_seq_points) {
12923                 NEW_SEQ_POINT (cfg, ins, METHOD_ENTRY_IL_OFFSET, FALSE);
12924                 MONO_ADD_INS (init_localsbb, ins);
12925                 NEW_SEQ_POINT (cfg, ins, METHOD_EXIT_IL_OFFSET, FALSE);
12926                 MONO_ADD_INS (cfg->bb_exit, ins);
12927         }
12928
12929         /*
12930          * Add seq points for IL offsets which have line number info, but wasn't generated a seq point during JITting because
12931          * the code they refer to was dead (#11880).
12932          */
12933         if (sym_seq_points) {
12934                 for (i = 0; i < header->code_size; ++i) {
12935                         if (mono_bitset_test_fast (seq_point_locs, i) && !mono_bitset_test_fast (seq_point_set_locs, i)) {
12936                                 MonoInst *ins;
12937
12938                                 NEW_SEQ_POINT (cfg, ins, i, FALSE);
12939                                 mono_add_seq_point (cfg, NULL, ins, SEQ_POINT_NATIVE_OFFSET_DEAD_CODE);
12940                         }
12941                 }
12942         }
12943
12944         cfg->ip = NULL;
12945
12946         if (cfg->method == method) {
12947                 MonoBasicBlock *bb;
12948                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
12949                         bb->region = mono_find_block_region (cfg, bb->real_offset);
12950                         if (cfg->spvars)
12951                                 mono_create_spvar_for_region (cfg, bb->region);
12952                         if (cfg->verbose_level > 2)
12953                                 printf ("REGION BB%d IL_%04x ID_%08X\n", bb->block_num, bb->real_offset, bb->region);
12954                 }
12955         }
12956
12957         if (inline_costs < 0) {
12958                 char *mname;
12959
12960                 /* Method is too large */
12961                 mname = mono_method_full_name (method, TRUE);
12962                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
12963                 cfg->exception_message = g_strdup_printf ("Method %s is too complex.", mname);
12964                 g_free (mname);
12965         }
12966
12967         if ((cfg->verbose_level > 2) && (cfg->method == method)) 
12968                 mono_print_code (cfg, "AFTER METHOD-TO-IR");
12969
12970         goto cleanup;
12971
12972 mono_error_exit:
12973         g_assert (!mono_error_ok (&cfg->error));
12974         goto cleanup;
12975  
12976  exception_exit:
12977         g_assert (cfg->exception_type != MONO_EXCEPTION_NONE);
12978         goto cleanup;
12979
12980  unverified:
12981         set_exception_type_from_invalid_il (cfg, method, ip);
12982         goto cleanup;
12983
12984  cleanup:
12985         g_slist_free (class_inits);
12986         mono_basic_block_free (original_bb);
12987         cfg->dont_inline = g_list_remove (cfg->dont_inline, method);
12988         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
12989         if (cfg->exception_type)
12990                 return -1;
12991         else
12992                 return inline_costs;
12993 }
12994
12995 static int
12996 store_membase_reg_to_store_membase_imm (int opcode)
12997 {
12998         switch (opcode) {
12999         case OP_STORE_MEMBASE_REG:
13000                 return OP_STORE_MEMBASE_IMM;
13001         case OP_STOREI1_MEMBASE_REG:
13002                 return OP_STOREI1_MEMBASE_IMM;
13003         case OP_STOREI2_MEMBASE_REG:
13004                 return OP_STOREI2_MEMBASE_IMM;
13005         case OP_STOREI4_MEMBASE_REG:
13006                 return OP_STOREI4_MEMBASE_IMM;
13007         case OP_STOREI8_MEMBASE_REG:
13008                 return OP_STOREI8_MEMBASE_IMM;
13009         default:
13010                 g_assert_not_reached ();
13011         }
13012
13013         return -1;
13014 }               
13015
13016 int
13017 mono_op_to_op_imm (int opcode)
13018 {
13019         switch (opcode) {
13020         case OP_IADD:
13021                 return OP_IADD_IMM;
13022         case OP_ISUB:
13023                 return OP_ISUB_IMM;
13024         case OP_IDIV:
13025                 return OP_IDIV_IMM;
13026         case OP_IDIV_UN:
13027                 return OP_IDIV_UN_IMM;
13028         case OP_IREM:
13029                 return OP_IREM_IMM;
13030         case OP_IREM_UN:
13031                 return OP_IREM_UN_IMM;
13032         case OP_IMUL:
13033                 return OP_IMUL_IMM;
13034         case OP_IAND:
13035                 return OP_IAND_IMM;
13036         case OP_IOR:
13037                 return OP_IOR_IMM;
13038         case OP_IXOR:
13039                 return OP_IXOR_IMM;
13040         case OP_ISHL:
13041                 return OP_ISHL_IMM;
13042         case OP_ISHR:
13043                 return OP_ISHR_IMM;
13044         case OP_ISHR_UN:
13045                 return OP_ISHR_UN_IMM;
13046
13047         case OP_LADD:
13048                 return OP_LADD_IMM;
13049         case OP_LSUB:
13050                 return OP_LSUB_IMM;
13051         case OP_LAND:
13052                 return OP_LAND_IMM;
13053         case OP_LOR:
13054                 return OP_LOR_IMM;
13055         case OP_LXOR:
13056                 return OP_LXOR_IMM;
13057         case OP_LSHL:
13058                 return OP_LSHL_IMM;
13059         case OP_LSHR:
13060                 return OP_LSHR_IMM;
13061         case OP_LSHR_UN:
13062                 return OP_LSHR_UN_IMM;
13063 #if SIZEOF_REGISTER == 8
13064         case OP_LREM:
13065                 return OP_LREM_IMM;
13066 #endif
13067
13068         case OP_COMPARE:
13069                 return OP_COMPARE_IMM;
13070         case OP_ICOMPARE:
13071                 return OP_ICOMPARE_IMM;
13072         case OP_LCOMPARE:
13073                 return OP_LCOMPARE_IMM;
13074
13075         case OP_STORE_MEMBASE_REG:
13076                 return OP_STORE_MEMBASE_IMM;
13077         case OP_STOREI1_MEMBASE_REG:
13078                 return OP_STOREI1_MEMBASE_IMM;
13079         case OP_STOREI2_MEMBASE_REG:
13080                 return OP_STOREI2_MEMBASE_IMM;
13081         case OP_STOREI4_MEMBASE_REG:
13082                 return OP_STOREI4_MEMBASE_IMM;
13083
13084 #if defined(TARGET_X86) || defined (TARGET_AMD64)
13085         case OP_X86_PUSH:
13086                 return OP_X86_PUSH_IMM;
13087         case OP_X86_COMPARE_MEMBASE_REG:
13088                 return OP_X86_COMPARE_MEMBASE_IMM;
13089 #endif
13090 #if defined(TARGET_AMD64)
13091         case OP_AMD64_ICOMPARE_MEMBASE_REG:
13092                 return OP_AMD64_ICOMPARE_MEMBASE_IMM;
13093 #endif
13094         case OP_VOIDCALL_REG:
13095                 return OP_VOIDCALL;
13096         case OP_CALL_REG:
13097                 return OP_CALL;
13098         case OP_LCALL_REG:
13099                 return OP_LCALL;
13100         case OP_FCALL_REG:
13101                 return OP_FCALL;
13102         case OP_LOCALLOC:
13103                 return OP_LOCALLOC_IMM;
13104         }
13105
13106         return -1;
13107 }
13108
13109 static int
13110 ldind_to_load_membase (int opcode)
13111 {
13112         switch (opcode) {
13113         case CEE_LDIND_I1:
13114                 return OP_LOADI1_MEMBASE;
13115         case CEE_LDIND_U1:
13116                 return OP_LOADU1_MEMBASE;
13117         case CEE_LDIND_I2:
13118                 return OP_LOADI2_MEMBASE;
13119         case CEE_LDIND_U2:
13120                 return OP_LOADU2_MEMBASE;
13121         case CEE_LDIND_I4:
13122                 return OP_LOADI4_MEMBASE;
13123         case CEE_LDIND_U4:
13124                 return OP_LOADU4_MEMBASE;
13125         case CEE_LDIND_I:
13126                 return OP_LOAD_MEMBASE;
13127         case CEE_LDIND_REF:
13128                 return OP_LOAD_MEMBASE;
13129         case CEE_LDIND_I8:
13130                 return OP_LOADI8_MEMBASE;
13131         case CEE_LDIND_R4:
13132                 return OP_LOADR4_MEMBASE;
13133         case CEE_LDIND_R8:
13134                 return OP_LOADR8_MEMBASE;
13135         default:
13136                 g_assert_not_reached ();
13137         }
13138
13139         return -1;
13140 }
13141
13142 static int
13143 stind_to_store_membase (int opcode)
13144 {
13145         switch (opcode) {
13146         case CEE_STIND_I1:
13147                 return OP_STOREI1_MEMBASE_REG;
13148         case CEE_STIND_I2:
13149                 return OP_STOREI2_MEMBASE_REG;
13150         case CEE_STIND_I4:
13151                 return OP_STOREI4_MEMBASE_REG;
13152         case CEE_STIND_I:
13153         case CEE_STIND_REF:
13154                 return OP_STORE_MEMBASE_REG;
13155         case CEE_STIND_I8:
13156                 return OP_STOREI8_MEMBASE_REG;
13157         case CEE_STIND_R4:
13158                 return OP_STORER4_MEMBASE_REG;
13159         case CEE_STIND_R8:
13160                 return OP_STORER8_MEMBASE_REG;
13161         default:
13162                 g_assert_not_reached ();
13163         }
13164
13165         return -1;
13166 }
13167
13168 int
13169 mono_load_membase_to_load_mem (int opcode)
13170 {
13171         // FIXME: Add a MONO_ARCH_HAVE_LOAD_MEM macro
13172 #if defined(TARGET_X86) || defined(TARGET_AMD64)
13173         switch (opcode) {
13174         case OP_LOAD_MEMBASE:
13175                 return OP_LOAD_MEM;
13176         case OP_LOADU1_MEMBASE:
13177                 return OP_LOADU1_MEM;
13178         case OP_LOADU2_MEMBASE:
13179                 return OP_LOADU2_MEM;
13180         case OP_LOADI4_MEMBASE:
13181                 return OP_LOADI4_MEM;
13182         case OP_LOADU4_MEMBASE:
13183                 return OP_LOADU4_MEM;
13184 #if SIZEOF_REGISTER == 8
13185         case OP_LOADI8_MEMBASE:
13186                 return OP_LOADI8_MEM;
13187 #endif
13188         }
13189 #endif
13190
13191         return -1;
13192 }
13193
13194 static inline int
13195 op_to_op_dest_membase (int store_opcode, int opcode)
13196 {
13197 #if defined(TARGET_X86)
13198         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG)))
13199                 return -1;
13200
13201         switch (opcode) {
13202         case OP_IADD:
13203                 return OP_X86_ADD_MEMBASE_REG;
13204         case OP_ISUB:
13205                 return OP_X86_SUB_MEMBASE_REG;
13206         case OP_IAND:
13207                 return OP_X86_AND_MEMBASE_REG;
13208         case OP_IOR:
13209                 return OP_X86_OR_MEMBASE_REG;
13210         case OP_IXOR:
13211                 return OP_X86_XOR_MEMBASE_REG;
13212         case OP_ADD_IMM:
13213         case OP_IADD_IMM:
13214                 return OP_X86_ADD_MEMBASE_IMM;
13215         case OP_SUB_IMM:
13216         case OP_ISUB_IMM:
13217                 return OP_X86_SUB_MEMBASE_IMM;
13218         case OP_AND_IMM:
13219         case OP_IAND_IMM:
13220                 return OP_X86_AND_MEMBASE_IMM;
13221         case OP_OR_IMM:
13222         case OP_IOR_IMM:
13223                 return OP_X86_OR_MEMBASE_IMM;
13224         case OP_XOR_IMM:
13225         case OP_IXOR_IMM:
13226                 return OP_X86_XOR_MEMBASE_IMM;
13227         case OP_MOVE:
13228                 return OP_NOP;
13229         }
13230 #endif
13231
13232 #if defined(TARGET_AMD64)
13233         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG) || (store_opcode == OP_STOREI8_MEMBASE_REG)))
13234                 return -1;
13235
13236         switch (opcode) {
13237         case OP_IADD:
13238                 return OP_X86_ADD_MEMBASE_REG;
13239         case OP_ISUB:
13240                 return OP_X86_SUB_MEMBASE_REG;
13241         case OP_IAND:
13242                 return OP_X86_AND_MEMBASE_REG;
13243         case OP_IOR:
13244                 return OP_X86_OR_MEMBASE_REG;
13245         case OP_IXOR:
13246                 return OP_X86_XOR_MEMBASE_REG;
13247         case OP_IADD_IMM:
13248                 return OP_X86_ADD_MEMBASE_IMM;
13249         case OP_ISUB_IMM:
13250                 return OP_X86_SUB_MEMBASE_IMM;
13251         case OP_IAND_IMM:
13252                 return OP_X86_AND_MEMBASE_IMM;
13253         case OP_IOR_IMM:
13254                 return OP_X86_OR_MEMBASE_IMM;
13255         case OP_IXOR_IMM:
13256                 return OP_X86_XOR_MEMBASE_IMM;
13257         case OP_LADD:
13258                 return OP_AMD64_ADD_MEMBASE_REG;
13259         case OP_LSUB:
13260                 return OP_AMD64_SUB_MEMBASE_REG;
13261         case OP_LAND:
13262                 return OP_AMD64_AND_MEMBASE_REG;
13263         case OP_LOR:
13264                 return OP_AMD64_OR_MEMBASE_REG;
13265         case OP_LXOR:
13266                 return OP_AMD64_XOR_MEMBASE_REG;
13267         case OP_ADD_IMM:
13268         case OP_LADD_IMM:
13269                 return OP_AMD64_ADD_MEMBASE_IMM;
13270         case OP_SUB_IMM:
13271         case OP_LSUB_IMM:
13272                 return OP_AMD64_SUB_MEMBASE_IMM;
13273         case OP_AND_IMM:
13274         case OP_LAND_IMM:
13275                 return OP_AMD64_AND_MEMBASE_IMM;
13276         case OP_OR_IMM:
13277         case OP_LOR_IMM:
13278                 return OP_AMD64_OR_MEMBASE_IMM;
13279         case OP_XOR_IMM:
13280         case OP_LXOR_IMM:
13281                 return OP_AMD64_XOR_MEMBASE_IMM;
13282         case OP_MOVE:
13283                 return OP_NOP;
13284         }
13285 #endif
13286
13287         return -1;
13288 }
13289
13290 static inline int
13291 op_to_op_store_membase (int store_opcode, int opcode)
13292 {
13293 #if defined(TARGET_X86) || defined(TARGET_AMD64)
13294         switch (opcode) {
13295         case OP_ICEQ:
13296                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
13297                         return OP_X86_SETEQ_MEMBASE;
13298         case OP_CNE:
13299                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
13300                         return OP_X86_SETNE_MEMBASE;
13301         }
13302 #endif
13303
13304         return -1;
13305 }
13306
13307 static inline int
13308 op_to_op_src1_membase (int load_opcode, int opcode)
13309 {
13310 #ifdef TARGET_X86
13311         /* FIXME: This has sign extension issues */
13312         /*
13313         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
13314                 return OP_X86_COMPARE_MEMBASE8_IMM;
13315         */
13316
13317         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
13318                 return -1;
13319
13320         switch (opcode) {
13321         case OP_X86_PUSH:
13322                 return OP_X86_PUSH_MEMBASE;
13323         case OP_COMPARE_IMM:
13324         case OP_ICOMPARE_IMM:
13325                 return OP_X86_COMPARE_MEMBASE_IMM;
13326         case OP_COMPARE:
13327         case OP_ICOMPARE:
13328                 return OP_X86_COMPARE_MEMBASE_REG;
13329         }
13330 #endif
13331
13332 #ifdef TARGET_AMD64
13333         /* FIXME: This has sign extension issues */
13334         /*
13335         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
13336                 return OP_X86_COMPARE_MEMBASE8_IMM;
13337         */
13338
13339         switch (opcode) {
13340         case OP_X86_PUSH:
13341 #ifdef __mono_ilp32__
13342                 if (load_opcode == OP_LOADI8_MEMBASE)
13343 #else
13344                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
13345 #endif
13346                         return OP_X86_PUSH_MEMBASE;
13347                 break;
13348                 /* FIXME: This only works for 32 bit immediates
13349         case OP_COMPARE_IMM:
13350         case OP_LCOMPARE_IMM:
13351                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
13352                         return OP_AMD64_COMPARE_MEMBASE_IMM;
13353                 */
13354         case OP_ICOMPARE_IMM:
13355                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
13356                         return OP_AMD64_ICOMPARE_MEMBASE_IMM;
13357                 break;
13358         case OP_COMPARE:
13359         case OP_LCOMPARE:
13360 #ifdef __mono_ilp32__
13361                 if (load_opcode == OP_LOAD_MEMBASE)
13362                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
13363                 if (load_opcode == OP_LOADI8_MEMBASE)
13364 #else
13365                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
13366 #endif
13367                         return OP_AMD64_COMPARE_MEMBASE_REG;
13368                 break;
13369         case OP_ICOMPARE:
13370                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
13371                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
13372                 break;
13373         }
13374 #endif
13375
13376         return -1;
13377 }
13378
13379 static inline int
13380 op_to_op_src2_membase (int load_opcode, int opcode)
13381 {
13382 #ifdef TARGET_X86
13383         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
13384                 return -1;
13385         
13386         switch (opcode) {
13387         case OP_COMPARE:
13388         case OP_ICOMPARE:
13389                 return OP_X86_COMPARE_REG_MEMBASE;
13390         case OP_IADD:
13391                 return OP_X86_ADD_REG_MEMBASE;
13392         case OP_ISUB:
13393                 return OP_X86_SUB_REG_MEMBASE;
13394         case OP_IAND:
13395                 return OP_X86_AND_REG_MEMBASE;
13396         case OP_IOR:
13397                 return OP_X86_OR_REG_MEMBASE;
13398         case OP_IXOR:
13399                 return OP_X86_XOR_REG_MEMBASE;
13400         }
13401 #endif
13402
13403 #ifdef TARGET_AMD64
13404 #ifdef __mono_ilp32__
13405         if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE) ) {
13406 #else
13407         if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)) {
13408 #endif
13409                 switch (opcode) {
13410                 case OP_ICOMPARE:
13411                         return OP_AMD64_ICOMPARE_REG_MEMBASE;
13412                 case OP_IADD:
13413                         return OP_X86_ADD_REG_MEMBASE;
13414                 case OP_ISUB:
13415                         return OP_X86_SUB_REG_MEMBASE;
13416                 case OP_IAND:
13417                         return OP_X86_AND_REG_MEMBASE;
13418                 case OP_IOR:
13419                         return OP_X86_OR_REG_MEMBASE;
13420                 case OP_IXOR:
13421                         return OP_X86_XOR_REG_MEMBASE;
13422                 }
13423 #ifdef __mono_ilp32__
13424         } else if (load_opcode == OP_LOADI8_MEMBASE) {
13425 #else
13426         } else if ((load_opcode == OP_LOADI8_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE)) {
13427 #endif
13428                 switch (opcode) {
13429                 case OP_COMPARE:
13430                 case OP_LCOMPARE:
13431                         return OP_AMD64_COMPARE_REG_MEMBASE;
13432                 case OP_LADD:
13433                         return OP_AMD64_ADD_REG_MEMBASE;
13434                 case OP_LSUB:
13435                         return OP_AMD64_SUB_REG_MEMBASE;
13436                 case OP_LAND:
13437                         return OP_AMD64_AND_REG_MEMBASE;
13438                 case OP_LOR:
13439                         return OP_AMD64_OR_REG_MEMBASE;
13440                 case OP_LXOR:
13441                         return OP_AMD64_XOR_REG_MEMBASE;
13442                 }
13443         }
13444 #endif
13445
13446         return -1;
13447 }
13448
13449 int
13450 mono_op_to_op_imm_noemul (int opcode)
13451 {
13452         switch (opcode) {
13453 #if SIZEOF_REGISTER == 4 && !defined(MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS)
13454         case OP_LSHR:
13455         case OP_LSHL:
13456         case OP_LSHR_UN:
13457                 return -1;
13458 #endif
13459 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
13460         case OP_IDIV:
13461         case OP_IDIV_UN:
13462         case OP_IREM:
13463         case OP_IREM_UN:
13464                 return -1;
13465 #endif
13466 #if defined(MONO_ARCH_EMULATE_MUL_DIV)
13467         case OP_IMUL:
13468                 return -1;
13469 #endif
13470         default:
13471                 return mono_op_to_op_imm (opcode);
13472         }
13473 }
13474
13475 /**
13476  * mono_handle_global_vregs:
13477  *
13478  *   Make vregs used in more than one bblock 'global', i.e. allocate a variable
13479  * for them.
13480  */
13481 void
13482 mono_handle_global_vregs (MonoCompile *cfg)
13483 {
13484         gint32 *vreg_to_bb;
13485         MonoBasicBlock *bb;
13486         int i, pos;
13487
13488         vreg_to_bb = mono_mempool_alloc0 (cfg->mempool, sizeof (gint32*) * cfg->next_vreg + 1);
13489
13490 #ifdef MONO_ARCH_SIMD_INTRINSICS
13491         if (cfg->uses_simd_intrinsics)
13492                 mono_simd_simplify_indirection (cfg);
13493 #endif
13494
13495         /* Find local vregs used in more than one bb */
13496         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
13497                 MonoInst *ins = bb->code;       
13498                 int block_num = bb->block_num;
13499
13500                 if (cfg->verbose_level > 2)
13501                         printf ("\nHANDLE-GLOBAL-VREGS BLOCK %d:\n", bb->block_num);
13502
13503                 cfg->cbb = bb;
13504                 for (; ins; ins = ins->next) {
13505                         const char *spec = INS_INFO (ins->opcode);
13506                         int regtype = 0, regindex;
13507                         gint32 prev_bb;
13508
13509                         if (G_UNLIKELY (cfg->verbose_level > 2))
13510                                 mono_print_ins (ins);
13511
13512                         g_assert (ins->opcode >= MONO_CEE_LAST);
13513
13514                         for (regindex = 0; regindex < 4; regindex ++) {
13515                                 int vreg = 0;
13516
13517                                 if (regindex == 0) {
13518                                         regtype = spec [MONO_INST_DEST];
13519                                         if (regtype == ' ')
13520                                                 continue;
13521                                         vreg = ins->dreg;
13522                                 } else if (regindex == 1) {
13523                                         regtype = spec [MONO_INST_SRC1];
13524                                         if (regtype == ' ')
13525                                                 continue;
13526                                         vreg = ins->sreg1;
13527                                 } else if (regindex == 2) {
13528                                         regtype = spec [MONO_INST_SRC2];
13529                                         if (regtype == ' ')
13530                                                 continue;
13531                                         vreg = ins->sreg2;
13532                                 } else if (regindex == 3) {
13533                                         regtype = spec [MONO_INST_SRC3];
13534                                         if (regtype == ' ')
13535                                                 continue;
13536                                         vreg = ins->sreg3;
13537                                 }
13538
13539 #if SIZEOF_REGISTER == 4
13540                                 /* In the LLVM case, the long opcodes are not decomposed */
13541                                 if (regtype == 'l' && !COMPILE_LLVM (cfg)) {
13542                                         /*
13543                                          * Since some instructions reference the original long vreg,
13544                                          * and some reference the two component vregs, it is quite hard
13545                                          * to determine when it needs to be global. So be conservative.
13546                                          */
13547                                         if (!get_vreg_to_inst (cfg, vreg)) {
13548                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
13549
13550                                                 if (cfg->verbose_level > 2)
13551                                                         printf ("LONG VREG R%d made global.\n", vreg);
13552                                         }
13553
13554                                         /*
13555                                          * Make the component vregs volatile since the optimizations can
13556                                          * get confused otherwise.
13557                                          */
13558                                         get_vreg_to_inst (cfg, vreg + 1)->flags |= MONO_INST_VOLATILE;
13559                                         get_vreg_to_inst (cfg, vreg + 2)->flags |= MONO_INST_VOLATILE;
13560                                 }
13561 #endif
13562
13563                                 g_assert (vreg != -1);
13564
13565                                 prev_bb = vreg_to_bb [vreg];
13566                                 if (prev_bb == 0) {
13567                                         /* 0 is a valid block num */
13568                                         vreg_to_bb [vreg] = block_num + 1;
13569                                 } else if ((prev_bb != block_num + 1) && (prev_bb != -1)) {
13570                                         if (((regtype == 'i' && (vreg < MONO_MAX_IREGS))) || (regtype == 'f' && (vreg < MONO_MAX_FREGS)))
13571                                                 continue;
13572
13573                                         if (!get_vreg_to_inst (cfg, vreg)) {
13574                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
13575                                                         printf ("VREG R%d used in BB%d and BB%d made global.\n", vreg, vreg_to_bb [vreg], block_num);
13576
13577                                                 switch (regtype) {
13578                                                 case 'i':
13579                                                         if (vreg_is_ref (cfg, vreg))
13580                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL, vreg);
13581                                                         else
13582                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL, vreg);
13583                                                         break;
13584                                                 case 'l':
13585                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
13586                                                         break;
13587                                                 case 'f':
13588                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.double_class->byval_arg, OP_LOCAL, vreg);
13589                                                         break;
13590                                                 case 'v':
13591                                                         mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, vreg);
13592                                                         break;
13593                                                 default:
13594                                                         g_assert_not_reached ();
13595                                                 }
13596                                         }
13597
13598                                         /* Flag as having been used in more than one bb */
13599                                         vreg_to_bb [vreg] = -1;
13600                                 }
13601                         }
13602                 }
13603         }
13604
13605         /* If a variable is used in only one bblock, convert it into a local vreg */
13606         for (i = 0; i < cfg->num_varinfo; i++) {
13607                 MonoInst *var = cfg->varinfo [i];
13608                 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
13609
13610                 switch (var->type) {
13611                 case STACK_I4:
13612                 case STACK_OBJ:
13613                 case STACK_PTR:
13614                 case STACK_MP:
13615                 case STACK_VTYPE:
13616 #if SIZEOF_REGISTER == 8
13617                 case STACK_I8:
13618 #endif
13619 #if !defined(TARGET_X86)
13620                 /* Enabling this screws up the fp stack on x86 */
13621                 case STACK_R8:
13622 #endif
13623                         if (mono_arch_is_soft_float ())
13624                                 break;
13625
13626                         /* Arguments are implicitly global */
13627                         /* Putting R4 vars into registers doesn't work currently */
13628                         /* The gsharedvt vars are implicitly referenced by ldaddr opcodes, but those opcodes are only generated later */
13629                         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) {
13630                                 /* 
13631                                  * Make that the variable's liveness interval doesn't contain a call, since
13632                                  * that would cause the lvreg to be spilled, making the whole optimization
13633                                  * useless.
13634                                  */
13635                                 /* This is too slow for JIT compilation */
13636 #if 0
13637                                 if (cfg->compile_aot && vreg_to_bb [var->dreg]) {
13638                                         MonoInst *ins;
13639                                         int def_index, call_index, ins_index;
13640                                         gboolean spilled = FALSE;
13641
13642                                         def_index = -1;
13643                                         call_index = -1;
13644                                         ins_index = 0;
13645                                         for (ins = vreg_to_bb [var->dreg]->code; ins; ins = ins->next) {
13646                                                 const char *spec = INS_INFO (ins->opcode);
13647
13648                                                 if ((spec [MONO_INST_DEST] != ' ') && (ins->dreg == var->dreg))
13649                                                         def_index = ins_index;
13650
13651                                                 if (((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg)) ||
13652                                                         ((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg))) {
13653                                                         if (call_index > def_index) {
13654                                                                 spilled = TRUE;
13655                                                                 break;
13656                                                         }
13657                                                 }
13658
13659                                                 if (MONO_IS_CALL (ins))
13660                                                         call_index = ins_index;
13661
13662                                                 ins_index ++;
13663                                         }
13664
13665                                         if (spilled)
13666                                                 break;
13667                                 }
13668 #endif
13669
13670                                 if (G_UNLIKELY (cfg->verbose_level > 2))
13671                                         printf ("CONVERTED R%d(%d) TO VREG.\n", var->dreg, vmv->idx);
13672                                 var->flags |= MONO_INST_IS_DEAD;
13673                                 cfg->vreg_to_inst [var->dreg] = NULL;
13674                         }
13675                         break;
13676                 }
13677         }
13678
13679         /* 
13680          * Compress the varinfo and vars tables so the liveness computation is faster and
13681          * takes up less space.
13682          */
13683         pos = 0;
13684         for (i = 0; i < cfg->num_varinfo; ++i) {
13685                 MonoInst *var = cfg->varinfo [i];
13686                 if (pos < i && cfg->locals_start == i)
13687                         cfg->locals_start = pos;
13688                 if (!(var->flags & MONO_INST_IS_DEAD)) {
13689                         if (pos < i) {
13690                                 cfg->varinfo [pos] = cfg->varinfo [i];
13691                                 cfg->varinfo [pos]->inst_c0 = pos;
13692                                 memcpy (&cfg->vars [pos], &cfg->vars [i], sizeof (MonoMethodVar));
13693                                 cfg->vars [pos].idx = pos;
13694 #if SIZEOF_REGISTER == 4
13695                                 if (cfg->varinfo [pos]->type == STACK_I8) {
13696                                         /* Modify the two component vars too */
13697                                         MonoInst *var1;
13698
13699                                         var1 = get_vreg_to_inst (cfg, cfg->varinfo [pos]->dreg + 1);
13700                                         var1->inst_c0 = pos;
13701                                         var1 = get_vreg_to_inst (cfg, cfg->varinfo [pos]->dreg + 2);
13702                                         var1->inst_c0 = pos;
13703                                 }
13704 #endif
13705                         }
13706                         pos ++;
13707                 }
13708         }
13709         cfg->num_varinfo = pos;
13710         if (cfg->locals_start > cfg->num_varinfo)
13711                 cfg->locals_start = cfg->num_varinfo;
13712 }
13713
13714 /**
13715  * mono_spill_global_vars:
13716  *
13717  *   Generate spill code for variables which are not allocated to registers, 
13718  * and replace vregs with their allocated hregs. *need_local_opts is set to TRUE if
13719  * code is generated which could be optimized by the local optimization passes.
13720  */
13721 void
13722 mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
13723 {
13724         MonoBasicBlock *bb;
13725         char spec2 [16];
13726         int orig_next_vreg;
13727         guint32 *vreg_to_lvreg;
13728         guint32 *lvregs;
13729         guint32 i, lvregs_len;
13730         gboolean dest_has_lvreg = FALSE;
13731         guint32 stacktypes [128];
13732         MonoInst **live_range_start, **live_range_end;
13733         MonoBasicBlock **live_range_start_bb, **live_range_end_bb;
13734         int *gsharedvt_vreg_to_idx = NULL;
13735
13736         *need_local_opts = FALSE;
13737
13738         memset (spec2, 0, sizeof (spec2));
13739
13740         /* FIXME: Move this function to mini.c */
13741         stacktypes ['i'] = STACK_PTR;
13742         stacktypes ['l'] = STACK_I8;
13743         stacktypes ['f'] = STACK_R8;
13744 #ifdef MONO_ARCH_SIMD_INTRINSICS
13745         stacktypes ['x'] = STACK_VTYPE;
13746 #endif
13747
13748 #if SIZEOF_REGISTER == 4
13749         /* Create MonoInsts for longs */
13750         for (i = 0; i < cfg->num_varinfo; i++) {
13751                 MonoInst *ins = cfg->varinfo [i];
13752
13753                 if ((ins->opcode != OP_REGVAR) && !(ins->flags & MONO_INST_IS_DEAD)) {
13754                         switch (ins->type) {
13755                         case STACK_R8:
13756                         case STACK_I8: {
13757                                 MonoInst *tree;
13758
13759                                 if (ins->type == STACK_R8 && !COMPILE_SOFT_FLOAT (cfg))
13760                                         break;
13761
13762                                 g_assert (ins->opcode == OP_REGOFFSET);
13763
13764                                 tree = get_vreg_to_inst (cfg, ins->dreg + 1);
13765                                 g_assert (tree);
13766                                 tree->opcode = OP_REGOFFSET;
13767                                 tree->inst_basereg = ins->inst_basereg;
13768                                 tree->inst_offset = ins->inst_offset + MINI_LS_WORD_OFFSET;
13769
13770                                 tree = get_vreg_to_inst (cfg, ins->dreg + 2);
13771                                 g_assert (tree);
13772                                 tree->opcode = OP_REGOFFSET;
13773                                 tree->inst_basereg = ins->inst_basereg;
13774                                 tree->inst_offset = ins->inst_offset + MINI_MS_WORD_OFFSET;
13775                                 break;
13776                         }
13777                         default:
13778                                 break;
13779                         }
13780                 }
13781         }
13782 #endif
13783
13784         if (cfg->compute_gc_maps) {
13785                 /* registers need liveness info even for !non refs */
13786                 for (i = 0; i < cfg->num_varinfo; i++) {
13787                         MonoInst *ins = cfg->varinfo [i];
13788
13789                         if (ins->opcode == OP_REGVAR)
13790                                 ins->flags |= MONO_INST_GC_TRACK;
13791                 }
13792         }
13793
13794         if (cfg->gsharedvt) {
13795                 gsharedvt_vreg_to_idx = mono_mempool_alloc0 (cfg->mempool, sizeof (int) * cfg->next_vreg);
13796
13797                 for (i = 0; i < cfg->num_varinfo; ++i) {
13798                         MonoInst *ins = cfg->varinfo [i];
13799                         int idx;
13800
13801                         if (mini_is_gsharedvt_variable_type (ins->inst_vtype)) {
13802                                 if (i >= cfg->locals_start) {
13803                                         /* Local */
13804                                         idx = get_gsharedvt_info_slot (cfg, ins->inst_vtype, MONO_RGCTX_INFO_LOCAL_OFFSET);
13805                                         gsharedvt_vreg_to_idx [ins->dreg] = idx + 1;
13806                                         ins->opcode = OP_GSHAREDVT_LOCAL;
13807                                         ins->inst_imm = idx;
13808                                 } else {
13809                                         /* Arg */
13810                                         gsharedvt_vreg_to_idx [ins->dreg] = -1;
13811                                         ins->opcode = OP_GSHAREDVT_ARG_REGOFFSET;
13812                                 }
13813                         }
13814                 }
13815         }
13816                 
13817         /* FIXME: widening and truncation */
13818
13819         /*
13820          * As an optimization, when a variable allocated to the stack is first loaded into 
13821          * an lvreg, we will remember the lvreg and use it the next time instead of loading
13822          * the variable again.
13823          */
13824         orig_next_vreg = cfg->next_vreg;
13825         vreg_to_lvreg = mono_mempool_alloc0 (cfg->mempool, sizeof (guint32) * cfg->next_vreg);
13826         lvregs = mono_mempool_alloc (cfg->mempool, sizeof (guint32) * 1024);
13827         lvregs_len = 0;
13828
13829         /* 
13830          * These arrays contain the first and last instructions accessing a given
13831          * variable.
13832          * Since we emit bblocks in the same order we process them here, and we
13833          * don't split live ranges, these will precisely describe the live range of
13834          * the variable, i.e. the instruction range where a valid value can be found
13835          * in the variables location.
13836          * The live range is computed using the liveness info computed by the liveness pass.
13837          * We can't use vmv->range, since that is an abstract live range, and we need
13838          * one which is instruction precise.
13839          * FIXME: Variables used in out-of-line bblocks have a hole in their live range.
13840          */
13841         /* FIXME: Only do this if debugging info is requested */
13842         live_range_start = g_new0 (MonoInst*, cfg->next_vreg);
13843         live_range_end = g_new0 (MonoInst*, cfg->next_vreg);
13844         live_range_start_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
13845         live_range_end_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
13846         
13847         /* Add spill loads/stores */
13848         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
13849                 MonoInst *ins;
13850
13851                 if (cfg->verbose_level > 2)
13852                         printf ("\nSPILL BLOCK %d:\n", bb->block_num);
13853
13854                 /* Clear vreg_to_lvreg array */
13855                 for (i = 0; i < lvregs_len; i++)
13856                         vreg_to_lvreg [lvregs [i]] = 0;
13857                 lvregs_len = 0;
13858
13859                 cfg->cbb = bb;
13860                 MONO_BB_FOR_EACH_INS (bb, ins) {
13861                         const char *spec = INS_INFO (ins->opcode);
13862                         int regtype, srcindex, sreg, tmp_reg, prev_dreg, num_sregs;
13863                         gboolean store, no_lvreg;
13864                         int sregs [MONO_MAX_SRC_REGS];
13865
13866                         if (G_UNLIKELY (cfg->verbose_level > 2))
13867                                 mono_print_ins (ins);
13868
13869                         if (ins->opcode == OP_NOP)
13870                                 continue;
13871
13872                         /* 
13873                          * We handle LDADDR here as well, since it can only be decomposed
13874                          * when variable addresses are known.
13875                          */
13876                         if (ins->opcode == OP_LDADDR) {
13877                                 MonoInst *var = ins->inst_p0;
13878
13879                                 if (var->opcode == OP_VTARG_ADDR) {
13880                                         /* Happens on SPARC/S390 where vtypes are passed by reference */
13881                                         MonoInst *vtaddr = var->inst_left;
13882                                         if (vtaddr->opcode == OP_REGVAR) {
13883                                                 ins->opcode = OP_MOVE;
13884                                                 ins->sreg1 = vtaddr->dreg;
13885                                         }
13886                                         else if (var->inst_left->opcode == OP_REGOFFSET) {
13887                                                 ins->opcode = OP_LOAD_MEMBASE;
13888                                                 ins->inst_basereg = vtaddr->inst_basereg;
13889                                                 ins->inst_offset = vtaddr->inst_offset;
13890                                         } else
13891                                                 NOT_IMPLEMENTED;
13892                                 } else if (cfg->gsharedvt && gsharedvt_vreg_to_idx [var->dreg] < 0) {
13893                                         /* gsharedvt arg passed by ref */
13894                                         g_assert (var->opcode == OP_GSHAREDVT_ARG_REGOFFSET);
13895
13896                                         ins->opcode = OP_LOAD_MEMBASE;
13897                                         ins->inst_basereg = var->inst_basereg;
13898                                         ins->inst_offset = var->inst_offset;
13899                                 } else if (cfg->gsharedvt && gsharedvt_vreg_to_idx [var->dreg]) {
13900                                         MonoInst *load, *load2, *load3;
13901                                         int idx = gsharedvt_vreg_to_idx [var->dreg] - 1;
13902                                         int reg1, reg2, reg3;
13903                                         MonoInst *info_var = cfg->gsharedvt_info_var;
13904                                         MonoInst *locals_var = cfg->gsharedvt_locals_var;
13905
13906                                         /*
13907                                          * gsharedvt local.
13908                                          * Compute the address of the local as gsharedvt_locals_var + gsharedvt_info_var->locals_offsets [idx].
13909                                          */
13910
13911                                         g_assert (var->opcode == OP_GSHAREDVT_LOCAL);
13912
13913                                         g_assert (info_var);
13914                                         g_assert (locals_var);
13915
13916                                         /* Mark the instruction used to compute the locals var as used */
13917                                         cfg->gsharedvt_locals_var_ins = NULL;
13918
13919                                         /* Load the offset */
13920                                         if (info_var->opcode == OP_REGOFFSET) {
13921                                                 reg1 = alloc_ireg (cfg);
13922                                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, reg1, info_var->inst_basereg, info_var->inst_offset);
13923                                         } else if (info_var->opcode == OP_REGVAR) {
13924                                                 load = NULL;
13925                                                 reg1 = info_var->dreg;
13926                                         } else {
13927                                                 g_assert_not_reached ();
13928                                         }
13929                                         reg2 = alloc_ireg (cfg);
13930                                         NEW_LOAD_MEMBASE (cfg, load2, OP_LOADI4_MEMBASE, reg2, reg1, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, entries) + (idx * sizeof (gpointer)));
13931                                         /* Load the locals area address */
13932                                         reg3 = alloc_ireg (cfg);
13933                                         if (locals_var->opcode == OP_REGOFFSET) {
13934                                                 NEW_LOAD_MEMBASE (cfg, load3, OP_LOAD_MEMBASE, reg3, locals_var->inst_basereg, locals_var->inst_offset);
13935                                         } else if (locals_var->opcode == OP_REGVAR) {
13936                                                 NEW_UNALU (cfg, load3, OP_MOVE, reg3, locals_var->dreg);
13937                                         } else {
13938                                                 g_assert_not_reached ();
13939                                         }
13940                                         /* Compute the address */
13941                                         ins->opcode = OP_PADD;
13942                                         ins->sreg1 = reg3;
13943                                         ins->sreg2 = reg2;
13944
13945                                         mono_bblock_insert_before_ins (bb, ins, load3);
13946                                         mono_bblock_insert_before_ins (bb, load3, load2);
13947                                         if (load)
13948                                                 mono_bblock_insert_before_ins (bb, load2, load);
13949                                 } else {
13950                                         g_assert (var->opcode == OP_REGOFFSET);
13951
13952                                         ins->opcode = OP_ADD_IMM;
13953                                         ins->sreg1 = var->inst_basereg;
13954                                         ins->inst_imm = var->inst_offset;
13955                                 }
13956
13957                                 *need_local_opts = TRUE;
13958                                 spec = INS_INFO (ins->opcode);
13959                         }
13960
13961                         if (ins->opcode < MONO_CEE_LAST) {
13962                                 mono_print_ins (ins);
13963                                 g_assert_not_reached ();
13964                         }
13965
13966                         /*
13967                          * Store opcodes have destbasereg in the dreg, but in reality, it is an
13968                          * src register.
13969                          * FIXME:
13970                          */
13971                         if (MONO_IS_STORE_MEMBASE (ins)) {
13972                                 tmp_reg = ins->dreg;
13973                                 ins->dreg = ins->sreg2;
13974                                 ins->sreg2 = tmp_reg;
13975                                 store = TRUE;
13976
13977                                 spec2 [MONO_INST_DEST] = ' ';
13978                                 spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
13979                                 spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
13980                                 spec2 [MONO_INST_SRC3] = ' ';
13981                                 spec = spec2;
13982                         } else if (MONO_IS_STORE_MEMINDEX (ins))
13983                                 g_assert_not_reached ();
13984                         else
13985                                 store = FALSE;
13986                         no_lvreg = FALSE;
13987
13988                         if (G_UNLIKELY (cfg->verbose_level > 2)) {
13989                                 printf ("\t %.3s %d", spec, ins->dreg);
13990                                 num_sregs = mono_inst_get_src_registers (ins, sregs);
13991                                 for (srcindex = 0; srcindex < num_sregs; ++srcindex)
13992                                         printf (" %d", sregs [srcindex]);
13993                                 printf ("\n");
13994                         }
13995
13996                         /***************/
13997                         /*    DREG     */
13998                         /***************/
13999                         regtype = spec [MONO_INST_DEST];
14000                         g_assert (((ins->dreg == -1) && (regtype == ' ')) || ((ins->dreg != -1) && (regtype != ' ')));
14001                         prev_dreg = -1;
14002
14003                         if ((ins->dreg != -1) && get_vreg_to_inst (cfg, ins->dreg)) {
14004                                 MonoInst *var = get_vreg_to_inst (cfg, ins->dreg);
14005                                 MonoInst *store_ins;
14006                                 int store_opcode;
14007                                 MonoInst *def_ins = ins;
14008                                 int dreg = ins->dreg; /* The original vreg */
14009
14010                                 store_opcode = mono_type_to_store_membase (cfg, var->inst_vtype);
14011
14012                                 if (var->opcode == OP_REGVAR) {
14013                                         ins->dreg = var->dreg;
14014                                 } 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)) {
14015                                         /* 
14016                                          * Instead of emitting a load+store, use a _membase opcode.
14017                                          */
14018                                         g_assert (var->opcode == OP_REGOFFSET);
14019                                         if (ins->opcode == OP_MOVE) {
14020                                                 NULLIFY_INS (ins);
14021                                                 def_ins = NULL;
14022                                         } else {
14023                                                 ins->opcode = op_to_op_dest_membase (store_opcode, ins->opcode);
14024                                                 ins->inst_basereg = var->inst_basereg;
14025                                                 ins->inst_offset = var->inst_offset;
14026                                                 ins->dreg = -1;
14027                                         }
14028                                         spec = INS_INFO (ins->opcode);
14029                                 } else {
14030                                         guint32 lvreg;
14031
14032                                         g_assert (var->opcode == OP_REGOFFSET);
14033
14034                                         prev_dreg = ins->dreg;
14035
14036                                         /* Invalidate any previous lvreg for this vreg */
14037                                         vreg_to_lvreg [ins->dreg] = 0;
14038
14039                                         lvreg = 0;
14040
14041                                         if (COMPILE_SOFT_FLOAT (cfg) && store_opcode == OP_STORER8_MEMBASE_REG) {
14042                                                 regtype = 'l';
14043                                                 store_opcode = OP_STOREI8_MEMBASE_REG;
14044                                         }
14045
14046                                         ins->dreg = alloc_dreg (cfg, stacktypes [regtype]);
14047
14048 #if SIZEOF_REGISTER != 8
14049                                         if (regtype == 'l') {
14050                                                 NEW_STORE_MEMBASE (cfg, store_ins, OP_STOREI4_MEMBASE_REG, var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET, ins->dreg + 1);
14051                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
14052                                                 NEW_STORE_MEMBASE (cfg, store_ins, OP_STOREI4_MEMBASE_REG, var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET, ins->dreg + 2);
14053                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
14054                                                 def_ins = store_ins;
14055                                         }
14056                                         else
14057 #endif
14058                                         {
14059                                                 g_assert (store_opcode != OP_STOREV_MEMBASE);
14060
14061                                                 /* Try to fuse the store into the instruction itself */
14062                                                 /* FIXME: Add more instructions */
14063                                                 if (!lvreg && ((ins->opcode == OP_ICONST) || ((ins->opcode == OP_I8CONST) && (ins->inst_c0 == 0)))) {
14064                                                         ins->opcode = store_membase_reg_to_store_membase_imm (store_opcode);
14065                                                         ins->inst_imm = ins->inst_c0;
14066                                                         ins->inst_destbasereg = var->inst_basereg;
14067                                                         ins->inst_offset = var->inst_offset;
14068                                                         spec = INS_INFO (ins->opcode);
14069                                                 } else if (!lvreg && ((ins->opcode == OP_MOVE) || (ins->opcode == OP_FMOVE) || (ins->opcode == OP_LMOVE) || (ins->opcode == OP_RMOVE))) {
14070                                                         ins->opcode = store_opcode;
14071                                                         ins->inst_destbasereg = var->inst_basereg;
14072                                                         ins->inst_offset = var->inst_offset;
14073
14074                                                         no_lvreg = TRUE;
14075
14076                                                         tmp_reg = ins->dreg;
14077                                                         ins->dreg = ins->sreg2;
14078                                                         ins->sreg2 = tmp_reg;
14079                                                         store = TRUE;
14080
14081                                                         spec2 [MONO_INST_DEST] = ' ';
14082                                                         spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
14083                                                         spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
14084                                                         spec2 [MONO_INST_SRC3] = ' ';
14085                                                         spec = spec2;
14086                                                 } else if (!lvreg && (op_to_op_store_membase (store_opcode, ins->opcode) != -1)) {
14087                                                         // FIXME: The backends expect the base reg to be in inst_basereg
14088                                                         ins->opcode = op_to_op_store_membase (store_opcode, ins->opcode);
14089                                                         ins->dreg = -1;
14090                                                         ins->inst_basereg = var->inst_basereg;
14091                                                         ins->inst_offset = var->inst_offset;
14092                                                         spec = INS_INFO (ins->opcode);
14093                                                 } else {
14094                                                         /* printf ("INS: "); mono_print_ins (ins); */
14095                                                         /* Create a store instruction */
14096                                                         NEW_STORE_MEMBASE (cfg, store_ins, store_opcode, var->inst_basereg, var->inst_offset, ins->dreg);
14097
14098                                                         /* Insert it after the instruction */
14099                                                         mono_bblock_insert_after_ins (bb, ins, store_ins);
14100
14101                                                         def_ins = store_ins;
14102
14103                                                         /* 
14104                                                          * We can't assign ins->dreg to var->dreg here, since the
14105                                                          * sregs could use it. So set a flag, and do it after
14106                                                          * the sregs.
14107                                                          */
14108                                                         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)))
14109                                                                 dest_has_lvreg = TRUE;
14110                                                 }
14111                                         }
14112                                 }
14113
14114                                 if (def_ins && !live_range_start [dreg]) {
14115                                         live_range_start [dreg] = def_ins;
14116                                         live_range_start_bb [dreg] = bb;
14117                                 }
14118
14119                                 if (cfg->compute_gc_maps && def_ins && (var->flags & MONO_INST_GC_TRACK)) {
14120                                         MonoInst *tmp;
14121
14122                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_DEF);
14123                                         tmp->inst_c1 = dreg;
14124                                         mono_bblock_insert_after_ins (bb, def_ins, tmp);
14125                                 }
14126                         }
14127
14128                         /************/
14129                         /*  SREGS   */
14130                         /************/
14131                         num_sregs = mono_inst_get_src_registers (ins, sregs);
14132                         for (srcindex = 0; srcindex < 3; ++srcindex) {
14133                                 regtype = spec [MONO_INST_SRC1 + srcindex];
14134                                 sreg = sregs [srcindex];
14135
14136                                 g_assert (((sreg == -1) && (regtype == ' ')) || ((sreg != -1) && (regtype != ' ')));
14137                                 if ((sreg != -1) && get_vreg_to_inst (cfg, sreg)) {
14138                                         MonoInst *var = get_vreg_to_inst (cfg, sreg);
14139                                         MonoInst *use_ins = ins;
14140                                         MonoInst *load_ins;
14141                                         guint32 load_opcode;
14142
14143                                         if (var->opcode == OP_REGVAR) {
14144                                                 sregs [srcindex] = var->dreg;
14145                                                 //mono_inst_set_src_registers (ins, sregs);
14146                                                 live_range_end [sreg] = use_ins;
14147                                                 live_range_end_bb [sreg] = bb;
14148
14149                                                 if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
14150                                                         MonoInst *tmp;
14151
14152                                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
14153                                                         /* var->dreg is a hreg */
14154                                                         tmp->inst_c1 = sreg;
14155                                                         mono_bblock_insert_after_ins (bb, ins, tmp);
14156                                                 }
14157
14158                                                 continue;
14159                                         }
14160
14161                                         g_assert (var->opcode == OP_REGOFFSET);
14162                                                 
14163                                         load_opcode = mono_type_to_load_membase (cfg, var->inst_vtype);
14164
14165                                         g_assert (load_opcode != OP_LOADV_MEMBASE);
14166
14167                                         if (vreg_to_lvreg [sreg]) {
14168                                                 g_assert (vreg_to_lvreg [sreg] != -1);
14169
14170                                                 /* The variable is already loaded to an lvreg */
14171                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
14172                                                         printf ("\t\tUse lvreg R%d for R%d.\n", vreg_to_lvreg [sreg], sreg);
14173                                                 sregs [srcindex] = vreg_to_lvreg [sreg];
14174                                                 //mono_inst_set_src_registers (ins, sregs);
14175                                                 continue;
14176                                         }
14177
14178                                         /* Try to fuse the load into the instruction */
14179                                         if ((srcindex == 0) && (op_to_op_src1_membase (load_opcode, ins->opcode) != -1)) {
14180                                                 ins->opcode = op_to_op_src1_membase (load_opcode, ins->opcode);
14181                                                 sregs [0] = var->inst_basereg;
14182                                                 //mono_inst_set_src_registers (ins, sregs);
14183                                                 ins->inst_offset = var->inst_offset;
14184                                         } else if ((srcindex == 1) && (op_to_op_src2_membase (load_opcode, ins->opcode) != -1)) {
14185                                                 ins->opcode = op_to_op_src2_membase (load_opcode, ins->opcode);
14186                                                 sregs [1] = var->inst_basereg;
14187                                                 //mono_inst_set_src_registers (ins, sregs);
14188                                                 ins->inst_offset = var->inst_offset;
14189                                         } else {
14190                                                 if (MONO_IS_REAL_MOVE (ins)) {
14191                                                         ins->opcode = OP_NOP;
14192                                                         sreg = ins->dreg;
14193                                                 } else {
14194                                                         //printf ("%d ", srcindex); mono_print_ins (ins);
14195
14196                                                         sreg = alloc_dreg (cfg, stacktypes [regtype]);
14197
14198                                                         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) {
14199                                                                 if (var->dreg == prev_dreg) {
14200                                                                         /*
14201                                                                          * sreg refers to the value loaded by the load
14202                                                                          * emitted below, but we need to use ins->dreg
14203                                                                          * since it refers to the store emitted earlier.
14204                                                                          */
14205                                                                         sreg = ins->dreg;
14206                                                                 }
14207                                                                 g_assert (sreg != -1);
14208                                                                 vreg_to_lvreg [var->dreg] = sreg;
14209                                                                 g_assert (lvregs_len < 1024);
14210                                                                 lvregs [lvregs_len ++] = var->dreg;
14211                                                         }
14212                                                 }
14213
14214                                                 sregs [srcindex] = sreg;
14215                                                 //mono_inst_set_src_registers (ins, sregs);
14216
14217 #if SIZEOF_REGISTER != 8
14218                                                 if (regtype == 'l') {
14219                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, sreg + 2, var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET);
14220                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14221                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, sreg + 1, var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET);
14222                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14223                                                         use_ins = load_ins;
14224                                                 }
14225                                                 else
14226 #endif
14227                                                 {
14228 #if SIZEOF_REGISTER == 4
14229                                                         g_assert (load_opcode != OP_LOADI8_MEMBASE);
14230 #endif
14231                                                         NEW_LOAD_MEMBASE (cfg, load_ins, load_opcode, sreg, var->inst_basereg, var->inst_offset);
14232                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14233                                                         use_ins = load_ins;
14234                                                 }
14235                                         }
14236
14237                                         if (var->dreg < orig_next_vreg) {
14238                                                 live_range_end [var->dreg] = use_ins;
14239                                                 live_range_end_bb [var->dreg] = bb;
14240                                         }
14241
14242                                         if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
14243                                                 MonoInst *tmp;
14244
14245                                                 MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
14246                                                 tmp->inst_c1 = var->dreg;
14247                                                 mono_bblock_insert_after_ins (bb, ins, tmp);
14248                                         }
14249                                 }
14250                         }
14251                         mono_inst_set_src_registers (ins, sregs);
14252
14253                         if (dest_has_lvreg) {
14254                                 g_assert (ins->dreg != -1);
14255                                 vreg_to_lvreg [prev_dreg] = ins->dreg;
14256                                 g_assert (lvregs_len < 1024);
14257                                 lvregs [lvregs_len ++] = prev_dreg;
14258                                 dest_has_lvreg = FALSE;
14259                         }
14260
14261                         if (store) {
14262                                 tmp_reg = ins->dreg;
14263                                 ins->dreg = ins->sreg2;
14264                                 ins->sreg2 = tmp_reg;
14265                         }
14266
14267                         if (MONO_IS_CALL (ins)) {
14268                                 /* Clear vreg_to_lvreg array */
14269                                 for (i = 0; i < lvregs_len; i++)
14270                                         vreg_to_lvreg [lvregs [i]] = 0;
14271                                 lvregs_len = 0;
14272                         } else if (ins->opcode == OP_NOP) {
14273                                 ins->dreg = -1;
14274                                 MONO_INST_NULLIFY_SREGS (ins);
14275                         }
14276
14277                         if (cfg->verbose_level > 2)
14278                                 mono_print_ins_index (1, ins);
14279                 }
14280
14281                 /* Extend the live range based on the liveness info */
14282                 if (cfg->compute_precise_live_ranges && bb->live_out_set && bb->code) {
14283                         for (i = 0; i < cfg->num_varinfo; i ++) {
14284                                 MonoMethodVar *vi = MONO_VARINFO (cfg, i);
14285
14286                                 if (vreg_is_volatile (cfg, vi->vreg))
14287                                         /* The liveness info is incomplete */
14288                                         continue;
14289
14290                                 if (mono_bitset_test_fast (bb->live_in_set, i) && !live_range_start [vi->vreg]) {
14291                                         /* Live from at least the first ins of this bb */
14292                                         live_range_start [vi->vreg] = bb->code;
14293                                         live_range_start_bb [vi->vreg] = bb;
14294                                 }
14295
14296                                 if (mono_bitset_test_fast (bb->live_out_set, i)) {
14297                                         /* Live at least until the last ins of this bb */
14298                                         live_range_end [vi->vreg] = bb->last_ins;
14299                                         live_range_end_bb [vi->vreg] = bb;
14300                                 }
14301                         }
14302                 }
14303         }
14304         
14305 #ifdef MONO_ARCH_HAVE_LIVERANGE_OPS
14306         /*
14307          * Emit LIVERANGE_START/LIVERANGE_END opcodes, the backend will implement them
14308          * by storing the current native offset into MonoMethodVar->live_range_start/end.
14309          */
14310         if (cfg->compute_precise_live_ranges && cfg->comp_done & MONO_COMP_LIVENESS) {
14311                 for (i = 0; i < cfg->num_varinfo; ++i) {
14312                         int vreg = MONO_VARINFO (cfg, i)->vreg;
14313                         MonoInst *ins;
14314
14315                         if (live_range_start [vreg]) {
14316                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_START);
14317                                 ins->inst_c0 = i;
14318                                 ins->inst_c1 = vreg;
14319                                 mono_bblock_insert_after_ins (live_range_start_bb [vreg], live_range_start [vreg], ins);
14320                         }
14321                         if (live_range_end [vreg]) {
14322                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_END);
14323                                 ins->inst_c0 = i;
14324                                 ins->inst_c1 = vreg;
14325                                 if (live_range_end [vreg] == live_range_end_bb [vreg]->last_ins)
14326                                         mono_add_ins_to_end (live_range_end_bb [vreg], ins);
14327                                 else
14328                                         mono_bblock_insert_after_ins (live_range_end_bb [vreg], live_range_end [vreg], ins);
14329                         }
14330                 }
14331         }
14332 #endif
14333
14334         if (cfg->gsharedvt_locals_var_ins) {
14335                 /* Nullify if unused */
14336                 cfg->gsharedvt_locals_var_ins->opcode = OP_PCONST;
14337                 cfg->gsharedvt_locals_var_ins->inst_imm = 0;
14338         }
14339
14340         g_free (live_range_start);
14341         g_free (live_range_end);
14342         g_free (live_range_start_bb);
14343         g_free (live_range_end_bb);
14344 }
14345
14346 /**
14347  * FIXME:
14348  * - use 'iadd' instead of 'int_add'
14349  * - handling ovf opcodes: decompose in method_to_ir.
14350  * - unify iregs/fregs
14351  *   -> partly done, the missing parts are:
14352  *   - a more complete unification would involve unifying the hregs as well, so
14353  *     code wouldn't need if (fp) all over the place. but that would mean the hregs
14354  *     would no longer map to the machine hregs, so the code generators would need to
14355  *     be modified. Also, on ia64 for example, niregs + nfregs > 256 -> bitmasks
14356  *     wouldn't work any more. Duplicating the code in mono_local_regalloc () into
14357  *     fp/non-fp branches speeds it up by about 15%.
14358  * - use sext/zext opcodes instead of shifts
14359  * - add OP_ICALL
14360  * - get rid of TEMPLOADs if possible and use vregs instead
14361  * - clean up usage of OP_P/OP_ opcodes
14362  * - cleanup usage of DUMMY_USE
14363  * - cleanup the setting of ins->type for MonoInst's which are pushed on the 
14364  *   stack
14365  * - set the stack type and allocate a dreg in the EMIT_NEW macros
14366  * - get rid of all the <foo>2 stuff when the new JIT is ready.
14367  * - make sure handle_stack_args () is called before the branch is emitted
14368  * - when the new IR is done, get rid of all unused stuff
14369  * - COMPARE/BEQ as separate instructions or unify them ?
14370  *   - keeping them separate allows specialized compare instructions like
14371  *     compare_imm, compare_membase
14372  *   - most back ends unify fp compare+branch, fp compare+ceq
14373  * - integrate mono_save_args into inline_method
14374  * - get rid of the empty bblocks created by MONO_EMIT_NEW_BRACH_BLOCK2
14375  * - handle long shift opts on 32 bit platforms somehow: they require 
14376  *   3 sregs (2 for arg1 and 1 for arg2)
14377  * - make byref a 'normal' type.
14378  * - use vregs for bb->out_stacks if possible, handle_global_vreg will make them a
14379  *   variable if needed.
14380  * - do not start a new IL level bblock when cfg->cbb is changed by a function call
14381  *   like inline_method.
14382  * - remove inlining restrictions
14383  * - fix LNEG and enable cfold of INEG
14384  * - generalize x86 optimizations like ldelema as a peephole optimization
14385  * - add store_mem_imm for amd64
14386  * - optimize the loading of the interruption flag in the managed->native wrappers
14387  * - avoid special handling of OP_NOP in passes
14388  * - move code inserting instructions into one function/macro.
14389  * - try a coalescing phase after liveness analysis
14390  * - add float -> vreg conversion + local optimizations on !x86
14391  * - figure out how to handle decomposed branches during optimizations, ie.
14392  *   compare+branch, op_jump_table+op_br etc.
14393  * - promote RuntimeXHandles to vregs
14394  * - vtype cleanups:
14395  *   - add a NEW_VARLOADA_VREG macro
14396  * - the vtype optimizations are blocked by the LDADDR opcodes generated for 
14397  *   accessing vtype fields.
14398  * - get rid of I8CONST on 64 bit platforms
14399  * - dealing with the increase in code size due to branches created during opcode
14400  *   decomposition:
14401  *   - use extended basic blocks
14402  *     - all parts of the JIT
14403  *     - handle_global_vregs () && local regalloc
14404  *   - avoid introducing global vregs during decomposition, like 'vtable' in isinst
14405  * - sources of increase in code size:
14406  *   - vtypes
14407  *   - long compares
14408  *   - isinst and castclass
14409  *   - lvregs not allocated to global registers even if used multiple times
14410  * - call cctors outside the JIT, to make -v output more readable and JIT timings more
14411  *   meaningful.
14412  * - check for fp stack leakage in other opcodes too. (-> 'exceptions' optimization)
14413  * - add all micro optimizations from the old JIT
14414  * - put tree optimizations into the deadce pass
14415  * - decompose op_start_handler/op_endfilter/op_endfinally earlier using an arch
14416  *   specific function.
14417  * - unify the float comparison opcodes with the other comparison opcodes, i.e.
14418  *   fcompare + branchCC.
14419  * - create a helper function for allocating a stack slot, taking into account 
14420  *   MONO_CFG_HAS_SPILLUP.
14421  * - merge r68207.
14422  * - merge the ia64 switch changes.
14423  * - optimize mono_regstate2_alloc_int/float.
14424  * - fix the pessimistic handling of variables accessed in exception handler blocks.
14425  * - need to write a tree optimization pass, but the creation of trees is difficult, i.e.
14426  *   parts of the tree could be separated by other instructions, killing the tree
14427  *   arguments, or stores killing loads etc. Also, should we fold loads into other
14428  *   instructions if the result of the load is used multiple times ?
14429  * - make the REM_IMM optimization in mini-x86.c arch-independent.
14430  * - LAST MERGE: 108395.
14431  * - when returning vtypes in registers, generate IR and append it to the end of the
14432  *   last bb instead of doing it in the epilog.
14433  * - change the store opcodes so they use sreg1 instead of dreg to store the base register.
14434  */
14435
14436 /*
14437
14438 NOTES
14439 -----
14440
14441 - When to decompose opcodes:
14442   - earlier: this makes some optimizations hard to implement, since the low level IR
14443   no longer contains the neccessary information. But it is easier to do.
14444   - later: harder to implement, enables more optimizations.
14445 - Branches inside bblocks:
14446   - created when decomposing complex opcodes. 
14447     - branches to another bblock: harmless, but not tracked by the branch 
14448       optimizations, so need to branch to a label at the start of the bblock.
14449     - branches to inside the same bblock: very problematic, trips up the local
14450       reg allocator. Can be fixed by spitting the current bblock, but that is a
14451       complex operation, since some local vregs can become global vregs etc.
14452 - Local/global vregs:
14453   - local vregs: temporary vregs used inside one bblock. Assigned to hregs by the
14454     local register allocator.
14455   - global vregs: used in more than one bblock. Have an associated MonoMethodVar
14456     structure, created by mono_create_var (). Assigned to hregs or the stack by
14457     the global register allocator.
14458 - When to do optimizations like alu->alu_imm:
14459   - earlier -> saves work later on since the IR will be smaller/simpler
14460   - later -> can work on more instructions
14461 - Handling of valuetypes:
14462   - When a vtype is pushed on the stack, a new temporary is created, an 
14463     instruction computing its address (LDADDR) is emitted and pushed on
14464     the stack. Need to optimize cases when the vtype is used immediately as in
14465     argument passing, stloc etc.
14466 - Instead of the to_end stuff in the old JIT, simply call the function handling
14467   the values on the stack before emitting the last instruction of the bb.
14468 */
14469
14470 #endif /* DISABLE_JIT */