cc25ae065d6916d516c5c0c1c695b98bb9784f29
[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-internals.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/monitor.h>
60 #include <mono/metadata/debug-mono-symfile.h>
61 #include <mono/utils/mono-compiler.h>
62 #include <mono/utils/mono-memory-model.h>
63 #include <mono/metadata/mono-basic-block.h>
64 #include <mono/metadata/reflection-internals.h>
65
66 #include "trace.h"
67
68 #include "ir-emit.h"
69
70 #include "jit-icalls.h"
71 #include "jit.h"
72 #include "debugger-agent.h"
73 #include "seq-points.h"
74 #include "aot-compiler.h"
75 #include "mini-llvm.h"
76
77 #define BRANCH_COST 10
78 #define INLINE_LENGTH_LIMIT 20
79
80 /* These have 'cfg' as an implicit argument */
81 #define INLINE_FAILURE(msg) do {                                                                        \
82         if ((cfg->method != cfg->current_method) && (cfg->current_method->wrapper_type == MONO_WRAPPER_NONE)) { \
83                 inline_failure (cfg, msg);                                                                              \
84                 goto exception_exit;                                                                                    \
85         } \
86         } while (0)
87 #define CHECK_CFG_EXCEPTION do {\
88                 if (cfg->exception_type != MONO_EXCEPTION_NONE) \
89                         goto exception_exit;                                            \
90         } while (0)
91 #define METHOD_ACCESS_FAILURE(method, cmethod) do {                     \
92                 method_access_failure ((cfg), (method), (cmethod));                     \
93                 goto exception_exit;                                                                            \
94         } while (0)
95 #define FIELD_ACCESS_FAILURE(method, field) do {                                        \
96                 field_access_failure ((cfg), (method), (field));                        \
97                 goto exception_exit;    \
98         } while (0)
99 #define GENERIC_SHARING_FAILURE(opcode) do {            \
100                 if (cfg->gshared) {                                                                     \
101                         gshared_failure (cfg, opcode, __FILE__, __LINE__);      \
102                         goto exception_exit;    \
103                 }                       \
104         } while (0)
105 #define GSHAREDVT_FAILURE(opcode) do {          \
106         if (cfg->gsharedvt) {                                                                                           \
107                 gsharedvt_failure (cfg, opcode, __FILE__, __LINE__);                    \
108                 goto exception_exit;                                                                                    \
109         }                                                                                                                                       \
110         } while (0)
111 #define OUT_OF_MEMORY_FAILURE do {      \
112                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);                \
113                 mono_error_set_out_of_memory (&cfg->error, "");                                 \
114                 goto exception_exit;    \
115         } while (0)
116 #define DISABLE_AOT(cfg) do { \
117                 if ((cfg)->verbose_level >= 2)                                            \
118                         printf ("AOT disabled: %s:%d\n", __FILE__, __LINE__);   \
119                 (cfg)->disable_aot = TRUE;                                                        \
120         } while (0)
121 #define LOAD_ERROR do { \
122                 break_on_unverified ();                                                         \
123                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD); \
124                 goto exception_exit;                                                                    \
125         } while (0)
126
127 #define TYPE_LOAD_ERROR(klass) do { \
128                 cfg->exception_ptr = klass; \
129                 LOAD_ERROR;                                     \
130         } while (0)
131
132 #define CHECK_CFG_ERROR do {\
133                 if (!mono_error_ok (&cfg->error)) { \
134                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);        \
135                         goto mono_error_exit; \
136                 } \
137         } while (0)
138
139 /* Determine whenever 'ins' represents a load of the 'this' argument */
140 #define MONO_CHECK_THIS(ins) (mono_method_signature (cfg->method)->hasthis && ((ins)->opcode == OP_MOVE) && ((ins)->sreg1 == cfg->args [0]->dreg))
141
142 static int ldind_to_load_membase (int opcode);
143 static int stind_to_store_membase (int opcode);
144
145 int mono_op_to_op_imm (int opcode);
146 int mono_op_to_op_imm_noemul (int opcode);
147
148 MONO_API MonoInst* mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig, MonoInst **args);
149
150 static int inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp,
151                                                   guchar *ip, guint real_offset, gboolean inline_always);
152 static MonoInst*
153 emit_llvmonly_virtual_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, int context_used, MonoInst **sp);
154
155 /* helper methods signatures */
156 static MonoMethodSignature *helper_sig_domain_get;
157 static MonoMethodSignature *helper_sig_rgctx_lazy_fetch_trampoline;
158 static MonoMethodSignature *helper_sig_llvmonly_imt_thunk;
159
160 /*
161  * Instruction metadata
162  */
163 #ifdef MINI_OP
164 #undef MINI_OP
165 #endif
166 #ifdef MINI_OP3
167 #undef MINI_OP3
168 #endif
169 #define MINI_OP(a,b,dest,src1,src2) dest, src1, src2, ' ',
170 #define MINI_OP3(a,b,dest,src1,src2,src3) dest, src1, src2, src3,
171 #define NONE ' '
172 #define IREG 'i'
173 #define FREG 'f'
174 #define VREG 'v'
175 #define XREG 'x'
176 #if SIZEOF_REGISTER == 8 && SIZEOF_REGISTER == SIZEOF_VOID_P
177 #define LREG IREG
178 #else
179 #define LREG 'l'
180 #endif
181 /* keep in sync with the enum in mini.h */
182 const char
183 ins_info[] = {
184 #include "mini-ops.h"
185 };
186 #undef MINI_OP
187 #undef MINI_OP3
188
189 #define MINI_OP(a,b,dest,src1,src2) ((src2) != NONE ? 2 : ((src1) != NONE ? 1 : 0)),
190 #define MINI_OP3(a,b,dest,src1,src2,src3) ((src3) != NONE ? 3 : ((src2) != NONE ? 2 : ((src1) != NONE ? 1 : 0))),
191 /* 
192  * This should contain the index of the last sreg + 1. This is not the same
193  * as the number of sregs for opcodes like IA64_CMP_EQ_IMM.
194  */
195 const gint8 ins_sreg_counts[] = {
196 #include "mini-ops.h"
197 };
198 #undef MINI_OP
199 #undef MINI_OP3
200
201 #define MONO_INIT_VARINFO(vi,id) do { \
202         (vi)->range.first_use.pos.bid = 0xffff; \
203         (vi)->reg = -1; \
204         (vi)->idx = (id); \
205 } while (0)
206
207 guint32
208 mono_alloc_ireg (MonoCompile *cfg)
209 {
210         return alloc_ireg (cfg);
211 }
212
213 guint32
214 mono_alloc_lreg (MonoCompile *cfg)
215 {
216         return alloc_lreg (cfg);
217 }
218
219 guint32
220 mono_alloc_freg (MonoCompile *cfg)
221 {
222         return alloc_freg (cfg);
223 }
224
225 guint32
226 mono_alloc_preg (MonoCompile *cfg)
227 {
228         return alloc_preg (cfg);
229 }
230
231 guint32
232 mono_alloc_dreg (MonoCompile *cfg, MonoStackType stack_type)
233 {
234         return alloc_dreg (cfg, stack_type);
235 }
236
237 /*
238  * mono_alloc_ireg_ref:
239  *
240  *   Allocate an IREG, and mark it as holding a GC ref.
241  */
242 guint32
243 mono_alloc_ireg_ref (MonoCompile *cfg)
244 {
245         return alloc_ireg_ref (cfg);
246 }
247
248 /*
249  * mono_alloc_ireg_mp:
250  *
251  *   Allocate an IREG, and mark it as holding a managed pointer.
252  */
253 guint32
254 mono_alloc_ireg_mp (MonoCompile *cfg)
255 {
256         return alloc_ireg_mp (cfg);
257 }
258
259 /*
260  * mono_alloc_ireg_copy:
261  *
262  *   Allocate an IREG with the same GC type as VREG.
263  */
264 guint32
265 mono_alloc_ireg_copy (MonoCompile *cfg, guint32 vreg)
266 {
267         if (vreg_is_ref (cfg, vreg))
268                 return alloc_ireg_ref (cfg);
269         else if (vreg_is_mp (cfg, vreg))
270                 return alloc_ireg_mp (cfg);
271         else
272                 return alloc_ireg (cfg);
273 }
274
275 guint
276 mono_type_to_regmove (MonoCompile *cfg, MonoType *type)
277 {
278         if (type->byref)
279                 return OP_MOVE;
280
281         type = mini_get_underlying_type (type);
282 handle_enum:
283         switch (type->type) {
284         case MONO_TYPE_I1:
285         case MONO_TYPE_U1:
286                 return OP_MOVE;
287         case MONO_TYPE_I2:
288         case MONO_TYPE_U2:
289                 return OP_MOVE;
290         case MONO_TYPE_I4:
291         case MONO_TYPE_U4:
292                 return OP_MOVE;
293         case MONO_TYPE_I:
294         case MONO_TYPE_U:
295         case MONO_TYPE_PTR:
296         case MONO_TYPE_FNPTR:
297                 return OP_MOVE;
298         case MONO_TYPE_CLASS:
299         case MONO_TYPE_STRING:
300         case MONO_TYPE_OBJECT:
301         case MONO_TYPE_SZARRAY:
302         case MONO_TYPE_ARRAY:    
303                 return OP_MOVE;
304         case MONO_TYPE_I8:
305         case MONO_TYPE_U8:
306 #if SIZEOF_REGISTER == 8
307                 return OP_MOVE;
308 #else
309                 return OP_LMOVE;
310 #endif
311         case MONO_TYPE_R4:
312                 return cfg->r4fp ? OP_RMOVE : OP_FMOVE;
313         case MONO_TYPE_R8:
314                 return OP_FMOVE;
315         case MONO_TYPE_VALUETYPE:
316                 if (type->data.klass->enumtype) {
317                         type = mono_class_enum_basetype (type->data.klass);
318                         goto handle_enum;
319                 }
320                 if (MONO_CLASS_IS_SIMD (cfg, mono_class_from_mono_type (type)))
321                         return OP_XMOVE;
322                 return OP_VMOVE;
323         case MONO_TYPE_TYPEDBYREF:
324                 return OP_VMOVE;
325         case MONO_TYPE_GENERICINST:
326                 type = &type->data.generic_class->container_class->byval_arg;
327                 goto handle_enum;
328         case MONO_TYPE_VAR:
329         case MONO_TYPE_MVAR:
330                 g_assert (cfg->gshared);
331                 if (mini_type_var_is_vt (type))
332                         return OP_VMOVE;
333                 else
334                         return mono_type_to_regmove (cfg, mini_get_underlying_type (type));
335         default:
336                 g_error ("unknown type 0x%02x in type_to_regstore", type->type);
337         }
338         return -1;
339 }
340
341 void
342 mono_print_bb (MonoBasicBlock *bb, const char *msg)
343 {
344         int i;
345         MonoInst *tree;
346
347         printf ("\n%s %d: [IN: ", msg, bb->block_num);
348         for (i = 0; i < bb->in_count; ++i)
349                 printf (" BB%d(%d)", bb->in_bb [i]->block_num, bb->in_bb [i]->dfn);
350         printf (", OUT: ");
351         for (i = 0; i < bb->out_count; ++i)
352                 printf (" BB%d(%d)", bb->out_bb [i]->block_num, bb->out_bb [i]->dfn);
353         printf (" ]\n");
354         for (tree = bb->code; tree; tree = tree->next)
355                 mono_print_ins_index (-1, tree);
356 }
357
358 void
359 mono_create_helper_signatures (void)
360 {
361         helper_sig_domain_get = mono_create_icall_signature ("ptr");
362         helper_sig_rgctx_lazy_fetch_trampoline = mono_create_icall_signature ("ptr ptr");
363         helper_sig_llvmonly_imt_thunk = mono_create_icall_signature ("ptr ptr ptr");
364 }
365
366 static MONO_NEVER_INLINE void
367 break_on_unverified (void)
368 {
369         if (mini_get_debug_options ()->break_on_unverified)
370                 G_BREAKPOINT ();
371 }
372
373 static MONO_NEVER_INLINE void
374 method_access_failure (MonoCompile *cfg, MonoMethod *method, MonoMethod *cil_method)
375 {
376         char *method_fname = mono_method_full_name (method, TRUE);
377         char *cil_method_fname = mono_method_full_name (cil_method, TRUE);
378         mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
379         mono_error_set_generic_error (&cfg->error, "System", "MethodAccessException", "Method `%s' is inaccessible from method `%s'\n", cil_method_fname, method_fname);
380         g_free (method_fname);
381         g_free (cil_method_fname);
382 }
383
384 static MONO_NEVER_INLINE void
385 field_access_failure (MonoCompile *cfg, MonoMethod *method, MonoClassField *field)
386 {
387         char *method_fname = mono_method_full_name (method, TRUE);
388         char *field_fname = mono_field_full_name (field);
389         mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
390         mono_error_set_generic_error (&cfg->error, "System", "FieldAccessException", "Field `%s' is inaccessible from method `%s'\n", field_fname, method_fname);
391         g_free (method_fname);
392         g_free (field_fname);
393 }
394
395 static MONO_NEVER_INLINE void
396 inline_failure (MonoCompile *cfg, const char *msg)
397 {
398         if (cfg->verbose_level >= 2)
399                 printf ("inline failed: %s\n", msg);
400         mono_cfg_set_exception (cfg, MONO_EXCEPTION_INLINE_FAILED);
401 }
402
403 static MONO_NEVER_INLINE void
404 gshared_failure (MonoCompile *cfg, int opcode, const char *file, int line)
405 {
406         if (cfg->verbose_level > 2)                                                                                     \
407                 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);
408         mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED);
409 }
410
411 static MONO_NEVER_INLINE void
412 gsharedvt_failure (MonoCompile *cfg, int opcode, const char *file, int line)
413 {
414         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);
415         if (cfg->verbose_level >= 2)
416                 printf ("%s\n", cfg->exception_message);
417         mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED);
418 }
419
420 /*
421  * When using gsharedvt, some instatiations might be verifiable, and some might be not. i.e. 
422  * foo<T> (int i) { ldarg.0; box T; }
423  */
424 #define UNVERIFIED do { \
425         if (cfg->gsharedvt) { \
426                 if (cfg->verbose_level > 2)                                                                     \
427                         printf ("gsharedvt method failed to verify, falling back to instantiation.\n"); \
428                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED); \
429                 goto exception_exit;                                                                                    \
430         }                                                                                                                                       \
431         break_on_unverified ();                                                                                         \
432         goto unverified;                                                                                                        \
433 } while (0)
434
435 #define GET_BBLOCK(cfg,tblock,ip) do {  \
436                 (tblock) = cfg->cil_offset_to_bb [(ip) - cfg->cil_start]; \
437                 if (!(tblock)) {        \
438                         if ((ip) >= end || (ip) < header->code) UNVERIFIED; \
439             NEW_BBLOCK (cfg, (tblock)); \
440                         (tblock)->cil_code = (ip);      \
441                         ADD_BBLOCK (cfg, (tblock));     \
442                 } \
443         } while (0)
444
445 #if defined(TARGET_X86) || defined(TARGET_AMD64)
446 #define EMIT_NEW_X86_LEA(cfg,dest,sr1,sr2,shift,imm) do { \
447                 MONO_INST_NEW (cfg, dest, OP_X86_LEA); \
448                 (dest)->dreg = alloc_ireg_mp ((cfg)); \
449                 (dest)->sreg1 = (sr1); \
450                 (dest)->sreg2 = (sr2); \
451                 (dest)->inst_imm = (imm); \
452                 (dest)->backend.shift_amount = (shift); \
453                 MONO_ADD_INS ((cfg)->cbb, (dest)); \
454         } while (0)
455 #endif
456
457 /* Emit conversions so both operands of a binary opcode are of the same type */
458 static void
459 add_widen_op (MonoCompile *cfg, MonoInst *ins, MonoInst **arg1_ref, MonoInst **arg2_ref)
460 {
461         MonoInst *arg1 = *arg1_ref;
462         MonoInst *arg2 = *arg2_ref;
463
464         if (cfg->r4fp &&
465                 ((arg1->type == STACK_R4 && arg2->type == STACK_R8) ||
466                  (arg1->type == STACK_R8 && arg2->type == STACK_R4))) {
467                 MonoInst *conv;
468
469                 /* Mixing r4/r8 is allowed by the spec */
470                 if (arg1->type == STACK_R4) {
471                         int dreg = alloc_freg (cfg);
472
473                         EMIT_NEW_UNALU (cfg, conv, OP_RCONV_TO_R8, dreg, arg1->dreg);
474                         conv->type = STACK_R8;
475                         ins->sreg1 = dreg;
476                         *arg1_ref = conv;
477                 }
478                 if (arg2->type == STACK_R4) {
479                         int dreg = alloc_freg (cfg);
480
481                         EMIT_NEW_UNALU (cfg, conv, OP_RCONV_TO_R8, dreg, arg2->dreg);
482                         conv->type = STACK_R8;
483                         ins->sreg2 = dreg;
484                         *arg2_ref = conv;
485                 }
486         }
487
488 #if SIZEOF_REGISTER == 8
489         /* FIXME: Need to add many more cases */
490         if ((arg1)->type == STACK_PTR && (arg2)->type == STACK_I4) {
491                 MonoInst *widen;
492
493                 int dr = alloc_preg (cfg);
494                 EMIT_NEW_UNALU (cfg, widen, OP_SEXT_I4, dr, (arg2)->dreg);
495                 (ins)->sreg2 = widen->dreg;
496         }
497 #endif
498 }
499
500 #define ADD_BINOP(op) do {      \
501                 MONO_INST_NEW (cfg, ins, (op)); \
502                 sp -= 2;        \
503                 ins->sreg1 = sp [0]->dreg;      \
504                 ins->sreg2 = sp [1]->dreg;      \
505                 type_from_op (cfg, ins, sp [0], sp [1]);        \
506                 CHECK_TYPE (ins);       \
507                 /* Have to insert a widening op */               \
508         add_widen_op (cfg, ins, &sp [0], &sp [1]);               \
509         ins->dreg = alloc_dreg ((cfg), (MonoStackType)(ins)->type); \
510         MONO_ADD_INS ((cfg)->cbb, (ins)); \
511         *sp++ = mono_decompose_opcode ((cfg), (ins));   \
512         } while (0)
513
514 #define ADD_UNOP(op) do {       \
515                 MONO_INST_NEW (cfg, ins, (op)); \
516                 sp--;   \
517                 ins->sreg1 = sp [0]->dreg;      \
518                 type_from_op (cfg, ins, sp [0], NULL);  \
519                 CHECK_TYPE (ins);       \
520         (ins)->dreg = alloc_dreg ((cfg), (MonoStackType)(ins)->type); \
521         MONO_ADD_INS ((cfg)->cbb, (ins)); \
522                 *sp++ = mono_decompose_opcode (cfg, ins);       \
523         } while (0)
524
525 #define ADD_BINCOND(next_block) do {    \
526                 MonoInst *cmp;  \
527                 sp -= 2; \
528                 MONO_INST_NEW(cfg, cmp, OP_COMPARE);    \
529                 cmp->sreg1 = sp [0]->dreg;      \
530                 cmp->sreg2 = sp [1]->dreg;      \
531                 type_from_op (cfg, cmp, sp [0], sp [1]);        \
532                 CHECK_TYPE (cmp);       \
533                 add_widen_op (cfg, cmp, &sp [0], &sp [1]);                                              \
534                 type_from_op (cfg, ins, sp [0], sp [1]);                                                        \
535                 ins->inst_many_bb = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);   \
536                 GET_BBLOCK (cfg, tblock, target);               \
537                 link_bblock (cfg, cfg->cbb, tblock);    \
538                 ins->inst_true_bb = tblock;     \
539                 if ((next_block)) {     \
540                         link_bblock (cfg, cfg->cbb, (next_block));      \
541                         ins->inst_false_bb = (next_block);      \
542                         start_new_bblock = 1;   \
543                 } else {        \
544                         GET_BBLOCK (cfg, tblock, ip);           \
545                         link_bblock (cfg, cfg->cbb, tblock);    \
546                         ins->inst_false_bb = tblock;    \
547                         start_new_bblock = 2;   \
548                 }       \
549                 if (sp != stack_start) {                                                                        \
550                     handle_stack_args (cfg, stack_start, sp - stack_start); \
551                         CHECK_UNVERIFIABLE (cfg); \
552                 } \
553         MONO_ADD_INS (cfg->cbb, cmp); \
554                 MONO_ADD_INS (cfg->cbb, ins);   \
555         } while (0)
556
557 /* *
558  * link_bblock: Links two basic blocks
559  *
560  * links two basic blocks in the control flow graph, the 'from'
561  * argument is the starting block and the 'to' argument is the block
562  * the control flow ends to after 'from'.
563  */
564 static void
565 link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
566 {
567         MonoBasicBlock **newa;
568         int i, found;
569
570 #if 0
571         if (from->cil_code) {
572                 if (to->cil_code)
573                         printf ("edge from IL%04x to IL_%04x\n", from->cil_code - cfg->cil_code, to->cil_code - cfg->cil_code);
574                 else
575                         printf ("edge from IL%04x to exit\n", from->cil_code - cfg->cil_code);
576         } else {
577                 if (to->cil_code)
578                         printf ("edge from entry to IL_%04x\n", to->cil_code - cfg->cil_code);
579                 else
580                         printf ("edge from entry to exit\n");
581         }
582 #endif
583
584         found = FALSE;
585         for (i = 0; i < from->out_count; ++i) {
586                 if (to == from->out_bb [i]) {
587                         found = TRUE;
588                         break;
589                 }
590         }
591         if (!found) {
592                 newa = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (from->out_count + 1));
593                 for (i = 0; i < from->out_count; ++i) {
594                         newa [i] = from->out_bb [i];
595                 }
596                 newa [i] = to;
597                 from->out_count++;
598                 from->out_bb = newa;
599         }
600
601         found = FALSE;
602         for (i = 0; i < to->in_count; ++i) {
603                 if (from == to->in_bb [i]) {
604                         found = TRUE;
605                         break;
606                 }
607         }
608         if (!found) {
609                 newa = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (to->in_count + 1));
610                 for (i = 0; i < to->in_count; ++i) {
611                         newa [i] = to->in_bb [i];
612                 }
613                 newa [i] = from;
614                 to->in_count++;
615                 to->in_bb = newa;
616         }
617 }
618
619 void
620 mono_link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
621 {
622         link_bblock (cfg, from, to);
623 }
624
625 /**
626  * mono_find_block_region:
627  *
628  *   We mark each basic block with a region ID. We use that to avoid BB
629  *   optimizations when blocks are in different regions.
630  *
631  * Returns:
632  *   A region token that encodes where this region is, and information
633  *   about the clause owner for this block.
634  *
635  *   The region encodes the try/catch/filter clause that owns this block
636  *   as well as the type.  -1 is a special value that represents a block
637  *   that is in none of try/catch/filter.
638  */
639 static int
640 mono_find_block_region (MonoCompile *cfg, int offset)
641 {
642         MonoMethodHeader *header = cfg->header;
643         MonoExceptionClause *clause;
644         int i;
645
646         for (i = 0; i < header->num_clauses; ++i) {
647                 clause = &header->clauses [i];
648                 if ((clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) && (offset >= clause->data.filter_offset) &&
649                     (offset < (clause->handler_offset)))
650                         return ((i + 1) << 8) | MONO_REGION_FILTER | clause->flags;
651                            
652                 if (MONO_OFFSET_IN_HANDLER (clause, offset)) {
653                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY)
654                                 return ((i + 1) << 8) | MONO_REGION_FINALLY | clause->flags;
655                         else if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
656                                 return ((i + 1) << 8) | MONO_REGION_FAULT | clause->flags;
657                         else
658                                 return ((i + 1) << 8) | MONO_REGION_CATCH | clause->flags;
659                 }
660         }
661         for (i = 0; i < header->num_clauses; ++i) {
662                 clause = &header->clauses [i];
663
664                 if (MONO_OFFSET_IN_CLAUSE (clause, offset))
665                         return ((i + 1) << 8) | clause->flags;
666         }
667
668         return -1;
669 }
670
671 static GList*
672 mono_find_final_block (MonoCompile *cfg, unsigned char *ip, unsigned char *target, int type)
673 {
674         MonoMethodHeader *header = cfg->header;
675         MonoExceptionClause *clause;
676         int i;
677         GList *res = NULL;
678
679         for (i = 0; i < header->num_clauses; ++i) {
680                 clause = &header->clauses [i];
681                 if (MONO_OFFSET_IN_CLAUSE (clause, (ip - header->code)) && 
682                     (!MONO_OFFSET_IN_CLAUSE (clause, (target - header->code)))) {
683                         if (clause->flags == type)
684                                 res = g_list_append (res, clause);
685                 }
686         }
687         return res;
688 }
689
690 static void
691 mono_create_spvar_for_region (MonoCompile *cfg, int region)
692 {
693         MonoInst *var;
694
695         var = (MonoInst *)g_hash_table_lookup (cfg->spvars, GINT_TO_POINTER (region));
696         if (var)
697                 return;
698
699         var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
700         /* prevent it from being register allocated */
701         var->flags |= MONO_INST_VOLATILE;
702
703         g_hash_table_insert (cfg->spvars, GINT_TO_POINTER (region), var);
704 }
705
706 MonoInst *
707 mono_find_exvar_for_offset (MonoCompile *cfg, int offset)
708 {
709         return (MonoInst *)g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
710 }
711
712 static MonoInst*
713 mono_create_exvar_for_offset (MonoCompile *cfg, int offset)
714 {
715         MonoInst *var;
716
717         var = (MonoInst *)g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
718         if (var)
719                 return var;
720
721         var = mono_compile_create_var (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL);
722         /* prevent it from being register allocated */
723         var->flags |= MONO_INST_VOLATILE;
724
725         g_hash_table_insert (cfg->exvars, GINT_TO_POINTER (offset), var);
726
727         return var;
728 }
729
730 /*
731  * Returns the type used in the eval stack when @type is loaded.
732  * FIXME: return a MonoType/MonoClass for the byref and VALUETYPE cases.
733  */
734 void
735 type_to_eval_stack_type (MonoCompile *cfg, MonoType *type, MonoInst *inst)
736 {
737         MonoClass *klass;
738
739         type = mini_get_underlying_type (type);
740         inst->klass = klass = mono_class_from_mono_type (type);
741         if (type->byref) {
742                 inst->type = STACK_MP;
743                 return;
744         }
745
746 handle_enum:
747         switch (type->type) {
748         case MONO_TYPE_VOID:
749                 inst->type = STACK_INV;
750                 return;
751         case MONO_TYPE_I1:
752         case MONO_TYPE_U1:
753         case MONO_TYPE_I2:
754         case MONO_TYPE_U2:
755         case MONO_TYPE_I4:
756         case MONO_TYPE_U4:
757                 inst->type = STACK_I4;
758                 return;
759         case MONO_TYPE_I:
760         case MONO_TYPE_U:
761         case MONO_TYPE_PTR:
762         case MONO_TYPE_FNPTR:
763                 inst->type = STACK_PTR;
764                 return;
765         case MONO_TYPE_CLASS:
766         case MONO_TYPE_STRING:
767         case MONO_TYPE_OBJECT:
768         case MONO_TYPE_SZARRAY:
769         case MONO_TYPE_ARRAY:    
770                 inst->type = STACK_OBJ;
771                 return;
772         case MONO_TYPE_I8:
773         case MONO_TYPE_U8:
774                 inst->type = STACK_I8;
775                 return;
776         case MONO_TYPE_R4:
777                 inst->type = cfg->r4_stack_type;
778                 break;
779         case MONO_TYPE_R8:
780                 inst->type = STACK_R8;
781                 return;
782         case MONO_TYPE_VALUETYPE:
783                 if (type->data.klass->enumtype) {
784                         type = mono_class_enum_basetype (type->data.klass);
785                         goto handle_enum;
786                 } else {
787                         inst->klass = klass;
788                         inst->type = STACK_VTYPE;
789                         return;
790                 }
791         case MONO_TYPE_TYPEDBYREF:
792                 inst->klass = mono_defaults.typed_reference_class;
793                 inst->type = STACK_VTYPE;
794                 return;
795         case MONO_TYPE_GENERICINST:
796                 type = &type->data.generic_class->container_class->byval_arg;
797                 goto handle_enum;
798         case MONO_TYPE_VAR:
799         case MONO_TYPE_MVAR:
800                 g_assert (cfg->gshared);
801                 if (mini_is_gsharedvt_type (type)) {
802                         g_assert (cfg->gsharedvt);
803                         inst->type = STACK_VTYPE;
804                 } else {
805                         type_to_eval_stack_type (cfg, mini_get_underlying_type (type), inst);
806                 }
807                 return;
808         default:
809                 g_error ("unknown type 0x%02x in eval stack type", type->type);
810         }
811 }
812
813 /*
814  * The following tables are used to quickly validate the IL code in type_from_op ().
815  */
816 static const char
817 bin_num_table [STACK_MAX] [STACK_MAX] = {
818         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
819         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
820         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
821         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
822         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_R8,  STACK_INV, STACK_INV, STACK_INV, STACK_R8},
823         {STACK_INV, STACK_MP,  STACK_INV, STACK_MP,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV},
824         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
825         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
826         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_R8, STACK_INV, STACK_INV, STACK_INV, STACK_R4}
827 };
828
829 static const char 
830 neg_table [] = {
831         STACK_INV, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_INV, STACK_INV, STACK_INV, STACK_R4
832 };
833
834 /* reduce the size of this table */
835 static const char
836 bin_int_table [STACK_MAX] [STACK_MAX] = {
837         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
838         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
839         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
840         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
841         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
842         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
843         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
844         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
845 };
846
847 static const char
848 bin_comp_table [STACK_MAX] [STACK_MAX] = {
849 /*      Inv i  L  p  F  &  O  vt r4 */
850         {0},
851         {0, 1, 0, 1, 0, 0, 0, 0}, /* i, int32 */
852         {0, 0, 1, 0, 0, 0, 0, 0}, /* L, int64 */
853         {0, 1, 0, 1, 0, 2, 4, 0}, /* p, ptr */
854         {0, 0, 0, 0, 1, 0, 0, 0, 1}, /* F, R8 */
855         {0, 0, 0, 2, 0, 1, 0, 0}, /* &, managed pointer */
856         {0, 0, 0, 4, 0, 0, 3, 0}, /* O, reference */
857         {0, 0, 0, 0, 0, 0, 0, 0}, /* vt value type */
858         {0, 0, 0, 0, 1, 0, 0, 0, 1}, /* r, r4 */
859 };
860
861 /* reduce the size of this table */
862 static const char
863 shift_table [STACK_MAX] [STACK_MAX] = {
864         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
865         {STACK_INV, STACK_I4,  STACK_INV, STACK_I4,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
866         {STACK_INV, STACK_I8,  STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
867         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
868         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
869         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
870         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
871         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
872 };
873
874 /*
875  * Tables to map from the non-specific opcode to the matching
876  * type-specific opcode.
877  */
878 /* handles from CEE_ADD to CEE_SHR_UN (CEE_REM_UN for floats) */
879 static const guint16
880 binops_op_map [STACK_MAX] = {
881         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
882 };
883
884 /* handles from CEE_NEG to CEE_CONV_U8 */
885 static const guint16
886 unops_op_map [STACK_MAX] = {
887         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
888 };
889
890 /* handles from CEE_CONV_U2 to CEE_SUB_OVF_UN */
891 static const guint16
892 ovfops_op_map [STACK_MAX] = {
893         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
894 };
895
896 /* handles from CEE_CONV_OVF_I1_UN to CEE_CONV_OVF_U_UN */
897 static const guint16
898 ovf2ops_op_map [STACK_MAX] = {
899         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
900 };
901
902 /* handles from CEE_CONV_OVF_I1 to CEE_CONV_OVF_U8 */
903 static const guint16
904 ovf3ops_op_map [STACK_MAX] = {
905         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
906 };
907
908 /* handles from CEE_BEQ to CEE_BLT_UN */
909 static const guint16
910 beqops_op_map [STACK_MAX] = {
911         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
912 };
913
914 /* handles from CEE_CEQ to CEE_CLT_UN */
915 static const guint16
916 ceqops_op_map [STACK_MAX] = {
917         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
918 };
919
920 /*
921  * Sets ins->type (the type on the eval stack) according to the
922  * type of the opcode and the arguments to it.
923  * Invalid IL code is marked by setting ins->type to the invalid value STACK_INV.
924  *
925  * FIXME: this function sets ins->type unconditionally in some cases, but
926  * it should set it to invalid for some types (a conv.x on an object)
927  */
928 static void
929 type_from_op (MonoCompile *cfg, MonoInst *ins, MonoInst *src1, MonoInst *src2)
930 {
931         switch (ins->opcode) {
932         /* binops */
933         case CEE_ADD:
934         case CEE_SUB:
935         case CEE_MUL:
936         case CEE_DIV:
937         case CEE_REM:
938                 /* FIXME: check unverifiable args for STACK_MP */
939                 ins->type = bin_num_table [src1->type] [src2->type];
940                 ins->opcode += binops_op_map [ins->type];
941                 break;
942         case CEE_DIV_UN:
943         case CEE_REM_UN:
944         case CEE_AND:
945         case CEE_OR:
946         case CEE_XOR:
947                 ins->type = bin_int_table [src1->type] [src2->type];
948                 ins->opcode += binops_op_map [ins->type];
949                 break;
950         case CEE_SHL:
951         case CEE_SHR:
952         case CEE_SHR_UN:
953                 ins->type = shift_table [src1->type] [src2->type];
954                 ins->opcode += binops_op_map [ins->type];
955                 break;
956         case OP_COMPARE:
957         case OP_LCOMPARE:
958         case OP_ICOMPARE:
959                 ins->type = bin_comp_table [src1->type] [src2->type] ? STACK_I4: STACK_INV;
960                 if ((src1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((src1->type == STACK_PTR) || (src1->type == STACK_OBJ) || (src1->type == STACK_MP))))
961                         ins->opcode = OP_LCOMPARE;
962                 else if (src1->type == STACK_R4)
963                         ins->opcode = OP_RCOMPARE;
964                 else if (src1->type == STACK_R8)
965                         ins->opcode = OP_FCOMPARE;
966                 else
967                         ins->opcode = OP_ICOMPARE;
968                 break;
969         case OP_ICOMPARE_IMM:
970                 ins->type = bin_comp_table [src1->type] [src1->type] ? STACK_I4 : STACK_INV;
971                 if ((src1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((src1->type == STACK_PTR) || (src1->type == STACK_OBJ) || (src1->type == STACK_MP))))
972                         ins->opcode = OP_LCOMPARE_IMM;          
973                 break;
974         case CEE_BEQ:
975         case CEE_BGE:
976         case CEE_BGT:
977         case CEE_BLE:
978         case CEE_BLT:
979         case CEE_BNE_UN:
980         case CEE_BGE_UN:
981         case CEE_BGT_UN:
982         case CEE_BLE_UN:
983         case CEE_BLT_UN:
984                 ins->opcode += beqops_op_map [src1->type];
985                 break;
986         case OP_CEQ:
987                 ins->type = bin_comp_table [src1->type] [src2->type] ? STACK_I4: STACK_INV;
988                 ins->opcode += ceqops_op_map [src1->type];
989                 break;
990         case OP_CGT:
991         case OP_CGT_UN:
992         case OP_CLT:
993         case OP_CLT_UN:
994                 ins->type = (bin_comp_table [src1->type] [src2->type] & 1) ? STACK_I4: STACK_INV;
995                 ins->opcode += ceqops_op_map [src1->type];
996                 break;
997         /* unops */
998         case CEE_NEG:
999                 ins->type = neg_table [src1->type];
1000                 ins->opcode += unops_op_map [ins->type];
1001                 break;
1002         case CEE_NOT:
1003                 if (src1->type >= STACK_I4 && src1->type <= STACK_PTR)
1004                         ins->type = src1->type;
1005                 else
1006                         ins->type = STACK_INV;
1007                 ins->opcode += unops_op_map [ins->type];
1008                 break;
1009         case CEE_CONV_I1:
1010         case CEE_CONV_I2:
1011         case CEE_CONV_I4:
1012         case CEE_CONV_U4:
1013                 ins->type = STACK_I4;
1014                 ins->opcode += unops_op_map [src1->type];
1015                 break;
1016         case CEE_CONV_R_UN:
1017                 ins->type = STACK_R8;
1018                 switch (src1->type) {
1019                 case STACK_I4:
1020                 case STACK_PTR:
1021                         ins->opcode = OP_ICONV_TO_R_UN;
1022                         break;
1023                 case STACK_I8:
1024                         ins->opcode = OP_LCONV_TO_R_UN; 
1025                         break;
1026                 }
1027                 break;
1028         case CEE_CONV_OVF_I1:
1029         case CEE_CONV_OVF_U1:
1030         case CEE_CONV_OVF_I2:
1031         case CEE_CONV_OVF_U2:
1032         case CEE_CONV_OVF_I4:
1033         case CEE_CONV_OVF_U4:
1034                 ins->type = STACK_I4;
1035                 ins->opcode += ovf3ops_op_map [src1->type];
1036                 break;
1037         case CEE_CONV_OVF_I_UN:
1038         case CEE_CONV_OVF_U_UN:
1039                 ins->type = STACK_PTR;
1040                 ins->opcode += ovf2ops_op_map [src1->type];
1041                 break;
1042         case CEE_CONV_OVF_I1_UN:
1043         case CEE_CONV_OVF_I2_UN:
1044         case CEE_CONV_OVF_I4_UN:
1045         case CEE_CONV_OVF_U1_UN:
1046         case CEE_CONV_OVF_U2_UN:
1047         case CEE_CONV_OVF_U4_UN:
1048                 ins->type = STACK_I4;
1049                 ins->opcode += ovf2ops_op_map [src1->type];
1050                 break;
1051         case CEE_CONV_U:
1052                 ins->type = STACK_PTR;
1053                 switch (src1->type) {
1054                 case STACK_I4:
1055                         ins->opcode = OP_ICONV_TO_U;
1056                         break;
1057                 case STACK_PTR:
1058                 case STACK_MP:
1059 #if SIZEOF_VOID_P == 8
1060                         ins->opcode = OP_LCONV_TO_U;
1061 #else
1062                         ins->opcode = OP_MOVE;
1063 #endif
1064                         break;
1065                 case STACK_I8:
1066                         ins->opcode = OP_LCONV_TO_U;
1067                         break;
1068                 case STACK_R8:
1069                         ins->opcode = OP_FCONV_TO_U;
1070                         break;
1071                 }
1072                 break;
1073         case CEE_CONV_I8:
1074         case CEE_CONV_U8:
1075                 ins->type = STACK_I8;
1076                 ins->opcode += unops_op_map [src1->type];
1077                 break;
1078         case CEE_CONV_OVF_I8:
1079         case CEE_CONV_OVF_U8:
1080                 ins->type = STACK_I8;
1081                 ins->opcode += ovf3ops_op_map [src1->type];
1082                 break;
1083         case CEE_CONV_OVF_U8_UN:
1084         case CEE_CONV_OVF_I8_UN:
1085                 ins->type = STACK_I8;
1086                 ins->opcode += ovf2ops_op_map [src1->type];
1087                 break;
1088         case CEE_CONV_R4:
1089                 ins->type = cfg->r4_stack_type;
1090                 ins->opcode += unops_op_map [src1->type];
1091                 break;
1092         case CEE_CONV_R8:
1093                 ins->type = STACK_R8;
1094                 ins->opcode += unops_op_map [src1->type];
1095                 break;
1096         case OP_CKFINITE:
1097                 ins->type = STACK_R8;           
1098                 break;
1099         case CEE_CONV_U2:
1100         case CEE_CONV_U1:
1101                 ins->type = STACK_I4;
1102                 ins->opcode += ovfops_op_map [src1->type];
1103                 break;
1104         case CEE_CONV_I:
1105         case CEE_CONV_OVF_I:
1106         case CEE_CONV_OVF_U:
1107                 ins->type = STACK_PTR;
1108                 ins->opcode += ovfops_op_map [src1->type];
1109                 break;
1110         case CEE_ADD_OVF:
1111         case CEE_ADD_OVF_UN:
1112         case CEE_MUL_OVF:
1113         case CEE_MUL_OVF_UN:
1114         case CEE_SUB_OVF:
1115         case CEE_SUB_OVF_UN:
1116                 ins->type = bin_num_table [src1->type] [src2->type];
1117                 ins->opcode += ovfops_op_map [src1->type];
1118                 if (ins->type == STACK_R8)
1119                         ins->type = STACK_INV;
1120                 break;
1121         case OP_LOAD_MEMBASE:
1122                 ins->type = STACK_PTR;
1123                 break;
1124         case OP_LOADI1_MEMBASE:
1125         case OP_LOADU1_MEMBASE:
1126         case OP_LOADI2_MEMBASE:
1127         case OP_LOADU2_MEMBASE:
1128         case OP_LOADI4_MEMBASE:
1129         case OP_LOADU4_MEMBASE:
1130                 ins->type = STACK_PTR;
1131                 break;
1132         case OP_LOADI8_MEMBASE:
1133                 ins->type = STACK_I8;
1134                 break;
1135         case OP_LOADR4_MEMBASE:
1136                 ins->type = cfg->r4_stack_type;
1137                 break;
1138         case OP_LOADR8_MEMBASE:
1139                 ins->type = STACK_R8;
1140                 break;
1141         default:
1142                 g_error ("opcode 0x%04x not handled in type from op", ins->opcode);
1143                 break;
1144         }
1145
1146         if (ins->type == STACK_MP)
1147                 ins->klass = mono_defaults.object_class;
1148 }
1149
1150 static const char 
1151 ldind_type [] = {
1152         STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_R8, STACK_OBJ
1153 };
1154
1155 #if 0
1156
1157 static const char
1158 param_table [STACK_MAX] [STACK_MAX] = {
1159         {0},
1160 };
1161
1162 static int
1163 check_values_to_signature (MonoInst *args, MonoType *this_ins, MonoMethodSignature *sig)
1164 {
1165         int i;
1166
1167         if (sig->hasthis) {
1168                 switch (args->type) {
1169                 case STACK_I4:
1170                 case STACK_I8:
1171                 case STACK_R8:
1172                 case STACK_VTYPE:
1173                 case STACK_INV:
1174                         return 0;
1175                 }
1176                 args++;
1177         }
1178         for (i = 0; i < sig->param_count; ++i) {
1179                 switch (args [i].type) {
1180                 case STACK_INV:
1181                         return 0;
1182                 case STACK_MP:
1183                         if (!sig->params [i]->byref)
1184                                 return 0;
1185                         continue;
1186                 case STACK_OBJ:
1187                         if (sig->params [i]->byref)
1188                                 return 0;
1189                         switch (sig->params [i]->type) {
1190                         case MONO_TYPE_CLASS:
1191                         case MONO_TYPE_STRING:
1192                         case MONO_TYPE_OBJECT:
1193                         case MONO_TYPE_SZARRAY:
1194                         case MONO_TYPE_ARRAY:
1195                                 break;
1196                         default:
1197                                 return 0;
1198                         }
1199                         continue;
1200                 case STACK_R8:
1201                         if (sig->params [i]->byref)
1202                                 return 0;
1203                         if (sig->params [i]->type != MONO_TYPE_R4 && sig->params [i]->type != MONO_TYPE_R8)
1204                                 return 0;
1205                         continue;
1206                 case STACK_PTR:
1207                 case STACK_I4:
1208                 case STACK_I8:
1209                 case STACK_VTYPE:
1210                         break;
1211                 }
1212                 /*if (!param_table [args [i].type] [sig->params [i]->type])
1213                         return 0;*/
1214         }
1215         return 1;
1216 }
1217 #endif
1218
1219 /*
1220  * When we need a pointer to the current domain many times in a method, we
1221  * call mono_domain_get() once and we store the result in a local variable.
1222  * This function returns the variable that represents the MonoDomain*.
1223  */
1224 inline static MonoInst *
1225 mono_get_domainvar (MonoCompile *cfg)
1226 {
1227         if (!cfg->domainvar)
1228                 cfg->domainvar = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1229         return cfg->domainvar;
1230 }
1231
1232 /*
1233  * The got_var contains the address of the Global Offset Table when AOT 
1234  * compiling.
1235  */
1236 MonoInst *
1237 mono_get_got_var (MonoCompile *cfg)
1238 {
1239         if (!cfg->compile_aot || !cfg->backend->need_got_var)
1240                 return NULL;
1241         if (!cfg->got_var) {
1242                 cfg->got_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1243         }
1244         return cfg->got_var;
1245 }
1246
1247 static MonoInst *
1248 mono_get_vtable_var (MonoCompile *cfg)
1249 {
1250         g_assert (cfg->gshared);
1251
1252         if (!cfg->rgctx_var) {
1253                 cfg->rgctx_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1254                 /* force the var to be stack allocated */
1255                 cfg->rgctx_var->flags |= MONO_INST_VOLATILE;
1256         }
1257
1258         return cfg->rgctx_var;
1259 }
1260
1261 static MonoType*
1262 type_from_stack_type (MonoInst *ins) {
1263         switch (ins->type) {
1264         case STACK_I4: return &mono_defaults.int32_class->byval_arg;
1265         case STACK_I8: return &mono_defaults.int64_class->byval_arg;
1266         case STACK_PTR: return &mono_defaults.int_class->byval_arg;
1267         case STACK_R4: return &mono_defaults.single_class->byval_arg;
1268         case STACK_R8: return &mono_defaults.double_class->byval_arg;
1269         case STACK_MP:
1270                 return &ins->klass->this_arg;
1271         case STACK_OBJ: return &mono_defaults.object_class->byval_arg;
1272         case STACK_VTYPE: return &ins->klass->byval_arg;
1273         default:
1274                 g_error ("stack type %d to monotype not handled\n", ins->type);
1275         }
1276         return NULL;
1277 }
1278
1279 static G_GNUC_UNUSED int
1280 type_to_stack_type (MonoCompile *cfg, MonoType *t)
1281 {
1282         t = mono_type_get_underlying_type (t);
1283         switch (t->type) {
1284         case MONO_TYPE_I1:
1285         case MONO_TYPE_U1:
1286         case MONO_TYPE_I2:
1287         case MONO_TYPE_U2:
1288         case MONO_TYPE_I4:
1289         case MONO_TYPE_U4:
1290                 return STACK_I4;
1291         case MONO_TYPE_I:
1292         case MONO_TYPE_U:
1293         case MONO_TYPE_PTR:
1294         case MONO_TYPE_FNPTR:
1295                 return STACK_PTR;
1296         case MONO_TYPE_CLASS:
1297         case MONO_TYPE_STRING:
1298         case MONO_TYPE_OBJECT:
1299         case MONO_TYPE_SZARRAY:
1300         case MONO_TYPE_ARRAY:    
1301                 return STACK_OBJ;
1302         case MONO_TYPE_I8:
1303         case MONO_TYPE_U8:
1304                 return STACK_I8;
1305         case MONO_TYPE_R4:
1306                 return cfg->r4_stack_type;
1307         case MONO_TYPE_R8:
1308                 return STACK_R8;
1309         case MONO_TYPE_VALUETYPE:
1310         case MONO_TYPE_TYPEDBYREF:
1311                 return STACK_VTYPE;
1312         case MONO_TYPE_GENERICINST:
1313                 if (mono_type_generic_inst_is_valuetype (t))
1314                         return STACK_VTYPE;
1315                 else
1316                         return STACK_OBJ;
1317                 break;
1318         default:
1319                 g_assert_not_reached ();
1320         }
1321
1322         return -1;
1323 }
1324
1325 static MonoClass*
1326 array_access_to_klass (int opcode)
1327 {
1328         switch (opcode) {
1329         case CEE_LDELEM_U1:
1330                 return mono_defaults.byte_class;
1331         case CEE_LDELEM_U2:
1332                 return mono_defaults.uint16_class;
1333         case CEE_LDELEM_I:
1334         case CEE_STELEM_I:
1335                 return mono_defaults.int_class;
1336         case CEE_LDELEM_I1:
1337         case CEE_STELEM_I1:
1338                 return mono_defaults.sbyte_class;
1339         case CEE_LDELEM_I2:
1340         case CEE_STELEM_I2:
1341                 return mono_defaults.int16_class;
1342         case CEE_LDELEM_I4:
1343         case CEE_STELEM_I4:
1344                 return mono_defaults.int32_class;
1345         case CEE_LDELEM_U4:
1346                 return mono_defaults.uint32_class;
1347         case CEE_LDELEM_I8:
1348         case CEE_STELEM_I8:
1349                 return mono_defaults.int64_class;
1350         case CEE_LDELEM_R4:
1351         case CEE_STELEM_R4:
1352                 return mono_defaults.single_class;
1353         case CEE_LDELEM_R8:
1354         case CEE_STELEM_R8:
1355                 return mono_defaults.double_class;
1356         case CEE_LDELEM_REF:
1357         case CEE_STELEM_REF:
1358                 return mono_defaults.object_class;
1359         default:
1360                 g_assert_not_reached ();
1361         }
1362         return NULL;
1363 }
1364
1365 /*
1366  * We try to share variables when possible
1367  */
1368 static MonoInst *
1369 mono_compile_get_interface_var (MonoCompile *cfg, int slot, MonoInst *ins)
1370 {
1371         MonoInst *res;
1372         int pos, vnum;
1373
1374         /* inlining can result in deeper stacks */ 
1375         if (slot >= cfg->header->max_stack)
1376                 return mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1377
1378         pos = ins->type - 1 + slot * STACK_MAX;
1379
1380         switch (ins->type) {
1381         case STACK_I4:
1382         case STACK_I8:
1383         case STACK_R8:
1384         case STACK_PTR:
1385         case STACK_MP:
1386         case STACK_OBJ:
1387                 if ((vnum = cfg->intvars [pos]))
1388                         return cfg->varinfo [vnum];
1389                 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1390                 cfg->intvars [pos] = res->inst_c0;
1391                 break;
1392         default:
1393                 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1394         }
1395         return res;
1396 }
1397
1398 static void
1399 mono_save_token_info (MonoCompile *cfg, MonoImage *image, guint32 token, gpointer key)
1400 {
1401         /* 
1402          * Don't use this if a generic_context is set, since that means AOT can't
1403          * look up the method using just the image+token.
1404          * table == 0 means this is a reference made from a wrapper.
1405          */
1406         if (cfg->compile_aot && !cfg->generic_context && (mono_metadata_token_table (token) > 0)) {
1407                 MonoJumpInfoToken *jump_info_token = (MonoJumpInfoToken *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoToken));
1408                 jump_info_token->image = image;
1409                 jump_info_token->token = token;
1410                 g_hash_table_insert (cfg->token_info_hash, key, jump_info_token);
1411         }
1412 }
1413
1414 /*
1415  * This function is called to handle items that are left on the evaluation stack
1416  * at basic block boundaries. What happens is that we save the values to local variables
1417  * and we reload them later when first entering the target basic block (with the
1418  * handle_loaded_temps () function).
1419  * A single joint point will use the same variables (stored in the array bb->out_stack or
1420  * bb->in_stack, if the basic block is before or after the joint point).
1421  *
1422  * This function needs to be called _before_ emitting the last instruction of
1423  * the bb (i.e. before emitting a branch).
1424  * If the stack merge fails at a join point, cfg->unverifiable is set.
1425  */
1426 static void
1427 handle_stack_args (MonoCompile *cfg, MonoInst **sp, int count)
1428 {
1429         int i, bindex;
1430         MonoBasicBlock *bb = cfg->cbb;
1431         MonoBasicBlock *outb;
1432         MonoInst *inst, **locals;
1433         gboolean found;
1434
1435         if (!count)
1436                 return;
1437         if (cfg->verbose_level > 3)
1438                 printf ("%d item(s) on exit from B%d\n", count, bb->block_num);
1439         if (!bb->out_scount) {
1440                 bb->out_scount = count;
1441                 //printf ("bblock %d has out:", bb->block_num);
1442                 found = FALSE;
1443                 for (i = 0; i < bb->out_count; ++i) {
1444                         outb = bb->out_bb [i];
1445                         /* exception handlers are linked, but they should not be considered for stack args */
1446                         if (outb->flags & BB_EXCEPTION_HANDLER)
1447                                 continue;
1448                         //printf (" %d", outb->block_num);
1449                         if (outb->in_stack) {
1450                                 found = TRUE;
1451                                 bb->out_stack = outb->in_stack;
1452                                 break;
1453                         }
1454                 }
1455                 //printf ("\n");
1456                 if (!found) {
1457                         bb->out_stack = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * count);
1458                         for (i = 0; i < count; ++i) {
1459                                 /* 
1460                                  * try to reuse temps already allocated for this purpouse, if they occupy the same
1461                                  * stack slot and if they are of the same type.
1462                                  * This won't cause conflicts since if 'local' is used to 
1463                                  * store one of the values in the in_stack of a bblock, then
1464                                  * the same variable will be used for the same outgoing stack 
1465                                  * slot as well. 
1466                                  * This doesn't work when inlining methods, since the bblocks
1467                                  * in the inlined methods do not inherit their in_stack from
1468                                  * the bblock they are inlined to. See bug #58863 for an
1469                                  * example.
1470                                  */
1471                                 if (cfg->inlined_method)
1472                                         bb->out_stack [i] = mono_compile_create_var (cfg, type_from_stack_type (sp [i]), OP_LOCAL);
1473                                 else
1474                                         bb->out_stack [i] = mono_compile_get_interface_var (cfg, i, sp [i]);
1475                         }
1476                 }
1477         }
1478
1479         for (i = 0; i < bb->out_count; ++i) {
1480                 outb = bb->out_bb [i];
1481                 /* exception handlers are linked, but they should not be considered for stack args */
1482                 if (outb->flags & BB_EXCEPTION_HANDLER)
1483                         continue;
1484                 if (outb->in_scount) {
1485                         if (outb->in_scount != bb->out_scount) {
1486                                 cfg->unverifiable = TRUE;
1487                                 return;
1488                         }
1489                         continue; /* check they are the same locals */
1490                 }
1491                 outb->in_scount = count;
1492                 outb->in_stack = bb->out_stack;
1493         }
1494
1495         locals = bb->out_stack;
1496         cfg->cbb = bb;
1497         for (i = 0; i < count; ++i) {
1498                 EMIT_NEW_TEMPSTORE (cfg, inst, locals [i]->inst_c0, sp [i]);
1499                 inst->cil_code = sp [i]->cil_code;
1500                 sp [i] = locals [i];
1501                 if (cfg->verbose_level > 3)
1502                         printf ("storing %d to temp %d\n", i, (int)locals [i]->inst_c0);
1503         }
1504
1505         /*
1506          * It is possible that the out bblocks already have in_stack assigned, and
1507          * the in_stacks differ. In this case, we will store to all the different 
1508          * in_stacks.
1509          */
1510
1511         found = TRUE;
1512         bindex = 0;
1513         while (found) {
1514                 /* Find a bblock which has a different in_stack */
1515                 found = FALSE;
1516                 while (bindex < bb->out_count) {
1517                         outb = bb->out_bb [bindex];
1518                         /* exception handlers are linked, but they should not be considered for stack args */
1519                         if (outb->flags & BB_EXCEPTION_HANDLER) {
1520                                 bindex++;
1521                                 continue;
1522                         }
1523                         if (outb->in_stack != locals) {
1524                                 for (i = 0; i < count; ++i) {
1525                                         EMIT_NEW_TEMPSTORE (cfg, inst, outb->in_stack [i]->inst_c0, sp [i]);
1526                                         inst->cil_code = sp [i]->cil_code;
1527                                         sp [i] = locals [i];
1528                                         if (cfg->verbose_level > 3)
1529                                                 printf ("storing %d to temp %d\n", i, (int)outb->in_stack [i]->inst_c0);
1530                                 }
1531                                 locals = outb->in_stack;
1532                                 found = TRUE;
1533                                 break;
1534                         }
1535                         bindex ++;
1536                 }
1537         }
1538 }
1539
1540 static MonoInst*
1541 emit_runtime_constant (MonoCompile *cfg, MonoJumpInfoType patch_type, gpointer data)
1542 {
1543         MonoInst *ins;
1544
1545         if (cfg->compile_aot) {
1546                 EMIT_NEW_AOTCONST (cfg, ins, patch_type, data);
1547         } else {
1548                 MonoJumpInfo ji;
1549                 gpointer target;
1550
1551                 ji.type = patch_type;
1552                 ji.data.target = data;
1553                 target = mono_resolve_patch_target (NULL, cfg->domain, NULL, &ji, FALSE);
1554
1555                 EMIT_NEW_PCONST (cfg, ins, target);
1556         }
1557         return ins;
1558 }
1559
1560 static void
1561 mini_emit_interface_bitmap_check (MonoCompile *cfg, int intf_bit_reg, int base_reg, int offset, MonoClass *klass)
1562 {
1563         int ibitmap_reg = alloc_preg (cfg);
1564 #ifdef COMPRESSED_INTERFACE_BITMAP
1565         MonoInst *args [2];
1566         MonoInst *res, *ins;
1567         NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, ibitmap_reg, base_reg, offset);
1568         MONO_ADD_INS (cfg->cbb, ins);
1569         args [0] = ins;
1570         args [1] = emit_runtime_constant (cfg, MONO_PATCH_INFO_IID, klass);
1571         res = mono_emit_jit_icall (cfg, mono_class_interface_match, args);
1572         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, intf_bit_reg, res->dreg);
1573 #else
1574         int ibitmap_byte_reg = alloc_preg (cfg);
1575
1576         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, ibitmap_reg, base_reg, offset);
1577
1578         if (cfg->compile_aot) {
1579                 int iid_reg = alloc_preg (cfg);
1580                 int shifted_iid_reg = alloc_preg (cfg);
1581                 int ibitmap_byte_address_reg = alloc_preg (cfg);
1582                 int masked_iid_reg = alloc_preg (cfg);
1583                 int iid_one_bit_reg = alloc_preg (cfg);
1584                 int iid_bit_reg = alloc_preg (cfg);
1585                 MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_IID);
1586                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, shifted_iid_reg, iid_reg, 3);
1587                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, ibitmap_byte_address_reg, ibitmap_reg, shifted_iid_reg);
1588                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, ibitmap_byte_reg, ibitmap_byte_address_reg, 0);
1589                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, masked_iid_reg, iid_reg, 7);
1590                 MONO_EMIT_NEW_ICONST (cfg, iid_one_bit_reg, 1);
1591                 MONO_EMIT_NEW_BIALU (cfg, OP_ISHL, iid_bit_reg, iid_one_bit_reg, masked_iid_reg);
1592                 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, intf_bit_reg, ibitmap_byte_reg, iid_bit_reg);
1593         } else {
1594                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, ibitmap_byte_reg, ibitmap_reg, klass->interface_id >> 3);
1595                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, intf_bit_reg, ibitmap_byte_reg, 1 << (klass->interface_id & 7));
1596         }
1597 #endif
1598 }
1599
1600 /* 
1601  * Emit code which loads into "intf_bit_reg" a nonzero value if the MonoClass
1602  * stored in "klass_reg" implements the interface "klass".
1603  */
1604 static void
1605 mini_emit_load_intf_bit_reg_class (MonoCompile *cfg, int intf_bit_reg, int klass_reg, MonoClass *klass)
1606 {
1607         mini_emit_interface_bitmap_check (cfg, intf_bit_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, interface_bitmap), klass);
1608 }
1609
1610 /* 
1611  * Emit code which loads into "intf_bit_reg" a nonzero value if the MonoVTable
1612  * stored in "vtable_reg" implements the interface "klass".
1613  */
1614 static void
1615 mini_emit_load_intf_bit_reg_vtable (MonoCompile *cfg, int intf_bit_reg, int vtable_reg, MonoClass *klass)
1616 {
1617         mini_emit_interface_bitmap_check (cfg, intf_bit_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, interface_bitmap), klass);
1618 }
1619
1620 /* 
1621  * Emit code which checks whenever the interface id of @klass is smaller than
1622  * than the value given by max_iid_reg.
1623 */
1624 static void
1625 mini_emit_max_iid_check (MonoCompile *cfg, int max_iid_reg, MonoClass *klass,
1626                                                  MonoBasicBlock *false_target)
1627 {
1628         if (cfg->compile_aot) {
1629                 int iid_reg = alloc_preg (cfg);
1630                 MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_IID);
1631                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, max_iid_reg, iid_reg);
1632         }
1633         else
1634                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, max_iid_reg, klass->interface_id);
1635         if (false_target)
1636                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBLT_UN, false_target);
1637         else
1638                 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "InvalidCastException");
1639 }
1640
1641 /* Same as above, but obtains max_iid from a vtable */
1642 static void
1643 mini_emit_max_iid_check_vtable (MonoCompile *cfg, int vtable_reg, MonoClass *klass,
1644                                                                  MonoBasicBlock *false_target)
1645 {
1646         int max_iid_reg = alloc_preg (cfg);
1647                 
1648         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, max_iid_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, max_interface_id));
1649         mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target);
1650 }
1651
1652 /* Same as above, but obtains max_iid from a klass */
1653 static void
1654 mini_emit_max_iid_check_class (MonoCompile *cfg, int klass_reg, MonoClass *klass,
1655                                                                  MonoBasicBlock *false_target)
1656 {
1657         int max_iid_reg = alloc_preg (cfg);
1658
1659         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, max_iid_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, max_interface_id));
1660         mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target);
1661 }
1662
1663 static void
1664 mini_emit_isninst_cast_inst (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoInst *klass_ins, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1665 {
1666         int idepth_reg = alloc_preg (cfg);
1667         int stypes_reg = alloc_preg (cfg);
1668         int stype = alloc_preg (cfg);
1669
1670         mono_class_setup_supertypes (klass);
1671
1672         if (klass->idepth > MONO_DEFAULT_SUPERTABLE_SIZE) {
1673                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, idepth_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, idepth));
1674                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, idepth_reg, klass->idepth);
1675                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBLT_UN, false_target);
1676         }
1677         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stypes_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, supertypes));
1678         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stype, stypes_reg, ((klass->idepth - 1) * SIZEOF_VOID_P));
1679         if (klass_ins) {
1680                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, stype, klass_ins->dreg);
1681         } else if (cfg->compile_aot) {
1682                 int const_reg = alloc_preg (cfg);
1683                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
1684                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, stype, const_reg);
1685         } else {
1686                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, stype, klass);
1687         }
1688         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, true_target);
1689 }
1690
1691 static void
1692 mini_emit_isninst_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1693 {
1694         mini_emit_isninst_cast_inst (cfg, klass_reg, klass, NULL, false_target, true_target);
1695 }
1696
1697 static void
1698 mini_emit_iface_cast (MonoCompile *cfg, int vtable_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1699 {
1700         int intf_reg = alloc_preg (cfg);
1701
1702         mini_emit_max_iid_check_vtable (cfg, vtable_reg, klass, false_target);
1703         mini_emit_load_intf_bit_reg_vtable (cfg, intf_reg, vtable_reg, klass);
1704         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, intf_reg, 0);
1705         if (true_target)
1706                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, true_target);
1707         else
1708                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");               
1709 }
1710
1711 /*
1712  * Variant of the above that takes a register to the class, not the vtable.
1713  */
1714 static void
1715 mini_emit_iface_class_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1716 {
1717         int intf_bit_reg = alloc_preg (cfg);
1718
1719         mini_emit_max_iid_check_class (cfg, klass_reg, klass, false_target);
1720         mini_emit_load_intf_bit_reg_class (cfg, intf_bit_reg, klass_reg, klass);
1721         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, intf_bit_reg, 0);
1722         if (true_target)
1723                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, true_target);
1724         else
1725                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
1726 }
1727
1728 static inline void
1729 mini_emit_class_check_inst (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoInst *klass_inst)
1730 {
1731         if (klass_inst) {
1732                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_inst->dreg);
1733         } else {
1734                 MonoInst *ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_CLASS, klass);
1735                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, ins->dreg);
1736         }
1737         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1738 }
1739
1740 static inline void
1741 mini_emit_class_check (MonoCompile *cfg, int klass_reg, MonoClass *klass)
1742 {
1743         mini_emit_class_check_inst (cfg, klass_reg, klass, NULL);
1744 }
1745
1746 static inline void
1747 mini_emit_class_check_branch (MonoCompile *cfg, int klass_reg, MonoClass *klass, int branch_op, MonoBasicBlock *target)
1748 {
1749         if (cfg->compile_aot) {
1750                 int const_reg = alloc_preg (cfg);
1751                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
1752                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, const_reg);
1753         } else {
1754                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
1755         }
1756         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, branch_op, target);
1757 }
1758
1759 static void
1760 mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoBasicBlock *object_is_null);
1761         
1762 static void
1763 mini_emit_castclass_inst (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoInst *klass_inst, MonoBasicBlock *object_is_null)
1764 {
1765         if (klass->rank) {
1766                 int rank_reg = alloc_preg (cfg);
1767                 int eclass_reg = alloc_preg (cfg);
1768
1769                 g_assert (!klass_inst);
1770                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, rank));
1771                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank);
1772                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1773                 //              MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
1774                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, cast_class));
1775                 if (klass->cast_class == mono_defaults.object_class) {
1776                         int parent_reg = alloc_preg (cfg);
1777                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, parent_reg, eclass_reg, MONO_STRUCT_OFFSET (MonoClass, parent));
1778                         mini_emit_class_check_branch (cfg, parent_reg, mono_defaults.enum_class->parent, OP_PBNE_UN, object_is_null);
1779                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1780                 } else if (klass->cast_class == mono_defaults.enum_class->parent) {
1781                         mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class->parent, OP_PBEQ, object_is_null);
1782                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1783                 } else if (klass->cast_class == mono_defaults.enum_class) {
1784                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1785                 } else if (klass->cast_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1786                         mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, NULL, NULL);
1787                 } else {
1788                         // Pass -1 as obj_reg to skip the check below for arrays of arrays
1789                         mini_emit_castclass (cfg, -1, eclass_reg, klass->cast_class, object_is_null);
1790                 }
1791
1792                 if ((klass->rank == 1) && (klass->byval_arg.type == MONO_TYPE_SZARRAY) && (obj_reg != -1)) {
1793                         /* Check that the object is a vector too */
1794                         int bounds_reg = alloc_preg (cfg);
1795                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, obj_reg, MONO_STRUCT_OFFSET (MonoArray, bounds));
1796                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
1797                         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1798                 }
1799         } else {
1800                 int idepth_reg = alloc_preg (cfg);
1801                 int stypes_reg = alloc_preg (cfg);
1802                 int stype = alloc_preg (cfg);
1803
1804                 mono_class_setup_supertypes (klass);
1805
1806                 if (klass->idepth > MONO_DEFAULT_SUPERTABLE_SIZE) {
1807                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, idepth_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, idepth));
1808                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, idepth_reg, klass->idepth);
1809                         MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "InvalidCastException");
1810                 }
1811                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stypes_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, supertypes));
1812                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stype, stypes_reg, ((klass->idepth - 1) * SIZEOF_VOID_P));
1813                 mini_emit_class_check_inst (cfg, stype, klass, klass_inst);
1814         }
1815 }
1816
1817 static void
1818 mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoBasicBlock *object_is_null)
1819 {
1820         mini_emit_castclass_inst (cfg, obj_reg, klass_reg, klass, NULL, object_is_null);
1821 }
1822
1823 static void 
1824 mini_emit_memset (MonoCompile *cfg, int destreg, int offset, int size, int val, int align)
1825 {
1826         int val_reg;
1827
1828         g_assert (val == 0);
1829
1830         if (align == 0)
1831                 align = 4;
1832
1833         if ((size <= SIZEOF_REGISTER) && (size <= align)) {
1834                 switch (size) {
1835                 case 1:
1836                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, destreg, offset, val);
1837                         return;
1838                 case 2:
1839                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI2_MEMBASE_IMM, destreg, offset, val);
1840                         return;
1841                 case 4:
1842                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI4_MEMBASE_IMM, destreg, offset, val);
1843                         return;
1844 #if SIZEOF_REGISTER == 8
1845                 case 8:
1846                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI8_MEMBASE_IMM, destreg, offset, val);
1847                         return;
1848 #endif
1849                 }
1850         }
1851
1852         val_reg = alloc_preg (cfg);
1853
1854         if (SIZEOF_REGISTER == 8)
1855                 MONO_EMIT_NEW_I8CONST (cfg, val_reg, val);
1856         else
1857                 MONO_EMIT_NEW_ICONST (cfg, val_reg, val);
1858
1859         if (align < 4) {
1860                 /* This could be optimized further if neccesary */
1861                 while (size >= 1) {
1862                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
1863                         offset += 1;
1864                         size -= 1;
1865                 }
1866                 return;
1867         }       
1868
1869         if (!cfg->backend->no_unaligned_access && SIZEOF_REGISTER == 8) {
1870                 if (offset % 8) {
1871                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
1872                         offset += 4;
1873                         size -= 4;
1874                 }
1875                 while (size >= 8) {
1876                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, destreg, offset, val_reg);
1877                         offset += 8;
1878                         size -= 8;
1879                 }
1880         }       
1881
1882         while (size >= 4) {
1883                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
1884                 offset += 4;
1885                 size -= 4;
1886         }
1887         while (size >= 2) {
1888                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, offset, val_reg);
1889                 offset += 2;
1890                 size -= 2;
1891         }
1892         while (size >= 1) {
1893                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
1894                 offset += 1;
1895                 size -= 1;
1896         }
1897 }
1898
1899 void 
1900 mini_emit_memcpy (MonoCompile *cfg, int destreg, int doffset, int srcreg, int soffset, int size, int align)
1901 {
1902         int cur_reg;
1903
1904         if (align == 0)
1905                 align = 4;
1906
1907         /*FIXME arbitrary hack to avoid unbound code expansion.*/
1908         g_assert (size < 10000);
1909
1910         if (align < 4) {
1911                 /* This could be optimized further if neccesary */
1912                 while (size >= 1) {
1913                         cur_reg = alloc_preg (cfg);
1914                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, cur_reg, srcreg, soffset);
1915                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, doffset, cur_reg);
1916                         doffset += 1;
1917                         soffset += 1;
1918                         size -= 1;
1919                 }
1920         }
1921
1922         if (!cfg->backend->no_unaligned_access && SIZEOF_REGISTER == 8) {
1923                 while (size >= 8) {
1924                         cur_reg = alloc_preg (cfg);
1925                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI8_MEMBASE, cur_reg, srcreg, soffset);
1926                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, destreg, doffset, cur_reg);
1927                         doffset += 8;
1928                         soffset += 8;
1929                         size -= 8;
1930                 }
1931         }       
1932
1933         while (size >= 4) {
1934                 cur_reg = alloc_preg (cfg);
1935                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, cur_reg, srcreg, soffset);
1936                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, doffset, cur_reg);
1937                 doffset += 4;
1938                 soffset += 4;
1939                 size -= 4;
1940         }
1941         while (size >= 2) {
1942                 cur_reg = alloc_preg (cfg);
1943                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, cur_reg, srcreg, soffset);
1944                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, doffset, cur_reg);
1945                 doffset += 2;
1946                 soffset += 2;
1947                 size -= 2;
1948         }
1949         while (size >= 1) {
1950                 cur_reg = alloc_preg (cfg);
1951                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, cur_reg, srcreg, soffset);
1952                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, doffset, cur_reg);
1953                 doffset += 1;
1954                 soffset += 1;
1955                 size -= 1;
1956         }
1957 }
1958
1959 static void
1960 emit_tls_set (MonoCompile *cfg, int sreg1, MonoTlsKey tls_key)
1961 {
1962         MonoInst *ins, *c;
1963
1964         if (cfg->compile_aot) {
1965                 EMIT_NEW_TLS_OFFSETCONST (cfg, c, tls_key);
1966                 MONO_INST_NEW (cfg, ins, OP_TLS_SET_REG);
1967                 ins->sreg1 = sreg1;
1968                 ins->sreg2 = c->dreg;
1969                 MONO_ADD_INS (cfg->cbb, ins);
1970         } else {
1971                 MONO_INST_NEW (cfg, ins, OP_TLS_SET);
1972                 ins->sreg1 = sreg1;
1973                 ins->inst_offset = mini_get_tls_offset (tls_key);
1974                 MONO_ADD_INS (cfg->cbb, ins);
1975         }
1976 }
1977
1978 /*
1979  * emit_push_lmf:
1980  *
1981  *   Emit IR to push the current LMF onto the LMF stack.
1982  */
1983 static void
1984 emit_push_lmf (MonoCompile *cfg)
1985 {
1986         /*
1987          * Emit IR to push the LMF:
1988          * lmf_addr = <lmf_addr from tls>
1989          * lmf->lmf_addr = lmf_addr
1990          * lmf->prev_lmf = *lmf_addr
1991          * *lmf_addr = lmf
1992          */
1993         int lmf_reg, prev_lmf_reg;
1994         MonoInst *ins, *lmf_ins;
1995
1996         if (!cfg->lmf_ir)
1997                 return;
1998
1999         if (cfg->lmf_ir_mono_lmf && mini_tls_get_supported (cfg, TLS_KEY_LMF)) {
2000                 /* Load current lmf */
2001                 lmf_ins = mono_get_lmf_intrinsic (cfg);
2002                 g_assert (lmf_ins);
2003                 MONO_ADD_INS (cfg->cbb, lmf_ins);
2004                 EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
2005                 lmf_reg = ins->dreg;
2006                 /* Save previous_lmf */
2007                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf), lmf_ins->dreg);
2008                 /* Set new LMF */
2009                 emit_tls_set (cfg, lmf_reg, TLS_KEY_LMF);
2010         } else {
2011                 /*
2012                  * Store lmf_addr in a variable, so it can be allocated to a global register.
2013                  */
2014                 if (!cfg->lmf_addr_var)
2015                         cfg->lmf_addr_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2016
2017 #ifdef HOST_WIN32
2018                 ins = mono_get_jit_tls_intrinsic (cfg);
2019                 if (ins) {
2020                         int jit_tls_dreg = ins->dreg;
2021
2022                         MONO_ADD_INS (cfg->cbb, ins);
2023                         lmf_reg = alloc_preg (cfg);
2024                         EMIT_NEW_BIALU_IMM (cfg, lmf_ins, OP_PADD_IMM, lmf_reg, jit_tls_dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, lmf));
2025                 } else {
2026                         lmf_ins = mono_emit_jit_icall (cfg, mono_get_lmf_addr, NULL);
2027                 }
2028 #else
2029                 lmf_ins = mono_get_lmf_addr_intrinsic (cfg);
2030                 if (lmf_ins) {
2031                         MONO_ADD_INS (cfg->cbb, lmf_ins);
2032                 } else {
2033 #ifdef TARGET_IOS
2034                         MonoInst *args [16], *jit_tls_ins, *ins;
2035
2036                         /* Inline mono_get_lmf_addr () */
2037                         /* jit_tls = pthread_getspecific (mono_jit_tls_id); lmf_addr = &jit_tls->lmf; */
2038
2039                         /* Load mono_jit_tls_id */
2040                         if (cfg->compile_aot)
2041                                 EMIT_NEW_AOTCONST (cfg, args [0], MONO_PATCH_INFO_JIT_TLS_ID, NULL);
2042                         else
2043                                 EMIT_NEW_ICONST (cfg, args [0], mono_jit_tls_id);
2044                         /* call pthread_getspecific () */
2045                         jit_tls_ins = mono_emit_jit_icall (cfg, pthread_getspecific, args);
2046                         /* lmf_addr = &jit_tls->lmf */
2047                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, cfg->lmf_addr_var->dreg, jit_tls_ins->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, lmf));
2048                         lmf_ins = ins;
2049 #else
2050                         lmf_ins = mono_emit_jit_icall (cfg, mono_get_lmf_addr, NULL);
2051 #endif
2052                 }
2053 #endif
2054                 lmf_ins->dreg = cfg->lmf_addr_var->dreg;
2055
2056                 EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
2057                 lmf_reg = ins->dreg;
2058
2059                 prev_lmf_reg = alloc_preg (cfg);
2060                 /* Save previous_lmf */
2061                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, cfg->lmf_addr_var->dreg, 0);
2062                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf), prev_lmf_reg);
2063                 /* Set new lmf */
2064                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, cfg->lmf_addr_var->dreg, 0, lmf_reg);
2065         }
2066 }
2067
2068 /*
2069  * emit_pop_lmf:
2070  *
2071  *   Emit IR to pop the current LMF from the LMF stack.
2072  */
2073 static void
2074 emit_pop_lmf (MonoCompile *cfg)
2075 {
2076         int lmf_reg, lmf_addr_reg, prev_lmf_reg;
2077         MonoInst *ins;
2078
2079         if (!cfg->lmf_ir)
2080                 return;
2081
2082         EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
2083         lmf_reg = ins->dreg;
2084
2085         if (cfg->lmf_ir_mono_lmf && mini_tls_get_supported (cfg, TLS_KEY_LMF)) {
2086                 /* Load previous_lmf */
2087                 prev_lmf_reg = alloc_preg (cfg);
2088                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf));
2089                 /* Set new LMF */
2090                 emit_tls_set (cfg, prev_lmf_reg, TLS_KEY_LMF);
2091         } else {
2092                 /*
2093                  * Emit IR to pop the LMF:
2094                  * *(lmf->lmf_addr) = lmf->prev_lmf
2095                  */
2096                 /* This could be called before emit_push_lmf () */
2097                 if (!cfg->lmf_addr_var)
2098                         cfg->lmf_addr_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2099                 lmf_addr_reg = cfg->lmf_addr_var->dreg;
2100
2101                 prev_lmf_reg = alloc_preg (cfg);
2102                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf));
2103                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_addr_reg, 0, prev_lmf_reg);
2104         }
2105 }
2106
2107 static void
2108 emit_instrumentation_call (MonoCompile *cfg, void *func)
2109 {
2110         MonoInst *iargs [1];
2111
2112         /*
2113          * Avoid instrumenting inlined methods since it can
2114          * distort profiling results.
2115          */
2116         if (cfg->method != cfg->current_method)
2117                 return;
2118
2119         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE) {
2120                 EMIT_NEW_METHODCONST (cfg, iargs [0], cfg->method);
2121                 mono_emit_jit_icall (cfg, func, iargs);
2122         }
2123 }
2124
2125 static int
2126 ret_type_to_call_opcode (MonoCompile *cfg, MonoType *type, int calli, int virt)
2127 {
2128 handle_enum:
2129         type = mini_get_underlying_type (type);
2130         switch (type->type) {
2131         case MONO_TYPE_VOID:
2132                 return calli? OP_VOIDCALL_REG: virt? OP_VOIDCALL_MEMBASE: OP_VOIDCALL;
2133         case MONO_TYPE_I1:
2134         case MONO_TYPE_U1:
2135         case MONO_TYPE_I2:
2136         case MONO_TYPE_U2:
2137         case MONO_TYPE_I4:
2138         case MONO_TYPE_U4:
2139                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2140         case MONO_TYPE_I:
2141         case MONO_TYPE_U:
2142         case MONO_TYPE_PTR:
2143         case MONO_TYPE_FNPTR:
2144                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2145         case MONO_TYPE_CLASS:
2146         case MONO_TYPE_STRING:
2147         case MONO_TYPE_OBJECT:
2148         case MONO_TYPE_SZARRAY:
2149         case MONO_TYPE_ARRAY:    
2150                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2151         case MONO_TYPE_I8:
2152         case MONO_TYPE_U8:
2153                 return calli? OP_LCALL_REG: virt? OP_LCALL_MEMBASE: OP_LCALL;
2154         case MONO_TYPE_R4:
2155                 if (cfg->r4fp)
2156                         return calli? OP_RCALL_REG: virt? OP_RCALL_MEMBASE: OP_RCALL;
2157                 else
2158                         return calli? OP_FCALL_REG: virt? OP_FCALL_MEMBASE: OP_FCALL;
2159         case MONO_TYPE_R8:
2160                 return calli? OP_FCALL_REG: virt? OP_FCALL_MEMBASE: OP_FCALL;
2161         case MONO_TYPE_VALUETYPE:
2162                 if (type->data.klass->enumtype) {
2163                         type = mono_class_enum_basetype (type->data.klass);
2164                         goto handle_enum;
2165                 } else
2166                         return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2167         case MONO_TYPE_TYPEDBYREF:
2168                 return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2169         case MONO_TYPE_GENERICINST:
2170                 type = &type->data.generic_class->container_class->byval_arg;
2171                 goto handle_enum;
2172         case MONO_TYPE_VAR:
2173         case MONO_TYPE_MVAR:
2174                 /* gsharedvt */
2175                 return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2176         default:
2177                 g_error ("unknown type 0x%02x in ret_type_to_call_opcode", type->type);
2178         }
2179         return -1;
2180 }
2181
2182 /*
2183  * target_type_is_incompatible:
2184  * @cfg: MonoCompile context
2185  *
2186  * Check that the item @arg on the evaluation stack can be stored
2187  * in the target type (can be a local, or field, etc).
2188  * The cfg arg can be used to check if we need verification or just
2189  * validity checks.
2190  *
2191  * Returns: non-0 value if arg can't be stored on a target.
2192  */
2193 static int
2194 target_type_is_incompatible (MonoCompile *cfg, MonoType *target, MonoInst *arg)
2195 {
2196         MonoType *simple_type;
2197         MonoClass *klass;
2198
2199         if (target->byref) {
2200                 /* FIXME: check that the pointed to types match */
2201                 if (arg->type == STACK_MP) {
2202                         MonoClass *base_class = mono_class_from_mono_type (target);
2203                         /* This is needed to handle gshared types + ldaddr */
2204                         simple_type = mini_get_underlying_type (&base_class->byval_arg);
2205                         return target->type != MONO_TYPE_I && arg->klass != base_class && arg->klass != mono_class_from_mono_type (simple_type);
2206                 }
2207                 if (arg->type == STACK_PTR)
2208                         return 0;
2209                 return 1;
2210         }
2211
2212         simple_type = mini_get_underlying_type (target);
2213         switch (simple_type->type) {
2214         case MONO_TYPE_VOID:
2215                 return 1;
2216         case MONO_TYPE_I1:
2217         case MONO_TYPE_U1:
2218         case MONO_TYPE_I2:
2219         case MONO_TYPE_U2:
2220         case MONO_TYPE_I4:
2221         case MONO_TYPE_U4:
2222                 if (arg->type != STACK_I4 && arg->type != STACK_PTR)
2223                         return 1;
2224                 return 0;
2225         case MONO_TYPE_PTR:
2226                 /* STACK_MP is needed when setting pinned locals */
2227                 if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
2228                         return 1;
2229                 return 0;
2230         case MONO_TYPE_I:
2231         case MONO_TYPE_U:
2232         case MONO_TYPE_FNPTR:
2233                 /* 
2234                  * Some opcodes like ldloca returns 'transient pointers' which can be stored in
2235                  * in native int. (#688008).
2236                  */
2237                 if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
2238                         return 1;
2239                 return 0;
2240         case MONO_TYPE_CLASS:
2241         case MONO_TYPE_STRING:
2242         case MONO_TYPE_OBJECT:
2243         case MONO_TYPE_SZARRAY:
2244         case MONO_TYPE_ARRAY:    
2245                 if (arg->type != STACK_OBJ)
2246                         return 1;
2247                 /* FIXME: check type compatibility */
2248                 return 0;
2249         case MONO_TYPE_I8:
2250         case MONO_TYPE_U8:
2251                 if (arg->type != STACK_I8)
2252                         return 1;
2253                 return 0;
2254         case MONO_TYPE_R4:
2255                 if (arg->type != cfg->r4_stack_type)
2256                         return 1;
2257                 return 0;
2258         case MONO_TYPE_R8:
2259                 if (arg->type != STACK_R8)
2260                         return 1;
2261                 return 0;
2262         case MONO_TYPE_VALUETYPE:
2263                 if (arg->type != STACK_VTYPE)
2264                         return 1;
2265                 klass = mono_class_from_mono_type (simple_type);
2266                 if (klass != arg->klass)
2267                         return 1;
2268                 return 0;
2269         case MONO_TYPE_TYPEDBYREF:
2270                 if (arg->type != STACK_VTYPE)
2271                         return 1;
2272                 klass = mono_class_from_mono_type (simple_type);
2273                 if (klass != arg->klass)
2274                         return 1;
2275                 return 0;
2276         case MONO_TYPE_GENERICINST:
2277                 if (mono_type_generic_inst_is_valuetype (simple_type)) {
2278                         MonoClass *target_class;
2279                         if (arg->type != STACK_VTYPE)
2280                                 return 1;
2281                         klass = mono_class_from_mono_type (simple_type);
2282                         target_class = mono_class_from_mono_type (target);
2283                         /* The second cases is needed when doing partial sharing */
2284                         if (klass != arg->klass && target_class != arg->klass && target_class != mono_class_from_mono_type (mini_get_underlying_type (&arg->klass->byval_arg)))
2285                                 return 1;
2286                         return 0;
2287                 } else {
2288                         if (arg->type != STACK_OBJ)
2289                                 return 1;
2290                         /* FIXME: check type compatibility */
2291                         return 0;
2292                 }
2293         case MONO_TYPE_VAR:
2294         case MONO_TYPE_MVAR:
2295                 g_assert (cfg->gshared);
2296                 if (mini_type_var_is_vt (simple_type)) {
2297                         if (arg->type != STACK_VTYPE)
2298                                 return 1;
2299                 } else {
2300                         if (arg->type != STACK_OBJ)
2301                                 return 1;
2302                 }
2303                 return 0;
2304         default:
2305                 g_error ("unknown type 0x%02x in target_type_is_incompatible", simple_type->type);
2306         }
2307         return 1;
2308 }
2309
2310 /*
2311  * Prepare arguments for passing to a function call.
2312  * Return a non-zero value if the arguments can't be passed to the given
2313  * signature.
2314  * The type checks are not yet complete and some conversions may need
2315  * casts on 32 or 64 bit architectures.
2316  *
2317  * FIXME: implement this using target_type_is_incompatible ()
2318  */
2319 static int
2320 check_call_signature (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args)
2321 {
2322         MonoType *simple_type;
2323         int i;
2324
2325         if (sig->hasthis) {
2326                 if (args [0]->type != STACK_OBJ && args [0]->type != STACK_MP && args [0]->type != STACK_PTR)
2327                         return 1;
2328                 args++;
2329         }
2330         for (i = 0; i < sig->param_count; ++i) {
2331                 if (sig->params [i]->byref) {
2332                         if (args [i]->type != STACK_MP && args [i]->type != STACK_PTR)
2333                                 return 1;
2334                         continue;
2335                 }
2336                 simple_type = mini_get_underlying_type (sig->params [i]);
2337 handle_enum:
2338                 switch (simple_type->type) {
2339                 case MONO_TYPE_VOID:
2340                         return 1;
2341                         continue;
2342                 case MONO_TYPE_I1:
2343                 case MONO_TYPE_U1:
2344                 case MONO_TYPE_I2:
2345                 case MONO_TYPE_U2:
2346                 case MONO_TYPE_I4:
2347                 case MONO_TYPE_U4:
2348                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR)
2349                                 return 1;
2350                         continue;
2351                 case MONO_TYPE_I:
2352                 case MONO_TYPE_U:
2353                 case MONO_TYPE_PTR:
2354                 case MONO_TYPE_FNPTR:
2355                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR && args [i]->type != STACK_MP && args [i]->type != STACK_OBJ)
2356                                 return 1;
2357                         continue;
2358                 case MONO_TYPE_CLASS:
2359                 case MONO_TYPE_STRING:
2360                 case MONO_TYPE_OBJECT:
2361                 case MONO_TYPE_SZARRAY:
2362                 case MONO_TYPE_ARRAY:    
2363                         if (args [i]->type != STACK_OBJ)
2364                                 return 1;
2365                         continue;
2366                 case MONO_TYPE_I8:
2367                 case MONO_TYPE_U8:
2368                         if (args [i]->type != STACK_I8)
2369                                 return 1;
2370                         continue;
2371                 case MONO_TYPE_R4:
2372                         if (args [i]->type != cfg->r4_stack_type)
2373                                 return 1;
2374                         continue;
2375                 case MONO_TYPE_R8:
2376                         if (args [i]->type != STACK_R8)
2377                                 return 1;
2378                         continue;
2379                 case MONO_TYPE_VALUETYPE:
2380                         if (simple_type->data.klass->enumtype) {
2381                                 simple_type = mono_class_enum_basetype (simple_type->data.klass);
2382                                 goto handle_enum;
2383                         }
2384                         if (args [i]->type != STACK_VTYPE)
2385                                 return 1;
2386                         continue;
2387                 case MONO_TYPE_TYPEDBYREF:
2388                         if (args [i]->type != STACK_VTYPE)
2389                                 return 1;
2390                         continue;
2391                 case MONO_TYPE_GENERICINST:
2392                         simple_type = &simple_type->data.generic_class->container_class->byval_arg;
2393                         goto handle_enum;
2394                 case MONO_TYPE_VAR:
2395                 case MONO_TYPE_MVAR:
2396                         /* gsharedvt */
2397                         if (args [i]->type != STACK_VTYPE)
2398                                 return 1;
2399                         continue;
2400                 default:
2401                         g_error ("unknown type 0x%02x in check_call_signature",
2402                                  simple_type->type);
2403                 }
2404         }
2405         return 0;
2406 }
2407
2408 static int
2409 callvirt_to_call (int opcode)
2410 {
2411         switch (opcode) {
2412         case OP_CALL_MEMBASE:
2413                 return OP_CALL;
2414         case OP_VOIDCALL_MEMBASE:
2415                 return OP_VOIDCALL;
2416         case OP_FCALL_MEMBASE:
2417                 return OP_FCALL;
2418         case OP_RCALL_MEMBASE:
2419                 return OP_RCALL;
2420         case OP_VCALL_MEMBASE:
2421                 return OP_VCALL;
2422         case OP_LCALL_MEMBASE:
2423                 return OP_LCALL;
2424         default:
2425                 g_assert_not_reached ();
2426         }
2427
2428         return -1;
2429 }
2430
2431 static int
2432 callvirt_to_call_reg (int opcode)
2433 {
2434         switch (opcode) {
2435         case OP_CALL_MEMBASE:
2436                 return OP_CALL_REG;
2437         case OP_VOIDCALL_MEMBASE:
2438                 return OP_VOIDCALL_REG;
2439         case OP_FCALL_MEMBASE:
2440                 return OP_FCALL_REG;
2441         case OP_RCALL_MEMBASE:
2442                 return OP_RCALL_REG;
2443         case OP_VCALL_MEMBASE:
2444                 return OP_VCALL_REG;
2445         case OP_LCALL_MEMBASE:
2446                 return OP_LCALL_REG;
2447         default:
2448                 g_assert_not_reached ();
2449         }
2450
2451         return -1;
2452 }
2453
2454 /* Either METHOD or IMT_ARG needs to be set */
2455 static void
2456 emit_imt_argument (MonoCompile *cfg, MonoCallInst *call, MonoMethod *method, MonoInst *imt_arg)
2457 {
2458         int method_reg;
2459
2460         if (COMPILE_LLVM (cfg)) {
2461                 if (imt_arg) {
2462                         method_reg = alloc_preg (cfg);
2463                         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
2464                 } else {
2465                         MonoInst *ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_METHODCONST, method);
2466                         method_reg = ins->dreg;
2467                 }
2468
2469 #ifdef ENABLE_LLVM
2470                 call->imt_arg_reg = method_reg;
2471 #endif
2472                 mono_call_inst_add_outarg_reg (cfg, call, method_reg, MONO_ARCH_IMT_REG, FALSE);
2473                 return;
2474         }
2475
2476         if (imt_arg) {
2477                 method_reg = alloc_preg (cfg);
2478                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
2479         } else {
2480                 MonoInst *ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_METHODCONST, method);
2481                 method_reg = ins->dreg;
2482         }
2483
2484         mono_call_inst_add_outarg_reg (cfg, call, method_reg, MONO_ARCH_IMT_REG, FALSE);
2485 }
2486
2487 static MonoJumpInfo *
2488 mono_patch_info_new (MonoMemPool *mp, int ip, MonoJumpInfoType type, gconstpointer target)
2489 {
2490         MonoJumpInfo *ji = (MonoJumpInfo *)mono_mempool_alloc (mp, sizeof (MonoJumpInfo));
2491
2492         ji->ip.i = ip;
2493         ji->type = type;
2494         ji->data.target = target;
2495
2496         return ji;
2497 }
2498
2499 static int
2500 mini_class_check_context_used (MonoCompile *cfg, MonoClass *klass)
2501 {
2502         if (cfg->gshared)
2503                 return mono_class_check_context_used (klass);
2504         else
2505                 return 0;
2506 }
2507
2508 static int
2509 mini_method_check_context_used (MonoCompile *cfg, MonoMethod *method)
2510 {
2511         if (cfg->gshared)
2512                 return mono_method_check_context_used (method);
2513         else
2514                 return 0;
2515 }
2516
2517 /*
2518  * check_method_sharing:
2519  *
2520  *   Check whenever the vtable or an mrgctx needs to be passed when calling CMETHOD.
2521  */
2522 static void
2523 check_method_sharing (MonoCompile *cfg, MonoMethod *cmethod, gboolean *out_pass_vtable, gboolean *out_pass_mrgctx)
2524 {
2525         gboolean pass_vtable = FALSE;
2526         gboolean pass_mrgctx = FALSE;
2527
2528         if (((cmethod->flags & METHOD_ATTRIBUTE_STATIC) || cmethod->klass->valuetype) &&
2529                 (cmethod->klass->generic_class || cmethod->klass->generic_container)) {
2530                 gboolean sharable = FALSE;
2531
2532                 if (mono_method_is_generic_sharable_full (cmethod, TRUE, TRUE, TRUE))
2533                         sharable = TRUE;
2534
2535                 /*
2536                  * Pass vtable iff target method might
2537                  * be shared, which means that sharing
2538                  * is enabled for its class and its
2539                  * context is sharable (and it's not a
2540                  * generic method).
2541                  */
2542                 if (sharable && !(mini_method_get_context (cmethod) && mini_method_get_context (cmethod)->method_inst))
2543                         pass_vtable = TRUE;
2544         }
2545
2546         if (mini_method_get_context (cmethod) &&
2547                 mini_method_get_context (cmethod)->method_inst) {
2548                 g_assert (!pass_vtable);
2549
2550                 if (mono_method_is_generic_sharable_full (cmethod, TRUE, TRUE, TRUE)) {
2551                         pass_mrgctx = TRUE;
2552                 } else {
2553                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (mono_method_signature (cmethod)))
2554                                 pass_mrgctx = TRUE;
2555                 }
2556         }
2557
2558         if (out_pass_vtable)
2559                 *out_pass_vtable = pass_vtable;
2560         if (out_pass_mrgctx)
2561                 *out_pass_mrgctx = pass_mrgctx;
2562 }
2563
2564 inline static MonoCallInst *
2565 mono_emit_call_args (MonoCompile *cfg, MonoMethodSignature *sig, 
2566                                          MonoInst **args, int calli, int virtual_, int tail, int rgctx, int unbox_trampoline)
2567 {
2568         MonoType *sig_ret;
2569         MonoCallInst *call;
2570 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
2571         int i;
2572 #endif
2573
2574         if (cfg->llvm_only)
2575                 tail = FALSE;
2576
2577         if (tail) {
2578                 emit_instrumentation_call (cfg, mono_profiler_method_leave);
2579
2580                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
2581         } else
2582                 MONO_INST_NEW_CALL (cfg, call, ret_type_to_call_opcode (cfg, sig->ret, calli, virtual_));
2583
2584         call->args = args;
2585         call->signature = sig;
2586         call->rgctx_reg = rgctx;
2587         sig_ret = mini_get_underlying_type (sig->ret);
2588
2589         type_to_eval_stack_type ((cfg), sig_ret, &call->inst);
2590
2591         if (tail) {
2592                 if (mini_type_is_vtype (sig_ret)) {
2593                         call->vret_var = cfg->vret_addr;
2594                         //g_assert_not_reached ();
2595                 }
2596         } else if (mini_type_is_vtype (sig_ret)) {
2597                 MonoInst *temp = mono_compile_create_var (cfg, sig_ret, OP_LOCAL);
2598                 MonoInst *loada;
2599
2600                 temp->backend.is_pinvoke = sig->pinvoke;
2601
2602                 /*
2603                  * We use a new opcode OP_OUTARG_VTRETADDR instead of LDADDR for emitting the
2604                  * address of return value to increase optimization opportunities.
2605                  * Before vtype decomposition, the dreg of the call ins itself represents the
2606                  * fact the call modifies the return value. After decomposition, the call will
2607                  * be transformed into one of the OP_VOIDCALL opcodes, and the VTRETADDR opcode
2608                  * will be transformed into an LDADDR.
2609                  */
2610                 MONO_INST_NEW (cfg, loada, OP_OUTARG_VTRETADDR);
2611                 loada->dreg = alloc_preg (cfg);
2612                 loada->inst_p0 = temp;
2613                 /* We reference the call too since call->dreg could change during optimization */
2614                 loada->inst_p1 = call;
2615                 MONO_ADD_INS (cfg->cbb, loada);
2616
2617                 call->inst.dreg = temp->dreg;
2618
2619                 call->vret_var = loada;
2620         } else if (!MONO_TYPE_IS_VOID (sig_ret))
2621                 call->inst.dreg = alloc_dreg (cfg, (MonoStackType)call->inst.type);
2622
2623 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
2624         if (COMPILE_SOFT_FLOAT (cfg)) {
2625                 /* 
2626                  * If the call has a float argument, we would need to do an r8->r4 conversion using 
2627                  * an icall, but that cannot be done during the call sequence since it would clobber
2628                  * the call registers + the stack. So we do it before emitting the call.
2629                  */
2630                 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
2631                         MonoType *t;
2632                         MonoInst *in = call->args [i];
2633
2634                         if (i >= sig->hasthis)
2635                                 t = sig->params [i - sig->hasthis];
2636                         else
2637                                 t = &mono_defaults.int_class->byval_arg;
2638                         t = mono_type_get_underlying_type (t);
2639
2640                         if (!t->byref && t->type == MONO_TYPE_R4) {
2641                                 MonoInst *iargs [1];
2642                                 MonoInst *conv;
2643
2644                                 iargs [0] = in;
2645                                 conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
2646
2647                                 /* The result will be in an int vreg */
2648                                 call->args [i] = conv;
2649                         }
2650                 }
2651         }
2652 #endif
2653
2654         call->need_unbox_trampoline = unbox_trampoline;
2655
2656 #ifdef ENABLE_LLVM
2657         if (COMPILE_LLVM (cfg))
2658                 mono_llvm_emit_call (cfg, call);
2659         else
2660                 mono_arch_emit_call (cfg, call);
2661 #else
2662         mono_arch_emit_call (cfg, call);
2663 #endif
2664
2665         cfg->param_area = MAX (cfg->param_area, call->stack_usage);
2666         cfg->flags |= MONO_CFG_HAS_CALLS;
2667         
2668         return call;
2669 }
2670
2671 static void
2672 set_rgctx_arg (MonoCompile *cfg, MonoCallInst *call, int rgctx_reg, MonoInst *rgctx_arg)
2673 {
2674         mono_call_inst_add_outarg_reg (cfg, call, rgctx_reg, MONO_ARCH_RGCTX_REG, FALSE);
2675         cfg->uses_rgctx_reg = TRUE;
2676         call->rgctx_reg = TRUE;
2677 #ifdef ENABLE_LLVM
2678         call->rgctx_arg_reg = rgctx_reg;
2679 #endif
2680 }       
2681
2682 inline static MonoInst*
2683 mono_emit_calli (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args, MonoInst *addr, MonoInst *imt_arg, MonoInst *rgctx_arg)
2684 {
2685         MonoCallInst *call;
2686         MonoInst *ins;
2687         int rgctx_reg = -1;
2688         gboolean check_sp = FALSE;
2689
2690         if (cfg->check_pinvoke_callconv && cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
2691                 WrapperInfo *info = mono_marshal_get_wrapper_info (cfg->method);
2692
2693                 if (info && info->subtype == WRAPPER_SUBTYPE_PINVOKE)
2694                         check_sp = TRUE;
2695         }
2696
2697         if (rgctx_arg) {
2698                 rgctx_reg = mono_alloc_preg (cfg);
2699                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, rgctx_arg->dreg);
2700         }
2701
2702         if (check_sp) {
2703                 if (!cfg->stack_inbalance_var)
2704                         cfg->stack_inbalance_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2705
2706                 MONO_INST_NEW (cfg, ins, OP_GET_SP);
2707                 ins->dreg = cfg->stack_inbalance_var->dreg;
2708                 MONO_ADD_INS (cfg->cbb, ins);
2709         }
2710
2711         call = mono_emit_call_args (cfg, sig, args, TRUE, FALSE, FALSE, rgctx_arg ? TRUE : FALSE, FALSE);
2712
2713         call->inst.sreg1 = addr->dreg;
2714
2715         if (imt_arg)
2716                 emit_imt_argument (cfg, call, NULL, imt_arg);
2717
2718         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2719
2720         if (check_sp) {
2721                 int sp_reg;
2722
2723                 sp_reg = mono_alloc_preg (cfg);
2724
2725                 MONO_INST_NEW (cfg, ins, OP_GET_SP);
2726                 ins->dreg = sp_reg;
2727                 MONO_ADD_INS (cfg->cbb, ins);
2728
2729                 /* Restore the stack so we don't crash when throwing the exception */
2730                 MONO_INST_NEW (cfg, ins, OP_SET_SP);
2731                 ins->sreg1 = cfg->stack_inbalance_var->dreg;
2732                 MONO_ADD_INS (cfg->cbb, ins);
2733
2734                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, cfg->stack_inbalance_var->dreg, sp_reg);
2735                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "ExecutionEngineException");
2736         }
2737
2738         if (rgctx_arg)
2739                 set_rgctx_arg (cfg, call, rgctx_reg, rgctx_arg);
2740
2741         return (MonoInst*)call;
2742 }
2743
2744 static MonoInst*
2745 emit_get_gsharedvt_info_klass (MonoCompile *cfg, MonoClass *klass, MonoRgctxInfoType rgctx_type);
2746
2747 static MonoInst*
2748 emit_get_rgctx_method (MonoCompile *cfg, int context_used, MonoMethod *cmethod, MonoRgctxInfoType rgctx_type);
2749 static MonoInst*
2750 emit_get_rgctx_klass (MonoCompile *cfg, int context_used, MonoClass *klass, MonoRgctxInfoType rgctx_type);
2751
2752 static MonoInst*
2753 mono_emit_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSignature *sig, gboolean tail,
2754                                                         MonoInst **args, MonoInst *this_ins, MonoInst *imt_arg, MonoInst *rgctx_arg)
2755 {
2756 #ifndef DISABLE_REMOTING
2757         gboolean might_be_remote = FALSE;
2758 #endif
2759         gboolean virtual_ = this_ins != NULL;
2760         gboolean enable_for_aot = TRUE;
2761         int context_used;
2762         MonoCallInst *call;
2763         MonoInst *call_target = NULL;
2764         int rgctx_reg = 0;
2765         gboolean need_unbox_trampoline;
2766
2767         if (!sig)
2768                 sig = mono_method_signature (method);
2769
2770         if (cfg->llvm_only && (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE))
2771                 g_assert_not_reached ();
2772
2773         if (rgctx_arg) {
2774                 rgctx_reg = mono_alloc_preg (cfg);
2775                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, rgctx_arg->dreg);
2776         }
2777
2778         if (method->string_ctor) {
2779                 /* Create the real signature */
2780                 /* FIXME: Cache these */
2781                 MonoMethodSignature *ctor_sig = mono_metadata_signature_dup_mempool (cfg->mempool, sig);
2782                 ctor_sig->ret = &mono_defaults.string_class->byval_arg;
2783
2784                 sig = ctor_sig;
2785         }
2786
2787         context_used = mini_method_check_context_used (cfg, method);
2788
2789 #ifndef DISABLE_REMOTING
2790         might_be_remote = this_ins && sig->hasthis &&
2791                 (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class) &&
2792                 !(method->flags & METHOD_ATTRIBUTE_VIRTUAL) && (!MONO_CHECK_THIS (this_ins) || context_used);
2793
2794         if (might_be_remote && context_used) {
2795                 MonoInst *addr;
2796
2797                 g_assert (cfg->gshared);
2798
2799                 addr = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK);
2800
2801                 return mono_emit_calli (cfg, sig, args, addr, NULL, NULL);
2802         }
2803 #endif
2804
2805         if (cfg->llvm_only && !call_target && virtual_ && (method->flags & METHOD_ATTRIBUTE_VIRTUAL))
2806                 return emit_llvmonly_virtual_call (cfg, method, sig, 0, args);
2807
2808         need_unbox_trampoline = method->klass == mono_defaults.object_class || (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE);
2809
2810         call = mono_emit_call_args (cfg, sig, args, FALSE, virtual_, tail, rgctx_arg ? TRUE : FALSE, need_unbox_trampoline);
2811
2812 #ifndef DISABLE_REMOTING
2813         if (might_be_remote)
2814                 call->method = mono_marshal_get_remoting_invoke_with_check (method);
2815         else
2816 #endif
2817                 call->method = method;
2818         call->inst.flags |= MONO_INST_HAS_METHOD;
2819         call->inst.inst_left = this_ins;
2820         call->tail_call = tail;
2821
2822         if (virtual_) {
2823                 int vtable_reg, slot_reg, this_reg;
2824                 int offset;
2825
2826                 this_reg = this_ins->dreg;
2827
2828                 if (!cfg->llvm_only && (method->klass->parent == mono_defaults.multicastdelegate_class) && !strcmp (method->name, "Invoke")) {
2829                         MonoInst *dummy_use;
2830
2831                         MONO_EMIT_NULL_CHECK (cfg, this_reg);
2832
2833                         /* Make a call to delegate->invoke_impl */
2834                         call->inst.inst_basereg = this_reg;
2835                         call->inst.inst_offset = MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl);
2836                         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2837
2838                         /* We must emit a dummy use here because the delegate trampoline will
2839                         replace the 'this' argument with the delegate target making this activation
2840                         no longer a root for the delegate.
2841                         This is an issue for delegates that target collectible code such as dynamic
2842                         methods of GC'able assemblies.
2843
2844                         For a test case look into #667921.
2845
2846                         FIXME: a dummy use is not the best way to do it as the local register allocator
2847                         will put it on a caller save register and spil it around the call. 
2848                         Ideally, we would either put it on a callee save register or only do the store part.  
2849                          */
2850                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, args [0]);
2851
2852                         return (MonoInst*)call;
2853                 }
2854
2855                 if ((!cfg->compile_aot || enable_for_aot) && 
2856                         (!(method->flags & METHOD_ATTRIBUTE_VIRTUAL) || 
2857                          (MONO_METHOD_IS_FINAL (method) &&
2858                           method->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK)) &&
2859                         !(mono_class_is_marshalbyref (method->klass) && context_used)) {
2860                         /* 
2861                          * the method is not virtual, we just need to ensure this is not null
2862                          * and then we can call the method directly.
2863                          */
2864 #ifndef DISABLE_REMOTING
2865                         if (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class) {
2866                                 /* 
2867                                  * The check above ensures method is not gshared, this is needed since
2868                                  * gshared methods can't have wrappers.
2869                                  */
2870                                 method = call->method = mono_marshal_get_remoting_invoke_with_check (method);
2871                         }
2872 #endif
2873
2874                         if (!method->string_ctor)
2875                                 MONO_EMIT_NEW_CHECK_THIS (cfg, this_reg);
2876
2877                         call->inst.opcode = callvirt_to_call (call->inst.opcode);
2878                 } else if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) && MONO_METHOD_IS_FINAL (method)) {
2879                         /*
2880                          * the method is virtual, but we can statically dispatch since either
2881                          * it's class or the method itself are sealed.
2882                          * But first we need to ensure it's not a null reference.
2883                          */
2884                         MONO_EMIT_NEW_CHECK_THIS (cfg, this_reg);
2885
2886                         call->inst.opcode = callvirt_to_call (call->inst.opcode);
2887                 } else if (call_target) {
2888                         vtable_reg = alloc_preg (cfg);
2889                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
2890
2891                         call->inst.opcode = callvirt_to_call_reg (call->inst.opcode);
2892                         call->inst.sreg1 = call_target->dreg;
2893                         call->inst.flags &= !MONO_INST_HAS_METHOD;
2894                 } else {
2895                         vtable_reg = alloc_preg (cfg);
2896                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
2897                         if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2898                                 guint32 imt_slot = mono_method_get_imt_slot (method);
2899                                 emit_imt_argument (cfg, call, call->method, imt_arg);
2900                                 slot_reg = vtable_reg;
2901                                 offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
2902                         } else {
2903                                 slot_reg = vtable_reg;
2904                                 offset = MONO_STRUCT_OFFSET (MonoVTable, vtable) +
2905                                         ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
2906                                 if (imt_arg) {
2907                                         g_assert (mono_method_signature (method)->generic_param_count);
2908                                         emit_imt_argument (cfg, call, call->method, imt_arg);
2909                                 }
2910                         }
2911
2912                         call->inst.sreg1 = slot_reg;
2913                         call->inst.inst_offset = offset;
2914                         call->is_virtual = TRUE;
2915                 }
2916         }
2917
2918         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2919
2920         if (rgctx_arg)
2921                 set_rgctx_arg (cfg, call, rgctx_reg, rgctx_arg);
2922
2923         return (MonoInst*)call;
2924 }
2925
2926 MonoInst*
2927 mono_emit_method_call (MonoCompile *cfg, MonoMethod *method, MonoInst **args, MonoInst *this_ins)
2928 {
2929         return mono_emit_method_call_full (cfg, method, mono_method_signature (method), FALSE, args, this_ins, NULL, NULL);
2930 }
2931
2932 MonoInst*
2933 mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig,
2934                                            MonoInst **args)
2935 {
2936         MonoCallInst *call;
2937
2938         g_assert (sig);
2939
2940         call = mono_emit_call_args (cfg, sig, args, FALSE, FALSE, FALSE, FALSE, FALSE);
2941         call->fptr = func;
2942
2943         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2944
2945         return (MonoInst*)call;
2946 }
2947
2948 MonoInst*
2949 mono_emit_jit_icall (MonoCompile *cfg, gconstpointer func, MonoInst **args)
2950 {
2951         MonoJitICallInfo *info = mono_find_jit_icall_by_addr (func);
2952
2953         g_assert (info);
2954
2955         return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
2956 }
2957
2958 /*
2959  * mono_emit_abs_call:
2960  *
2961  *   Emit a call to the runtime function described by PATCH_TYPE and DATA.
2962  */
2963 inline static MonoInst*
2964 mono_emit_abs_call (MonoCompile *cfg, MonoJumpInfoType patch_type, gconstpointer data, 
2965                                         MonoMethodSignature *sig, MonoInst **args)
2966 {
2967         MonoJumpInfo *ji = mono_patch_info_new (cfg->mempool, 0, patch_type, data);
2968         MonoInst *ins;
2969
2970         /* 
2971          * We pass ji as the call address, the PATCH_INFO_ABS resolving code will
2972          * handle it.
2973          */
2974         if (cfg->abs_patches == NULL)
2975                 cfg->abs_patches = g_hash_table_new (NULL, NULL);
2976         g_hash_table_insert (cfg->abs_patches, ji, ji);
2977         ins = mono_emit_native_call (cfg, ji, sig, args);
2978         ((MonoCallInst*)ins)->fptr_is_patch = TRUE;
2979         return ins;
2980 }
2981
2982 static MonoMethodSignature*
2983 sig_to_rgctx_sig (MonoMethodSignature *sig)
2984 {
2985         // FIXME: memory allocation
2986         MonoMethodSignature *res;
2987         int i;
2988
2989         res = (MonoMethodSignature *)g_malloc (MONO_SIZEOF_METHOD_SIGNATURE + (sig->param_count + 1) * sizeof (MonoType*));
2990         memcpy (res, sig, MONO_SIZEOF_METHOD_SIGNATURE);
2991         res->param_count = sig->param_count + 1;
2992         for (i = 0; i < sig->param_count; ++i)
2993                 res->params [i] = sig->params [i];
2994         res->params [sig->param_count] = &mono_defaults.int_class->this_arg;
2995         return res;
2996 }
2997
2998 /* Make an indirect call to FSIG passing an additional argument */
2999 static MonoInst*
3000 emit_extra_arg_calli (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **orig_args, int arg_reg, MonoInst *call_target)
3001 {
3002         MonoMethodSignature *csig;
3003         MonoInst *args_buf [16];
3004         MonoInst **args;
3005         int i, pindex, tmp_reg;
3006
3007         /* Make a call with an rgctx/extra arg */
3008         if (fsig->param_count + 2 < 16)
3009                 args = args_buf;
3010         else
3011                 args = (MonoInst **)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (fsig->param_count + 2));
3012         pindex = 0;
3013         if (fsig->hasthis)
3014                 args [pindex ++] = orig_args [0];
3015         for (i = 0; i < fsig->param_count; ++i)
3016                 args [pindex ++] = orig_args [fsig->hasthis + i];
3017         tmp_reg = alloc_preg (cfg);
3018         EMIT_NEW_UNALU (cfg, args [pindex], OP_MOVE, tmp_reg, arg_reg);
3019         csig = sig_to_rgctx_sig (fsig);
3020         return mono_emit_calli (cfg, csig, args, call_target, NULL, NULL);
3021 }
3022
3023 /* Emit an indirect call to the function descriptor ADDR */
3024 static MonoInst*
3025 emit_llvmonly_calli (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, MonoInst *addr)
3026 {
3027         int addr_reg, arg_reg;
3028         MonoInst *call_target;
3029
3030         g_assert (cfg->llvm_only);
3031
3032         /*
3033          * addr points to a <addr, arg> pair, load both of them, and
3034          * make a call to addr, passing arg as an extra arg.
3035          */
3036         addr_reg = alloc_preg (cfg);
3037         EMIT_NEW_LOAD_MEMBASE (cfg, call_target, OP_LOAD_MEMBASE, addr_reg, addr->dreg, 0);
3038         arg_reg = alloc_preg (cfg);
3039         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, arg_reg, addr->dreg, sizeof (gpointer));
3040
3041         return emit_extra_arg_calli (cfg, fsig, args, arg_reg, call_target);
3042 }
3043
3044 static gboolean
3045 direct_icalls_enabled (MonoCompile *cfg)
3046 {
3047         /* LLVM on amd64 can't handle calls to non-32 bit addresses */
3048 #ifdef TARGET_AMD64
3049         if (cfg->compile_llvm)
3050                 return FALSE;
3051 #endif
3052         if (cfg->gen_sdb_seq_points || cfg->disable_direct_icalls)
3053                 return FALSE;
3054         return TRUE;
3055 }
3056
3057 MonoInst*
3058 mono_emit_jit_icall_by_info (MonoCompile *cfg, MonoJitICallInfo *info, MonoInst **args)
3059 {
3060         /*
3061          * Call the jit icall without a wrapper if possible.
3062          * The wrapper is needed for the following reasons:
3063          * - to handle exceptions thrown using mono_raise_exceptions () from the
3064          *   icall function. The EH code needs the lmf frame pushed by the
3065          *   wrapper to be able to unwind back to managed code.
3066          * - to be able to do stack walks for asynchronously suspended
3067          *   threads when debugging.
3068          */
3069         if (info->no_raise && direct_icalls_enabled (cfg)) {
3070                 char *name;
3071                 int costs;
3072
3073                 if (!info->wrapper_method) {
3074                         name = g_strdup_printf ("__icall_wrapper_%s", info->name);
3075                         info->wrapper_method = mono_marshal_get_icall_wrapper (info->sig, name, info->func, TRUE);
3076                         g_free (name);
3077                         mono_memory_barrier ();
3078                 }
3079
3080                 /*
3081                  * Inline the wrapper method, which is basically a call to the C icall, and
3082                  * an exception check.
3083                  */
3084                 costs = inline_method (cfg, info->wrapper_method, NULL,
3085                                                            args, NULL, cfg->real_offset, TRUE);
3086                 g_assert (costs > 0);
3087                 g_assert (!MONO_TYPE_IS_VOID (info->sig->ret));
3088
3089                 return args [0];
3090         } else {
3091                 return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
3092         }
3093 }
3094  
3095 static MonoInst*
3096 mono_emit_widen_call_res (MonoCompile *cfg, MonoInst *ins, MonoMethodSignature *fsig)
3097 {
3098         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
3099                 if ((fsig->pinvoke || LLVM_ENABLED) && !fsig->ret->byref) {
3100                         int widen_op = -1;
3101
3102                         /* 
3103                          * Native code might return non register sized integers 
3104                          * without initializing the upper bits.
3105                          */
3106                         switch (mono_type_to_load_membase (cfg, fsig->ret)) {
3107                         case OP_LOADI1_MEMBASE:
3108                                 widen_op = OP_ICONV_TO_I1;
3109                                 break;
3110                         case OP_LOADU1_MEMBASE:
3111                                 widen_op = OP_ICONV_TO_U1;
3112                                 break;
3113                         case OP_LOADI2_MEMBASE:
3114                                 widen_op = OP_ICONV_TO_I2;
3115                                 break;
3116                         case OP_LOADU2_MEMBASE:
3117                                 widen_op = OP_ICONV_TO_U2;
3118                                 break;
3119                         default:
3120                                 break;
3121                         }
3122
3123                         if (widen_op != -1) {
3124                                 int dreg = alloc_preg (cfg);
3125                                 MonoInst *widen;
3126
3127                                 EMIT_NEW_UNALU (cfg, widen, widen_op, dreg, ins->dreg);
3128                                 widen->type = ins->type;
3129                                 ins = widen;
3130                         }
3131                 }
3132         }
3133
3134         return ins;
3135 }
3136
3137 static MonoMethod*
3138 get_memcpy_method (void)
3139 {
3140         static MonoMethod *memcpy_method = NULL;
3141         if (!memcpy_method) {
3142                 memcpy_method = mono_class_get_method_from_name (mono_defaults.string_class, "memcpy", 3);
3143                 if (!memcpy_method)
3144                         g_error ("Old corlib found. Install a new one");
3145         }
3146         return memcpy_method;
3147 }
3148
3149 static void
3150 create_write_barrier_bitmap (MonoCompile *cfg, MonoClass *klass, unsigned *wb_bitmap, int offset)
3151 {
3152         MonoClassField *field;
3153         gpointer iter = NULL;
3154
3155         while ((field = mono_class_get_fields (klass, &iter))) {
3156                 int foffset;
3157
3158                 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
3159                         continue;
3160                 foffset = klass->valuetype ? field->offset - sizeof (MonoObject): field->offset;
3161                 if (mini_type_is_reference (mono_field_get_type (field))) {
3162                         g_assert ((foffset % SIZEOF_VOID_P) == 0);
3163                         *wb_bitmap |= 1 << ((offset + foffset) / SIZEOF_VOID_P);
3164                 } else {
3165                         MonoClass *field_class = mono_class_from_mono_type (field->type);
3166                         if (field_class->has_references)
3167                                 create_write_barrier_bitmap (cfg, field_class, wb_bitmap, offset + foffset);
3168                 }
3169         }
3170 }
3171
3172 static void
3173 emit_write_barrier (MonoCompile *cfg, MonoInst *ptr, MonoInst *value)
3174 {
3175         int card_table_shift_bits;
3176         gpointer card_table_mask;
3177         guint8 *card_table;
3178         MonoInst *dummy_use;
3179         int nursery_shift_bits;
3180         size_t nursery_size;
3181
3182         if (!cfg->gen_write_barriers)
3183                 return;
3184
3185         card_table = mono_gc_get_card_table (&card_table_shift_bits, &card_table_mask);
3186
3187         mono_gc_get_nursery (&nursery_shift_bits, &nursery_size);
3188
3189         if (cfg->backend->have_card_table_wb && !cfg->compile_aot && card_table && nursery_shift_bits > 0 && !COMPILE_LLVM (cfg)) {
3190                 MonoInst *wbarrier;
3191
3192                 MONO_INST_NEW (cfg, wbarrier, OP_CARD_TABLE_WBARRIER);
3193                 wbarrier->sreg1 = ptr->dreg;
3194                 wbarrier->sreg2 = value->dreg;
3195                 MONO_ADD_INS (cfg->cbb, wbarrier);
3196         } else if (card_table && !cfg->compile_aot && !mono_gc_card_table_nursery_check ()) {
3197                 int offset_reg = alloc_preg (cfg);
3198                 int card_reg;
3199                 MonoInst *ins;
3200
3201                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_UN_IMM, offset_reg, ptr->dreg, card_table_shift_bits);
3202                 if (card_table_mask)
3203                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, offset_reg, offset_reg, card_table_mask);
3204
3205                 /*We can't use PADD_IMM since the cardtable might end up in high addresses and amd64 doesn't support
3206                  * IMM's larger than 32bits.
3207                  */
3208                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_CARD_TABLE_ADDR, NULL);
3209                 card_reg = ins->dreg;
3210
3211                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, offset_reg, offset_reg, card_reg);
3212                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, offset_reg, 0, 1);
3213         } else {
3214                 MonoMethod *write_barrier = mono_gc_get_write_barrier ();
3215                 mono_emit_method_call (cfg, write_barrier, &ptr, NULL);
3216         }
3217
3218         EMIT_NEW_DUMMY_USE (cfg, dummy_use, value);
3219 }
3220
3221 static gboolean
3222 mono_emit_wb_aware_memcpy (MonoCompile *cfg, MonoClass *klass, MonoInst *iargs[4], int size, int align)
3223 {
3224         int dest_ptr_reg, tmp_reg, destreg, srcreg, offset;
3225         unsigned need_wb = 0;
3226
3227         if (align == 0)
3228                 align = 4;
3229
3230         /*types with references can't have alignment smaller than sizeof(void*) */
3231         if (align < SIZEOF_VOID_P)
3232                 return FALSE;
3233
3234         /*This value cannot be bigger than 32 due to the way we calculate the required wb bitmap.*/
3235         if (size > 32 * SIZEOF_VOID_P)
3236                 return FALSE;
3237
3238         create_write_barrier_bitmap (cfg, klass, &need_wb, 0);
3239
3240         /* We don't unroll more than 5 stores to avoid code bloat. */
3241         if (size > 5 * SIZEOF_VOID_P) {
3242                 /*This is harmless and simplify mono_gc_wbarrier_value_copy_bitmap */
3243                 size += (SIZEOF_VOID_P - 1);
3244                 size &= ~(SIZEOF_VOID_P - 1);
3245
3246                 EMIT_NEW_ICONST (cfg, iargs [2], size);
3247                 EMIT_NEW_ICONST (cfg, iargs [3], need_wb);
3248                 mono_emit_jit_icall (cfg, mono_gc_wbarrier_value_copy_bitmap, iargs);
3249                 return TRUE;
3250         }
3251
3252         destreg = iargs [0]->dreg;
3253         srcreg = iargs [1]->dreg;
3254         offset = 0;
3255
3256         dest_ptr_reg = alloc_preg (cfg);
3257         tmp_reg = alloc_preg (cfg);
3258
3259         /*tmp = dreg*/
3260         EMIT_NEW_UNALU (cfg, iargs [0], OP_MOVE, dest_ptr_reg, destreg);
3261
3262         while (size >= SIZEOF_VOID_P) {
3263                 MonoInst *load_inst;
3264                 MONO_INST_NEW (cfg, load_inst, OP_LOAD_MEMBASE);
3265                 load_inst->dreg = tmp_reg;
3266                 load_inst->inst_basereg = srcreg;
3267                 load_inst->inst_offset = offset;
3268                 MONO_ADD_INS (cfg->cbb, load_inst);
3269
3270                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, dest_ptr_reg, 0, tmp_reg);
3271
3272                 if (need_wb & 0x1)
3273                         emit_write_barrier (cfg, iargs [0], load_inst);
3274
3275                 offset += SIZEOF_VOID_P;
3276                 size -= SIZEOF_VOID_P;
3277                 need_wb >>= 1;
3278
3279                 /*tmp += sizeof (void*)*/
3280                 if (size >= SIZEOF_VOID_P) {
3281                         NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, dest_ptr_reg, dest_ptr_reg, SIZEOF_VOID_P);
3282                         MONO_ADD_INS (cfg->cbb, iargs [0]);
3283                 }
3284         }
3285
3286         /* Those cannot be references since size < sizeof (void*) */
3287         while (size >= 4) {
3288                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, tmp_reg, srcreg, offset);
3289                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, tmp_reg);
3290                 offset += 4;
3291                 size -= 4;
3292         }
3293
3294         while (size >= 2) {
3295                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, tmp_reg, srcreg, offset);
3296                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, offset, tmp_reg);
3297                 offset += 2;
3298                 size -= 2;
3299         }
3300
3301         while (size >= 1) {
3302                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, tmp_reg, srcreg, offset);
3303                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, tmp_reg);
3304                 offset += 1;
3305                 size -= 1;
3306         }
3307
3308         return TRUE;
3309 }
3310
3311 /*
3312  * Emit code to copy a valuetype of type @klass whose address is stored in
3313  * @src->dreg to memory whose address is stored at @dest->dreg.
3314  */
3315 void
3316 mini_emit_stobj (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *klass, gboolean native)
3317 {
3318         MonoInst *iargs [4];
3319         int n;
3320         guint32 align = 0;
3321         MonoMethod *memcpy_method;
3322         MonoInst *size_ins = NULL;
3323         MonoInst *memcpy_ins = NULL;
3324
3325         g_assert (klass);
3326         if (cfg->gshared)
3327                 klass = mono_class_from_mono_type (mini_get_underlying_type (&klass->byval_arg));
3328
3329         /*
3330          * This check breaks with spilled vars... need to handle it during verification anyway.
3331          * g_assert (klass && klass == src->klass && klass == dest->klass);
3332          */
3333
3334         if (mini_is_gsharedvt_klass (klass)) {
3335                 g_assert (!native);
3336                 size_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_VALUE_SIZE);
3337                 memcpy_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_MEMCPY);
3338         }
3339
3340         if (native)
3341                 n = mono_class_native_size (klass, &align);
3342         else
3343                 n = mono_class_value_size (klass, &align);
3344
3345         /* if native is true there should be no references in the struct */
3346         if (cfg->gen_write_barriers && (klass->has_references || size_ins) && !native) {
3347                 /* Avoid barriers when storing to the stack */
3348                 if (!((dest->opcode == OP_ADD_IMM && dest->sreg1 == cfg->frame_reg) ||
3349                           (dest->opcode == OP_LDADDR))) {
3350                         int context_used;
3351
3352                         iargs [0] = dest;
3353                         iargs [1] = src;
3354
3355                         context_used = mini_class_check_context_used (cfg, klass);
3356
3357                         /* It's ok to intrinsify under gsharing since shared code types are layout stable. */
3358                         if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && mono_emit_wb_aware_memcpy (cfg, klass, iargs, n, align)) {
3359                                 return;
3360                         } else if (context_used) {
3361                                 iargs [2] = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
3362                         }  else {
3363                                 iargs [2] = emit_runtime_constant (cfg, MONO_PATCH_INFO_CLASS, klass);
3364                                 if (!cfg->compile_aot)
3365                                         mono_class_compute_gc_descriptor (klass);
3366                         }
3367
3368                         if (size_ins)
3369                                 mono_emit_jit_icall (cfg, mono_gsharedvt_value_copy, iargs);
3370                         else
3371                                 mono_emit_jit_icall (cfg, mono_value_copy, iargs);
3372                         return;
3373                 }
3374         }
3375
3376         if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 8) {
3377                 /* FIXME: Optimize the case when src/dest is OP_LDADDR */
3378                 mini_emit_memcpy (cfg, dest->dreg, 0, src->dreg, 0, n, align);
3379         } else {
3380                 iargs [0] = dest;
3381                 iargs [1] = src;
3382                 if (size_ins)
3383                         iargs [2] = size_ins;
3384                 else
3385                         EMIT_NEW_ICONST (cfg, iargs [2], n);
3386                 
3387                 memcpy_method = get_memcpy_method ();
3388                 if (memcpy_ins)
3389                         mono_emit_calli (cfg, mono_method_signature (memcpy_method), iargs, memcpy_ins, NULL, NULL);
3390                 else
3391                         mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
3392         }
3393 }
3394
3395 static MonoMethod*
3396 get_memset_method (void)
3397 {
3398         static MonoMethod *memset_method = NULL;
3399         if (!memset_method) {
3400                 memset_method = mono_class_get_method_from_name (mono_defaults.string_class, "memset", 3);
3401                 if (!memset_method)
3402                         g_error ("Old corlib found. Install a new one");
3403         }
3404         return memset_method;
3405 }
3406
3407 void
3408 mini_emit_initobj (MonoCompile *cfg, MonoInst *dest, const guchar *ip, MonoClass *klass)
3409 {
3410         MonoInst *iargs [3];
3411         int n;
3412         guint32 align;
3413         MonoMethod *memset_method;
3414         MonoInst *size_ins = NULL;
3415         MonoInst *bzero_ins = NULL;
3416         static MonoMethod *bzero_method;
3417
3418         /* FIXME: Optimize this for the case when dest is an LDADDR */
3419         mono_class_init (klass);
3420         if (mini_is_gsharedvt_klass (klass)) {
3421                 size_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_VALUE_SIZE);
3422                 bzero_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_BZERO);
3423                 if (!bzero_method)
3424                         bzero_method = mono_class_get_method_from_name (mono_defaults.string_class, "bzero_aligned_1", 2);
3425                 g_assert (bzero_method);
3426                 iargs [0] = dest;
3427                 iargs [1] = size_ins;
3428                 mono_emit_calli (cfg, mono_method_signature (bzero_method), iargs, bzero_ins, NULL, NULL);
3429                 return;
3430         }
3431
3432         klass = mono_class_from_mono_type (mini_get_underlying_type (&klass->byval_arg));
3433
3434         n = mono_class_value_size (klass, &align);
3435
3436         if (n <= sizeof (gpointer) * 8) {
3437                 mini_emit_memset (cfg, dest->dreg, 0, n, 0, align);
3438         }
3439         else {
3440                 memset_method = get_memset_method ();
3441                 iargs [0] = dest;
3442                 EMIT_NEW_ICONST (cfg, iargs [1], 0);
3443                 EMIT_NEW_ICONST (cfg, iargs [2], n);
3444                 mono_emit_method_call (cfg, memset_method, iargs, NULL);
3445         }
3446 }
3447
3448 /*
3449  * emit_get_rgctx:
3450  *
3451  *   Emit IR to return either the this pointer for instance method,
3452  * or the mrgctx for static methods.
3453  */
3454 static MonoInst*
3455 emit_get_rgctx (MonoCompile *cfg, MonoMethod *method, int context_used)
3456 {
3457         MonoInst *this_ins = NULL;
3458
3459         g_assert (cfg->gshared);
3460
3461         if (!(method->flags & METHOD_ATTRIBUTE_STATIC) &&
3462                         !(context_used & MONO_GENERIC_CONTEXT_USED_METHOD) &&
3463                         !method->klass->valuetype)
3464                 EMIT_NEW_ARGLOAD (cfg, this_ins, 0);
3465
3466         if (context_used & MONO_GENERIC_CONTEXT_USED_METHOD) {
3467                 MonoInst *mrgctx_loc, *mrgctx_var;
3468
3469                 g_assert (!this_ins);
3470                 g_assert (method->is_inflated && mono_method_get_context (method)->method_inst);
3471
3472                 mrgctx_loc = mono_get_vtable_var (cfg);
3473                 EMIT_NEW_TEMPLOAD (cfg, mrgctx_var, mrgctx_loc->inst_c0);
3474
3475                 return mrgctx_var;
3476         } else if (method->flags & METHOD_ATTRIBUTE_STATIC || method->klass->valuetype) {
3477                 MonoInst *vtable_loc, *vtable_var;
3478
3479                 g_assert (!this_ins);
3480
3481                 vtable_loc = mono_get_vtable_var (cfg);
3482                 EMIT_NEW_TEMPLOAD (cfg, vtable_var, vtable_loc->inst_c0);
3483
3484                 if (method->is_inflated && mono_method_get_context (method)->method_inst) {
3485                         MonoInst *mrgctx_var = vtable_var;
3486                         int vtable_reg;
3487
3488                         vtable_reg = alloc_preg (cfg);
3489                         EMIT_NEW_LOAD_MEMBASE (cfg, vtable_var, OP_LOAD_MEMBASE, vtable_reg, mrgctx_var->dreg, MONO_STRUCT_OFFSET (MonoMethodRuntimeGenericContext, class_vtable));
3490                         vtable_var->type = STACK_PTR;
3491                 }
3492
3493                 return vtable_var;
3494         } else {
3495                 MonoInst *ins;
3496                 int vtable_reg;
3497         
3498                 vtable_reg = alloc_preg (cfg);
3499                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, vtable_reg, this_ins->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3500                 return ins;
3501         }
3502 }
3503
3504 static MonoJumpInfoRgctxEntry *
3505 mono_patch_info_rgctx_entry_new (MonoMemPool *mp, MonoMethod *method, gboolean in_mrgctx, MonoJumpInfoType patch_type, gconstpointer patch_data, MonoRgctxInfoType info_type)
3506 {
3507         MonoJumpInfoRgctxEntry *res = (MonoJumpInfoRgctxEntry *)mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoRgctxEntry));
3508         res->method = method;
3509         res->in_mrgctx = in_mrgctx;
3510         res->data = (MonoJumpInfo *)mono_mempool_alloc0 (mp, sizeof (MonoJumpInfo));
3511         res->data->type = patch_type;
3512         res->data->data.target = patch_data;
3513         res->info_type = info_type;
3514
3515         return res;
3516 }
3517
3518 static inline MonoInst*
3519 emit_rgctx_fetch_inline (MonoCompile *cfg, MonoInst *rgctx, MonoJumpInfoRgctxEntry *entry)
3520 {
3521         MonoInst *args [16];
3522         MonoInst *call;
3523
3524         // FIXME: No fastpath since the slot is not a compile time constant
3525         args [0] = rgctx;
3526         EMIT_NEW_AOTCONST (cfg, args [1], MONO_PATCH_INFO_RGCTX_SLOT_INDEX, entry);
3527         if (entry->in_mrgctx)
3528                 call = mono_emit_jit_icall (cfg, mono_fill_method_rgctx, args);
3529         else
3530                 call = mono_emit_jit_icall (cfg, mono_fill_class_rgctx, args);
3531         return call;
3532 #if 0
3533         /*
3534          * FIXME: This can be called during decompose, which is a problem since it creates
3535          * new bblocks.
3536          * Also, the fastpath doesn't work since the slot number is dynamically allocated.
3537          */
3538         int i, slot, depth, index, rgctx_reg, val_reg, res_reg;
3539         gboolean mrgctx;
3540         MonoBasicBlock *is_null_bb, *end_bb;
3541         MonoInst *res, *ins, *call;
3542         MonoInst *args[16];
3543
3544         slot = mini_get_rgctx_entry_slot (entry);
3545
3546         mrgctx = MONO_RGCTX_SLOT_IS_MRGCTX (slot);
3547         index = MONO_RGCTX_SLOT_INDEX (slot);
3548         if (mrgctx)
3549                 index += MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
3550         for (depth = 0; ; ++depth) {
3551                 int size = mono_class_rgctx_get_array_size (depth, mrgctx);
3552
3553                 if (index < size - 1)
3554                         break;
3555                 index -= size - 1;
3556         }
3557
3558         NEW_BBLOCK (cfg, end_bb);
3559         NEW_BBLOCK (cfg, is_null_bb);
3560
3561         if (mrgctx) {
3562                 rgctx_reg = rgctx->dreg;
3563         } else {
3564                 rgctx_reg = alloc_preg (cfg);
3565
3566                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, rgctx_reg, rgctx->dreg, MONO_STRUCT_OFFSET (MonoVTable, runtime_generic_context));
3567                 // FIXME: Avoid this check by allocating the table when the vtable is created etc.
3568                 NEW_BBLOCK (cfg, is_null_bb);
3569
3570                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rgctx_reg, 0);
3571                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3572         }
3573
3574         for (i = 0; i < depth; ++i) {
3575                 int array_reg = alloc_preg (cfg);
3576
3577                 /* load ptr to next array */
3578                 if (mrgctx && i == 0)
3579                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, rgctx_reg, MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT);
3580                 else
3581                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, rgctx_reg, 0);
3582                 rgctx_reg = array_reg;
3583                 /* is the ptr null? */
3584                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rgctx_reg, 0);
3585                 /* if yes, jump to actual trampoline */
3586                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3587         }
3588
3589         /* fetch slot */
3590         val_reg = alloc_preg (cfg);
3591         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, val_reg, rgctx_reg, (index + 1) * sizeof (gpointer));
3592         /* is the slot null? */
3593         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, val_reg, 0);
3594         /* if yes, jump to actual trampoline */
3595         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3596
3597         /* Fastpath */
3598         res_reg = alloc_preg (cfg);
3599         MONO_INST_NEW (cfg, ins, OP_MOVE);
3600         ins->dreg = res_reg;
3601         ins->sreg1 = val_reg;
3602         MONO_ADD_INS (cfg->cbb, ins);
3603         res = ins;
3604         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3605
3606         /* Slowpath */
3607         MONO_START_BB (cfg, is_null_bb);
3608         args [0] = rgctx;
3609         EMIT_NEW_ICONST (cfg, args [1], index);
3610         if (mrgctx)
3611                 call = mono_emit_jit_icall (cfg, mono_fill_method_rgctx, args);
3612         else
3613                 call = mono_emit_jit_icall (cfg, mono_fill_class_rgctx, args);
3614         MONO_INST_NEW (cfg, ins, OP_MOVE);
3615         ins->dreg = res_reg;
3616         ins->sreg1 = call->dreg;
3617         MONO_ADD_INS (cfg->cbb, ins);
3618         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3619
3620         MONO_START_BB (cfg, end_bb);
3621
3622         return res;
3623 #endif
3624 }
3625
3626 /*
3627  * emit_rgctx_fetch:
3628  *
3629  *   Emit IR to load the value of the rgctx entry ENTRY from the rgctx
3630  * given by RGCTX.
3631  */
3632 static inline MonoInst*
3633 emit_rgctx_fetch (MonoCompile *cfg, MonoInst *rgctx, MonoJumpInfoRgctxEntry *entry)
3634 {
3635         if (cfg->llvm_only)
3636                 return emit_rgctx_fetch_inline (cfg, rgctx, entry);
3637         else
3638                 return mono_emit_abs_call (cfg, MONO_PATCH_INFO_RGCTX_FETCH, entry, helper_sig_rgctx_lazy_fetch_trampoline, &rgctx);
3639 }
3640
3641 static MonoInst*
3642 emit_get_rgctx_klass (MonoCompile *cfg, int context_used,
3643                                           MonoClass *klass, MonoRgctxInfoType rgctx_type)
3644 {
3645         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);
3646         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3647
3648         return emit_rgctx_fetch (cfg, rgctx, entry);
3649 }
3650
3651 static MonoInst*
3652 emit_get_rgctx_sig (MonoCompile *cfg, int context_used,
3653                                         MonoMethodSignature *sig, MonoRgctxInfoType rgctx_type)
3654 {
3655         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);
3656         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3657
3658         return emit_rgctx_fetch (cfg, rgctx, entry);
3659 }
3660
3661 static MonoInst*
3662 emit_get_rgctx_gsharedvt_call (MonoCompile *cfg, int context_used,
3663                                                            MonoMethodSignature *sig, MonoMethod *cmethod, MonoRgctxInfoType rgctx_type)
3664 {
3665         MonoJumpInfoGSharedVtCall *call_info;
3666         MonoJumpInfoRgctxEntry *entry;
3667         MonoInst *rgctx;
3668
3669         call_info = (MonoJumpInfoGSharedVtCall *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoGSharedVtCall));
3670         call_info->sig = sig;
3671         call_info->method = cmethod;
3672
3673         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);
3674         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3675
3676         return emit_rgctx_fetch (cfg, rgctx, entry);
3677 }
3678
3679 /*
3680  * emit_get_rgctx_virt_method:
3681  *
3682  *   Return data for method VIRT_METHOD for a receiver of type KLASS.
3683  */
3684 static MonoInst*
3685 emit_get_rgctx_virt_method (MonoCompile *cfg, int context_used,
3686                                                         MonoClass *klass, MonoMethod *virt_method, MonoRgctxInfoType rgctx_type)
3687 {
3688         MonoJumpInfoVirtMethod *info;
3689         MonoJumpInfoRgctxEntry *entry;
3690         MonoInst *rgctx;
3691
3692         info = (MonoJumpInfoVirtMethod *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoVirtMethod));
3693         info->klass = klass;
3694         info->method = virt_method;
3695
3696         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);
3697         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3698
3699         return emit_rgctx_fetch (cfg, rgctx, entry);
3700 }
3701
3702 static MonoInst*
3703 emit_get_rgctx_gsharedvt_method (MonoCompile *cfg, int context_used,
3704                                                                  MonoMethod *cmethod, MonoGSharedVtMethodInfo *info)
3705 {
3706         MonoJumpInfoRgctxEntry *entry;
3707         MonoInst *rgctx;
3708
3709         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);
3710         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3711
3712         return emit_rgctx_fetch (cfg, rgctx, entry);
3713 }
3714
3715 /*
3716  * emit_get_rgctx_method:
3717  *
3718  *   Emit IR to load the property RGCTX_TYPE of CMETHOD. If context_used is 0, emit
3719  * normal constants, else emit a load from the rgctx.
3720  */
3721 static MonoInst*
3722 emit_get_rgctx_method (MonoCompile *cfg, int context_used,
3723                                            MonoMethod *cmethod, MonoRgctxInfoType rgctx_type)
3724 {
3725         if (!context_used) {
3726                 MonoInst *ins;
3727
3728                 switch (rgctx_type) {
3729                 case MONO_RGCTX_INFO_METHOD:
3730                         EMIT_NEW_METHODCONST (cfg, ins, cmethod);
3731                         return ins;
3732                 case MONO_RGCTX_INFO_METHOD_RGCTX:
3733                         EMIT_NEW_METHOD_RGCTX_CONST (cfg, ins, cmethod);
3734                         return ins;
3735                 default:
3736                         g_assert_not_reached ();
3737                 }
3738         } else {
3739                 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);
3740                 MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3741
3742                 return emit_rgctx_fetch (cfg, rgctx, entry);
3743         }
3744 }
3745
3746 static MonoInst*
3747 emit_get_rgctx_field (MonoCompile *cfg, int context_used,
3748                                           MonoClassField *field, MonoRgctxInfoType rgctx_type)
3749 {
3750         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);
3751         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3752
3753         return emit_rgctx_fetch (cfg, rgctx, entry);
3754 }
3755
3756 static int
3757 get_gsharedvt_info_slot (MonoCompile *cfg, gpointer data, MonoRgctxInfoType rgctx_type)
3758 {
3759         MonoGSharedVtMethodInfo *info = cfg->gsharedvt_info;
3760         MonoRuntimeGenericContextInfoTemplate *template_;
3761         int i, idx;
3762
3763         g_assert (info);
3764
3765         for (i = 0; i < info->num_entries; ++i) {
3766                 MonoRuntimeGenericContextInfoTemplate *otemplate = &info->entries [i];
3767
3768                 if (otemplate->info_type == rgctx_type && otemplate->data == data && rgctx_type != MONO_RGCTX_INFO_LOCAL_OFFSET)
3769                         return i;
3770         }
3771
3772         if (info->num_entries == info->count_entries) {
3773                 MonoRuntimeGenericContextInfoTemplate *new_entries;
3774                 int new_count_entries = info->count_entries ? info->count_entries * 2 : 16;
3775
3776                 new_entries = (MonoRuntimeGenericContextInfoTemplate *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoRuntimeGenericContextInfoTemplate) * new_count_entries);
3777
3778                 memcpy (new_entries, info->entries, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
3779                 info->entries = new_entries;
3780                 info->count_entries = new_count_entries;
3781         }
3782
3783         idx = info->num_entries;
3784         template_ = &info->entries [idx];
3785         template_->info_type = rgctx_type;
3786         template_->data = data;
3787
3788         info->num_entries ++;
3789
3790         return idx;
3791 }
3792
3793 /*
3794  * emit_get_gsharedvt_info:
3795  *
3796  *   This is similar to emit_get_rgctx_.., but loads the data from the gsharedvt info var instead of calling an rgctx fetch trampoline.
3797  */
3798 static MonoInst*
3799 emit_get_gsharedvt_info (MonoCompile *cfg, gpointer data, MonoRgctxInfoType rgctx_type)
3800 {
3801         MonoInst *ins;
3802         int idx, dreg;
3803
3804         idx = get_gsharedvt_info_slot (cfg, data, rgctx_type);
3805         /* Load info->entries [idx] */
3806         dreg = alloc_preg (cfg);
3807         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, cfg->gsharedvt_info_var->dreg, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, entries) + (idx * sizeof (gpointer)));
3808
3809         return ins;
3810 }
3811
3812 static MonoInst*
3813 emit_get_gsharedvt_info_klass (MonoCompile *cfg, MonoClass *klass, MonoRgctxInfoType rgctx_type)
3814 {
3815         return emit_get_gsharedvt_info (cfg, &klass->byval_arg, rgctx_type);
3816 }
3817
3818 /*
3819  * On return the caller must check @klass for load errors.
3820  */
3821 static void
3822 emit_class_init (MonoCompile *cfg, MonoClass *klass)
3823 {
3824         MonoInst *vtable_arg;
3825         int context_used;
3826
3827         context_used = mini_class_check_context_used (cfg, klass);
3828
3829         if (context_used) {
3830                 vtable_arg = emit_get_rgctx_klass (cfg, context_used,
3831                                                                                    klass, MONO_RGCTX_INFO_VTABLE);
3832         } else {
3833                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
3834
3835                 if (!vtable)
3836                         return;
3837                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
3838         }
3839
3840         if (!COMPILE_LLVM (cfg) && cfg->backend->have_op_generic_class_init) {
3841                 MonoInst *ins;
3842
3843                 /*
3844                  * Using an opcode instead of emitting IR here allows the hiding of the call inside the opcode,
3845                  * so this doesn't have to clobber any regs and it doesn't break basic blocks.
3846                  */
3847                 MONO_INST_NEW (cfg, ins, OP_GENERIC_CLASS_INIT);
3848                 ins->sreg1 = vtable_arg->dreg;
3849                 MONO_ADD_INS (cfg->cbb, ins);
3850         } else {
3851                 static int byte_offset = -1;
3852                 static guint8 bitmask;
3853                 int bits_reg, inited_reg;
3854                 MonoBasicBlock *inited_bb;
3855                 MonoInst *args [16];
3856
3857                 if (byte_offset < 0)
3858                         mono_marshal_find_bitfield_offset (MonoVTable, initialized, &byte_offset, &bitmask);
3859
3860                 bits_reg = alloc_ireg (cfg);
3861                 inited_reg = alloc_ireg (cfg);
3862
3863                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, bits_reg, vtable_arg->dreg, byte_offset);
3864                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, inited_reg, bits_reg, bitmask);
3865
3866                 NEW_BBLOCK (cfg, inited_bb);
3867
3868                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, inited_reg, 0);
3869                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, inited_bb);
3870
3871                 args [0] = vtable_arg;
3872                 mono_emit_jit_icall (cfg, mono_generic_class_init, args);
3873
3874                 MONO_START_BB (cfg, inited_bb);
3875         }
3876 }
3877
3878 static void
3879 emit_seq_point (MonoCompile *cfg, MonoMethod *method, guint8* ip, gboolean intr_loc, gboolean nonempty_stack)
3880 {
3881         MonoInst *ins;
3882
3883         if (cfg->gen_seq_points && cfg->method == method) {
3884                 NEW_SEQ_POINT (cfg, ins, ip - cfg->header->code, intr_loc);
3885                 if (nonempty_stack)
3886                         ins->flags |= MONO_INST_NONEMPTY_STACK;
3887                 MONO_ADD_INS (cfg->cbb, ins);
3888         }
3889 }
3890
3891 static void
3892 save_cast_details (MonoCompile *cfg, MonoClass *klass, int obj_reg, gboolean null_check)
3893 {
3894         if (mini_get_debug_options ()->better_cast_details) {
3895                 int vtable_reg = alloc_preg (cfg);
3896                 int klass_reg = alloc_preg (cfg);
3897                 MonoBasicBlock *is_null_bb = NULL;
3898                 MonoInst *tls_get;
3899                 int to_klass_reg, context_used;
3900
3901                 if (null_check) {
3902                         NEW_BBLOCK (cfg, is_null_bb);
3903
3904                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
3905                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3906                 }
3907
3908                 tls_get = mono_get_jit_tls_intrinsic (cfg);
3909                 if (!tls_get) {
3910                         fprintf (stderr, "error: --debug=casts not supported on this platform.\n.");
3911                         exit (1);
3912                 }
3913
3914                 MONO_ADD_INS (cfg->cbb, tls_get);
3915                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3916                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
3917
3918                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), klass_reg);
3919
3920                 context_used = mini_class_check_context_used (cfg, klass);
3921                 if (context_used) {
3922                         MonoInst *class_ins;
3923
3924                         class_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
3925                         to_klass_reg = class_ins->dreg;
3926                 } else {
3927                         to_klass_reg = alloc_preg (cfg);
3928                         MONO_EMIT_NEW_CLASSCONST (cfg, to_klass_reg, klass);
3929                 }
3930                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_to), to_klass_reg);
3931
3932                 if (null_check)
3933                         MONO_START_BB (cfg, is_null_bb);
3934         }
3935 }
3936
3937 static void
3938 reset_cast_details (MonoCompile *cfg)
3939 {
3940         /* Reset the variables holding the cast details */
3941         if (mini_get_debug_options ()->better_cast_details) {
3942                 MonoInst *tls_get = mono_get_jit_tls_intrinsic (cfg);
3943
3944                 MONO_ADD_INS (cfg->cbb, tls_get);
3945                 /* It is enough to reset the from field */
3946                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), 0);
3947         }
3948 }
3949
3950 /*
3951  * On return the caller must check @array_class for load errors
3952  */
3953 static void
3954 mini_emit_check_array_type (MonoCompile *cfg, MonoInst *obj, MonoClass *array_class)
3955 {
3956         int vtable_reg = alloc_preg (cfg);
3957         int context_used;
3958
3959         context_used = mini_class_check_context_used (cfg, array_class);
3960
3961         save_cast_details (cfg, array_class, obj->dreg, FALSE);
3962
3963         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3964
3965         if (cfg->opt & MONO_OPT_SHARED) {
3966                 int class_reg = alloc_preg (cfg);
3967                 MonoInst *ins;
3968
3969                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, class_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
3970                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_CLASS, array_class);
3971                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, class_reg, ins->dreg);
3972         } else if (context_used) {
3973                 MonoInst *vtable_ins;
3974
3975                 vtable_ins = emit_get_rgctx_klass (cfg, context_used, array_class, MONO_RGCTX_INFO_VTABLE);
3976                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, vtable_reg, vtable_ins->dreg);
3977         } else {
3978                 if (cfg->compile_aot) {
3979                         int vt_reg;
3980                         MonoVTable *vtable;
3981
3982                         if (!(vtable = mono_class_vtable (cfg->domain, array_class)))
3983                                 return;
3984                         vt_reg = alloc_preg (cfg);
3985                         MONO_EMIT_NEW_VTABLECONST (cfg, vt_reg, vtable);
3986                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, vtable_reg, vt_reg);
3987                 } else {
3988                         MonoVTable *vtable;
3989                         if (!(vtable = mono_class_vtable (cfg->domain, array_class)))
3990                                 return;
3991                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vtable);
3992                 }
3993         }
3994         
3995         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "ArrayTypeMismatchException");
3996
3997         reset_cast_details (cfg);
3998 }
3999
4000 /**
4001  * Handles unbox of a Nullable<T>. If context_used is non zero, then shared 
4002  * generic code is generated.
4003  */
4004 static MonoInst*
4005 handle_unbox_nullable (MonoCompile* cfg, MonoInst* val, MonoClass* klass, int context_used)
4006 {
4007         MonoMethod* method = mono_class_get_method_from_name (klass, "Unbox", 1);
4008
4009         if (context_used) {
4010                 MonoInst *rgctx, *addr;
4011
4012                 /* FIXME: What if the class is shared?  We might not
4013                    have to get the address of the method from the
4014                    RGCTX. */
4015                 addr = emit_get_rgctx_method (cfg, context_used, method,
4016                                                                           MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
4017                 if (cfg->llvm_only && cfg->gsharedvt) {
4018                         return emit_llvmonly_calli (cfg, mono_method_signature (method), &val, addr);
4019                 } else {
4020                         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
4021
4022                         return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
4023                 }
4024         } else {
4025                 gboolean pass_vtable, pass_mrgctx;
4026                 MonoInst *rgctx_arg = NULL;
4027
4028                 check_method_sharing (cfg, method, &pass_vtable, &pass_mrgctx);
4029                 g_assert (!pass_mrgctx);
4030
4031                 if (pass_vtable) {
4032                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
4033
4034                         g_assert (vtable);
4035                         EMIT_NEW_VTABLECONST (cfg, rgctx_arg, vtable);
4036                 }
4037
4038                 return mono_emit_method_call_full (cfg, method, NULL, FALSE, &val, NULL, NULL, rgctx_arg);
4039         }
4040 }
4041
4042 static MonoInst*
4043 handle_unbox (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, int context_used)
4044 {
4045         MonoInst *add;
4046         int obj_reg;
4047         int vtable_reg = alloc_dreg (cfg ,STACK_PTR);
4048         int klass_reg = alloc_dreg (cfg ,STACK_PTR);
4049         int eclass_reg = alloc_dreg (cfg ,STACK_PTR);
4050         int rank_reg = alloc_dreg (cfg ,STACK_I4);
4051
4052         obj_reg = sp [0]->dreg;
4053         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4054         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
4055
4056         /* FIXME: generics */
4057         g_assert (klass->rank == 0);
4058                         
4059         // Check rank == 0
4060         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, 0);
4061         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
4062
4063         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4064         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, element_class));
4065
4066         if (context_used) {
4067                 MonoInst *element_class;
4068
4069                 /* This assertion is from the unboxcast insn */
4070                 g_assert (klass->rank == 0);
4071
4072                 element_class = emit_get_rgctx_klass (cfg, context_used,
4073                                 klass, MONO_RGCTX_INFO_ELEMENT_KLASS);
4074
4075                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, eclass_reg, element_class->dreg);
4076                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
4077         } else {
4078                 save_cast_details (cfg, klass->element_class, obj_reg, FALSE);
4079                 mini_emit_class_check (cfg, eclass_reg, klass->element_class);
4080                 reset_cast_details (cfg);
4081         }
4082
4083         NEW_BIALU_IMM (cfg, add, OP_ADD_IMM, alloc_dreg (cfg, STACK_MP), obj_reg, sizeof (MonoObject));
4084         MONO_ADD_INS (cfg->cbb, add);
4085         add->type = STACK_MP;
4086         add->klass = klass;
4087
4088         return add;
4089 }
4090
4091 static MonoInst*
4092 handle_unbox_gsharedvt (MonoCompile *cfg, MonoClass *klass, MonoInst *obj)
4093 {
4094         MonoInst *addr, *klass_inst, *is_ref, *args[16];
4095         MonoBasicBlock *is_ref_bb, *is_nullable_bb, *end_bb;
4096         MonoInst *ins;
4097         int dreg, addr_reg;
4098
4099         klass_inst = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_KLASS);
4100
4101         /* obj */
4102         args [0] = obj;
4103
4104         /* klass */
4105         args [1] = klass_inst;
4106
4107         /* CASTCLASS */
4108         obj = mono_emit_jit_icall (cfg, mono_object_castclass_unbox, args);
4109
4110         NEW_BBLOCK (cfg, is_ref_bb);
4111         NEW_BBLOCK (cfg, is_nullable_bb);
4112         NEW_BBLOCK (cfg, end_bb);
4113         is_ref = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_CLASS_BOX_TYPE);
4114         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, MONO_GSHAREDVT_BOX_TYPE_REF);
4115         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
4116
4117         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
4118         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_nullable_bb);
4119
4120         /* This will contain either the address of the unboxed vtype, or an address of the temporary where the ref is stored */
4121         addr_reg = alloc_dreg (cfg, STACK_MP);
4122
4123         /* Non-ref case */
4124         /* UNBOX */
4125         NEW_BIALU_IMM (cfg, addr, OP_ADD_IMM, addr_reg, obj->dreg, sizeof (MonoObject));
4126         MONO_ADD_INS (cfg->cbb, addr);
4127
4128         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4129
4130         /* Ref case */
4131         MONO_START_BB (cfg, is_ref_bb);
4132
4133         /* Save the ref to a temporary */
4134         dreg = alloc_ireg (cfg);
4135         EMIT_NEW_VARLOADA_VREG (cfg, addr, dreg, &klass->byval_arg);
4136         addr->dreg = addr_reg;
4137         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, obj->dreg);
4138         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4139
4140         /* Nullable case */
4141         MONO_START_BB (cfg, is_nullable_bb);
4142
4143         {
4144                 MonoInst *addr = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX);
4145                 MonoInst *unbox_call;
4146                 MonoMethodSignature *unbox_sig;
4147
4148                 unbox_sig = (MonoMethodSignature *)mono_mempool_alloc0 (cfg->mempool, MONO_SIZEOF_METHOD_SIGNATURE + (1 * sizeof (MonoType *)));
4149                 unbox_sig->ret = &klass->byval_arg;
4150                 unbox_sig->param_count = 1;
4151                 unbox_sig->params [0] = &mono_defaults.object_class->byval_arg;
4152
4153                 if (cfg->llvm_only)
4154                         unbox_call = emit_llvmonly_calli (cfg, unbox_sig, &obj, addr);
4155                 else
4156                         unbox_call = mono_emit_calli (cfg, unbox_sig, &obj, addr, NULL, NULL);
4157
4158                 EMIT_NEW_VARLOADA_VREG (cfg, addr, unbox_call->dreg, &klass->byval_arg);
4159                 addr->dreg = addr_reg;
4160         }
4161
4162         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4163
4164         /* End */
4165         MONO_START_BB (cfg, end_bb);
4166
4167         /* LDOBJ */
4168         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr_reg, 0);
4169
4170         return ins;
4171 }
4172
4173 /*
4174  * Returns NULL and set the cfg exception on error.
4175  */
4176 static MonoInst*
4177 handle_alloc (MonoCompile *cfg, MonoClass *klass, gboolean for_box, int context_used)
4178 {
4179         MonoInst *iargs [2];
4180         void *alloc_ftn;
4181
4182         if (context_used) {
4183                 MonoInst *data;
4184                 MonoRgctxInfoType rgctx_info;
4185                 MonoInst *iargs [2];
4186                 gboolean known_instance_size = !mini_is_gsharedvt_klass (klass);
4187
4188                 MonoMethod *managed_alloc = mono_gc_get_managed_allocator (klass, for_box, known_instance_size);
4189
4190                 if (cfg->opt & MONO_OPT_SHARED)
4191                         rgctx_info = MONO_RGCTX_INFO_KLASS;
4192                 else
4193                         rgctx_info = MONO_RGCTX_INFO_VTABLE;
4194                 data = emit_get_rgctx_klass (cfg, context_used, klass, rgctx_info);
4195
4196                 if (cfg->opt & MONO_OPT_SHARED) {
4197                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
4198                         iargs [1] = data;
4199                         alloc_ftn = ves_icall_object_new;
4200                 } else {
4201                         iargs [0] = data;
4202                         alloc_ftn = ves_icall_object_new_specific;
4203                 }
4204
4205                 if (managed_alloc && !(cfg->opt & MONO_OPT_SHARED)) {
4206                         if (known_instance_size) {
4207                                 int size = mono_class_instance_size (klass);
4208                                 if (size < sizeof (MonoObject))
4209                                         g_error ("Invalid size %d for class %s", size, mono_type_get_full_name (klass));
4210
4211                                 EMIT_NEW_ICONST (cfg, iargs [1], mono_gc_get_aligned_size_for_allocator (size));
4212                         }
4213                         return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
4214                 }
4215
4216                 return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
4217         }
4218
4219         if (cfg->opt & MONO_OPT_SHARED) {
4220                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
4221                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
4222
4223                 alloc_ftn = ves_icall_object_new;
4224         } else if (cfg->compile_aot && cfg->cbb->out_of_line && klass->type_token && klass->image == mono_defaults.corlib && !klass->generic_class) {
4225                 /* This happens often in argument checking code, eg. throw new FooException... */
4226                 /* Avoid relocations and save some space by calling a helper function specialized to mscorlib */
4227                 EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (klass->type_token));
4228                 return mono_emit_jit_icall (cfg, mono_helper_newobj_mscorlib, iargs);
4229         } else {
4230                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
4231                 MonoMethod *managed_alloc = NULL;
4232                 gboolean pass_lw;
4233
4234                 if (!vtable) {
4235                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4236                         cfg->exception_ptr = klass;
4237                         return NULL;
4238                 }
4239
4240                 managed_alloc = mono_gc_get_managed_allocator (klass, for_box, TRUE);
4241
4242                 if (managed_alloc) {
4243                         int size = mono_class_instance_size (klass);
4244                         if (size < sizeof (MonoObject))
4245                                 g_error ("Invalid size %d for class %s", size, mono_type_get_full_name (klass));
4246
4247                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
4248                         EMIT_NEW_ICONST (cfg, iargs [1], mono_gc_get_aligned_size_for_allocator (size));
4249                         return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
4250                 }
4251                 alloc_ftn = mono_class_get_allocation_ftn (vtable, for_box, &pass_lw);
4252                 if (pass_lw) {
4253                         guint32 lw = vtable->klass->instance_size;
4254                         lw = ((lw + (sizeof (gpointer) - 1)) & ~(sizeof (gpointer) - 1)) / sizeof (gpointer);
4255                         EMIT_NEW_ICONST (cfg, iargs [0], lw);
4256                         EMIT_NEW_VTABLECONST (cfg, iargs [1], vtable);
4257                 }
4258                 else {
4259                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
4260                 }
4261         }
4262
4263         return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
4264 }
4265         
4266 /*
4267  * Returns NULL and set the cfg exception on error.
4268  */     
4269 static MonoInst*
4270 handle_box (MonoCompile *cfg, MonoInst *val, MonoClass *klass, int context_used)
4271 {
4272         MonoInst *alloc, *ins;
4273
4274         if (mono_class_is_nullable (klass)) {
4275                 MonoMethod* method = mono_class_get_method_from_name (klass, "Box", 1);
4276
4277                 if (context_used) {
4278                         if (cfg->llvm_only && cfg->gsharedvt) {
4279                                 MonoInst *addr = emit_get_rgctx_method (cfg, context_used, method,
4280                                                                                                                 MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
4281                                 return emit_llvmonly_calli (cfg, mono_method_signature (method), &val, addr);
4282                         } else {
4283                                 /* FIXME: What if the class is shared?  We might not
4284                                    have to get the method address from the RGCTX. */
4285                                 MonoInst *addr = emit_get_rgctx_method (cfg, context_used, method,
4286                                                                                                                 MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
4287                                 MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
4288
4289                                 return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
4290                         }
4291                 } else {
4292                         gboolean pass_vtable, pass_mrgctx;
4293                         MonoInst *rgctx_arg = NULL;
4294
4295                         check_method_sharing (cfg, method, &pass_vtable, &pass_mrgctx);
4296                         g_assert (!pass_mrgctx);
4297
4298                         if (pass_vtable) {
4299                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
4300
4301                                 g_assert (vtable);
4302                                 EMIT_NEW_VTABLECONST (cfg, rgctx_arg, vtable);
4303                         }
4304
4305                         return mono_emit_method_call_full (cfg, method, NULL, FALSE, &val, NULL, NULL, rgctx_arg);
4306                 }
4307         }
4308
4309         if (mini_is_gsharedvt_klass (klass)) {
4310                 MonoBasicBlock *is_ref_bb, *is_nullable_bb, *end_bb;
4311                 MonoInst *res, *is_ref, *src_var, *addr;
4312                 int dreg;
4313
4314                 dreg = alloc_ireg (cfg);
4315
4316                 NEW_BBLOCK (cfg, is_ref_bb);
4317                 NEW_BBLOCK (cfg, is_nullable_bb);
4318                 NEW_BBLOCK (cfg, end_bb);
4319                 is_ref = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_CLASS_BOX_TYPE);
4320                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, MONO_GSHAREDVT_BOX_TYPE_REF);
4321                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
4322
4323                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
4324                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_nullable_bb);
4325
4326                 /* Non-ref case */
4327                 alloc = handle_alloc (cfg, klass, TRUE, context_used);
4328                 if (!alloc)
4329                         return NULL;
4330                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
4331                 ins->opcode = OP_STOREV_MEMBASE;
4332
4333                 EMIT_NEW_UNALU (cfg, res, OP_MOVE, dreg, alloc->dreg);
4334                 res->type = STACK_OBJ;
4335                 res->klass = klass;
4336                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4337                 
4338                 /* Ref case */
4339                 MONO_START_BB (cfg, is_ref_bb);
4340
4341                 /* val is a vtype, so has to load the value manually */
4342                 src_var = get_vreg_to_inst (cfg, val->dreg);
4343                 if (!src_var)
4344                         src_var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, val->dreg);
4345                 EMIT_NEW_VARLOADA (cfg, addr, src_var, src_var->inst_vtype);
4346                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, addr->dreg, 0);
4347                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4348
4349                 /* Nullable case */
4350                 MONO_START_BB (cfg, is_nullable_bb);
4351
4352                 {
4353                         MonoInst *addr = emit_get_gsharedvt_info_klass (cfg, klass,
4354                                                                                                         MONO_RGCTX_INFO_NULLABLE_CLASS_BOX);
4355                         MonoInst *box_call;
4356                         MonoMethodSignature *box_sig;
4357
4358                         /*
4359                          * klass is Nullable<T>, need to call Nullable<T>.Box () using a gsharedvt signature, but we cannot
4360                          * construct that method at JIT time, so have to do things by hand.
4361                          */
4362                         box_sig = (MonoMethodSignature *)mono_mempool_alloc0 (cfg->mempool, MONO_SIZEOF_METHOD_SIGNATURE + (1 * sizeof (MonoType *)));
4363                         box_sig->ret = &mono_defaults.object_class->byval_arg;
4364                         box_sig->param_count = 1;
4365                         box_sig->params [0] = &klass->byval_arg;
4366
4367                         if (cfg->llvm_only)
4368                                 box_call = emit_llvmonly_calli (cfg, box_sig, &val, addr);
4369                         else
4370                                 box_call = mono_emit_calli (cfg, box_sig, &val, addr, NULL, NULL);
4371                         EMIT_NEW_UNALU (cfg, res, OP_MOVE, dreg, box_call->dreg);
4372                         res->type = STACK_OBJ;
4373                         res->klass = klass;
4374                 }
4375
4376                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4377
4378                 MONO_START_BB (cfg, end_bb);
4379
4380                 return res;
4381         } else {
4382                 alloc = handle_alloc (cfg, klass, TRUE, context_used);
4383                 if (!alloc)
4384                         return NULL;
4385
4386                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
4387                 return alloc;
4388         }
4389 }
4390
4391 static gboolean
4392 mini_class_has_reference_variant_generic_argument (MonoCompile *cfg, MonoClass *klass, int context_used)
4393 {
4394         int i;
4395         MonoGenericContainer *container;
4396         MonoGenericInst *ginst;
4397
4398         if (klass->generic_class) {
4399                 container = klass->generic_class->container_class->generic_container;
4400                 ginst = klass->generic_class->context.class_inst;
4401         } else if (klass->generic_container && context_used) {
4402                 container = klass->generic_container;
4403                 ginst = container->context.class_inst;
4404         } else {
4405                 return FALSE;
4406         }
4407
4408         for (i = 0; i < container->type_argc; ++i) {
4409                 MonoType *type;
4410                 if (!(mono_generic_container_get_param_info (container, i)->flags & (MONO_GEN_PARAM_VARIANT|MONO_GEN_PARAM_COVARIANT)))
4411                         continue;
4412                 type = ginst->type_argv [i];
4413                 if (mini_type_is_reference (type))
4414                         return TRUE;
4415         }
4416         return FALSE;
4417 }
4418
4419 static GHashTable* direct_icall_type_hash;
4420
4421 static gboolean
4422 icall_is_direct_callable (MonoCompile *cfg, MonoMethod *cmethod)
4423 {
4424         /* LLVM on amd64 can't handle calls to non-32 bit addresses */
4425         if (!direct_icalls_enabled (cfg))
4426                 return FALSE;
4427
4428         /*
4429          * An icall is directly callable if it doesn't directly or indirectly call mono_raise_exception ().
4430          * Whitelist a few icalls for now.
4431          */
4432         if (!direct_icall_type_hash) {
4433                 GHashTable *h = g_hash_table_new (g_str_hash, g_str_equal);
4434
4435                 g_hash_table_insert (h, (char*)"Decimal", GUINT_TO_POINTER (1));
4436                 g_hash_table_insert (h, (char*)"Number", GUINT_TO_POINTER (1));
4437                 g_hash_table_insert (h, (char*)"Buffer", GUINT_TO_POINTER (1));
4438                 g_hash_table_insert (h, (char*)"Monitor", GUINT_TO_POINTER (1));
4439                 mono_memory_barrier ();
4440                 direct_icall_type_hash = h;
4441         }
4442
4443         if (cmethod->klass == mono_defaults.math_class)
4444                 return TRUE;
4445         /* No locking needed */
4446         if (cmethod->klass->image == mono_defaults.corlib && g_hash_table_lookup (direct_icall_type_hash, cmethod->klass->name))
4447                 return TRUE;
4448         return FALSE;
4449 }
4450
4451 #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)
4452
4453 static MonoInst*
4454 emit_castclass_with_cache (MonoCompile *cfg, MonoClass *klass, MonoInst **args)
4455 {
4456         MonoMethod *mono_castclass;
4457         MonoInst *res;
4458
4459         mono_castclass = mono_marshal_get_castclass_with_cache ();
4460
4461         save_cast_details (cfg, klass, args [0]->dreg, TRUE);
4462         res = mono_emit_method_call (cfg, mono_castclass, args, NULL);
4463         reset_cast_details (cfg);
4464
4465         return res;
4466 }
4467
4468 static int
4469 get_castclass_cache_idx (MonoCompile *cfg)
4470 {
4471         /* Each CASTCLASS_CACHE patch needs a unique index which identifies the call site */
4472         cfg->castclass_cache_index ++;
4473         return (cfg->method_index << 16) | cfg->castclass_cache_index;
4474 }
4475
4476 static MonoInst*
4477 emit_castclass_with_cache_nonshared (MonoCompile *cfg, MonoInst *obj, MonoClass *klass)
4478 {
4479         MonoInst *args [3];
4480         int idx;
4481
4482         /* obj */
4483         args [0] = obj;
4484
4485         /* klass */
4486         EMIT_NEW_CLASSCONST (cfg, args [1], klass);
4487
4488         /* inline cache*/
4489         idx = get_castclass_cache_idx (cfg);
4490         args [2] = emit_runtime_constant (cfg, MONO_PATCH_INFO_CASTCLASS_CACHE, GINT_TO_POINTER (idx));
4491
4492         /*The wrapper doesn't inline well so the bloat of inlining doesn't pay off.*/
4493         return emit_castclass_with_cache (cfg, klass, args);
4494 }
4495
4496 /*
4497  * Returns NULL and set the cfg exception on error.
4498  */
4499 static MonoInst*
4500 handle_castclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src, guint8 *ip, int *inline_costs)
4501 {
4502         MonoBasicBlock *is_null_bb;
4503         int obj_reg = src->dreg;
4504         int vtable_reg = alloc_preg (cfg);
4505         int context_used;
4506         MonoInst *klass_inst = NULL, *res;
4507
4508         context_used = mini_class_check_context_used (cfg, klass);
4509
4510         if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
4511                 res = emit_castclass_with_cache_nonshared (cfg, src, klass);
4512                 (*inline_costs) += 2;
4513                 return res;
4514         } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
4515                 MonoMethod *mono_castclass;
4516                 MonoInst *iargs [1];
4517                 int costs;
4518
4519                 mono_castclass = mono_marshal_get_castclass (klass); 
4520                 iargs [0] = src;
4521                                 
4522                 save_cast_details (cfg, klass, src->dreg, TRUE);
4523                 costs = inline_method (cfg, mono_castclass, mono_method_signature (mono_castclass), 
4524                                                            iargs, ip, cfg->real_offset, TRUE);
4525                 reset_cast_details (cfg);
4526                 CHECK_CFG_EXCEPTION;
4527                 g_assert (costs > 0);
4528                                 
4529                 cfg->real_offset += 5;
4530
4531                 (*inline_costs) += costs;
4532
4533                 return src;
4534         }
4535
4536         if (context_used) {
4537                 MonoInst *args [3];
4538
4539                 if(mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || is_complex_isinst (klass)) {
4540                         MonoInst *cache_ins;
4541
4542                         cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
4543
4544                         /* obj */
4545                         args [0] = src;
4546
4547                         /* klass - it's the second element of the cache entry*/
4548                         EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer));
4549
4550                         /* cache */
4551                         args [2] = cache_ins;
4552
4553                         return emit_castclass_with_cache (cfg, klass, args);
4554                 }
4555
4556                 klass_inst = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
4557         }
4558
4559         NEW_BBLOCK (cfg, is_null_bb);
4560
4561         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4562         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
4563
4564         save_cast_details (cfg, klass, obj_reg, FALSE);
4565
4566         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4567                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4568                 mini_emit_iface_cast (cfg, vtable_reg, klass, NULL, NULL);
4569         } else {
4570                 int klass_reg = alloc_preg (cfg);
4571
4572                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4573
4574                 if (!klass->rank && !cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && (klass->flags & TYPE_ATTRIBUTE_SEALED)) {
4575                         /* the remoting code is broken, access the class for now */
4576                         if (0) { /*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
4577                                 MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
4578                                 if (!vt) {
4579                                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4580                                         cfg->exception_ptr = klass;
4581                                         return NULL;
4582                                 }
4583                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vt);
4584                         } else {
4585                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4586                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
4587                         }
4588                         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
4589                 } else {
4590                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4591                         mini_emit_castclass_inst (cfg, obj_reg, klass_reg, klass, klass_inst, is_null_bb);
4592                 }
4593         }
4594
4595         MONO_START_BB (cfg, is_null_bb);
4596
4597         reset_cast_details (cfg);
4598
4599         return src;
4600
4601 exception_exit:
4602         return NULL;
4603 }
4604
4605 /*
4606  * Returns NULL and set the cfg exception on error.
4607  */
4608 static MonoInst*
4609 handle_isinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context_used)
4610 {
4611         MonoInst *ins;
4612         MonoBasicBlock *is_null_bb, *false_bb, *end_bb;
4613         int obj_reg = src->dreg;
4614         int vtable_reg = alloc_preg (cfg);
4615         int res_reg = alloc_ireg_ref (cfg);
4616         MonoInst *klass_inst = NULL;
4617
4618         if (context_used) {
4619                 MonoInst *args [3];
4620
4621                 if(mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || is_complex_isinst (klass)) {
4622                         MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
4623                         MonoInst *cache_ins;
4624
4625                         cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
4626
4627                         /* obj */
4628                         args [0] = src;
4629
4630                         /* klass - it's the second element of the cache entry*/
4631                         EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer));
4632
4633                         /* cache */
4634                         args [2] = cache_ins;
4635
4636                         return mono_emit_method_call (cfg, mono_isinst, args, NULL);
4637                 }
4638
4639                 klass_inst = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
4640         }
4641
4642         NEW_BBLOCK (cfg, is_null_bb);
4643         NEW_BBLOCK (cfg, false_bb);
4644         NEW_BBLOCK (cfg, end_bb);
4645
4646         /* Do the assignment at the beginning, so the other assignment can be if converted */
4647         EMIT_NEW_UNALU (cfg, ins, OP_MOVE, res_reg, obj_reg);
4648         ins->type = STACK_OBJ;
4649         ins->klass = klass;
4650
4651         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4652         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_null_bb);
4653
4654         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4655
4656         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4657                 g_assert (!context_used);
4658                 /* the is_null_bb target simply copies the input register to the output */
4659                 mini_emit_iface_cast (cfg, vtable_reg, klass, false_bb, is_null_bb);
4660         } else {
4661                 int klass_reg = alloc_preg (cfg);
4662
4663                 if (klass->rank) {
4664                         int rank_reg = alloc_preg (cfg);
4665                         int eclass_reg = alloc_preg (cfg);
4666
4667                         g_assert (!context_used);
4668                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
4669                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank);
4670                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4671                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4672                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, cast_class));
4673                         if (klass->cast_class == mono_defaults.object_class) {
4674                                 int parent_reg = alloc_preg (cfg);
4675                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, parent_reg, eclass_reg, MONO_STRUCT_OFFSET (MonoClass, parent));
4676                                 mini_emit_class_check_branch (cfg, parent_reg, mono_defaults.enum_class->parent, OP_PBNE_UN, is_null_bb);
4677                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);
4678                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4679                         } else if (klass->cast_class == mono_defaults.enum_class->parent) {
4680                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class->parent, OP_PBEQ, is_null_bb);
4681                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);                          
4682                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4683                         } else if (klass->cast_class == mono_defaults.enum_class) {
4684                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);
4685                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4686                         } else if (klass->cast_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
4687                                 mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb);
4688                         } else {
4689                                 if ((klass->rank == 1) && (klass->byval_arg.type == MONO_TYPE_SZARRAY)) {
4690                                         /* Check that the object is a vector too */
4691                                         int bounds_reg = alloc_preg (cfg);
4692                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, obj_reg, MONO_STRUCT_OFFSET (MonoArray, bounds));
4693                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
4694                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4695                                 }
4696
4697                                 /* the is_null_bb target simply copies the input register to the output */
4698                                 mini_emit_isninst_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb);
4699                         }
4700                 } else if (mono_class_is_nullable (klass)) {
4701                         g_assert (!context_used);
4702                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4703                         /* the is_null_bb target simply copies the input register to the output */
4704                         mini_emit_isninst_cast (cfg, klass_reg, klass->cast_class, false_bb, is_null_bb);
4705                 } else {
4706                         if (!cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && (klass->flags & TYPE_ATTRIBUTE_SEALED)) {
4707                                 g_assert (!context_used);
4708                                 /* the remoting code is broken, access the class for now */
4709                                 if (0) {/*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
4710                                         MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
4711                                         if (!vt) {
4712                                                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4713                                                 cfg->exception_ptr = klass;
4714                                                 return NULL;
4715                                         }
4716                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vt);
4717                                 } else {
4718                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4719                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
4720                                 }
4721                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4722                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, is_null_bb);
4723                         } else {
4724                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4725                                 /* the is_null_bb target simply copies the input register to the output */
4726                                 mini_emit_isninst_cast_inst (cfg, klass_reg, klass, klass_inst, false_bb, is_null_bb);
4727                         }
4728                 }
4729         }
4730
4731         MONO_START_BB (cfg, false_bb);
4732
4733         MONO_EMIT_NEW_PCONST (cfg, res_reg, 0);
4734         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4735
4736         MONO_START_BB (cfg, is_null_bb);
4737
4738         MONO_START_BB (cfg, end_bb);
4739
4740         return ins;
4741 }
4742
4743 static MonoInst*
4744 handle_cisinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
4745 {
4746         /* This opcode takes as input an object reference and a class, and returns:
4747         0) if the object is an instance of the class,
4748         1) if the object is not instance of the class,
4749         2) if the object is a proxy whose type cannot be determined */
4750
4751         MonoInst *ins;
4752 #ifndef DISABLE_REMOTING
4753         MonoBasicBlock *true_bb, *false_bb, *false2_bb, *end_bb, *no_proxy_bb, *interface_fail_bb;
4754 #else
4755         MonoBasicBlock *true_bb, *false_bb, *end_bb;
4756 #endif
4757         int obj_reg = src->dreg;
4758         int dreg = alloc_ireg (cfg);
4759         int tmp_reg;
4760 #ifndef DISABLE_REMOTING
4761         int klass_reg = alloc_preg (cfg);
4762 #endif
4763
4764         NEW_BBLOCK (cfg, true_bb);
4765         NEW_BBLOCK (cfg, false_bb);
4766         NEW_BBLOCK (cfg, end_bb);
4767 #ifndef DISABLE_REMOTING
4768         NEW_BBLOCK (cfg, false2_bb);
4769         NEW_BBLOCK (cfg, no_proxy_bb);
4770 #endif
4771
4772         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4773         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, false_bb);
4774
4775         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4776 #ifndef DISABLE_REMOTING
4777                 NEW_BBLOCK (cfg, interface_fail_bb);
4778 #endif
4779
4780                 tmp_reg = alloc_preg (cfg);
4781                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4782 #ifndef DISABLE_REMOTING
4783                 mini_emit_iface_cast (cfg, tmp_reg, klass, interface_fail_bb, true_bb);
4784                 MONO_START_BB (cfg, interface_fail_bb);
4785                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4786                 
4787                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, false_bb);
4788
4789                 tmp_reg = alloc_preg (cfg);
4790                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4791                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4792                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false2_bb);                
4793 #else
4794                 mini_emit_iface_cast (cfg, tmp_reg, klass, false_bb, true_bb);
4795 #endif
4796         } else {
4797 #ifndef DISABLE_REMOTING
4798                 tmp_reg = alloc_preg (cfg);
4799                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4800                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4801
4802                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, no_proxy_bb);          
4803                 tmp_reg = alloc_preg (cfg);
4804                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, remote_class));
4805                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoRemoteClass, proxy_class));
4806
4807                 tmp_reg = alloc_preg (cfg);             
4808                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4809                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4810                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, no_proxy_bb);
4811                 
4812                 mini_emit_isninst_cast (cfg, klass_reg, klass, false2_bb, true_bb);
4813                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false2_bb);
4814
4815                 MONO_START_BB (cfg, no_proxy_bb);
4816
4817                 mini_emit_isninst_cast (cfg, klass_reg, klass, false_bb, true_bb);
4818 #else
4819                 g_error ("transparent proxy support is disabled while trying to JIT code that uses it");
4820 #endif
4821         }
4822
4823         MONO_START_BB (cfg, false_bb);
4824
4825         MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4826         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4827
4828 #ifndef DISABLE_REMOTING
4829         MONO_START_BB (cfg, false2_bb);
4830
4831         MONO_EMIT_NEW_ICONST (cfg, dreg, 2);
4832         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4833 #endif
4834
4835         MONO_START_BB (cfg, true_bb);
4836
4837         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
4838
4839         MONO_START_BB (cfg, end_bb);
4840
4841         /* FIXME: */
4842         MONO_INST_NEW (cfg, ins, OP_ICONST);
4843         ins->dreg = dreg;
4844         ins->type = STACK_I4;
4845
4846         return ins;
4847 }
4848
4849 static MonoInst*
4850 handle_ccastclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
4851 {
4852         /* This opcode takes as input an object reference and a class, and returns:
4853         0) if the object is an instance of the class,
4854         1) if the object is a proxy whose type cannot be determined
4855         an InvalidCastException exception is thrown otherwhise*/
4856         
4857         MonoInst *ins;
4858 #ifndef DISABLE_REMOTING
4859         MonoBasicBlock *end_bb, *ok_result_bb, *no_proxy_bb, *interface_fail_bb, *fail_1_bb;
4860 #else
4861         MonoBasicBlock *ok_result_bb;
4862 #endif
4863         int obj_reg = src->dreg;
4864         int dreg = alloc_ireg (cfg);
4865         int tmp_reg = alloc_preg (cfg);
4866
4867 #ifndef DISABLE_REMOTING
4868         int klass_reg = alloc_preg (cfg);
4869         NEW_BBLOCK (cfg, end_bb);
4870 #endif
4871
4872         NEW_BBLOCK (cfg, ok_result_bb);
4873
4874         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4875         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, ok_result_bb);
4876
4877         save_cast_details (cfg, klass, obj_reg, FALSE);
4878
4879         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4880 #ifndef DISABLE_REMOTING
4881                 NEW_BBLOCK (cfg, interface_fail_bb);
4882         
4883                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4884                 mini_emit_iface_cast (cfg, tmp_reg, klass, interface_fail_bb, ok_result_bb);
4885                 MONO_START_BB (cfg, interface_fail_bb);
4886                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4887
4888                 mini_emit_class_check (cfg, klass_reg, mono_defaults.transparent_proxy_class);
4889
4890                 tmp_reg = alloc_preg (cfg);             
4891                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4892                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4893                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
4894                 
4895                 MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4896                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4897 #else
4898                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4899                 mini_emit_iface_cast (cfg, tmp_reg, klass, NULL, NULL);
4900                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, ok_result_bb);
4901 #endif
4902         } else {
4903 #ifndef DISABLE_REMOTING
4904                 NEW_BBLOCK (cfg, no_proxy_bb);
4905
4906                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4907                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4908                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, no_proxy_bb);          
4909
4910                 tmp_reg = alloc_preg (cfg);
4911                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, remote_class));
4912                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoRemoteClass, proxy_class));
4913
4914                 tmp_reg = alloc_preg (cfg);
4915                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4916                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4917                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, no_proxy_bb);
4918
4919                 NEW_BBLOCK (cfg, fail_1_bb);
4920                 
4921                 mini_emit_isninst_cast (cfg, klass_reg, klass, fail_1_bb, ok_result_bb);
4922
4923                 MONO_START_BB (cfg, fail_1_bb);
4924
4925                 MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4926                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4927
4928                 MONO_START_BB (cfg, no_proxy_bb);
4929
4930                 mini_emit_castclass (cfg, obj_reg, klass_reg, klass, ok_result_bb);
4931 #else
4932                 g_error ("Transparent proxy support is disabled while trying to JIT code that uses it");
4933 #endif
4934         }
4935
4936         MONO_START_BB (cfg, ok_result_bb);
4937
4938         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
4939
4940 #ifndef DISABLE_REMOTING
4941         MONO_START_BB (cfg, end_bb);
4942 #endif
4943
4944         /* FIXME: */
4945         MONO_INST_NEW (cfg, ins, OP_ICONST);
4946         ins->dreg = dreg;
4947         ins->type = STACK_I4;
4948
4949         return ins;
4950 }
4951
4952 static G_GNUC_UNUSED MonoInst*
4953 handle_enum_has_flag (MonoCompile *cfg, MonoClass *klass, MonoInst *enum_this, MonoInst *enum_flag)
4954 {
4955         MonoType *enum_type = mono_type_get_underlying_type (&klass->byval_arg);
4956         guint32 load_opc = mono_type_to_load_membase (cfg, enum_type);
4957         gboolean is_i4;
4958
4959         switch (enum_type->type) {
4960         case MONO_TYPE_I8:
4961         case MONO_TYPE_U8:
4962 #if SIZEOF_REGISTER == 8
4963         case MONO_TYPE_I:
4964         case MONO_TYPE_U:
4965 #endif
4966                 is_i4 = FALSE;
4967                 break;
4968         default:
4969                 is_i4 = TRUE;
4970                 break;
4971         }
4972
4973         {
4974                 MonoInst *load, *and_, *cmp, *ceq;
4975                 int enum_reg = is_i4 ? alloc_ireg (cfg) : alloc_lreg (cfg);
4976                 int and_reg = is_i4 ? alloc_ireg (cfg) : alloc_lreg (cfg);
4977                 int dest_reg = alloc_ireg (cfg);
4978
4979                 EMIT_NEW_LOAD_MEMBASE (cfg, load, load_opc, enum_reg, enum_this->dreg, 0);
4980                 EMIT_NEW_BIALU (cfg, and_, is_i4 ? OP_IAND : OP_LAND, and_reg, enum_reg, enum_flag->dreg);
4981                 EMIT_NEW_BIALU (cfg, cmp, is_i4 ? OP_ICOMPARE : OP_LCOMPARE, -1, and_reg, enum_flag->dreg);
4982                 EMIT_NEW_UNALU (cfg, ceq, is_i4 ? OP_ICEQ : OP_LCEQ, dest_reg, -1);
4983
4984                 ceq->type = STACK_I4;
4985
4986                 if (!is_i4) {
4987                         load = mono_decompose_opcode (cfg, load);
4988                         and_ = mono_decompose_opcode (cfg, and_);
4989                         cmp = mono_decompose_opcode (cfg, cmp);
4990                         ceq = mono_decompose_opcode (cfg, ceq);
4991                 }
4992
4993                 return ceq;
4994         }
4995 }
4996
4997 /*
4998  * Returns NULL and set the cfg exception on error.
4999  */
5000 static G_GNUC_UNUSED MonoInst*
5001 handle_delegate_ctor (MonoCompile *cfg, MonoClass *klass, MonoInst *target, MonoMethod *method, int context_used, gboolean virtual_)
5002 {
5003         MonoInst *ptr;
5004         int dreg;
5005         gpointer trampoline;
5006         MonoInst *obj, *method_ins, *tramp_ins;
5007         MonoDomain *domain;
5008         guint8 **code_slot;
5009
5010         if (virtual_ && !cfg->llvm_only) {
5011                 MonoMethod *invoke = mono_get_delegate_invoke (klass);
5012                 g_assert (invoke);
5013
5014                 if (!mono_get_delegate_virtual_invoke_impl (mono_method_signature (invoke), context_used ? NULL : method))
5015                         return NULL;
5016         }
5017
5018         obj = handle_alloc (cfg, klass, FALSE, mono_class_check_context_used (klass));
5019         if (!obj)
5020                 return NULL;
5021
5022         /* Inline the contents of mono_delegate_ctor */
5023
5024         /* Set target field */
5025         /* Optimize away setting of NULL target */
5026         if (!(target->opcode == OP_PCONST && target->inst_p0 == 0)) {
5027                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, target), target->dreg);
5028                 if (cfg->gen_write_barriers) {
5029                         dreg = alloc_preg (cfg);
5030                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, target));
5031                         emit_write_barrier (cfg, ptr, target);
5032                 }
5033         }
5034
5035         /* Set method field */
5036         method_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD);
5037         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method), method_ins->dreg);
5038
5039         /* 
5040          * To avoid looking up the compiled code belonging to the target method
5041          * in mono_delegate_trampoline (), we allocate a per-domain memory slot to
5042          * store it, and we fill it after the method has been compiled.
5043          */
5044         if (!method->dynamic && !(cfg->opt & MONO_OPT_SHARED)) {
5045                 MonoInst *code_slot_ins;
5046
5047                 if (context_used) {
5048                         code_slot_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD_DELEGATE_CODE);
5049                 } else {
5050                         domain = mono_domain_get ();
5051                         mono_domain_lock (domain);
5052                         if (!domain_jit_info (domain)->method_code_hash)
5053                                 domain_jit_info (domain)->method_code_hash = g_hash_table_new (NULL, NULL);
5054                         code_slot = (guint8 **)g_hash_table_lookup (domain_jit_info (domain)->method_code_hash, method);
5055                         if (!code_slot) {
5056                                 code_slot = (guint8 **)mono_domain_alloc0 (domain, sizeof (gpointer));
5057                                 g_hash_table_insert (domain_jit_info (domain)->method_code_hash, method, code_slot);
5058                         }
5059                         mono_domain_unlock (domain);
5060
5061                         code_slot_ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_METHOD_CODE_SLOT, method);
5062                 }
5063                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_code), code_slot_ins->dreg);                
5064         }
5065
5066         if (cfg->llvm_only) {
5067                 MonoInst *args [16];
5068
5069                 if (virtual_) {
5070                         args [0] = obj;
5071                         args [1] = target;
5072                         args [2] = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD);
5073                         mono_emit_jit_icall (cfg, mono_llvmonly_init_delegate_virtual, args);
5074                 } else {
5075                         args [0] = obj;
5076                         mono_emit_jit_icall (cfg, mono_llvmonly_init_delegate, args);
5077                 }
5078
5079                 return obj;
5080         }
5081
5082         if (cfg->compile_aot) {
5083                 MonoDelegateClassMethodPair *del_tramp;
5084
5085                 del_tramp = (MonoDelegateClassMethodPair *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoDelegateClassMethodPair));
5086                 del_tramp->klass = klass;
5087                 del_tramp->method = context_used ? NULL : method;
5088                 del_tramp->is_virtual = virtual_;
5089                 EMIT_NEW_AOTCONST (cfg, tramp_ins, MONO_PATCH_INFO_DELEGATE_TRAMPOLINE, del_tramp);
5090         } else {
5091                 if (virtual_)
5092                         trampoline = mono_create_delegate_virtual_trampoline (cfg->domain, klass, context_used ? NULL : method);
5093                 else
5094                         trampoline = mono_create_delegate_trampoline_info (cfg->domain, klass, context_used ? NULL : method);
5095                 EMIT_NEW_PCONST (cfg, tramp_ins, trampoline);
5096         }
5097
5098         /* Set invoke_impl field */
5099         if (virtual_) {
5100                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl), tramp_ins->dreg);
5101         } else {
5102                 dreg = alloc_preg (cfg);
5103                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, tramp_ins->dreg, MONO_STRUCT_OFFSET (MonoDelegateTrampInfo, invoke_impl));
5104                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl), dreg);
5105
5106                 dreg = alloc_preg (cfg);
5107                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, tramp_ins->dreg, MONO_STRUCT_OFFSET (MonoDelegateTrampInfo, method_ptr));
5108                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr), dreg);
5109         }
5110
5111         dreg = alloc_preg (cfg);
5112         MONO_EMIT_NEW_ICONST (cfg, dreg, virtual_ ? 1 : 0);
5113         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_is_virtual), dreg);
5114
5115         /* All the checks which are in mono_delegate_ctor () are done by the delegate trampoline */
5116
5117         return obj;
5118 }
5119
5120 static MonoInst*
5121 handle_array_new (MonoCompile *cfg, int rank, MonoInst **sp, unsigned char *ip)
5122 {
5123         MonoJitICallInfo *info;
5124
5125         /* Need to register the icall so it gets an icall wrapper */
5126         info = mono_get_array_new_va_icall (rank);
5127
5128         cfg->flags |= MONO_CFG_HAS_VARARGS;
5129
5130         /* mono_array_new_va () needs a vararg calling convention */
5131         cfg->exception_message = g_strdup ("array-new");
5132         cfg->disable_llvm = TRUE;
5133
5134         /* FIXME: This uses info->sig, but it should use the signature of the wrapper */
5135         return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, sp);
5136 }
5137
5138 /*
5139  * handle_constrained_gsharedvt_call:
5140  *
5141  *   Handle constrained calls where the receiver is a gsharedvt type.
5142  * Return the instruction representing the call. Set the cfg exception on failure.
5143  */
5144 static MonoInst*
5145 handle_constrained_gsharedvt_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp, MonoClass *constrained_class,
5146                                                                    gboolean *ref_emit_widen)
5147 {
5148         MonoInst *ins = NULL;
5149         gboolean emit_widen = *ref_emit_widen;
5150
5151         /*
5152          * Constrained calls need to behave differently at runtime dependending on whenever the receiver is instantiated as ref type or as a vtype.
5153          * 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
5154          * pack the arguments into an array, and do the rest of the work in in an icall.
5155          */
5156         if (((cmethod->klass == mono_defaults.object_class) || (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) || (!cmethod->klass->valuetype && cmethod->klass->image != mono_defaults.corlib)) &&
5157                 (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)) &&
5158                 (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]))))) {
5159                 MonoInst *args [16];
5160
5161                 /*
5162                  * This case handles calls to
5163                  * - object:ToString()/Equals()/GetHashCode(),
5164                  * - System.IComparable<T>:CompareTo()
5165                  * - System.IEquatable<T>:Equals ()
5166                  * plus some simple interface calls enough to support AsyncTaskMethodBuilder.
5167                  */
5168
5169                 args [0] = sp [0];
5170                 if (mono_method_check_context_used (cmethod))
5171                         args [1] = emit_get_rgctx_method (cfg, mono_method_check_context_used (cmethod), cmethod, MONO_RGCTX_INFO_METHOD);
5172                 else
5173                         EMIT_NEW_METHODCONST (cfg, args [1], cmethod);
5174                 args [2] = emit_get_rgctx_klass (cfg, mono_class_check_context_used (constrained_class), constrained_class, MONO_RGCTX_INFO_KLASS);
5175
5176                 /* !fsig->hasthis is for the wrapper for the Object.GetType () icall */
5177                 if (fsig->hasthis && fsig->param_count) {
5178                         /* Pass the arguments using a localloc-ed array using the format expected by runtime_invoke () */
5179                         MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
5180                         ins->dreg = alloc_preg (cfg);
5181                         ins->inst_imm = fsig->param_count * sizeof (mgreg_t);
5182                         MONO_ADD_INS (cfg->cbb, ins);
5183                         args [4] = ins;
5184
5185                         if (mini_is_gsharedvt_type (fsig->params [0])) {
5186                                 int addr_reg, deref_arg_reg;
5187
5188                                 ins = emit_get_gsharedvt_info_klass (cfg, mono_class_from_mono_type (fsig->params [0]), MONO_RGCTX_INFO_CLASS_BOX_TYPE);
5189                                 deref_arg_reg = alloc_preg (cfg);
5190                                 /* deref_arg = BOX_TYPE != MONO_GSHAREDVT_BOX_TYPE_VTYPE */
5191                                 EMIT_NEW_BIALU_IMM (cfg, args [3], OP_ISUB_IMM, deref_arg_reg, ins->dreg, 1);
5192
5193                                 EMIT_NEW_VARLOADA_VREG (cfg, ins, sp [1]->dreg, fsig->params [0]);
5194                                 addr_reg = ins->dreg;
5195                                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [4]->dreg, 0, addr_reg);
5196                         } else {
5197                                 EMIT_NEW_ICONST (cfg, args [3], 0);
5198                                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [4]->dreg, 0, sp [1]->dreg);
5199                         }
5200                 } else {
5201                         EMIT_NEW_ICONST (cfg, args [3], 0);
5202                         EMIT_NEW_ICONST (cfg, args [4], 0);
5203                 }
5204                 ins = mono_emit_jit_icall (cfg, mono_gsharedvt_constrained_call, args);
5205                 emit_widen = FALSE;
5206
5207                 if (mini_is_gsharedvt_type (fsig->ret)) {
5208                         ins = handle_unbox_gsharedvt (cfg, mono_class_from_mono_type (fsig->ret), ins);
5209                 } else if (MONO_TYPE_IS_PRIMITIVE (fsig->ret) || MONO_TYPE_ISSTRUCT (fsig->ret)) {
5210                         MonoInst *add;
5211
5212                         /* Unbox */
5213                         NEW_BIALU_IMM (cfg, add, OP_ADD_IMM, alloc_dreg (cfg, STACK_MP), ins->dreg, sizeof (MonoObject));
5214                         MONO_ADD_INS (cfg->cbb, add);
5215                         /* Load value */
5216                         NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, add->dreg, 0);
5217                         MONO_ADD_INS (cfg->cbb, ins);
5218                         /* ins represents the call result */
5219                 }
5220         } else {
5221                 GSHAREDVT_FAILURE (CEE_CALLVIRT);
5222         }
5223
5224         *ref_emit_widen = emit_widen;
5225
5226         return ins;
5227
5228  exception_exit:
5229         return NULL;
5230 }
5231
5232 static void
5233 mono_emit_load_got_addr (MonoCompile *cfg)
5234 {
5235         MonoInst *getaddr, *dummy_use;
5236
5237         if (!cfg->got_var || cfg->got_var_allocated)
5238                 return;
5239
5240         MONO_INST_NEW (cfg, getaddr, OP_LOAD_GOTADDR);
5241         getaddr->cil_code = cfg->header->code;
5242         getaddr->dreg = cfg->got_var->dreg;
5243
5244         /* Add it to the start of the first bblock */
5245         if (cfg->bb_entry->code) {
5246                 getaddr->next = cfg->bb_entry->code;
5247                 cfg->bb_entry->code = getaddr;
5248         }
5249         else
5250                 MONO_ADD_INS (cfg->bb_entry, getaddr);
5251
5252         cfg->got_var_allocated = TRUE;
5253
5254         /* 
5255          * Add a dummy use to keep the got_var alive, since real uses might
5256          * only be generated by the back ends.
5257          * Add it to end_bblock, so the variable's lifetime covers the whole
5258          * method.
5259          * It would be better to make the usage of the got var explicit in all
5260          * cases when the backend needs it (i.e. calls, throw etc.), so this
5261          * wouldn't be needed.
5262          */
5263         NEW_DUMMY_USE (cfg, dummy_use, cfg->got_var);
5264         MONO_ADD_INS (cfg->bb_exit, dummy_use);
5265 }
5266
5267 static int inline_limit;
5268 static gboolean inline_limit_inited;
5269
5270 static gboolean
5271 mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method)
5272 {
5273         MonoMethodHeaderSummary header;
5274         MonoVTable *vtable;
5275 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
5276         MonoMethodSignature *sig = mono_method_signature (method);
5277         int i;
5278 #endif
5279
5280         if (cfg->disable_inline)
5281                 return FALSE;
5282         if (cfg->gshared)
5283                 return FALSE;
5284
5285         if (cfg->inline_depth > 10)
5286                 return FALSE;
5287
5288         if (!mono_method_get_header_summary (method, &header))
5289                 return FALSE;
5290
5291         /*runtime, icall and pinvoke are checked by summary call*/
5292         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_NOINLINING) ||
5293             (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) ||
5294             (mono_class_is_marshalbyref (method->klass)) ||
5295             header.has_clauses)
5296                 return FALSE;
5297
5298         /* also consider num_locals? */
5299         /* Do the size check early to avoid creating vtables */
5300         if (!inline_limit_inited) {
5301                 if (g_getenv ("MONO_INLINELIMIT"))
5302                         inline_limit = atoi (g_getenv ("MONO_INLINELIMIT"));
5303                 else
5304                         inline_limit = INLINE_LENGTH_LIMIT;
5305                 inline_limit_inited = TRUE;
5306         }
5307         if (header.code_size >= inline_limit && !(method->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING))
5308                 return FALSE;
5309
5310         /*
5311          * if we can initialize the class of the method right away, we do,
5312          * otherwise we don't allow inlining if the class needs initialization,
5313          * since it would mean inserting a call to mono_runtime_class_init()
5314          * inside the inlined code
5315          */
5316         if (!(cfg->opt & MONO_OPT_SHARED)) {
5317                 /* The AggressiveInlining hint is a good excuse to force that cctor to run. */
5318                 if (method->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING) {
5319                         vtable = mono_class_vtable (cfg->domain, method->klass);
5320                         if (!vtable)
5321                                 return FALSE;
5322                         if (!cfg->compile_aot)
5323                                 mono_runtime_class_init (vtable);
5324                 } else if (method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) {
5325                         if (cfg->run_cctors && method->klass->has_cctor) {
5326                                 /*FIXME it would easier and lazier to just use mono_class_try_get_vtable */
5327                                 if (!method->klass->runtime_info)
5328                                         /* No vtable created yet */
5329                                         return FALSE;
5330                                 vtable = mono_class_vtable (cfg->domain, method->klass);
5331                                 if (!vtable)
5332                                         return FALSE;
5333                                 /* This makes so that inline cannot trigger */
5334                                 /* .cctors: too many apps depend on them */
5335                                 /* running with a specific order... */
5336                                 if (! vtable->initialized)
5337                                         return FALSE;
5338                                 mono_runtime_class_init (vtable);
5339                         }
5340                 } else if (mono_class_needs_cctor_run (method->klass, NULL)) {
5341                         if (!method->klass->runtime_info)
5342                                 /* No vtable created yet */
5343                                 return FALSE;
5344                         vtable = mono_class_vtable (cfg->domain, method->klass);
5345                         if (!vtable)
5346                                 return FALSE;
5347                         if (!vtable->initialized)
5348                                 return FALSE;
5349                 }
5350         } else {
5351                 /* 
5352                  * If we're compiling for shared code
5353                  * the cctor will need to be run at aot method load time, for example,
5354                  * or at the end of the compilation of the inlining method.
5355                  */
5356                 if (mono_class_needs_cctor_run (method->klass, NULL) && !((method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT)))
5357                         return FALSE;
5358         }
5359
5360 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
5361         if (mono_arch_is_soft_float ()) {
5362                 /* FIXME: */
5363                 if (sig->ret && sig->ret->type == MONO_TYPE_R4)
5364                         return FALSE;
5365                 for (i = 0; i < sig->param_count; ++i)
5366                         if (!sig->params [i]->byref && sig->params [i]->type == MONO_TYPE_R4)
5367                                 return FALSE;
5368         }
5369 #endif
5370
5371         if (g_list_find (cfg->dont_inline, method))
5372                 return FALSE;
5373
5374         return TRUE;
5375 }
5376
5377 static gboolean
5378 mini_field_access_needs_cctor_run (MonoCompile *cfg, MonoMethod *method, MonoClass *klass, MonoVTable *vtable)
5379 {
5380         if (!cfg->compile_aot) {
5381                 g_assert (vtable);
5382                 if (vtable->initialized)
5383                         return FALSE;
5384         }
5385
5386         if (klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) {
5387                 if (cfg->method == method)
5388                         return FALSE;
5389         }
5390
5391         if (!mono_class_needs_cctor_run (klass, method))
5392                 return FALSE;
5393
5394         if (! (method->flags & METHOD_ATTRIBUTE_STATIC) && (klass == method->klass))
5395                 /* The initialization is already done before the method is called */
5396                 return FALSE;
5397
5398         return TRUE;
5399 }
5400
5401 static MonoInst*
5402 mini_emit_ldelema_1_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index, gboolean bcheck)
5403 {
5404         MonoInst *ins;
5405         guint32 size;
5406         int mult_reg, add_reg, array_reg, index_reg, index2_reg;
5407         int context_used;
5408
5409         if (mini_is_gsharedvt_variable_klass (klass)) {
5410                 size = -1;
5411         } else {
5412                 mono_class_init (klass);
5413                 size = mono_class_array_element_size (klass);
5414         }
5415
5416         mult_reg = alloc_preg (cfg);
5417         array_reg = arr->dreg;
5418         index_reg = index->dreg;
5419
5420 #if SIZEOF_REGISTER == 8
5421         /* The array reg is 64 bits but the index reg is only 32 */
5422         if (COMPILE_LLVM (cfg)) {
5423                 /* Not needed */
5424                 index2_reg = index_reg;
5425         } else {
5426                 index2_reg = alloc_preg (cfg);
5427                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index2_reg, index_reg);
5428         }
5429 #else
5430         if (index->type == STACK_I8) {
5431                 index2_reg = alloc_preg (cfg);
5432                 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I4, index2_reg, index_reg);
5433         } else {
5434                 index2_reg = index_reg;
5435         }
5436 #endif
5437
5438         if (bcheck)
5439                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index2_reg);
5440
5441 #if defined(TARGET_X86) || defined(TARGET_AMD64)
5442         if (size == 1 || size == 2 || size == 4 || size == 8) {
5443                 static const int fast_log2 [] = { 1, 0, 1, -1, 2, -1, -1, -1, 3 };
5444
5445                 EMIT_NEW_X86_LEA (cfg, ins, array_reg, index2_reg, fast_log2 [size], MONO_STRUCT_OFFSET (MonoArray, vector));
5446                 ins->klass = mono_class_get_element_class (klass);
5447                 ins->type = STACK_MP;
5448
5449                 return ins;
5450         }
5451 #endif          
5452
5453         add_reg = alloc_ireg_mp (cfg);
5454
5455         if (size == -1) {
5456                 MonoInst *rgctx_ins;
5457
5458                 /* gsharedvt */
5459                 g_assert (cfg->gshared);
5460                 context_used = mini_class_check_context_used (cfg, klass);
5461                 g_assert (context_used);
5462                 rgctx_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE);
5463                 MONO_EMIT_NEW_BIALU (cfg, OP_IMUL, mult_reg, index2_reg, rgctx_ins->dreg);
5464         } else {
5465                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MUL_IMM, mult_reg, index2_reg, size);
5466         }
5467         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, array_reg, mult_reg);
5468         NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, MONO_STRUCT_OFFSET (MonoArray, vector));
5469         ins->klass = mono_class_get_element_class (klass);
5470         ins->type = STACK_MP;
5471         MONO_ADD_INS (cfg->cbb, ins);
5472
5473         return ins;
5474 }
5475
5476 static MonoInst*
5477 mini_emit_ldelema_2_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index_ins1, MonoInst *index_ins2)
5478 {
5479         int bounds_reg = alloc_preg (cfg);
5480         int add_reg = alloc_ireg_mp (cfg);
5481         int mult_reg = alloc_preg (cfg);
5482         int mult2_reg = alloc_preg (cfg);
5483         int low1_reg = alloc_preg (cfg);
5484         int low2_reg = alloc_preg (cfg);
5485         int high1_reg = alloc_preg (cfg);
5486         int high2_reg = alloc_preg (cfg);
5487         int realidx1_reg = alloc_preg (cfg);
5488         int realidx2_reg = alloc_preg (cfg);
5489         int sum_reg = alloc_preg (cfg);
5490         int index1, index2, tmpreg;
5491         MonoInst *ins;
5492         guint32 size;
5493
5494         mono_class_init (klass);
5495         size = mono_class_array_element_size (klass);
5496
5497         index1 = index_ins1->dreg;
5498         index2 = index_ins2->dreg;
5499
5500 #if SIZEOF_REGISTER == 8
5501         /* The array reg is 64 bits but the index reg is only 32 */
5502         if (COMPILE_LLVM (cfg)) {
5503                 /* Not needed */
5504         } else {
5505                 tmpreg = alloc_preg (cfg);
5506                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, tmpreg, index1);
5507                 index1 = tmpreg;
5508                 tmpreg = alloc_preg (cfg);
5509                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, tmpreg, index2);
5510                 index2 = tmpreg;
5511         }
5512 #else
5513         // FIXME: Do we need to do something here for i8 indexes, like in ldelema_1_ins ?
5514         tmpreg = -1;
5515 #endif
5516
5517         /* range checking */
5518         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, 
5519                                        arr->dreg, MONO_STRUCT_OFFSET (MonoArray, bounds));
5520
5521         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low1_reg, 
5522                                        bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
5523         MONO_EMIT_NEW_BIALU (cfg, OP_PSUB, realidx1_reg, index1, low1_reg);
5524         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high1_reg, 
5525                                        bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, length));
5526         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, high1_reg, realidx1_reg);
5527         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException");
5528
5529         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low2_reg, 
5530                                        bounds_reg, sizeof (MonoArrayBounds) + MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
5531         MONO_EMIT_NEW_BIALU (cfg, OP_PSUB, realidx2_reg, index2, low2_reg);
5532         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high2_reg, 
5533                                        bounds_reg, sizeof (MonoArrayBounds) + MONO_STRUCT_OFFSET (MonoArrayBounds, length));
5534         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, high2_reg, realidx2_reg);
5535         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException");
5536
5537         MONO_EMIT_NEW_BIALU (cfg, OP_PMUL, mult_reg, high2_reg, realidx1_reg);
5538         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, mult_reg, realidx2_reg);
5539         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PMUL_IMM, mult2_reg, sum_reg, size);
5540         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult2_reg, arr->dreg);
5541         NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, MONO_STRUCT_OFFSET (MonoArray, vector));
5542
5543         ins->type = STACK_MP;
5544         ins->klass = klass;
5545         MONO_ADD_INS (cfg->cbb, ins);
5546
5547         return ins;
5548 }
5549
5550 static MonoInst*
5551 mini_emit_ldelema_ins (MonoCompile *cfg, MonoMethod *cmethod, MonoInst **sp, unsigned char *ip, gboolean is_set)
5552 {
5553         int rank;
5554         MonoInst *addr;
5555         MonoMethod *addr_method;
5556         int element_size;
5557         MonoClass *eclass = cmethod->klass->element_class;
5558
5559         rank = mono_method_signature (cmethod)->param_count - (is_set? 1: 0);
5560
5561         if (rank == 1)
5562                 return mini_emit_ldelema_1_ins (cfg, eclass, sp [0], sp [1], TRUE);
5563
5564         /* emit_ldelema_2 depends on OP_LMUL */
5565         if (!cfg->backend->emulate_mul_div && rank == 2 && (cfg->opt & MONO_OPT_INTRINS) && !mini_is_gsharedvt_variable_klass (eclass)) {
5566                 return mini_emit_ldelema_2_ins (cfg, eclass, sp [0], sp [1], sp [2]);
5567         }
5568
5569         if (mini_is_gsharedvt_variable_klass (eclass))
5570                 element_size = 0;
5571         else
5572                 element_size = mono_class_array_element_size (eclass);
5573         addr_method = mono_marshal_get_array_address (rank, element_size);
5574         addr = mono_emit_method_call (cfg, addr_method, sp, NULL);
5575
5576         return addr;
5577 }
5578
5579 static MonoBreakPolicy
5580 always_insert_breakpoint (MonoMethod *method)
5581 {
5582         return MONO_BREAK_POLICY_ALWAYS;
5583 }
5584
5585 static MonoBreakPolicyFunc break_policy_func = always_insert_breakpoint;
5586
5587 /**
5588  * mono_set_break_policy:
5589  * policy_callback: the new callback function
5590  *
5591  * Allow embedders to decide wherther to actually obey breakpoint instructions
5592  * (both break IL instructions and Debugger.Break () method calls), for example
5593  * to not allow an app to be aborted by a perfectly valid IL opcode when executing
5594  * untrusted or semi-trusted code.
5595  *
5596  * @policy_callback will be called every time a break point instruction needs to
5597  * be inserted with the method argument being the method that calls Debugger.Break()
5598  * or has the IL break instruction. The callback should return #MONO_BREAK_POLICY_NEVER
5599  * if it wants the breakpoint to not be effective in the given method.
5600  * #MONO_BREAK_POLICY_ALWAYS is the default.
5601  */
5602 void
5603 mono_set_break_policy (MonoBreakPolicyFunc policy_callback)
5604 {
5605         if (policy_callback)
5606                 break_policy_func = policy_callback;
5607         else
5608                 break_policy_func = always_insert_breakpoint;
5609 }
5610
5611 static gboolean
5612 should_insert_brekpoint (MonoMethod *method) {
5613         switch (break_policy_func (method)) {
5614         case MONO_BREAK_POLICY_ALWAYS:
5615                 return TRUE;
5616         case MONO_BREAK_POLICY_NEVER:
5617                 return FALSE;
5618         case MONO_BREAK_POLICY_ON_DBG:
5619                 g_warning ("mdb no longer supported");
5620                 return FALSE;
5621         default:
5622                 g_warning ("Incorrect value returned from break policy callback");
5623                 return FALSE;
5624         }
5625 }
5626
5627 /* optimize the simple GetGenericValueImpl/SetGenericValueImpl generic icalls */
5628 static MonoInst*
5629 emit_array_generic_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set)
5630 {
5631         MonoInst *addr, *store, *load;
5632         MonoClass *eklass = mono_class_from_mono_type (fsig->params [2]);
5633
5634         /* the bounds check is already done by the callers */
5635         addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1], FALSE);
5636         if (is_set) {
5637                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, args [2]->dreg, 0);
5638                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, addr->dreg, 0, load->dreg);
5639                 if (mini_type_is_reference (fsig->params [2]))
5640                         emit_write_barrier (cfg, addr, load);
5641         } else {
5642                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, addr->dreg, 0);
5643                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, args [2]->dreg, 0, load->dreg);
5644         }
5645         return store;
5646 }
5647
5648
5649 static gboolean
5650 generic_class_is_reference_type (MonoCompile *cfg, MonoClass *klass)
5651 {
5652         return mini_type_is_reference (&klass->byval_arg);
5653 }
5654
5655 static MonoInst*
5656 emit_array_store (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, gboolean safety_checks)
5657 {
5658         if (safety_checks && generic_class_is_reference_type (cfg, klass) &&
5659                 !(sp [2]->opcode == OP_PCONST && sp [2]->inst_p0 == NULL)) {
5660                 MonoClass *obj_array = mono_array_class_get_cached (mono_defaults.object_class, 1);
5661                 MonoMethod *helper = mono_marshal_get_virtual_stelemref (obj_array);
5662                 MonoInst *iargs [3];
5663
5664                 if (!helper->slot)
5665                         mono_class_setup_vtable (obj_array);
5666                 g_assert (helper->slot);
5667
5668                 if (sp [0]->type != STACK_OBJ)
5669                         return NULL;
5670                 if (sp [2]->type != STACK_OBJ)
5671                         return NULL;
5672
5673                 iargs [2] = sp [2];
5674                 iargs [1] = sp [1];
5675                 iargs [0] = sp [0];
5676
5677                 return mono_emit_method_call (cfg, helper, iargs, sp [0]);
5678         } else {
5679                 MonoInst *ins;
5680
5681                 if (mini_is_gsharedvt_variable_klass (klass)) {
5682                         MonoInst *addr;
5683
5684                         // FIXME-VT: OP_ICONST optimization
5685                         addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
5686                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
5687                         ins->opcode = OP_STOREV_MEMBASE;
5688                 } else if (sp [1]->opcode == OP_ICONST) {
5689                         int array_reg = sp [0]->dreg;
5690                         int index_reg = sp [1]->dreg;
5691                         int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + MONO_STRUCT_OFFSET (MonoArray, vector);
5692
5693                         if (SIZEOF_REGISTER == 8 && COMPILE_LLVM (cfg))
5694                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, index_reg, index_reg);
5695
5696                         if (safety_checks)
5697                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
5698                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset, sp [2]->dreg);
5699                 } else {
5700                         MonoInst *addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], safety_checks);
5701                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
5702                         if (generic_class_is_reference_type (cfg, klass))
5703                                 emit_write_barrier (cfg, addr, sp [2]);
5704                 }
5705                 return ins;
5706         }
5707 }
5708
5709 static MonoInst*
5710 emit_array_unsafe_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set)
5711 {
5712         MonoClass *eklass;
5713         
5714         if (is_set)
5715                 eklass = mono_class_from_mono_type (fsig->params [2]);
5716         else
5717                 eklass = mono_class_from_mono_type (fsig->ret);
5718
5719         if (is_set) {
5720                 return emit_array_store (cfg, eklass, args, FALSE);
5721         } else {
5722                 MonoInst *ins, *addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1], FALSE);
5723                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &eklass->byval_arg, addr->dreg, 0);
5724                 return ins;
5725         }
5726 }
5727
5728 static gboolean
5729 is_unsafe_mov_compatible (MonoCompile *cfg, MonoClass *param_klass, MonoClass *return_klass)
5730 {
5731         uint32_t align;
5732         int param_size, return_size;
5733
5734         param_klass = mono_class_from_mono_type (mini_get_underlying_type (&param_klass->byval_arg));
5735         return_klass = mono_class_from_mono_type (mini_get_underlying_type (&return_klass->byval_arg));
5736
5737         if (cfg->verbose_level > 3)
5738                 printf ("[UNSAFE-MOV-INTRISIC] %s <- %s\n", return_klass->name, param_klass->name);
5739
5740         //Don't allow mixing reference types with value types
5741         if (param_klass->valuetype != return_klass->valuetype) {
5742                 if (cfg->verbose_level > 3)
5743                         printf ("[UNSAFE-MOV-INTRISIC]\tone of the args is a valuetype and the other is not\n");
5744                 return FALSE;
5745         }
5746
5747         if (!param_klass->valuetype) {
5748                 if (cfg->verbose_level > 3)
5749                         printf ("[UNSAFE-MOV-INTRISIC]\targs are reference types\n");
5750                 return TRUE;
5751         }
5752
5753         //That are blitable
5754         if (param_klass->has_references || return_klass->has_references)
5755                 return FALSE;
5756
5757         /* Avoid mixing structs and primitive types/enums, they need to be handled differently in the JIT */
5758         if ((MONO_TYPE_ISSTRUCT (&param_klass->byval_arg) && !MONO_TYPE_ISSTRUCT (&return_klass->byval_arg)) ||
5759                 (!MONO_TYPE_ISSTRUCT (&param_klass->byval_arg) && MONO_TYPE_ISSTRUCT (&return_klass->byval_arg))) {
5760                         if (cfg->verbose_level > 3)
5761                                 printf ("[UNSAFE-MOV-INTRISIC]\tmixing structs and scalars\n");
5762                 return FALSE;
5763         }
5764
5765         if (param_klass->byval_arg.type == MONO_TYPE_R4 || param_klass->byval_arg.type == MONO_TYPE_R8 ||
5766                 return_klass->byval_arg.type == MONO_TYPE_R4 || return_klass->byval_arg.type == MONO_TYPE_R8) {
5767                 if (cfg->verbose_level > 3)
5768                         printf ("[UNSAFE-MOV-INTRISIC]\tfloat or double are not supported\n");
5769                 return FALSE;
5770         }
5771
5772         param_size = mono_class_value_size (param_klass, &align);
5773         return_size = mono_class_value_size (return_klass, &align);
5774
5775         //We can do it if sizes match
5776         if (param_size == return_size) {
5777                 if (cfg->verbose_level > 3)
5778                         printf ("[UNSAFE-MOV-INTRISIC]\tsame size\n");
5779                 return TRUE;
5780         }
5781
5782         //No simple way to handle struct if sizes don't match
5783         if (MONO_TYPE_ISSTRUCT (&param_klass->byval_arg)) {
5784                 if (cfg->verbose_level > 3)
5785                         printf ("[UNSAFE-MOV-INTRISIC]\tsize mismatch and type is a struct\n");
5786                 return FALSE;
5787         }
5788
5789         /*
5790          * Same reg size category.
5791          * A quick note on why we don't require widening here.
5792          * The intrinsic is "R Array.UnsafeMov<S,R> (S s)".
5793          *
5794          * Since the source value comes from a function argument, the JIT will already have
5795          * the value in a VREG and performed any widening needed before (say, when loading from a field).
5796          */
5797         if (param_size <= 4 && return_size <= 4) {
5798                 if (cfg->verbose_level > 3)
5799                         printf ("[UNSAFE-MOV-INTRISIC]\tsize mismatch but both are of the same reg class\n");
5800                 return TRUE;
5801         }
5802
5803         return FALSE;
5804 }
5805
5806 static MonoInst*
5807 emit_array_unsafe_mov (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args)
5808 {
5809         MonoClass *param_klass = mono_class_from_mono_type (fsig->params [0]);
5810         MonoClass *return_klass = mono_class_from_mono_type (fsig->ret);
5811
5812         if (mini_is_gsharedvt_variable_type (fsig->ret))
5813                 return NULL;
5814
5815         //Valuetypes that are semantically equivalent or numbers than can be widened to
5816         if (is_unsafe_mov_compatible (cfg, param_klass, return_klass))
5817                 return args [0];
5818
5819         //Arrays of valuetypes that are semantically equivalent
5820         if (param_klass->rank == 1 && return_klass->rank == 1 && is_unsafe_mov_compatible (cfg, param_klass->element_class, return_klass->element_class))
5821                 return args [0];
5822
5823         return NULL;
5824 }
5825
5826 static MonoInst*
5827 mini_emit_inst_for_ctor (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5828 {
5829 #ifdef MONO_ARCH_SIMD_INTRINSICS
5830         MonoInst *ins = NULL;
5831
5832         if (cfg->opt & MONO_OPT_SIMD) {
5833                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
5834                 if (ins)
5835                         return ins;
5836         }
5837 #endif
5838
5839         return mono_emit_native_types_intrinsics (cfg, cmethod, fsig, args);
5840 }
5841
5842 static MonoInst*
5843 emit_memory_barrier (MonoCompile *cfg, int kind)
5844 {
5845         MonoInst *ins = NULL;
5846         MONO_INST_NEW (cfg, ins, OP_MEMORY_BARRIER);
5847         MONO_ADD_INS (cfg->cbb, ins);
5848         ins->backend.memory_barrier_kind = kind;
5849
5850         return ins;
5851 }
5852
5853 static MonoInst*
5854 llvm_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5855 {
5856         MonoInst *ins = NULL;
5857         int opcode = 0;
5858
5859         /* The LLVM backend supports these intrinsics */
5860         if (cmethod->klass == mono_defaults.math_class) {
5861                 if (strcmp (cmethod->name, "Sin") == 0) {
5862                         opcode = OP_SIN;
5863                 } else if (strcmp (cmethod->name, "Cos") == 0) {
5864                         opcode = OP_COS;
5865                 } else if (strcmp (cmethod->name, "Sqrt") == 0) {
5866                         opcode = OP_SQRT;
5867                 } else if (strcmp (cmethod->name, "Abs") == 0 && fsig->params [0]->type == MONO_TYPE_R8) {
5868                         opcode = OP_ABS;
5869                 }
5870
5871                 if (opcode && fsig->param_count == 1) {
5872                         MONO_INST_NEW (cfg, ins, opcode);
5873                         ins->type = STACK_R8;
5874                         ins->dreg = mono_alloc_freg (cfg);
5875                         ins->sreg1 = args [0]->dreg;
5876                         MONO_ADD_INS (cfg->cbb, ins);
5877                 }
5878
5879                 opcode = 0;
5880                 if (cfg->opt & MONO_OPT_CMOV) {
5881                         if (strcmp (cmethod->name, "Min") == 0) {
5882                                 if (fsig->params [0]->type == MONO_TYPE_I4)
5883                                         opcode = OP_IMIN;
5884                                 if (fsig->params [0]->type == MONO_TYPE_U4)
5885                                         opcode = OP_IMIN_UN;
5886                                 else if (fsig->params [0]->type == MONO_TYPE_I8)
5887                                         opcode = OP_LMIN;
5888                                 else if (fsig->params [0]->type == MONO_TYPE_U8)
5889                                         opcode = OP_LMIN_UN;
5890                         } else if (strcmp (cmethod->name, "Max") == 0) {
5891                                 if (fsig->params [0]->type == MONO_TYPE_I4)
5892                                         opcode = OP_IMAX;
5893                                 if (fsig->params [0]->type == MONO_TYPE_U4)
5894                                         opcode = OP_IMAX_UN;
5895                                 else if (fsig->params [0]->type == MONO_TYPE_I8)
5896                                         opcode = OP_LMAX;
5897                                 else if (fsig->params [0]->type == MONO_TYPE_U8)
5898                                         opcode = OP_LMAX_UN;
5899                         }
5900                 }
5901
5902                 if (opcode && fsig->param_count == 2) {
5903                         MONO_INST_NEW (cfg, ins, opcode);
5904                         ins->type = fsig->params [0]->type == MONO_TYPE_I4 ? STACK_I4 : STACK_I8;
5905                         ins->dreg = mono_alloc_ireg (cfg);
5906                         ins->sreg1 = args [0]->dreg;
5907                         ins->sreg2 = args [1]->dreg;
5908                         MONO_ADD_INS (cfg->cbb, ins);
5909                 }
5910         }
5911
5912         return ins;
5913 }
5914
5915 static MonoInst*
5916 mini_emit_inst_for_sharable_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5917 {
5918         if (cmethod->klass == mono_defaults.array_class) {
5919                 if (strcmp (cmethod->name, "UnsafeStore") == 0)
5920                         return emit_array_unsafe_access (cfg, fsig, args, TRUE);
5921                 else if (strcmp (cmethod->name, "UnsafeLoad") == 0)
5922                         return emit_array_unsafe_access (cfg, fsig, args, FALSE);
5923                 else if (strcmp (cmethod->name, "UnsafeMov") == 0)
5924                         return emit_array_unsafe_mov (cfg, fsig, args);
5925         }
5926
5927         return NULL;
5928 }
5929
5930 static MonoInst*
5931 mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5932 {
5933         MonoInst *ins = NULL;
5934
5935         static MonoClass *runtime_helpers_class = NULL;
5936         if (! runtime_helpers_class)
5937                 runtime_helpers_class = mono_class_from_name (mono_defaults.corlib,
5938                         "System.Runtime.CompilerServices", "RuntimeHelpers");
5939
5940         if (cmethod->klass == mono_defaults.string_class) {
5941                 if (strcmp (cmethod->name, "get_Chars") == 0 && fsig->param_count + fsig->hasthis == 2) {
5942                         int dreg = alloc_ireg (cfg);
5943                         int index_reg = alloc_preg (cfg);
5944                         int add_reg = alloc_preg (cfg);
5945
5946 #if SIZEOF_REGISTER == 8
5947                         if (COMPILE_LLVM (cfg)) {
5948                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, index_reg, args [1]->dreg);
5949                         } else {
5950                                 /* The array reg is 64 bits but the index reg is only 32 */
5951                                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index_reg, args [1]->dreg);
5952                         }
5953 #else
5954                         index_reg = args [1]->dreg;
5955 #endif  
5956                         MONO_EMIT_BOUNDS_CHECK (cfg, args [0]->dreg, MonoString, length, index_reg);
5957
5958 #if defined(TARGET_X86) || defined(TARGET_AMD64)
5959                         EMIT_NEW_X86_LEA (cfg, ins, args [0]->dreg, index_reg, 1, MONO_STRUCT_OFFSET (MonoString, chars));
5960                         add_reg = ins->dreg;
5961                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
5962                                                                    add_reg, 0);
5963 #else
5964                         int mult_reg = alloc_preg (cfg);
5965                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, mult_reg, index_reg, 1);
5966                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult_reg, args [0]->dreg);
5967                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
5968                                                                    add_reg, MONO_STRUCT_OFFSET (MonoString, chars));
5969 #endif
5970                         type_from_op (cfg, ins, NULL, NULL);
5971                         return ins;
5972                 } else if (strcmp (cmethod->name, "get_Length") == 0 && fsig->param_count + fsig->hasthis == 1) {
5973                         int dreg = alloc_ireg (cfg);
5974                         /* Decompose later to allow more optimizations */
5975                         EMIT_NEW_UNALU (cfg, ins, OP_STRLEN, dreg, args [0]->dreg);
5976                         ins->type = STACK_I4;
5977                         ins->flags |= MONO_INST_FAULT;
5978                         cfg->cbb->has_array_access = TRUE;
5979                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
5980
5981                         return ins;
5982                 } else 
5983                         return NULL;
5984         } else if (cmethod->klass == mono_defaults.object_class) {
5985                 if (strcmp (cmethod->name, "GetType") == 0 && fsig->param_count + fsig->hasthis == 1) {
5986                         int dreg = alloc_ireg_ref (cfg);
5987                         int vt_reg = alloc_preg (cfg);
5988                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vt_reg, args [0]->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
5989                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, vt_reg, MONO_STRUCT_OFFSET (MonoVTable, type));
5990                         type_from_op (cfg, ins, NULL, NULL);
5991
5992                         return ins;
5993                 } else if (!cfg->backend->emulate_mul_div && strcmp (cmethod->name, "InternalGetHashCode") == 0 && fsig->param_count == 1 && !mono_gc_is_moving ()) {
5994                         int dreg = alloc_ireg (cfg);
5995                         int t1 = alloc_ireg (cfg);
5996         
5997                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, t1, args [0]->dreg, 3);
5998                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_MUL_IMM, dreg, t1, 2654435761u);
5999                         ins->type = STACK_I4;
6000
6001                         return ins;
6002                 } else if (strcmp (cmethod->name, ".ctor") == 0 && fsig->param_count == 0) {
6003                         MONO_INST_NEW (cfg, ins, OP_NOP);
6004                         MONO_ADD_INS (cfg->cbb, ins);
6005                         return ins;
6006                 } else
6007                         return NULL;
6008         } else if (cmethod->klass == mono_defaults.array_class) {
6009                 if (strcmp (cmethod->name, "GetGenericValueImpl") == 0 && fsig->param_count + fsig->hasthis == 3 && !cfg->gsharedvt)
6010                         return emit_array_generic_access (cfg, fsig, args, FALSE);
6011                 else if (strcmp (cmethod->name, "SetGenericValueImpl") == 0 && fsig->param_count + fsig->hasthis == 3 && !cfg->gsharedvt)
6012                         return emit_array_generic_access (cfg, fsig, args, TRUE);
6013
6014 #ifndef MONO_BIG_ARRAYS
6015                 /*
6016                  * This is an inline version of GetLength/GetLowerBound(0) used frequently in
6017                  * Array methods.
6018                  */
6019                 else if (((strcmp (cmethod->name, "GetLength") == 0 && fsig->param_count + fsig->hasthis == 2) ||
6020                          (strcmp (cmethod->name, "GetLowerBound") == 0 && fsig->param_count + fsig->hasthis == 2)) &&
6021                          args [1]->opcode == OP_ICONST && args [1]->inst_c0 == 0) {
6022                         int dreg = alloc_ireg (cfg);
6023                         int bounds_reg = alloc_ireg_mp (cfg);
6024                         MonoBasicBlock *end_bb, *szarray_bb;
6025                         gboolean get_length = strcmp (cmethod->name, "GetLength") == 0;
6026
6027                         NEW_BBLOCK (cfg, end_bb);
6028                         NEW_BBLOCK (cfg, szarray_bb);
6029
6030                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOAD_MEMBASE, bounds_reg,
6031                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, bounds));
6032                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
6033                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, szarray_bb);
6034                         /* Non-szarray case */
6035                         if (get_length)
6036                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
6037                                                                            bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, length));
6038                         else
6039                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
6040                                                                            bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
6041                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
6042                         MONO_START_BB (cfg, szarray_bb);
6043                         /* Szarray case */
6044                         if (get_length)
6045                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
6046                                                                            args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, max_length));
6047                         else
6048                                 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
6049                         MONO_START_BB (cfg, end_bb);
6050
6051                         EMIT_NEW_UNALU (cfg, ins, OP_MOVE, dreg, dreg);
6052                         ins->type = STACK_I4;
6053                         
6054                         return ins;
6055                 }
6056 #endif
6057
6058                 if (cmethod->name [0] != 'g')
6059                         return NULL;
6060
6061                 if (strcmp (cmethod->name, "get_Rank") == 0 && fsig->param_count + fsig->hasthis == 1) {
6062                         int dreg = alloc_ireg (cfg);
6063                         int vtable_reg = alloc_preg (cfg);
6064                         MONO_EMIT_NEW_LOAD_MEMBASE_OP_FAULT (cfg, OP_LOAD_MEMBASE, vtable_reg, 
6065                                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
6066                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU1_MEMBASE, dreg,
6067                                                                    vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
6068                         type_from_op (cfg, ins, NULL, NULL);
6069
6070                         return ins;
6071                 } else if (strcmp (cmethod->name, "get_Length") == 0 && fsig->param_count + fsig->hasthis == 1) {
6072                         int dreg = alloc_ireg (cfg);
6073
6074                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOADI4_MEMBASE, dreg, 
6075                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, max_length));
6076                         type_from_op (cfg, ins, NULL, NULL);
6077
6078                         return ins;
6079                 } else
6080                         return NULL;
6081         } else if (cmethod->klass == runtime_helpers_class) {
6082                 if (strcmp (cmethod->name, "get_OffsetToStringData") == 0 && fsig->param_count == 0) {
6083                         EMIT_NEW_ICONST (cfg, ins, MONO_STRUCT_OFFSET (MonoString, chars));
6084                         return ins;
6085                 } else
6086                         return NULL;
6087         } else if (cmethod->klass == mono_defaults.monitor_class) {
6088                 gboolean is_enter = FALSE;
6089                 gboolean is_v4 = FALSE;
6090
6091                 if (!strcmp (cmethod->name, "enter_with_atomic_var") && mono_method_signature (cmethod)->param_count == 2) {
6092                         is_enter = TRUE;
6093                         is_v4 = TRUE;
6094                 }
6095                 if (!strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1)
6096                         is_enter = TRUE;
6097
6098                 if (is_enter) {
6099                         /*
6100                          * To make async stack traces work, icalls which can block should have a wrapper.
6101                          * For Monitor.Enter, emit two calls: a fastpath which doesn't have a wrapper, and a slowpath, which does.
6102                          */
6103                         MonoBasicBlock *end_bb;
6104
6105                         NEW_BBLOCK (cfg, end_bb);
6106
6107                         ins = mono_emit_jit_icall (cfg, is_v4 ? (gpointer)mono_monitor_enter_v4_fast : (gpointer)mono_monitor_enter_fast, args);
6108                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, ins->dreg, 0);
6109                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, end_bb);
6110                         ins = mono_emit_jit_icall (cfg, is_v4 ? (gpointer)mono_monitor_enter_v4 : (gpointer)mono_monitor_enter, args);
6111                         MONO_START_BB (cfg, end_bb);
6112                         return ins;
6113                 }
6114         } else if (cmethod->klass == mono_defaults.thread_class) {
6115                 if (strcmp (cmethod->name, "SpinWait_nop") == 0 && fsig->param_count == 0) {
6116                         MONO_INST_NEW (cfg, ins, OP_RELAXED_NOP);
6117                         MONO_ADD_INS (cfg->cbb, ins);
6118                         return ins;
6119                 } else if (strcmp (cmethod->name, "MemoryBarrier") == 0 && fsig->param_count == 0) {
6120                         return emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6121                 } else if (!strcmp (cmethod->name, "VolatileRead") && fsig->param_count == 1) {
6122                         guint32 opcode = 0;
6123                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
6124
6125                         if (fsig->params [0]->type == MONO_TYPE_I1)
6126                                 opcode = OP_LOADI1_MEMBASE;
6127                         else if (fsig->params [0]->type == MONO_TYPE_U1)
6128                                 opcode = OP_LOADU1_MEMBASE;
6129                         else if (fsig->params [0]->type == MONO_TYPE_I2)
6130                                 opcode = OP_LOADI2_MEMBASE;
6131                         else if (fsig->params [0]->type == MONO_TYPE_U2)
6132                                 opcode = OP_LOADU2_MEMBASE;
6133                         else if (fsig->params [0]->type == MONO_TYPE_I4)
6134                                 opcode = OP_LOADI4_MEMBASE;
6135                         else if (fsig->params [0]->type == MONO_TYPE_U4)
6136                                 opcode = OP_LOADU4_MEMBASE;
6137                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_U8)
6138                                 opcode = OP_LOADI8_MEMBASE;
6139                         else if (fsig->params [0]->type == MONO_TYPE_R4)
6140                                 opcode = OP_LOADR4_MEMBASE;
6141                         else if (fsig->params [0]->type == MONO_TYPE_R8)
6142                                 opcode = OP_LOADR8_MEMBASE;
6143                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I || fsig->params [0]->type == MONO_TYPE_U)
6144                                 opcode = OP_LOAD_MEMBASE;
6145
6146                         if (opcode) {
6147                                 MONO_INST_NEW (cfg, ins, opcode);
6148                                 ins->inst_basereg = args [0]->dreg;
6149                                 ins->inst_offset = 0;
6150                                 MONO_ADD_INS (cfg->cbb, ins);
6151
6152                                 switch (fsig->params [0]->type) {
6153                                 case MONO_TYPE_I1:
6154                                 case MONO_TYPE_U1:
6155                                 case MONO_TYPE_I2:
6156                                 case MONO_TYPE_U2:
6157                                 case MONO_TYPE_I4:
6158                                 case MONO_TYPE_U4:
6159                                         ins->dreg = mono_alloc_ireg (cfg);
6160                                         ins->type = STACK_I4;
6161                                         break;
6162                                 case MONO_TYPE_I8:
6163                                 case MONO_TYPE_U8:
6164                                         ins->dreg = mono_alloc_lreg (cfg);
6165                                         ins->type = STACK_I8;
6166                                         break;
6167                                 case MONO_TYPE_I:
6168                                 case MONO_TYPE_U:
6169                                         ins->dreg = mono_alloc_ireg (cfg);
6170 #if SIZEOF_REGISTER == 8
6171                                         ins->type = STACK_I8;
6172 #else
6173                                         ins->type = STACK_I4;
6174 #endif
6175                                         break;
6176                                 case MONO_TYPE_R4:
6177                                 case MONO_TYPE_R8:
6178                                         ins->dreg = mono_alloc_freg (cfg);
6179                                         ins->type = STACK_R8;
6180                                         break;
6181                                 default:
6182                                         g_assert (mini_type_is_reference (fsig->params [0]));
6183                                         ins->dreg = mono_alloc_ireg_ref (cfg);
6184                                         ins->type = STACK_OBJ;
6185                                         break;
6186                                 }
6187
6188                                 if (opcode == OP_LOADI8_MEMBASE)
6189                                         ins = mono_decompose_opcode (cfg, ins);
6190
6191                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6192
6193                                 return ins;
6194                         }
6195                 } else if (!strcmp (cmethod->name, "VolatileWrite") && fsig->param_count == 2) {
6196                         guint32 opcode = 0;
6197                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
6198
6199                         if (fsig->params [0]->type == MONO_TYPE_I1 || fsig->params [0]->type == MONO_TYPE_U1)
6200                                 opcode = OP_STOREI1_MEMBASE_REG;
6201                         else if (fsig->params [0]->type == MONO_TYPE_I2 || fsig->params [0]->type == MONO_TYPE_U2)
6202                                 opcode = OP_STOREI2_MEMBASE_REG;
6203                         else if (fsig->params [0]->type == MONO_TYPE_I4 || fsig->params [0]->type == MONO_TYPE_U4)
6204                                 opcode = OP_STOREI4_MEMBASE_REG;
6205                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_U8)
6206                                 opcode = OP_STOREI8_MEMBASE_REG;
6207                         else if (fsig->params [0]->type == MONO_TYPE_R4)
6208                                 opcode = OP_STORER4_MEMBASE_REG;
6209                         else if (fsig->params [0]->type == MONO_TYPE_R8)
6210                                 opcode = OP_STORER8_MEMBASE_REG;
6211                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I || fsig->params [0]->type == MONO_TYPE_U)
6212                                 opcode = OP_STORE_MEMBASE_REG;
6213
6214                         if (opcode) {
6215                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6216
6217                                 MONO_INST_NEW (cfg, ins, opcode);
6218                                 ins->sreg1 = args [1]->dreg;
6219                                 ins->inst_destbasereg = args [0]->dreg;
6220                                 ins->inst_offset = 0;
6221                                 MONO_ADD_INS (cfg->cbb, ins);
6222
6223                                 if (opcode == OP_STOREI8_MEMBASE_REG)
6224                                         ins = mono_decompose_opcode (cfg, ins);
6225
6226                                 return ins;
6227                         }
6228                 }
6229         } else if (cmethod->klass->image == mono_defaults.corlib &&
6230                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
6231                            (strcmp (cmethod->klass->name, "Interlocked") == 0)) {
6232                 ins = NULL;
6233
6234 #if SIZEOF_REGISTER == 8
6235                 if (!cfg->llvm_only && strcmp (cmethod->name, "Read") == 0 && fsig->param_count == 1 && (fsig->params [0]->type == MONO_TYPE_I8)) {
6236                         if (!cfg->llvm_only && mono_arch_opcode_supported (OP_ATOMIC_LOAD_I8)) {
6237                                 MONO_INST_NEW (cfg, ins, OP_ATOMIC_LOAD_I8);
6238                                 ins->dreg = mono_alloc_preg (cfg);
6239                                 ins->sreg1 = args [0]->dreg;
6240                                 ins->type = STACK_I8;
6241                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_SEQ;
6242                                 MONO_ADD_INS (cfg->cbb, ins);
6243                         } else {
6244                                 MonoInst *load_ins;
6245
6246                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6247
6248                                 /* 64 bit reads are already atomic */
6249                                 MONO_INST_NEW (cfg, load_ins, OP_LOADI8_MEMBASE);
6250                                 load_ins->dreg = mono_alloc_preg (cfg);
6251                                 load_ins->inst_basereg = args [0]->dreg;
6252                                 load_ins->inst_offset = 0;
6253                                 load_ins->type = STACK_I8;
6254                                 MONO_ADD_INS (cfg->cbb, load_ins);
6255
6256                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6257
6258                                 ins = load_ins;
6259                         }
6260                 }
6261 #endif
6262
6263                 if (strcmp (cmethod->name, "Increment") == 0 && fsig->param_count == 1) {
6264                         MonoInst *ins_iconst;
6265                         guint32 opcode = 0;
6266
6267                         if (fsig->params [0]->type == MONO_TYPE_I4) {
6268                                 opcode = OP_ATOMIC_ADD_I4;
6269                                 cfg->has_atomic_add_i4 = TRUE;
6270                         }
6271 #if SIZEOF_REGISTER == 8
6272                         else if (fsig->params [0]->type == MONO_TYPE_I8)
6273                                 opcode = OP_ATOMIC_ADD_I8;
6274 #endif
6275                         if (opcode) {
6276                                 if (!mono_arch_opcode_supported (opcode))
6277                                         return NULL;
6278                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
6279                                 ins_iconst->inst_c0 = 1;
6280                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
6281                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
6282
6283                                 MONO_INST_NEW (cfg, ins, opcode);
6284                                 ins->dreg = mono_alloc_ireg (cfg);
6285                                 ins->inst_basereg = args [0]->dreg;
6286                                 ins->inst_offset = 0;
6287                                 ins->sreg2 = ins_iconst->dreg;
6288                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
6289                                 MONO_ADD_INS (cfg->cbb, ins);
6290                         }
6291                 } else if (strcmp (cmethod->name, "Decrement") == 0 && fsig->param_count == 1) {
6292                         MonoInst *ins_iconst;
6293                         guint32 opcode = 0;
6294
6295                         if (fsig->params [0]->type == MONO_TYPE_I4) {
6296                                 opcode = OP_ATOMIC_ADD_I4;
6297                                 cfg->has_atomic_add_i4 = TRUE;
6298                         }
6299 #if SIZEOF_REGISTER == 8
6300                         else if (fsig->params [0]->type == MONO_TYPE_I8)
6301                                 opcode = OP_ATOMIC_ADD_I8;
6302 #endif
6303                         if (opcode) {
6304                                 if (!mono_arch_opcode_supported (opcode))
6305                                         return NULL;
6306                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
6307                                 ins_iconst->inst_c0 = -1;
6308                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
6309                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
6310
6311                                 MONO_INST_NEW (cfg, ins, opcode);
6312                                 ins->dreg = mono_alloc_ireg (cfg);
6313                                 ins->inst_basereg = args [0]->dreg;
6314                                 ins->inst_offset = 0;
6315                                 ins->sreg2 = ins_iconst->dreg;
6316                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
6317                                 MONO_ADD_INS (cfg->cbb, ins);
6318                         }
6319                 } else if (strcmp (cmethod->name, "Add") == 0 && fsig->param_count == 2) {
6320                         guint32 opcode = 0;
6321
6322                         if (fsig->params [0]->type == MONO_TYPE_I4) {
6323                                 opcode = OP_ATOMIC_ADD_I4;
6324                                 cfg->has_atomic_add_i4 = TRUE;
6325                         }
6326 #if SIZEOF_REGISTER == 8
6327                         else if (fsig->params [0]->type == MONO_TYPE_I8)
6328                                 opcode = OP_ATOMIC_ADD_I8;
6329 #endif
6330                         if (opcode) {
6331                                 if (!mono_arch_opcode_supported (opcode))
6332                                         return NULL;
6333                                 MONO_INST_NEW (cfg, ins, opcode);
6334                                 ins->dreg = mono_alloc_ireg (cfg);
6335                                 ins->inst_basereg = args [0]->dreg;
6336                                 ins->inst_offset = 0;
6337                                 ins->sreg2 = args [1]->dreg;
6338                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
6339                                 MONO_ADD_INS (cfg->cbb, ins);
6340                         }
6341                 }
6342                 else if (strcmp (cmethod->name, "Exchange") == 0 && fsig->param_count == 2) {
6343                         MonoInst *f2i = NULL, *i2f;
6344                         guint32 opcode, f2i_opcode, i2f_opcode;
6345                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
6346                         gboolean is_float = fsig->params [0]->type == MONO_TYPE_R4 || fsig->params [0]->type == MONO_TYPE_R8;
6347
6348                         if (fsig->params [0]->type == MONO_TYPE_I4 ||
6349                             fsig->params [0]->type == MONO_TYPE_R4) {
6350                                 opcode = OP_ATOMIC_EXCHANGE_I4;
6351                                 f2i_opcode = OP_MOVE_F_TO_I4;
6352                                 i2f_opcode = OP_MOVE_I4_TO_F;
6353                                 cfg->has_atomic_exchange_i4 = TRUE;
6354                         }
6355 #if SIZEOF_REGISTER == 8
6356                         else if (is_ref ||
6357                                  fsig->params [0]->type == MONO_TYPE_I8 ||
6358                                  fsig->params [0]->type == MONO_TYPE_R8 ||
6359                                  fsig->params [0]->type == MONO_TYPE_I) {
6360                                 opcode = OP_ATOMIC_EXCHANGE_I8;
6361                                 f2i_opcode = OP_MOVE_F_TO_I8;
6362                                 i2f_opcode = OP_MOVE_I8_TO_F;
6363                         }
6364 #else
6365                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I) {
6366                                 opcode = OP_ATOMIC_EXCHANGE_I4;
6367                                 cfg->has_atomic_exchange_i4 = TRUE;
6368                         }
6369 #endif
6370                         else
6371                                 return NULL;
6372
6373                         if (!mono_arch_opcode_supported (opcode))
6374                                 return NULL;
6375
6376                         if (is_float) {
6377                                 /* TODO: Decompose these opcodes instead of bailing here. */
6378                                 if (COMPILE_SOFT_FLOAT (cfg))
6379                                         return NULL;
6380
6381                                 MONO_INST_NEW (cfg, f2i, f2i_opcode);
6382                                 f2i->dreg = mono_alloc_ireg (cfg);
6383                                 f2i->sreg1 = args [1]->dreg;
6384                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
6385                                         f2i->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6386                                 MONO_ADD_INS (cfg->cbb, f2i);
6387                         }
6388
6389                         MONO_INST_NEW (cfg, ins, opcode);
6390                         ins->dreg = is_ref ? mono_alloc_ireg_ref (cfg) : mono_alloc_ireg (cfg);
6391                         ins->inst_basereg = args [0]->dreg;
6392                         ins->inst_offset = 0;
6393                         ins->sreg2 = is_float ? f2i->dreg : args [1]->dreg;
6394                         MONO_ADD_INS (cfg->cbb, ins);
6395
6396                         switch (fsig->params [0]->type) {
6397                         case MONO_TYPE_I4:
6398                                 ins->type = STACK_I4;
6399                                 break;
6400                         case MONO_TYPE_I8:
6401                                 ins->type = STACK_I8;
6402                                 break;
6403                         case MONO_TYPE_I:
6404 #if SIZEOF_REGISTER == 8
6405                                 ins->type = STACK_I8;
6406 #else
6407                                 ins->type = STACK_I4;
6408 #endif
6409                                 break;
6410                         case MONO_TYPE_R4:
6411                         case MONO_TYPE_R8:
6412                                 ins->type = STACK_R8;
6413                                 break;
6414                         default:
6415                                 g_assert (mini_type_is_reference (fsig->params [0]));
6416                                 ins->type = STACK_OBJ;
6417                                 break;
6418                         }
6419
6420                         if (is_float) {
6421                                 MONO_INST_NEW (cfg, i2f, i2f_opcode);
6422                                 i2f->dreg = mono_alloc_freg (cfg);
6423                                 i2f->sreg1 = ins->dreg;
6424                                 i2f->type = STACK_R8;
6425                                 if (i2f_opcode == OP_MOVE_I4_TO_F)
6426                                         i2f->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6427                                 MONO_ADD_INS (cfg->cbb, i2f);
6428
6429                                 ins = i2f;
6430                         }
6431
6432                         if (cfg->gen_write_barriers && is_ref)
6433                                 emit_write_barrier (cfg, args [0], args [1]);
6434                 }
6435                 else if ((strcmp (cmethod->name, "CompareExchange") == 0) && fsig->param_count == 3) {
6436                         MonoInst *f2i_new = NULL, *f2i_cmp = NULL, *i2f;
6437                         guint32 opcode, f2i_opcode, i2f_opcode;
6438                         gboolean is_ref = mini_type_is_reference (fsig->params [1]);
6439                         gboolean is_float = fsig->params [1]->type == MONO_TYPE_R4 || fsig->params [1]->type == MONO_TYPE_R8;
6440
6441                         if (fsig->params [1]->type == MONO_TYPE_I4 ||
6442                             fsig->params [1]->type == MONO_TYPE_R4) {
6443                                 opcode = OP_ATOMIC_CAS_I4;
6444                                 f2i_opcode = OP_MOVE_F_TO_I4;
6445                                 i2f_opcode = OP_MOVE_I4_TO_F;
6446                                 cfg->has_atomic_cas_i4 = TRUE;
6447                         }
6448 #if SIZEOF_REGISTER == 8
6449                         else if (is_ref ||
6450                                  fsig->params [1]->type == MONO_TYPE_I8 ||
6451                                  fsig->params [1]->type == MONO_TYPE_R8 ||
6452                                  fsig->params [1]->type == MONO_TYPE_I) {
6453                                 opcode = OP_ATOMIC_CAS_I8;
6454                                 f2i_opcode = OP_MOVE_F_TO_I8;
6455                                 i2f_opcode = OP_MOVE_I8_TO_F;
6456                         }
6457 #else
6458                         else if (is_ref || fsig->params [1]->type == MONO_TYPE_I) {
6459                                 opcode = OP_ATOMIC_CAS_I4;
6460                                 cfg->has_atomic_cas_i4 = TRUE;
6461                         }
6462 #endif
6463                         else
6464                                 return NULL;
6465
6466                         if (!mono_arch_opcode_supported (opcode))
6467                                 return NULL;
6468
6469                         if (is_float) {
6470                                 /* TODO: Decompose these opcodes instead of bailing here. */
6471                                 if (COMPILE_SOFT_FLOAT (cfg))
6472                                         return NULL;
6473
6474                                 MONO_INST_NEW (cfg, f2i_new, f2i_opcode);
6475                                 f2i_new->dreg = mono_alloc_ireg (cfg);
6476                                 f2i_new->sreg1 = args [1]->dreg;
6477                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
6478                                         f2i_new->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6479                                 MONO_ADD_INS (cfg->cbb, f2i_new);
6480
6481                                 MONO_INST_NEW (cfg, f2i_cmp, f2i_opcode);
6482                                 f2i_cmp->dreg = mono_alloc_ireg (cfg);
6483                                 f2i_cmp->sreg1 = args [2]->dreg;
6484                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
6485                                         f2i_cmp->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6486                                 MONO_ADD_INS (cfg->cbb, f2i_cmp);
6487                         }
6488
6489                         MONO_INST_NEW (cfg, ins, opcode);
6490                         ins->dreg = is_ref ? alloc_ireg_ref (cfg) : alloc_ireg (cfg);
6491                         ins->sreg1 = args [0]->dreg;
6492                         ins->sreg2 = is_float ? f2i_new->dreg : args [1]->dreg;
6493                         ins->sreg3 = is_float ? f2i_cmp->dreg : args [2]->dreg;
6494                         MONO_ADD_INS (cfg->cbb, ins);
6495
6496                         switch (fsig->params [1]->type) {
6497                         case MONO_TYPE_I4:
6498                                 ins->type = STACK_I4;
6499                                 break;
6500                         case MONO_TYPE_I8:
6501                                 ins->type = STACK_I8;
6502                                 break;
6503                         case MONO_TYPE_I:
6504 #if SIZEOF_REGISTER == 8
6505                                 ins->type = STACK_I8;
6506 #else
6507                                 ins->type = STACK_I4;
6508 #endif
6509                                 break;
6510                         case MONO_TYPE_R4:
6511                                 ins->type = cfg->r4_stack_type;
6512                                 break;
6513                         case MONO_TYPE_R8:
6514                                 ins->type = STACK_R8;
6515                                 break;
6516                         default:
6517                                 g_assert (mini_type_is_reference (fsig->params [1]));
6518                                 ins->type = STACK_OBJ;
6519                                 break;
6520                         }
6521
6522                         if (is_float) {
6523                                 MONO_INST_NEW (cfg, i2f, i2f_opcode);
6524                                 i2f->dreg = mono_alloc_freg (cfg);
6525                                 i2f->sreg1 = ins->dreg;
6526                                 i2f->type = STACK_R8;
6527                                 if (i2f_opcode == OP_MOVE_I4_TO_F)
6528                                         i2f->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6529                                 MONO_ADD_INS (cfg->cbb, i2f);
6530
6531                                 ins = i2f;
6532                         }
6533
6534                         if (cfg->gen_write_barriers && is_ref)
6535                                 emit_write_barrier (cfg, args [0], args [1]);
6536                 }
6537                 else if ((strcmp (cmethod->name, "CompareExchange") == 0) && fsig->param_count == 4 &&
6538                          fsig->params [1]->type == MONO_TYPE_I4) {
6539                         MonoInst *cmp, *ceq;
6540
6541                         if (!mono_arch_opcode_supported (OP_ATOMIC_CAS_I4))
6542                                 return NULL;
6543
6544                         /* int32 r = CAS (location, value, comparand); */
6545                         MONO_INST_NEW (cfg, ins, OP_ATOMIC_CAS_I4);
6546                         ins->dreg = alloc_ireg (cfg);
6547                         ins->sreg1 = args [0]->dreg;
6548                         ins->sreg2 = args [1]->dreg;
6549                         ins->sreg3 = args [2]->dreg;
6550                         ins->type = STACK_I4;
6551                         MONO_ADD_INS (cfg->cbb, ins);
6552
6553                         /* bool result = r == comparand; */
6554                         MONO_INST_NEW (cfg, cmp, OP_ICOMPARE);
6555                         cmp->sreg1 = ins->dreg;
6556                         cmp->sreg2 = args [2]->dreg;
6557                         cmp->type = STACK_I4;
6558                         MONO_ADD_INS (cfg->cbb, cmp);
6559
6560                         MONO_INST_NEW (cfg, ceq, OP_ICEQ);
6561                         ceq->dreg = alloc_ireg (cfg);
6562                         ceq->type = STACK_I4;
6563                         MONO_ADD_INS (cfg->cbb, ceq);
6564
6565                         /* *success = result; */
6566                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, args [3]->dreg, 0, ceq->dreg);
6567
6568                         cfg->has_atomic_cas_i4 = TRUE;
6569                 }
6570                 else if (strcmp (cmethod->name, "MemoryBarrier") == 0 && fsig->param_count == 0)
6571                         ins = emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6572
6573                 if (ins)
6574                         return ins;
6575         } else if (cmethod->klass->image == mono_defaults.corlib &&
6576                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
6577                            (strcmp (cmethod->klass->name, "Volatile") == 0)) {
6578                 ins = NULL;
6579
6580                 if (!cfg->llvm_only && !strcmp (cmethod->name, "Read") && fsig->param_count == 1) {
6581                         guint32 opcode = 0;
6582                         MonoType *t = fsig->params [0];
6583                         gboolean is_ref;
6584                         gboolean is_float = t->type == MONO_TYPE_R4 || t->type == MONO_TYPE_R8;
6585
6586                         g_assert (t->byref);
6587                         /* t is a byref type, so the reference check is more complicated */
6588                         is_ref = mini_type_is_reference (&mono_class_from_mono_type (t)->byval_arg);
6589                         if (t->type == MONO_TYPE_I1)
6590                                 opcode = OP_ATOMIC_LOAD_I1;
6591                         else if (t->type == MONO_TYPE_U1 || t->type == MONO_TYPE_BOOLEAN)
6592                                 opcode = OP_ATOMIC_LOAD_U1;
6593                         else if (t->type == MONO_TYPE_I2)
6594                                 opcode = OP_ATOMIC_LOAD_I2;
6595                         else if (t->type == MONO_TYPE_U2)
6596                                 opcode = OP_ATOMIC_LOAD_U2;
6597                         else if (t->type == MONO_TYPE_I4)
6598                                 opcode = OP_ATOMIC_LOAD_I4;
6599                         else if (t->type == MONO_TYPE_U4)
6600                                 opcode = OP_ATOMIC_LOAD_U4;
6601                         else if (t->type == MONO_TYPE_R4)
6602                                 opcode = OP_ATOMIC_LOAD_R4;
6603                         else if (t->type == MONO_TYPE_R8)
6604                                 opcode = OP_ATOMIC_LOAD_R8;
6605 #if SIZEOF_REGISTER == 8
6606                         else if (t->type == MONO_TYPE_I8 || t->type == MONO_TYPE_I)
6607                                 opcode = OP_ATOMIC_LOAD_I8;
6608                         else if (is_ref || t->type == MONO_TYPE_U8 || t->type == MONO_TYPE_U)
6609                                 opcode = OP_ATOMIC_LOAD_U8;
6610 #else
6611                         else if (t->type == MONO_TYPE_I)
6612                                 opcode = OP_ATOMIC_LOAD_I4;
6613                         else if (is_ref || t->type == MONO_TYPE_U)
6614                                 opcode = OP_ATOMIC_LOAD_U4;
6615 #endif
6616
6617                         if (opcode) {
6618                                 if (!mono_arch_opcode_supported (opcode))
6619                                         return NULL;
6620
6621                                 MONO_INST_NEW (cfg, ins, opcode);
6622                                 ins->dreg = is_ref ? mono_alloc_ireg_ref (cfg) : (is_float ? mono_alloc_freg (cfg) : mono_alloc_ireg (cfg));
6623                                 ins->sreg1 = args [0]->dreg;
6624                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_ACQ;
6625                                 MONO_ADD_INS (cfg->cbb, ins);
6626
6627                                 switch (t->type) {
6628                                 case MONO_TYPE_BOOLEAN:
6629                                 case MONO_TYPE_I1:
6630                                 case MONO_TYPE_U1:
6631                                 case MONO_TYPE_I2:
6632                                 case MONO_TYPE_U2:
6633                                 case MONO_TYPE_I4:
6634                                 case MONO_TYPE_U4:
6635                                         ins->type = STACK_I4;
6636                                         break;
6637                                 case MONO_TYPE_I8:
6638                                 case MONO_TYPE_U8:
6639                                         ins->type = STACK_I8;
6640                                         break;
6641                                 case MONO_TYPE_I:
6642                                 case MONO_TYPE_U:
6643 #if SIZEOF_REGISTER == 8
6644                                         ins->type = STACK_I8;
6645 #else
6646                                         ins->type = STACK_I4;
6647 #endif
6648                                         break;
6649                                 case MONO_TYPE_R4:
6650                                         ins->type = cfg->r4_stack_type;
6651                                         break;
6652                                 case MONO_TYPE_R8:
6653                                         ins->type = STACK_R8;
6654                                         break;
6655                                 default:
6656                                         g_assert (is_ref);
6657                                         ins->type = STACK_OBJ;
6658                                         break;
6659                                 }
6660                         }
6661                 }
6662
6663                 if (!cfg->llvm_only && !strcmp (cmethod->name, "Write") && fsig->param_count == 2) {
6664                         guint32 opcode = 0;
6665                         MonoType *t = fsig->params [0];
6666                         gboolean is_ref;
6667
6668                         g_assert (t->byref);
6669                         is_ref = mini_type_is_reference (&mono_class_from_mono_type (t)->byval_arg);
6670                         if (t->type == MONO_TYPE_I1)
6671                                 opcode = OP_ATOMIC_STORE_I1;
6672                         else if (t->type == MONO_TYPE_U1 || t->type == MONO_TYPE_BOOLEAN)
6673                                 opcode = OP_ATOMIC_STORE_U1;
6674                         else if (t->type == MONO_TYPE_I2)
6675                                 opcode = OP_ATOMIC_STORE_I2;
6676                         else if (t->type == MONO_TYPE_U2)
6677                                 opcode = OP_ATOMIC_STORE_U2;
6678                         else if (t->type == MONO_TYPE_I4)
6679                                 opcode = OP_ATOMIC_STORE_I4;
6680                         else if (t->type == MONO_TYPE_U4)
6681                                 opcode = OP_ATOMIC_STORE_U4;
6682                         else if (t->type == MONO_TYPE_R4)
6683                                 opcode = OP_ATOMIC_STORE_R4;
6684                         else if (t->type == MONO_TYPE_R8)
6685                                 opcode = OP_ATOMIC_STORE_R8;
6686 #if SIZEOF_REGISTER == 8
6687                         else if (t->type == MONO_TYPE_I8 || t->type == MONO_TYPE_I)
6688                                 opcode = OP_ATOMIC_STORE_I8;
6689                         else if (is_ref || t->type == MONO_TYPE_U8 || t->type == MONO_TYPE_U)
6690                                 opcode = OP_ATOMIC_STORE_U8;
6691 #else
6692                         else if (t->type == MONO_TYPE_I)
6693                                 opcode = OP_ATOMIC_STORE_I4;
6694                         else if (is_ref || t->type == MONO_TYPE_U)
6695                                 opcode = OP_ATOMIC_STORE_U4;
6696 #endif
6697
6698                         if (opcode) {
6699                                 if (!mono_arch_opcode_supported (opcode))
6700                                         return NULL;
6701
6702                                 MONO_INST_NEW (cfg, ins, opcode);
6703                                 ins->dreg = args [0]->dreg;
6704                                 ins->sreg1 = args [1]->dreg;
6705                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_REL;
6706                                 MONO_ADD_INS (cfg->cbb, ins);
6707
6708                                 if (cfg->gen_write_barriers && is_ref)
6709                                         emit_write_barrier (cfg, args [0], args [1]);
6710                         }
6711                 }
6712
6713                 if (ins)
6714                         return ins;
6715         } else if (cmethod->klass->image == mono_defaults.corlib &&
6716                            (strcmp (cmethod->klass->name_space, "System.Diagnostics") == 0) &&
6717                            (strcmp (cmethod->klass->name, "Debugger") == 0)) {
6718                 if (!strcmp (cmethod->name, "Break") && fsig->param_count == 0) {
6719                         if (should_insert_brekpoint (cfg->method)) {
6720                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
6721                         } else {
6722                                 MONO_INST_NEW (cfg, ins, OP_NOP);
6723                                 MONO_ADD_INS (cfg->cbb, ins);
6724                         }
6725                         return ins;
6726                 }
6727         } else if (cmethod->klass->image == mono_defaults.corlib &&
6728                    (strcmp (cmethod->klass->name_space, "System") == 0) &&
6729                    (strcmp (cmethod->klass->name, "Environment") == 0)) {
6730                 if (!strcmp (cmethod->name, "get_IsRunningOnWindows") && fsig->param_count == 0) {
6731 #ifdef TARGET_WIN32
6732                         EMIT_NEW_ICONST (cfg, ins, 1);
6733 #else
6734                         EMIT_NEW_ICONST (cfg, ins, 0);
6735 #endif
6736                 }
6737         } else if (cmethod->klass->image == mono_defaults.corlib &&
6738                            (strcmp (cmethod->klass->name_space, "System.Reflection") == 0) &&
6739                            (strcmp (cmethod->klass->name, "Assembly") == 0)) {
6740                 if (cfg->llvm_only && !strcmp (cmethod->name, "GetExecutingAssembly")) {
6741                         /* No stack walks are currently available, so implement this as an intrinsic */
6742                         MonoInst *assembly_ins;
6743
6744                         EMIT_NEW_AOTCONST (cfg, assembly_ins, MONO_PATCH_INFO_IMAGE, cfg->method->klass->image);
6745                         ins = mono_emit_jit_icall (cfg, mono_get_assembly_object, &assembly_ins);
6746                         return ins;
6747                 }
6748         } else if (cmethod->klass->image == mono_defaults.corlib &&
6749                            (strcmp (cmethod->klass->name_space, "System.Reflection") == 0) &&
6750                            (strcmp (cmethod->klass->name, "MethodBase") == 0)) {
6751                 if (cfg->llvm_only && !strcmp (cmethod->name, "GetCurrentMethod")) {
6752                         /* No stack walks are currently available, so implement this as an intrinsic */
6753                         MonoInst *method_ins;
6754                         MonoMethod *declaring = cfg->method;
6755
6756                         /* This returns the declaring generic method */
6757                         if (declaring->is_inflated)
6758                                 declaring = ((MonoMethodInflated*)cfg->method)->declaring;
6759                         EMIT_NEW_AOTCONST (cfg, method_ins, MONO_PATCH_INFO_METHODCONST, declaring);
6760                         ins = mono_emit_jit_icall (cfg, mono_get_method_object, &method_ins);
6761                         cfg->no_inline = TRUE;
6762                         if (cfg->method != cfg->current_method)
6763                                 inline_failure (cfg, "MethodBase:GetCurrentMethod ()");
6764                         return ins;
6765                 }
6766         } else if (cmethod->klass == mono_defaults.math_class) {
6767                 /* 
6768                  * There is general branchless code for Min/Max, but it does not work for 
6769                  * all inputs:
6770                  * http://everything2.com/?node_id=1051618
6771                  */
6772         } else if (((!strcmp (cmethod->klass->image->assembly->aname.name, "MonoMac") ||
6773                     !strcmp (cmethod->klass->image->assembly->aname.name, "monotouch")) &&
6774                                 !strcmp (cmethod->klass->name_space, "XamCore.ObjCRuntime") &&
6775                                 !strcmp (cmethod->klass->name, "Selector")) ||
6776                            (!strcmp (cmethod->klass->image->assembly->aname.name, "Xamarin.iOS") &&
6777                                 !strcmp (cmethod->klass->name_space, "ObjCRuntime") &&
6778                                 !strcmp (cmethod->klass->name, "Selector"))
6779                            ) {
6780                 if (cfg->backend->have_objc_get_selector &&
6781                         !strcmp (cmethod->name, "GetHandle") && fsig->param_count == 1 &&
6782                     (args [0]->opcode == OP_GOT_ENTRY || args [0]->opcode == OP_AOTCONST) &&
6783                     cfg->compile_aot && !cfg->llvm_only) {
6784                         MonoInst *pi;
6785                         MonoJumpInfoToken *ji;
6786                         MonoString *s;
6787
6788                         // FIXME: llvmonly
6789
6790                         cfg->exception_message = g_strdup ("GetHandle");
6791                         cfg->disable_llvm = TRUE;
6792
6793                         if (args [0]->opcode == OP_GOT_ENTRY) {
6794                                 pi = (MonoInst *)args [0]->inst_p1;
6795                                 g_assert (pi->opcode == OP_PATCH_INFO);
6796                                 g_assert (GPOINTER_TO_INT (pi->inst_p1) == MONO_PATCH_INFO_LDSTR);
6797                                 ji = (MonoJumpInfoToken *)pi->inst_p0;
6798                         } else {
6799                                 g_assert (GPOINTER_TO_INT (args [0]->inst_p1) == MONO_PATCH_INFO_LDSTR);
6800                                 ji = (MonoJumpInfoToken *)args [0]->inst_p0;
6801                         }
6802
6803                         NULLIFY_INS (args [0]);
6804
6805                         // FIXME: Ugly
6806                         s = mono_ldstr (cfg->domain, ji->image, mono_metadata_token_index (ji->token));
6807                         MONO_INST_NEW (cfg, ins, OP_OBJC_GET_SELECTOR);
6808                         ins->dreg = mono_alloc_ireg (cfg);
6809                         // FIXME: Leaks
6810                         ins->inst_p0 = mono_string_to_utf8 (s);
6811                         MONO_ADD_INS (cfg->cbb, ins);
6812                         return ins;
6813                 }
6814         }
6815
6816 #ifdef MONO_ARCH_SIMD_INTRINSICS
6817         if (cfg->opt & MONO_OPT_SIMD) {
6818                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
6819                 if (ins)
6820                         return ins;
6821         }
6822 #endif
6823
6824         ins = mono_emit_native_types_intrinsics (cfg, cmethod, fsig, args);
6825         if (ins)
6826                 return ins;
6827
6828         if (COMPILE_LLVM (cfg)) {
6829                 ins = llvm_emit_inst_for_method (cfg, cmethod, fsig, args);
6830                 if (ins)
6831                         return ins;
6832         }
6833
6834         return mono_arch_emit_inst_for_method (cfg, cmethod, fsig, args);
6835 }
6836
6837 /*
6838  * This entry point could be used later for arbitrary method
6839  * redirection.
6840  */
6841 inline static MonoInst*
6842 mini_redirect_call (MonoCompile *cfg, MonoMethod *method,  
6843                                         MonoMethodSignature *signature, MonoInst **args, MonoInst *this_ins)
6844 {
6845         if (method->klass == mono_defaults.string_class) {
6846                 /* managed string allocation support */
6847                 if (strcmp (method->name, "InternalAllocateStr") == 0 && !(mono_profiler_events & MONO_PROFILE_ALLOCATIONS) && !(cfg->opt & MONO_OPT_SHARED)) {
6848                         MonoInst *iargs [2];
6849                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
6850                         MonoMethod *managed_alloc = NULL;
6851
6852                         g_assert (vtable); /*Should not fail since it System.String*/
6853 #ifndef MONO_CROSS_COMPILE
6854                         managed_alloc = mono_gc_get_managed_allocator (method->klass, FALSE, FALSE);
6855 #endif
6856                         if (!managed_alloc)
6857                                 return NULL;
6858                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
6859                         iargs [1] = args [0];
6860                         return mono_emit_method_call (cfg, managed_alloc, iargs, this_ins);
6861                 }
6862         }
6863         return NULL;
6864 }
6865
6866 static void
6867 mono_save_args (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **sp)
6868 {
6869         MonoInst *store, *temp;
6870         int i;
6871
6872         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
6873                 MonoType *argtype = (sig->hasthis && (i == 0)) ? type_from_stack_type (*sp) : sig->params [i - sig->hasthis];
6874
6875                 /*
6876                  * FIXME: We should use *args++ = sp [0], but that would mean the arg
6877                  * would be different than the MonoInst's used to represent arguments, and
6878                  * the ldelema implementation can't deal with that.
6879                  * Solution: When ldelema is used on an inline argument, create a var for 
6880                  * it, emit ldelema on that var, and emit the saving code below in
6881                  * inline_method () if needed.
6882                  */
6883                 temp = mono_compile_create_var (cfg, argtype, OP_LOCAL);
6884                 cfg->args [i] = temp;
6885                 /* This uses cfg->args [i] which is set by the preceeding line */
6886                 EMIT_NEW_ARGSTORE (cfg, store, i, *sp);
6887                 store->cil_code = sp [0]->cil_code;
6888                 sp++;
6889         }
6890 }
6891
6892 #define MONO_INLINE_CALLED_LIMITED_METHODS 1
6893 #define MONO_INLINE_CALLER_LIMITED_METHODS 1
6894
6895 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
6896 static gboolean
6897 check_inline_called_method_name_limit (MonoMethod *called_method)
6898 {
6899         int strncmp_result;
6900         static const char *limit = NULL;
6901         
6902         if (limit == NULL) {
6903                 const char *limit_string = g_getenv ("MONO_INLINE_CALLED_METHOD_NAME_LIMIT");
6904
6905                 if (limit_string != NULL)
6906                         limit = limit_string;
6907                 else
6908                         limit = "";
6909         }
6910
6911         if (limit [0] != '\0') {
6912                 char *called_method_name = mono_method_full_name (called_method, TRUE);
6913
6914                 strncmp_result = strncmp (called_method_name, limit, strlen (limit));
6915                 g_free (called_method_name);
6916         
6917                 //return (strncmp_result <= 0);
6918                 return (strncmp_result == 0);
6919         } else {
6920                 return TRUE;
6921         }
6922 }
6923 #endif
6924
6925 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
6926 static gboolean
6927 check_inline_caller_method_name_limit (MonoMethod *caller_method)
6928 {
6929         int strncmp_result;
6930         static const char *limit = NULL;
6931         
6932         if (limit == NULL) {
6933                 const char *limit_string = g_getenv ("MONO_INLINE_CALLER_METHOD_NAME_LIMIT");
6934                 if (limit_string != NULL) {
6935                         limit = limit_string;
6936                 } else {
6937                         limit = "";
6938                 }
6939         }
6940
6941         if (limit [0] != '\0') {
6942                 char *caller_method_name = mono_method_full_name (caller_method, TRUE);
6943
6944                 strncmp_result = strncmp (caller_method_name, limit, strlen (limit));
6945                 g_free (caller_method_name);
6946         
6947                 //return (strncmp_result <= 0);
6948                 return (strncmp_result == 0);
6949         } else {
6950                 return TRUE;
6951         }
6952 }
6953 #endif
6954
6955 static void
6956 emit_init_rvar (MonoCompile *cfg, int dreg, MonoType *rtype)
6957 {
6958         static double r8_0 = 0.0;
6959         static float r4_0 = 0.0;
6960         MonoInst *ins;
6961         int t;
6962
6963         rtype = mini_get_underlying_type (rtype);
6964         t = rtype->type;
6965
6966         if (rtype->byref) {
6967                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
6968         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
6969                 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
6970         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
6971                 MONO_EMIT_NEW_I8CONST (cfg, dreg, 0);
6972         } else if (cfg->r4fp && t == MONO_TYPE_R4) {
6973                 MONO_INST_NEW (cfg, ins, OP_R4CONST);
6974                 ins->type = STACK_R4;
6975                 ins->inst_p0 = (void*)&r4_0;
6976                 ins->dreg = dreg;
6977                 MONO_ADD_INS (cfg->cbb, ins);
6978         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
6979                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
6980                 ins->type = STACK_R8;
6981                 ins->inst_p0 = (void*)&r8_0;
6982                 ins->dreg = dreg;
6983                 MONO_ADD_INS (cfg->cbb, ins);
6984         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
6985                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (rtype))) {
6986                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (rtype));
6987         } else if (((t == MONO_TYPE_VAR) || (t == MONO_TYPE_MVAR)) && mini_type_var_is_vt (rtype)) {
6988                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (rtype));
6989         } else {
6990                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
6991         }
6992 }
6993
6994 static void
6995 emit_dummy_init_rvar (MonoCompile *cfg, int dreg, MonoType *rtype)
6996 {
6997         int t;
6998
6999         rtype = mini_get_underlying_type (rtype);
7000         t = rtype->type;
7001
7002         if (rtype->byref) {
7003                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_PCONST);
7004         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
7005                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_ICONST);
7006         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
7007                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_I8CONST);
7008         } else if (cfg->r4fp && t == MONO_TYPE_R4) {
7009                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_R4CONST);
7010         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
7011                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_R8CONST);
7012         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
7013                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (rtype))) {
7014                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_VZERO);
7015         } else if (((t == MONO_TYPE_VAR) || (t == MONO_TYPE_MVAR)) && mini_type_var_is_vt (rtype)) {
7016                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_VZERO);
7017         } else {
7018                 emit_init_rvar (cfg, dreg, rtype);
7019         }
7020 }
7021
7022 /* If INIT is FALSE, emit dummy initialization statements to keep the IR valid */
7023 static void
7024 emit_init_local (MonoCompile *cfg, int local, MonoType *type, gboolean init)
7025 {
7026         MonoInst *var = cfg->locals [local];
7027         if (COMPILE_SOFT_FLOAT (cfg)) {
7028                 MonoInst *store;
7029                 int reg = alloc_dreg (cfg, (MonoStackType)var->type);
7030                 emit_init_rvar (cfg, reg, type);
7031                 EMIT_NEW_LOCSTORE (cfg, store, local, cfg->cbb->last_ins);
7032         } else {
7033                 if (init)
7034                         emit_init_rvar (cfg, var->dreg, type);
7035                 else
7036                         emit_dummy_init_rvar (cfg, var->dreg, type);
7037         }
7038 }
7039
7040 /*
7041  * inline_method:
7042  *
7043  *   Return the cost of inlining CMETHOD.
7044  */
7045 static int
7046 inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp,
7047                            guchar *ip, guint real_offset, gboolean inline_always)
7048 {
7049         MonoInst *ins, *rvar = NULL;
7050         MonoMethodHeader *cheader;
7051         MonoBasicBlock *ebblock, *sbblock;
7052         int i, costs;
7053         MonoMethod *prev_inlined_method;
7054         MonoInst **prev_locals, **prev_args;
7055         MonoType **prev_arg_types;
7056         guint prev_real_offset;
7057         GHashTable *prev_cbb_hash;
7058         MonoBasicBlock **prev_cil_offset_to_bb;
7059         MonoBasicBlock *prev_cbb;
7060         unsigned char* prev_cil_start;
7061         guint32 prev_cil_offset_to_bb_len;
7062         MonoMethod *prev_current_method;
7063         MonoGenericContext *prev_generic_context;
7064         gboolean ret_var_set, prev_ret_var_set, prev_disable_inline, virtual_ = FALSE;
7065
7066         g_assert (cfg->exception_type == MONO_EXCEPTION_NONE);
7067
7068 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
7069         if ((! inline_always) && ! check_inline_called_method_name_limit (cmethod))
7070                 return 0;
7071 #endif
7072 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
7073         if ((! inline_always) && ! check_inline_caller_method_name_limit (cfg->method))
7074                 return 0;
7075 #endif
7076
7077         if (!fsig)
7078                 fsig = mono_method_signature (cmethod);
7079
7080         if (cfg->verbose_level > 2)
7081                 printf ("INLINE START %p %s -> %s\n", cmethod,  mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
7082
7083         if (!cmethod->inline_info) {
7084                 cfg->stat_inlineable_methods++;
7085                 cmethod->inline_info = 1;
7086         }
7087
7088         /* allocate local variables */
7089         cheader = mono_method_get_header (cmethod);
7090
7091         if (cheader == NULL || mono_loader_get_last_error ()) {
7092                 if (cheader)
7093                         mono_metadata_free_mh (cheader);
7094                 if (inline_always && mono_loader_get_last_error ()) {
7095                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
7096                         mono_error_set_from_loader_error (&cfg->error);
7097                 }
7098
7099                 mono_loader_clear_error ();
7100                 return 0;
7101         }
7102
7103         /*Must verify before creating locals as it can cause the JIT to assert.*/
7104         if (mono_compile_is_broken (cfg, cmethod, FALSE)) {
7105                 mono_metadata_free_mh (cheader);
7106                 return 0;
7107         }
7108
7109         /* allocate space to store the return value */
7110         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
7111                 rvar = mono_compile_create_var (cfg, fsig->ret, OP_LOCAL);
7112         }
7113
7114         prev_locals = cfg->locals;
7115         cfg->locals = (MonoInst **)mono_mempool_alloc0 (cfg->mempool, cheader->num_locals * sizeof (MonoInst*));
7116         for (i = 0; i < cheader->num_locals; ++i)
7117                 cfg->locals [i] = mono_compile_create_var (cfg, cheader->locals [i], OP_LOCAL);
7118
7119         /* allocate start and end blocks */
7120         /* This is needed so if the inline is aborted, we can clean up */
7121         NEW_BBLOCK (cfg, sbblock);
7122         sbblock->real_offset = real_offset;
7123
7124         NEW_BBLOCK (cfg, ebblock);
7125         ebblock->block_num = cfg->num_bblocks++;
7126         ebblock->real_offset = real_offset;
7127
7128         prev_args = cfg->args;
7129         prev_arg_types = cfg->arg_types;
7130         prev_inlined_method = cfg->inlined_method;
7131         cfg->inlined_method = cmethod;
7132         cfg->ret_var_set = FALSE;
7133         cfg->inline_depth ++;
7134         prev_real_offset = cfg->real_offset;
7135         prev_cbb_hash = cfg->cbb_hash;
7136         prev_cil_offset_to_bb = cfg->cil_offset_to_bb;
7137         prev_cil_offset_to_bb_len = cfg->cil_offset_to_bb_len;
7138         prev_cil_start = cfg->cil_start;
7139         prev_cbb = cfg->cbb;
7140         prev_current_method = cfg->current_method;
7141         prev_generic_context = cfg->generic_context;
7142         prev_ret_var_set = cfg->ret_var_set;
7143         prev_disable_inline = cfg->disable_inline;
7144
7145         if (ip && *ip == CEE_CALLVIRT && !(cmethod->flags & METHOD_ATTRIBUTE_STATIC))
7146                 virtual_ = TRUE;
7147
7148         costs = mono_method_to_ir (cfg, cmethod, sbblock, ebblock, rvar, sp, real_offset, virtual_);
7149
7150         ret_var_set = cfg->ret_var_set;
7151
7152         cfg->inlined_method = prev_inlined_method;
7153         cfg->real_offset = prev_real_offset;
7154         cfg->cbb_hash = prev_cbb_hash;
7155         cfg->cil_offset_to_bb = prev_cil_offset_to_bb;
7156         cfg->cil_offset_to_bb_len = prev_cil_offset_to_bb_len;
7157         cfg->cil_start = prev_cil_start;
7158         cfg->locals = prev_locals;
7159         cfg->args = prev_args;
7160         cfg->arg_types = prev_arg_types;
7161         cfg->current_method = prev_current_method;
7162         cfg->generic_context = prev_generic_context;
7163         cfg->ret_var_set = prev_ret_var_set;
7164         cfg->disable_inline = prev_disable_inline;
7165         cfg->inline_depth --;
7166
7167         if ((costs >= 0 && costs < 60) || inline_always || (costs >= 0 && (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING))) {
7168                 if (cfg->verbose_level > 2)
7169                         printf ("INLINE END %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
7170                 
7171                 cfg->stat_inlined_methods++;
7172
7173                 /* always add some code to avoid block split failures */
7174                 MONO_INST_NEW (cfg, ins, OP_NOP);
7175                 MONO_ADD_INS (prev_cbb, ins);
7176
7177                 prev_cbb->next_bb = sbblock;
7178                 link_bblock (cfg, prev_cbb, sbblock);
7179
7180                 /* 
7181                  * Get rid of the begin and end bblocks if possible to aid local
7182                  * optimizations.
7183                  */
7184                 mono_merge_basic_blocks (cfg, prev_cbb, sbblock);
7185
7186                 if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] != ebblock))
7187                         mono_merge_basic_blocks (cfg, prev_cbb, prev_cbb->out_bb [0]);
7188
7189                 if ((ebblock->in_count == 1) && ebblock->in_bb [0]->out_count == 1) {
7190                         MonoBasicBlock *prev = ebblock->in_bb [0];
7191
7192                         if (prev->next_bb == ebblock) {
7193                                 mono_merge_basic_blocks (cfg, prev, ebblock);
7194                                 cfg->cbb = prev;
7195                                 if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] == prev)) {
7196                                         mono_merge_basic_blocks (cfg, prev_cbb, prev);
7197                                         cfg->cbb = prev_cbb;
7198                                 }
7199                         } else {
7200                                 /* There could be a bblock after 'prev', and making 'prev' the current bb could cause problems */
7201                                 cfg->cbb = ebblock;
7202                         }
7203                 } else {
7204                         /* 
7205                          * Its possible that the rvar is set in some prev bblock, but not in others.
7206                          * (#1835).
7207                          */
7208                         if (rvar) {
7209                                 MonoBasicBlock *bb;
7210
7211                                 for (i = 0; i < ebblock->in_count; ++i) {
7212                                         bb = ebblock->in_bb [i];
7213
7214                                         if (bb->last_ins && bb->last_ins->opcode == OP_NOT_REACHED) {
7215                                                 cfg->cbb = bb;
7216
7217                                                 emit_init_rvar (cfg, rvar->dreg, fsig->ret);
7218                                         }
7219                                 }
7220                         }
7221
7222                         cfg->cbb = ebblock;
7223                 }
7224
7225                 if (rvar) {
7226                         /*
7227                          * If the inlined method contains only a throw, then the ret var is not 
7228                          * set, so set it to a dummy value.
7229                          */
7230                         if (!ret_var_set)
7231                                 emit_init_rvar (cfg, rvar->dreg, fsig->ret);
7232
7233                         EMIT_NEW_TEMPLOAD (cfg, ins, rvar->inst_c0);
7234                         *sp++ = ins;
7235                 }
7236                 cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
7237                 return costs + 1;
7238         } else {
7239                 if (cfg->verbose_level > 2)
7240                         printf ("INLINE ABORTED %s (cost %d)\n", mono_method_full_name (cmethod, TRUE), costs);
7241                 cfg->exception_type = MONO_EXCEPTION_NONE;
7242                 mono_loader_clear_error ();
7243
7244                 /* This gets rid of the newly added bblocks */
7245                 cfg->cbb = prev_cbb;
7246         }
7247         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
7248         return 0;
7249 }
7250
7251 /*
7252  * Some of these comments may well be out-of-date.
7253  * Design decisions: we do a single pass over the IL code (and we do bblock 
7254  * splitting/merging in the few cases when it's required: a back jump to an IL
7255  * address that was not already seen as bblock starting point).
7256  * Code is validated as we go (full verification is still better left to metadata/verify.c).
7257  * Complex operations are decomposed in simpler ones right away. We need to let the 
7258  * arch-specific code peek and poke inside this process somehow (except when the 
7259  * optimizations can take advantage of the full semantic info of coarse opcodes).
7260  * All the opcodes of the form opcode.s are 'normalized' to opcode.
7261  * MonoInst->opcode initially is the IL opcode or some simplification of that 
7262  * (OP_LOAD, OP_STORE). The arch-specific code may rearrange it to an arch-specific 
7263  * opcode with value bigger than OP_LAST.
7264  * At this point the IR can be handed over to an interpreter, a dumb code generator
7265  * or to the optimizing code generator that will translate it to SSA form.
7266  *
7267  * Profiling directed optimizations.
7268  * We may compile by default with few or no optimizations and instrument the code
7269  * or the user may indicate what methods to optimize the most either in a config file
7270  * or through repeated runs where the compiler applies offline the optimizations to 
7271  * each method and then decides if it was worth it.
7272  */
7273
7274 #define CHECK_TYPE(ins) if (!(ins)->type) UNVERIFIED
7275 #define CHECK_STACK(num) if ((sp - stack_start) < (num)) UNVERIFIED
7276 #define CHECK_STACK_OVF(num) if (((sp - stack_start) + (num)) > header->max_stack) UNVERIFIED
7277 #define CHECK_ARG(num) if ((unsigned)(num) >= (unsigned)num_args) UNVERIFIED
7278 #define CHECK_LOCAL(num) if ((unsigned)(num) >= (unsigned)header->num_locals) UNVERIFIED
7279 #define CHECK_OPSIZE(size) if (ip + size > end) UNVERIFIED
7280 #define CHECK_UNVERIFIABLE(cfg) if (cfg->unverifiable) UNVERIFIED
7281 #define CHECK_TYPELOAD(klass) if (!(klass) || (klass)->exception_type) TYPE_LOAD_ERROR ((klass))
7282
7283 /* offset from br.s -> br like opcodes */
7284 #define BIG_BRANCH_OFFSET 13
7285
7286 static gboolean
7287 ip_in_bb (MonoCompile *cfg, MonoBasicBlock *bb, const guint8* ip)
7288 {
7289         MonoBasicBlock *b = cfg->cil_offset_to_bb [ip - cfg->cil_start];
7290
7291         return b == NULL || b == bb;
7292 }
7293
7294 static int
7295 get_basic_blocks (MonoCompile *cfg, MonoMethodHeader* header, guint real_offset, unsigned char *start, unsigned char *end, unsigned char **pos)
7296 {
7297         unsigned char *ip = start;
7298         unsigned char *target;
7299         int i;
7300         guint cli_addr;
7301         MonoBasicBlock *bblock;
7302         const MonoOpcode *opcode;
7303
7304         while (ip < end) {
7305                 cli_addr = ip - start;
7306                 i = mono_opcode_value ((const guint8 **)&ip, end);
7307                 if (i < 0)
7308                         UNVERIFIED;
7309                 opcode = &mono_opcodes [i];
7310                 switch (opcode->argument) {
7311                 case MonoInlineNone:
7312                         ip++; 
7313                         break;
7314                 case MonoInlineString:
7315                 case MonoInlineType:
7316                 case MonoInlineField:
7317                 case MonoInlineMethod:
7318                 case MonoInlineTok:
7319                 case MonoInlineSig:
7320                 case MonoShortInlineR:
7321                 case MonoInlineI:
7322                         ip += 5;
7323                         break;
7324                 case MonoInlineVar:
7325                         ip += 3;
7326                         break;
7327                 case MonoShortInlineVar:
7328                 case MonoShortInlineI:
7329                         ip += 2;
7330                         break;
7331                 case MonoShortInlineBrTarget:
7332                         target = start + cli_addr + 2 + (signed char)ip [1];
7333                         GET_BBLOCK (cfg, bblock, target);
7334                         ip += 2;
7335                         if (ip < end)
7336                                 GET_BBLOCK (cfg, bblock, ip);
7337                         break;
7338                 case MonoInlineBrTarget:
7339                         target = start + cli_addr + 5 + (gint32)read32 (ip + 1);
7340                         GET_BBLOCK (cfg, bblock, target);
7341                         ip += 5;
7342                         if (ip < end)
7343                                 GET_BBLOCK (cfg, bblock, ip);
7344                         break;
7345                 case MonoInlineSwitch: {
7346                         guint32 n = read32 (ip + 1);
7347                         guint32 j;
7348                         ip += 5;
7349                         cli_addr += 5 + 4 * n;
7350                         target = start + cli_addr;
7351                         GET_BBLOCK (cfg, bblock, target);
7352                         
7353                         for (j = 0; j < n; ++j) {
7354                                 target = start + cli_addr + (gint32)read32 (ip);
7355                                 GET_BBLOCK (cfg, bblock, target);
7356                                 ip += 4;
7357                         }
7358                         break;
7359                 }
7360                 case MonoInlineR:
7361                 case MonoInlineI8:
7362                         ip += 9;
7363                         break;
7364                 default:
7365                         g_assert_not_reached ();
7366                 }
7367
7368                 if (i == CEE_THROW) {
7369                         unsigned char *bb_start = ip - 1;
7370                         
7371                         /* Find the start of the bblock containing the throw */
7372                         bblock = NULL;
7373                         while ((bb_start >= start) && !bblock) {
7374                                 bblock = cfg->cil_offset_to_bb [(bb_start) - start];
7375                                 bb_start --;
7376                         }
7377                         if (bblock)
7378                                 bblock->out_of_line = 1;
7379                 }
7380         }
7381         return 0;
7382 unverified:
7383 exception_exit:
7384         *pos = ip;
7385         return 1;
7386 }
7387
7388 static inline MonoMethod *
7389 mini_get_method_allow_open (MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context, MonoError *error)
7390 {
7391         MonoMethod *method;
7392
7393         mono_error_init (error);
7394
7395         if (m->wrapper_type != MONO_WRAPPER_NONE) {
7396                 method = (MonoMethod *)mono_method_get_wrapper_data (m, token);
7397                 if (context) {
7398                         method = mono_class_inflate_generic_method_checked (method, context, error);
7399                 }
7400         } else {
7401                 method = mono_get_method_checked (m->klass->image, token, klass, context, error);
7402         }
7403
7404         return method;
7405 }
7406
7407 static inline MonoMethod *
7408 mini_get_method (MonoCompile *cfg, MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
7409 {
7410         MonoError error;
7411         MonoMethod *method = mini_get_method_allow_open (m, token, klass, context, cfg ? &cfg->error : &error);
7412
7413         if (method && cfg && !cfg->gshared && mono_class_is_open_constructed_type (&method->klass->byval_arg)) {
7414                 mono_error_set_bad_image (&cfg->error, cfg->method->klass->image, "Method with open type while not compiling gshared");
7415                 method = NULL;
7416         }
7417
7418         if (!method && !cfg)
7419                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
7420
7421         return method;
7422 }
7423
7424 static inline MonoClass*
7425 mini_get_class (MonoMethod *method, guint32 token, MonoGenericContext *context)
7426 {
7427         MonoError error;
7428         MonoClass *klass;
7429
7430         if (method->wrapper_type != MONO_WRAPPER_NONE) {
7431                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
7432                 if (context)
7433                         klass = mono_class_inflate_generic_class (klass, context);
7434         } else {
7435                 klass = mono_class_get_and_inflate_typespec_checked (method->klass->image, token, context, &error);
7436                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
7437         }
7438         if (klass)
7439                 mono_class_init (klass);
7440         return klass;
7441 }
7442
7443 static inline MonoMethodSignature*
7444 mini_get_signature (MonoMethod *method, guint32 token, MonoGenericContext *context)
7445 {
7446         MonoMethodSignature *fsig;
7447
7448         if (method->wrapper_type != MONO_WRAPPER_NONE) {
7449                 fsig = (MonoMethodSignature *)mono_method_get_wrapper_data (method, token);
7450         } else {
7451                 fsig = mono_metadata_parse_signature (method->klass->image, token);
7452         }
7453         if (context) {
7454                 MonoError error;
7455                 fsig = mono_inflate_generic_signature(fsig, context, &error);
7456                 // FIXME:
7457                 g_assert(mono_error_ok(&error));
7458         }
7459         return fsig;
7460 }
7461
7462 static MonoMethod*
7463 throw_exception (void)
7464 {
7465         static MonoMethod *method = NULL;
7466
7467         if (!method) {
7468                 MonoSecurityManager *secman = mono_security_manager_get_methods ();
7469                 method = mono_class_get_method_from_name (secman->securitymanager, "ThrowException", 1);
7470         }
7471         g_assert (method);
7472         return method;
7473 }
7474
7475 static void
7476 emit_throw_exception (MonoCompile *cfg, MonoException *ex)
7477 {
7478         MonoMethod *thrower = throw_exception ();
7479         MonoInst *args [1];
7480
7481         EMIT_NEW_PCONST (cfg, args [0], ex);
7482         mono_emit_method_call (cfg, thrower, args, NULL);
7483 }
7484
7485 /*
7486  * Return the original method is a wrapper is specified. We can only access 
7487  * the custom attributes from the original method.
7488  */
7489 static MonoMethod*
7490 get_original_method (MonoMethod *method)
7491 {
7492         if (method->wrapper_type == MONO_WRAPPER_NONE)
7493                 return method;
7494
7495         /* native code (which is like Critical) can call any managed method XXX FIXME XXX to validate all usages */
7496         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED)
7497                 return NULL;
7498
7499         /* in other cases we need to find the original method */
7500         return mono_marshal_method_from_wrapper (method);
7501 }
7502
7503 static void
7504 ensure_method_is_allowed_to_access_field (MonoCompile *cfg, MonoMethod *caller, MonoClassField *field)
7505 {
7506         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
7507         MonoException *ex = mono_security_core_clr_is_field_access_allowed (get_original_method (caller), field);
7508         if (ex)
7509                 emit_throw_exception (cfg, ex);
7510 }
7511
7512 static void
7513 ensure_method_is_allowed_to_call_method (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee)
7514 {
7515         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
7516         MonoException *ex = mono_security_core_clr_is_call_allowed (get_original_method (caller), callee);
7517         if (ex)
7518                 emit_throw_exception (cfg, ex);
7519 }
7520
7521 /*
7522  * Check that the IL instructions at ip are the array initialization
7523  * sequence and return the pointer to the data and the size.
7524  */
7525 static const char*
7526 initialize_array_data (MonoMethod *method, gboolean aot, unsigned char *ip, MonoClass *klass, guint32 len, int *out_size, guint32 *out_field_token)
7527 {
7528         /*
7529          * newarr[System.Int32]
7530          * dup
7531          * ldtoken field valuetype ...
7532          * call void class [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype [mscorlib]System.RuntimeFieldHandle)
7533          */
7534         if (ip [0] == CEE_DUP && ip [1] == CEE_LDTOKEN && ip [5] == 0x4 && ip [6] == CEE_CALL) {
7535                 MonoError error;
7536                 guint32 token = read32 (ip + 7);
7537                 guint32 field_token = read32 (ip + 2);
7538                 guint32 field_index = field_token & 0xffffff;
7539                 guint32 rva;
7540                 const char *data_ptr;
7541                 int size = 0;
7542                 MonoMethod *cmethod;
7543                 MonoClass *dummy_class;
7544                 MonoClassField *field = mono_field_from_token_checked (method->klass->image, field_token, &dummy_class, NULL, &error);
7545                 int dummy_align;
7546
7547                 if (!field) {
7548                         mono_error_cleanup (&error); /* FIXME don't swallow the error */
7549                         return NULL;
7550                 }
7551
7552                 *out_field_token = field_token;
7553
7554                 cmethod = mini_get_method (NULL, method, token, NULL, NULL);
7555                 if (!cmethod)
7556                         return NULL;
7557                 if (strcmp (cmethod->name, "InitializeArray") || strcmp (cmethod->klass->name, "RuntimeHelpers") || cmethod->klass->image != mono_defaults.corlib)
7558                         return NULL;
7559                 switch (mono_type_get_underlying_type (&klass->byval_arg)->type) {
7560                 case MONO_TYPE_BOOLEAN:
7561                 case MONO_TYPE_I1:
7562                 case MONO_TYPE_U1:
7563                         size = 1; break;
7564                 /* we need to swap on big endian, so punt. Should we handle R4 and R8 as well? */
7565 #if TARGET_BYTE_ORDER == G_LITTLE_ENDIAN
7566                 case MONO_TYPE_CHAR:
7567                 case MONO_TYPE_I2:
7568                 case MONO_TYPE_U2:
7569                         size = 2; break;
7570                 case MONO_TYPE_I4:
7571                 case MONO_TYPE_U4:
7572                 case MONO_TYPE_R4:
7573                         size = 4; break;
7574                 case MONO_TYPE_R8:
7575                 case MONO_TYPE_I8:
7576                 case MONO_TYPE_U8:
7577                         size = 8; break;
7578 #endif
7579                 default:
7580                         return NULL;
7581                 }
7582                 size *= len;
7583                 if (size > mono_type_size (field->type, &dummy_align))
7584                     return NULL;
7585                 *out_size = size;
7586                 /*g_print ("optimized in %s: size: %d, numelems: %d\n", method->name, size, newarr->inst_newa_len->inst_c0);*/
7587                 if (!image_is_dynamic (method->klass->image)) {
7588                         field_index = read32 (ip + 2) & 0xffffff;
7589                         mono_metadata_field_info (method->klass->image, field_index - 1, NULL, &rva, NULL);
7590                         data_ptr = mono_image_rva_map (method->klass->image, rva);
7591                         /*g_print ("field: 0x%08x, rva: %d, rva_ptr: %p\n", read32 (ip + 2), rva, data_ptr);*/
7592                         /* for aot code we do the lookup on load */
7593                         if (aot && data_ptr)
7594                                 return (const char *)GUINT_TO_POINTER (rva);
7595                 } else {
7596                         /*FIXME is it possible to AOT a SRE assembly not meant to be saved? */ 
7597                         g_assert (!aot);
7598                         data_ptr = mono_field_get_data (field);
7599                 }
7600                 return data_ptr;
7601         }
7602         return NULL;
7603 }
7604
7605 static void
7606 set_exception_type_from_invalid_il (MonoCompile *cfg, MonoMethod *method, unsigned char *ip)
7607 {
7608         char *method_fname = mono_method_full_name (method, TRUE);
7609         char *method_code;
7610         MonoMethodHeader *header = mono_method_get_header (method);
7611
7612         if (header->code_size == 0)
7613                 method_code = g_strdup ("method body is empty.");
7614         else
7615                 method_code = mono_disasm_code_one (NULL, method, ip, NULL);
7616         mono_cfg_set_exception_invalid_program (cfg, g_strdup_printf ("Invalid IL code in %s: %s\n", method_fname, method_code));
7617         g_free (method_fname);
7618         g_free (method_code);
7619         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
7620 }
7621
7622 static void
7623 emit_stloc_ir (MonoCompile *cfg, MonoInst **sp, MonoMethodHeader *header, int n)
7624 {
7625         MonoInst *ins;
7626         guint32 opcode = mono_type_to_regmove (cfg, header->locals [n]);
7627         if ((opcode == OP_MOVE) && cfg->cbb->last_ins == sp [0]  &&
7628                         ((sp [0]->opcode == OP_ICONST) || (sp [0]->opcode == OP_I8CONST))) {
7629                 /* Optimize reg-reg moves away */
7630                 /* 
7631                  * Can't optimize other opcodes, since sp[0] might point to
7632                  * the last ins of a decomposed opcode.
7633                  */
7634                 sp [0]->dreg = (cfg)->locals [n]->dreg;
7635         } else {
7636                 EMIT_NEW_LOCSTORE (cfg, ins, n, *sp);
7637         }
7638 }
7639
7640 /*
7641  * ldloca inhibits many optimizations so try to get rid of it in common
7642  * cases.
7643  */
7644 static inline unsigned char *
7645 emit_optimized_ldloca_ir (MonoCompile *cfg, unsigned char *ip, unsigned char *end, int size)
7646 {
7647         int local, token;
7648         MonoClass *klass;
7649         MonoType *type;
7650
7651         if (size == 1) {
7652                 local = ip [1];
7653                 ip += 2;
7654         } else {
7655                 local = read16 (ip + 2);
7656                 ip += 4;
7657         }
7658         
7659         if (ip + 6 < end && (ip [0] == CEE_PREFIX1) && (ip [1] == CEE_INITOBJ) && ip_in_bb (cfg, cfg->cbb, ip + 1)) {
7660                 /* From the INITOBJ case */
7661                 token = read32 (ip + 2);
7662                 klass = mini_get_class (cfg->current_method, token, cfg->generic_context);
7663                 CHECK_TYPELOAD (klass);
7664                 type = mini_get_underlying_type (&klass->byval_arg);
7665                 emit_init_local (cfg, local, type, TRUE);
7666                 return ip + 6;
7667         }
7668  exception_exit:
7669         return NULL;
7670 }
7671
7672 static MonoInst*
7673 emit_llvmonly_virtual_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, int context_used, MonoInst **sp)
7674 {
7675         MonoInst *icall_args [16];
7676         MonoInst *call_target, *ins, *vtable_ins;
7677         int arg_reg, this_reg, vtable_reg;
7678         gboolean is_iface = cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE;
7679         gboolean is_gsharedvt = cfg->gsharedvt && mini_is_gsharedvt_variable_signature (fsig);
7680         gboolean variant_iface = FALSE;
7681         guint32 slot;
7682         int offset;
7683
7684         /*
7685          * In llvm-only mode, vtables contain function descriptors instead of
7686          * method addresses/trampolines.
7687          */
7688         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
7689
7690         if (is_iface)
7691                 slot = mono_method_get_imt_slot (cmethod);
7692         else
7693                 slot = mono_method_get_vtable_index (cmethod);
7694
7695         this_reg = sp [0]->dreg;
7696
7697         if (is_iface && mono_class_has_variant_generic_params (cmethod->klass))
7698                 variant_iface = TRUE;
7699
7700         if (!fsig->generic_param_count && !is_iface && !is_gsharedvt) {
7701                 /*
7702                  * The simplest case, a normal virtual call.
7703                  */
7704                 int slot_reg = alloc_preg (cfg);
7705                 int addr_reg = alloc_preg (cfg);
7706                 int arg_reg = alloc_preg (cfg);
7707                 MonoBasicBlock *non_null_bb;
7708
7709                 vtable_reg = alloc_preg (cfg);
7710                 EMIT_NEW_LOAD_MEMBASE (cfg, vtable_ins, OP_LOAD_MEMBASE, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
7711                 offset = MONO_STRUCT_OFFSET (MonoVTable, vtable) + (slot * SIZEOF_VOID_P);
7712
7713                 /* Load the vtable slot, which contains a function descriptor. */
7714                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, slot_reg, vtable_reg, offset);
7715
7716                 NEW_BBLOCK (cfg, non_null_bb);
7717
7718                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, slot_reg, 0);
7719                 cfg->cbb->last_ins->flags |= MONO_INST_LIKELY;
7720                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, non_null_bb);
7721
7722                 /* Slow path */
7723                 // FIXME: Make the wrapper use the preserveall cconv
7724                 // FIXME: Use one icall per slot for small slot numbers ?
7725                 icall_args [0] = vtable_ins;
7726                 EMIT_NEW_ICONST (cfg, icall_args [1], slot);
7727                 /* Make the icall return the vtable slot value to save some code space */
7728                 ins = mono_emit_jit_icall (cfg, mono_init_vtable_slot, icall_args);
7729                 ins->dreg = slot_reg;
7730                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, non_null_bb);
7731
7732                 /* Fastpath */
7733                 MONO_START_BB (cfg, non_null_bb);
7734                 /* Load the address + arg from the vtable slot */
7735                 EMIT_NEW_LOAD_MEMBASE (cfg, call_target, OP_LOAD_MEMBASE, addr_reg, slot_reg, 0);
7736                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, arg_reg, slot_reg, SIZEOF_VOID_P);
7737
7738                 return emit_extra_arg_calli (cfg, fsig, sp, arg_reg, call_target);
7739         }
7740
7741         if (!fsig->generic_param_count && is_iface && !variant_iface && !is_gsharedvt) {
7742                 /*
7743                  * A simple interface call
7744                  *
7745                  * We make a call through an imt slot to obtain the function descriptor we need to call.
7746                  * The imt slot contains a function descriptor for a runtime function + arg.
7747                  */
7748                 int slot_reg = alloc_preg (cfg);
7749                 int addr_reg = alloc_preg (cfg);
7750                 int arg_reg = alloc_preg (cfg);
7751                 MonoInst *thunk_addr_ins, *thunk_arg_ins, *ftndesc_ins;
7752
7753                 vtable_reg = alloc_preg (cfg);
7754                 EMIT_NEW_LOAD_MEMBASE (cfg, vtable_ins, OP_LOAD_MEMBASE, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
7755                 offset = ((gint32)slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
7756
7757                 /*
7758                  * The slot is already initialized when the vtable is created so there is no need
7759                  * to check it here.
7760                  */
7761
7762                 /* Load the imt slot, which contains a function descriptor. */
7763                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, slot_reg, vtable_reg, offset);
7764
7765                 /* Load the address + arg of the imt thunk from the imt slot */
7766                 EMIT_NEW_LOAD_MEMBASE (cfg, thunk_addr_ins, OP_LOAD_MEMBASE, addr_reg, slot_reg, 0);
7767                 EMIT_NEW_LOAD_MEMBASE (cfg, thunk_arg_ins, OP_LOAD_MEMBASE, arg_reg, slot_reg, SIZEOF_VOID_P);
7768                 /*
7769                  * IMT thunks in llvm-only mode are C functions which take an info argument
7770                  * plus the imt method and return the ftndesc to call.
7771                  */
7772                 icall_args [0] = thunk_arg_ins;
7773                 icall_args [1] = emit_get_rgctx_method (cfg, context_used,
7774                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD);
7775                 ftndesc_ins = mono_emit_calli (cfg, helper_sig_llvmonly_imt_thunk, icall_args, thunk_addr_ins, NULL, NULL);
7776
7777                 return emit_llvmonly_calli (cfg, fsig, sp, ftndesc_ins);
7778         }
7779
7780         if ((fsig->generic_param_count || variant_iface) && !is_gsharedvt) {
7781                 /*
7782                  * This is similar to the interface case, the vtable slot points to an imt thunk which is
7783                  * dynamically extended as more instantiations are discovered.
7784                  * This handles generic virtual methods both on classes and interfaces.
7785                  */
7786                 int slot_reg = alloc_preg (cfg);
7787                 int addr_reg = alloc_preg (cfg);
7788                 int arg_reg = alloc_preg (cfg);
7789                 int ftndesc_reg = alloc_preg (cfg);
7790                 MonoInst *thunk_addr_ins, *thunk_arg_ins, *ftndesc_ins;
7791                 MonoBasicBlock *slowpath_bb, *end_bb;
7792
7793                 NEW_BBLOCK (cfg, slowpath_bb);
7794                 NEW_BBLOCK (cfg, end_bb);
7795
7796                 vtable_reg = alloc_preg (cfg);
7797                 EMIT_NEW_LOAD_MEMBASE (cfg, vtable_ins, OP_LOAD_MEMBASE, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
7798                 if (is_iface)
7799                         offset = ((gint32)slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
7800                 else
7801                         offset = MONO_STRUCT_OFFSET (MonoVTable, vtable) + (slot * SIZEOF_VOID_P);
7802
7803                 /* Load the slot, which contains a function descriptor. */
7804                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, slot_reg, vtable_reg, offset);
7805
7806                 /* These slots are not initialized, so fall back to the slow path until they are initialized */
7807                 /* That happens when mono_method_add_generic_virtual_invocation () creates an IMT thunk */
7808                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, slot_reg, 0);
7809                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, slowpath_bb);
7810
7811                 /* Fastpath */
7812                 /* Same as with iface calls */
7813                 EMIT_NEW_LOAD_MEMBASE (cfg, thunk_addr_ins, OP_LOAD_MEMBASE, addr_reg, slot_reg, 0);
7814                 EMIT_NEW_LOAD_MEMBASE (cfg, thunk_arg_ins, OP_LOAD_MEMBASE, arg_reg, slot_reg, SIZEOF_VOID_P);
7815                 icall_args [0] = thunk_arg_ins;
7816                 icall_args [1] = emit_get_rgctx_method (cfg, context_used,
7817                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD);
7818                 ftndesc_ins = mono_emit_calli (cfg, helper_sig_llvmonly_imt_thunk, icall_args, thunk_addr_ins, NULL, NULL);
7819                 ftndesc_ins->dreg = ftndesc_reg;
7820                 /*
7821                  * Unlike normal iface calls, these imt thunks can return NULL, i.e. when they are passed an instantiation
7822                  * they don't know about yet. Fall back to the slowpath in that case.
7823                  */
7824                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, ftndesc_reg, 0);
7825                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, slowpath_bb);
7826
7827                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
7828
7829                 /* Slowpath */
7830                 MONO_START_BB (cfg, slowpath_bb);
7831                 icall_args [0] = vtable_ins;
7832                 EMIT_NEW_ICONST (cfg, icall_args [1], slot);
7833                 icall_args [2] = emit_get_rgctx_method (cfg, context_used,
7834                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD);
7835                 if (is_iface)
7836                         ftndesc_ins = mono_emit_jit_icall (cfg, mono_resolve_generic_virtual_iface_call, icall_args);
7837                 else
7838                         ftndesc_ins = mono_emit_jit_icall (cfg, mono_resolve_generic_virtual_call, icall_args);
7839                 ftndesc_ins->dreg = ftndesc_reg;
7840                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
7841
7842                 /* Common case */
7843                 MONO_START_BB (cfg, end_bb);
7844                 return emit_llvmonly_calli (cfg, fsig, sp, ftndesc_ins);
7845         }
7846
7847         /*
7848          * Non-optimized cases
7849          */
7850         icall_args [0] = sp [0];
7851         EMIT_NEW_ICONST (cfg, icall_args [1], slot);
7852
7853         icall_args [2] = emit_get_rgctx_method (cfg, context_used,
7854                                                                                         cmethod, MONO_RGCTX_INFO_METHOD);
7855
7856         arg_reg = alloc_preg (cfg);
7857         MONO_EMIT_NEW_PCONST (cfg, arg_reg, NULL);
7858         EMIT_NEW_VARLOADA_VREG (cfg, icall_args [3], arg_reg, &mono_defaults.int_class->byval_arg);
7859
7860         g_assert (is_gsharedvt);
7861         if (is_iface)
7862                 call_target = mono_emit_jit_icall (cfg, mono_resolve_iface_call_gsharedvt, icall_args);
7863         else
7864                 call_target = mono_emit_jit_icall (cfg, mono_resolve_vcall_gsharedvt, icall_args);
7865
7866         /*
7867          * Pass the extra argument even if the callee doesn't receive it, most
7868          * calling conventions allow this.
7869          */
7870         return emit_extra_arg_calli (cfg, fsig, sp, arg_reg, call_target);
7871 }
7872
7873 static gboolean
7874 is_exception_class (MonoClass *klass)
7875 {
7876         while (klass) {
7877                 if (klass == mono_defaults.exception_class)
7878                         return TRUE;
7879                 klass = klass->parent;
7880         }
7881         return FALSE;
7882 }
7883
7884 /*
7885  * is_jit_optimizer_disabled:
7886  *
7887  *   Determine whenever M's assembly has a DebuggableAttribute with the
7888  * IsJITOptimizerDisabled flag set.
7889  */
7890 static gboolean
7891 is_jit_optimizer_disabled (MonoMethod *m)
7892 {
7893         MonoAssembly *ass = m->klass->image->assembly;
7894         MonoCustomAttrInfo* attrs;
7895         static MonoClass *klass;
7896         int i;
7897         gboolean val = FALSE;
7898
7899         g_assert (ass);
7900         if (ass->jit_optimizer_disabled_inited)
7901                 return ass->jit_optimizer_disabled;
7902
7903         if (!klass)
7904                 klass = mono_class_from_name (mono_defaults.corlib, "System.Diagnostics", "DebuggableAttribute");
7905         if (!klass) {
7906                 /* Linked away */
7907                 ass->jit_optimizer_disabled = FALSE;
7908                 mono_memory_barrier ();
7909                 ass->jit_optimizer_disabled_inited = TRUE;
7910                 return FALSE;
7911         }
7912
7913         attrs = mono_custom_attrs_from_assembly (ass);
7914         if (attrs) {
7915                 for (i = 0; i < attrs->num_attrs; ++i) {
7916                         MonoCustomAttrEntry *attr = &attrs->attrs [i];
7917                         const gchar *p;
7918                         MonoMethodSignature *sig;
7919
7920                         if (!attr->ctor || attr->ctor->klass != klass)
7921                                 continue;
7922                         /* Decode the attribute. See reflection.c */
7923                         p = (const char*)attr->data;
7924                         g_assert (read16 (p) == 0x0001);
7925                         p += 2;
7926
7927                         // FIXME: Support named parameters
7928                         sig = mono_method_signature (attr->ctor);
7929                         if (sig->param_count != 2 || sig->params [0]->type != MONO_TYPE_BOOLEAN || sig->params [1]->type != MONO_TYPE_BOOLEAN)
7930                                 continue;
7931                         /* Two boolean arguments */
7932                         p ++;
7933                         val = *p;
7934                 }
7935                 mono_custom_attrs_free (attrs);
7936         }
7937
7938         ass->jit_optimizer_disabled = val;
7939         mono_memory_barrier ();
7940         ass->jit_optimizer_disabled_inited = TRUE;
7941
7942         return val;
7943 }
7944
7945 static gboolean
7946 is_supported_tail_call (MonoCompile *cfg, MonoMethod *method, MonoMethod *cmethod, MonoMethodSignature *fsig, int call_opcode)
7947 {
7948         gboolean supported_tail_call;
7949         int i;
7950
7951         supported_tail_call = mono_arch_tail_call_supported (cfg, mono_method_signature (method), mono_method_signature (cmethod));
7952
7953         for (i = 0; i < fsig->param_count; ++i) {
7954                 if (fsig->params [i]->byref || fsig->params [i]->type == MONO_TYPE_PTR || fsig->params [i]->type == MONO_TYPE_FNPTR)
7955                         /* These can point to the current method's stack */
7956                         supported_tail_call = FALSE;
7957         }
7958         if (fsig->hasthis && cmethod->klass->valuetype)
7959                 /* this might point to the current method's stack */
7960                 supported_tail_call = FALSE;
7961         if (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
7962                 supported_tail_call = FALSE;
7963         if (cfg->method->save_lmf)
7964                 supported_tail_call = FALSE;
7965         if (cmethod->wrapper_type && cmethod->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD)
7966                 supported_tail_call = FALSE;
7967         if (call_opcode != CEE_CALL)
7968                 supported_tail_call = FALSE;
7969
7970         /* Debugging support */
7971 #if 0
7972         if (supported_tail_call) {
7973                 if (!mono_debug_count ())
7974                         supported_tail_call = FALSE;
7975         }
7976 #endif
7977
7978         return supported_tail_call;
7979 }
7980
7981 /*
7982  * handle_ctor_call:
7983  *
7984  *   Handle calls made to ctors from NEWOBJ opcodes.
7985  */
7986 static void
7987 handle_ctor_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, int context_used,
7988                                   MonoInst **sp, guint8 *ip, int *inline_costs)
7989 {
7990         MonoInst *vtable_arg = NULL, *callvirt_this_arg = NULL, *ins;
7991
7992         if (cmethod->klass->valuetype && mono_class_generic_sharing_enabled (cmethod->klass) &&
7993                                         mono_method_is_generic_sharable (cmethod, TRUE)) {
7994                 if (cmethod->is_inflated && mono_method_get_context (cmethod)->method_inst) {
7995                         mono_class_vtable (cfg->domain, cmethod->klass);
7996                         CHECK_TYPELOAD (cmethod->klass);
7997
7998                         vtable_arg = emit_get_rgctx_method (cfg, context_used,
7999                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
8000                 } else {
8001                         if (context_used) {
8002                                 vtable_arg = emit_get_rgctx_klass (cfg, context_used,
8003                                                                                                    cmethod->klass, MONO_RGCTX_INFO_VTABLE);
8004                         } else {
8005                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
8006
8007                                 CHECK_TYPELOAD (cmethod->klass);
8008                                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
8009                         }
8010                 }
8011         }
8012
8013         /* Avoid virtual calls to ctors if possible */
8014         if (mono_class_is_marshalbyref (cmethod->klass))
8015                 callvirt_this_arg = sp [0];
8016
8017         if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_ctor (cfg, cmethod, fsig, sp))) {
8018                 g_assert (MONO_TYPE_IS_VOID (fsig->ret));
8019                 CHECK_CFG_EXCEPTION;
8020         } else if ((cfg->opt & MONO_OPT_INLINE) && cmethod && !context_used && !vtable_arg &&
8021                            mono_method_check_inlining (cfg, cmethod) &&
8022                            !mono_class_is_subclass_of (cmethod->klass, mono_defaults.exception_class, FALSE)) {
8023                 int costs;
8024
8025                 if ((costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, FALSE))) {
8026                         cfg->real_offset += 5;
8027
8028                         *inline_costs += costs - 5;
8029                 } else {
8030                         INLINE_FAILURE ("inline failure");
8031                         // FIXME-VT: Clean this up
8032                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig))
8033                                 GSHAREDVT_FAILURE(*ip);
8034                         mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, callvirt_this_arg, NULL, NULL);
8035                 }
8036         } else if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) {
8037                 MonoInst *addr;
8038
8039                 addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE);
8040
8041                 if (cfg->llvm_only) {
8042                         // FIXME: Avoid initializing vtable_arg
8043                         emit_llvmonly_calli (cfg, fsig, sp, addr);
8044                 } else {
8045                         mono_emit_calli (cfg, fsig, sp, addr, NULL, vtable_arg);
8046                 }
8047         } else if (context_used &&
8048                            ((!mono_method_is_generic_sharable_full (cmethod, TRUE, FALSE, FALSE) ||
8049                                  !mono_class_generic_sharing_enabled (cmethod->klass)) || cfg->gsharedvt)) {
8050                 MonoInst *cmethod_addr;
8051
8052                 /* Generic calls made out of gsharedvt methods cannot be patched, so use an indirect call */
8053
8054                 if (cfg->llvm_only) {
8055                         MonoInst *addr = emit_get_rgctx_method (cfg, context_used, cmethod,
8056                                                                                                         MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
8057                         emit_llvmonly_calli (cfg, fsig, sp, addr);
8058                 } else {
8059                         cmethod_addr = emit_get_rgctx_method (cfg, context_used,
8060                                                                                                   cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
8061
8062                         mono_emit_calli (cfg, fsig, sp, cmethod_addr, NULL, vtable_arg);
8063                 }
8064         } else {
8065                 INLINE_FAILURE ("ctor call");
8066                 ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp,
8067                                                                                   callvirt_this_arg, NULL, vtable_arg);
8068         }
8069  exception_exit:
8070         return;
8071 }
8072
8073 static void
8074 emit_setret (MonoCompile *cfg, MonoInst *val)
8075 {
8076         MonoType *ret_type = mini_get_underlying_type (mono_method_signature (cfg->method)->ret);
8077         MonoInst *ins;
8078
8079         if (mini_type_to_stind (cfg, ret_type) == CEE_STOBJ) {
8080                 MonoInst *ret_addr;
8081
8082                 if (!cfg->vret_addr) {
8083                         EMIT_NEW_VARSTORE (cfg, ins, cfg->ret, ret_type, val);
8084                 } else {
8085                         EMIT_NEW_RETLOADA (cfg, ret_addr);
8086
8087                         EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STOREV_MEMBASE, ret_addr->dreg, 0, val->dreg);
8088                         ins->klass = mono_class_from_mono_type (ret_type);
8089                 }
8090         } else {
8091 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
8092                 if (COMPILE_SOFT_FLOAT (cfg) && !ret_type->byref && ret_type->type == MONO_TYPE_R4) {
8093                         MonoInst *iargs [1];
8094                         MonoInst *conv;
8095
8096                         iargs [0] = val;
8097                         conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
8098                         mono_arch_emit_setret (cfg, cfg->method, conv);
8099                 } else {
8100                         mono_arch_emit_setret (cfg, cfg->method, val);
8101                 }
8102 #else
8103                 mono_arch_emit_setret (cfg, cfg->method, val);
8104 #endif
8105         }
8106 }
8107
8108 /*
8109  * mono_method_to_ir:
8110  *
8111  *   Translate the .net IL into linear IR.
8112  */
8113 int
8114 mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock, 
8115                    MonoInst *return_var, MonoInst **inline_args, 
8116                    guint inline_offset, gboolean is_virtual_call)
8117 {
8118         MonoError error;
8119         MonoInst *ins, **sp, **stack_start;
8120         MonoBasicBlock *tblock = NULL, *init_localsbb = NULL;
8121         MonoSimpleBasicBlock *bb = NULL, *original_bb = NULL;
8122         MonoMethod *cmethod, *method_definition;
8123         MonoInst **arg_array;
8124         MonoMethodHeader *header;
8125         MonoImage *image;
8126         guint32 token, ins_flag;
8127         MonoClass *klass;
8128         MonoClass *constrained_class = NULL;
8129         unsigned char *ip, *end, *target, *err_pos;
8130         MonoMethodSignature *sig;
8131         MonoGenericContext *generic_context = NULL;
8132         MonoGenericContainer *generic_container = NULL;
8133         MonoType **param_types;
8134         int i, n, start_new_bblock, dreg;
8135         int num_calls = 0, inline_costs = 0;
8136         int breakpoint_id = 0;
8137         guint num_args;
8138         GSList *class_inits = NULL;
8139         gboolean dont_verify, dont_verify_stloc, readonly = FALSE;
8140         int context_used;
8141         gboolean init_locals, seq_points, skip_dead_blocks;
8142         gboolean sym_seq_points = FALSE;
8143         MonoDebugMethodInfo *minfo;
8144         MonoBitSet *seq_point_locs = NULL;
8145         MonoBitSet *seq_point_set_locs = NULL;
8146
8147         cfg->disable_inline = is_jit_optimizer_disabled (method);
8148
8149         /* serialization and xdomain stuff may need access to private fields and methods */
8150         dont_verify = method->klass->image->assembly->corlib_internal? TRUE: FALSE;
8151         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE;
8152         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH;
8153         dont_verify |= method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE; /* bug #77896 */
8154         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP;
8155         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP_INVOKE;
8156
8157         /* still some type unsafety issues in marshal wrappers... (unknown is PtrToStructure) */
8158         dont_verify_stloc = method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE;
8159         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_UNKNOWN;
8160         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED;
8161         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_STELEMREF;
8162
8163         image = method->klass->image;
8164         header = mono_method_get_header (method);
8165         if (!header) {
8166                 if (mono_loader_get_last_error ()) {
8167                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
8168                         mono_error_set_from_loader_error (&cfg->error);
8169                 } else {
8170                         mono_cfg_set_exception_invalid_program (cfg, g_strdup_printf ("Missing or incorrect header for method %s", cfg->method->name));
8171                 }
8172                 goto exception_exit;
8173         }
8174         generic_container = mono_method_get_generic_container (method);
8175         sig = mono_method_signature (method);
8176         num_args = sig->hasthis + sig->param_count;
8177         ip = (unsigned char*)header->code;
8178         cfg->cil_start = ip;
8179         end = ip + header->code_size;
8180         cfg->stat_cil_code_size += header->code_size;
8181
8182         seq_points = cfg->gen_seq_points && cfg->method == method;
8183
8184         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
8185                 /* We could hit a seq point before attaching to the JIT (#8338) */
8186                 seq_points = FALSE;
8187         }
8188
8189         if (cfg->gen_sdb_seq_points && cfg->method == method) {
8190                 minfo = mono_debug_lookup_method (method);
8191                 if (minfo) {
8192                         MonoSymSeqPoint *sps;
8193                         int i, n_il_offsets;
8194
8195                         mono_debug_get_seq_points (minfo, NULL, NULL, NULL, &sps, &n_il_offsets);
8196                         seq_point_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
8197                         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);
8198                         sym_seq_points = TRUE;
8199                         for (i = 0; i < n_il_offsets; ++i) {
8200                                 if (sps [i].il_offset < header->code_size)
8201                                         mono_bitset_set_fast (seq_point_locs, sps [i].il_offset);
8202                         }
8203                         g_free (sps);
8204                 } else if (!method->wrapper_type && !method->dynamic && mono_debug_image_has_debug_info (method->klass->image)) {
8205                         /* Methods without line number info like auto-generated property accessors */
8206                         seq_point_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
8207                         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);
8208                         sym_seq_points = TRUE;
8209                 }
8210         }
8211
8212         /* 
8213          * Methods without init_locals set could cause asserts in various passes
8214          * (#497220). To work around this, we emit dummy initialization opcodes
8215          * (OP_DUMMY_ICONST etc.) which generate no code. These are only supported
8216          * on some platforms.
8217          */
8218         if ((cfg->opt & MONO_OPT_UNSAFE) && cfg->backend->have_dummy_init)
8219                 init_locals = header->init_locals;
8220         else
8221                 init_locals = TRUE;
8222
8223         method_definition = method;
8224         while (method_definition->is_inflated) {
8225                 MonoMethodInflated *imethod = (MonoMethodInflated *) method_definition;
8226                 method_definition = imethod->declaring;
8227         }
8228
8229         /* SkipVerification is not allowed if core-clr is enabled */
8230         if (!dont_verify && mini_assembly_can_skip_verification (cfg->domain, method)) {
8231                 dont_verify = TRUE;
8232                 dont_verify_stloc = TRUE;
8233         }
8234
8235         if (sig->is_inflated)
8236                 generic_context = mono_method_get_context (method);
8237         else if (generic_container)
8238                 generic_context = &generic_container->context;
8239         cfg->generic_context = generic_context;
8240
8241         if (!cfg->gshared)
8242                 g_assert (!sig->has_type_parameters);
8243
8244         if (sig->generic_param_count && method->wrapper_type == MONO_WRAPPER_NONE) {
8245                 g_assert (method->is_inflated);
8246                 g_assert (mono_method_get_context (method)->method_inst);
8247         }
8248         if (method->is_inflated && mono_method_get_context (method)->method_inst)
8249                 g_assert (sig->generic_param_count);
8250
8251         if (cfg->method == method) {
8252                 cfg->real_offset = 0;
8253         } else {
8254                 cfg->real_offset = inline_offset;
8255         }
8256
8257         cfg->cil_offset_to_bb = (MonoBasicBlock **)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoBasicBlock*) * header->code_size);
8258         cfg->cil_offset_to_bb_len = header->code_size;
8259
8260         cfg->current_method = method;
8261
8262         if (cfg->verbose_level > 2)
8263                 printf ("method to IR %s\n", mono_method_full_name (method, TRUE));
8264
8265         param_types = (MonoType **)mono_mempool_alloc (cfg->mempool, sizeof (MonoType*) * num_args);
8266         if (sig->hasthis)
8267                 param_types [0] = method->klass->valuetype?&method->klass->this_arg:&method->klass->byval_arg;
8268         for (n = 0; n < sig->param_count; ++n)
8269                 param_types [n + sig->hasthis] = sig->params [n];
8270         cfg->arg_types = param_types;
8271
8272         cfg->dont_inline = g_list_prepend (cfg->dont_inline, method);
8273         if (cfg->method == method) {
8274
8275                 if (cfg->prof_options & MONO_PROFILE_INS_COVERAGE)
8276                         cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, header->code_size);
8277
8278                 /* ENTRY BLOCK */
8279                 NEW_BBLOCK (cfg, start_bblock);
8280                 cfg->bb_entry = start_bblock;
8281                 start_bblock->cil_code = NULL;
8282                 start_bblock->cil_length = 0;
8283
8284                 /* EXIT BLOCK */
8285                 NEW_BBLOCK (cfg, end_bblock);
8286                 cfg->bb_exit = end_bblock;
8287                 end_bblock->cil_code = NULL;
8288                 end_bblock->cil_length = 0;
8289                 end_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
8290                 g_assert (cfg->num_bblocks == 2);
8291
8292                 arg_array = cfg->args;
8293
8294                 if (header->num_clauses) {
8295                         cfg->spvars = g_hash_table_new (NULL, NULL);
8296                         cfg->exvars = g_hash_table_new (NULL, NULL);
8297                 }
8298                 /* handle exception clauses */
8299                 for (i = 0; i < header->num_clauses; ++i) {
8300                         MonoBasicBlock *try_bb;
8301                         MonoExceptionClause *clause = &header->clauses [i];
8302                         GET_BBLOCK (cfg, try_bb, ip + clause->try_offset);
8303
8304                         try_bb->real_offset = clause->try_offset;
8305                         try_bb->try_start = TRUE;
8306                         try_bb->region = ((i + 1) << 8) | clause->flags;
8307                         GET_BBLOCK (cfg, tblock, ip + clause->handler_offset);
8308                         tblock->real_offset = clause->handler_offset;
8309                         tblock->flags |= BB_EXCEPTION_HANDLER;
8310
8311                         /*
8312                          * Linking the try block with the EH block hinders inlining as we won't be able to 
8313                          * merge the bblocks from inlining and produce an artificial hole for no good reason.
8314                          */
8315                         if (COMPILE_LLVM (cfg))
8316                                 link_bblock (cfg, try_bb, tblock);
8317
8318                         if (*(ip + clause->handler_offset) == CEE_POP)
8319                                 tblock->flags |= BB_EXCEPTION_DEAD_OBJ;
8320
8321                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY ||
8322                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER ||
8323                             clause->flags == MONO_EXCEPTION_CLAUSE_FAULT) {
8324                                 MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
8325                                 MONO_ADD_INS (tblock, ins);
8326
8327                                 if (seq_points && clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY && clause->flags != MONO_EXCEPTION_CLAUSE_FILTER) {
8328                                         /* finally clauses already have a seq point */
8329                                         /* seq points for filter clauses are emitted below */
8330                                         NEW_SEQ_POINT (cfg, ins, clause->handler_offset, TRUE);
8331                                         MONO_ADD_INS (tblock, ins);
8332                                 }
8333
8334                                 /* todo: is a fault block unsafe to optimize? */
8335                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
8336                                         tblock->flags |= BB_EXCEPTION_UNSAFE;
8337                         }
8338
8339                         /*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);
8340                           while (p < end) {
8341                           printf ("%s", mono_disasm_code_one (NULL, method, p, &p));
8342                           }*/
8343                         /* catch and filter blocks get the exception object on the stack */
8344                         if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE ||
8345                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
8346
8347                                 /* mostly like handle_stack_args (), but just sets the input args */
8348                                 /* printf ("handling clause at IL_%04x\n", clause->handler_offset); */
8349                                 tblock->in_scount = 1;
8350                                 tblock->in_stack = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
8351                                 tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
8352
8353                                 cfg->cbb = tblock;
8354
8355 #ifdef MONO_CONTEXT_SET_LLVM_EXC_REG
8356                                 /* The EH code passes in the exception in a register to both JITted and LLVM compiled code */
8357                                 if (!cfg->compile_llvm) {
8358                                         MONO_INST_NEW (cfg, ins, OP_GET_EX_OBJ);
8359                                         ins->dreg = tblock->in_stack [0]->dreg;
8360                                         MONO_ADD_INS (tblock, ins);
8361                                 }
8362 #else
8363                                 MonoInst *dummy_use;
8364
8365                                 /* 
8366                                  * Add a dummy use for the exvar so its liveness info will be
8367                                  * correct.
8368                                  */
8369                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, tblock->in_stack [0]);
8370 #endif
8371
8372                                 if (seq_points && clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
8373                                         NEW_SEQ_POINT (cfg, ins, clause->handler_offset, TRUE);
8374                                         MONO_ADD_INS (tblock, ins);
8375                                 }
8376                                 
8377                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
8378                                         GET_BBLOCK (cfg, tblock, ip + clause->data.filter_offset);
8379                                         tblock->flags |= BB_EXCEPTION_HANDLER;
8380                                         tblock->real_offset = clause->data.filter_offset;
8381                                         tblock->in_scount = 1;
8382                                         tblock->in_stack = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
8383                                         /* The filter block shares the exvar with the handler block */
8384                                         tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
8385                                         MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
8386                                         MONO_ADD_INS (tblock, ins);
8387                                 }
8388                         }
8389
8390                         if (clause->flags != MONO_EXCEPTION_CLAUSE_FILTER &&
8391                                         clause->data.catch_class &&
8392                                         cfg->gshared &&
8393                                         mono_class_check_context_used (clause->data.catch_class)) {
8394                                 /*
8395                                  * In shared generic code with catch
8396                                  * clauses containing type variables
8397                                  * the exception handling code has to
8398                                  * be able to get to the rgctx.
8399                                  * Therefore we have to make sure that
8400                                  * the vtable/mrgctx argument (for
8401                                  * static or generic methods) or the
8402                                  * "this" argument (for non-static
8403                                  * methods) are live.
8404                                  */
8405                                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
8406                                                 mini_method_get_context (method)->method_inst ||
8407                                                 method->klass->valuetype) {
8408                                         mono_get_vtable_var (cfg);
8409                                 } else {
8410                                         MonoInst *dummy_use;
8411
8412                                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, arg_array [0]);
8413                                 }
8414                         }
8415                 }
8416         } else {
8417                 arg_array = (MonoInst **) alloca (sizeof (MonoInst *) * num_args);
8418                 cfg->cbb = start_bblock;
8419                 cfg->args = arg_array;
8420                 mono_save_args (cfg, sig, inline_args);
8421         }
8422
8423         /* FIRST CODE BLOCK */
8424         NEW_BBLOCK (cfg, tblock);
8425         tblock->cil_code = ip;
8426         cfg->cbb = tblock;
8427         cfg->ip = ip;
8428
8429         ADD_BBLOCK (cfg, tblock);
8430
8431         if (cfg->method == method) {
8432                 breakpoint_id = mono_debugger_method_has_breakpoint (method);
8433                 if (breakpoint_id) {
8434                         MONO_INST_NEW (cfg, ins, OP_BREAK);
8435                         MONO_ADD_INS (cfg->cbb, ins);
8436                 }
8437         }
8438
8439         /* we use a separate basic block for the initialization code */
8440         NEW_BBLOCK (cfg, init_localsbb);
8441         cfg->bb_init = init_localsbb;
8442         init_localsbb->real_offset = cfg->real_offset;
8443         start_bblock->next_bb = init_localsbb;
8444         init_localsbb->next_bb = cfg->cbb;
8445         link_bblock (cfg, start_bblock, init_localsbb);
8446         link_bblock (cfg, init_localsbb, cfg->cbb);
8447                 
8448         cfg->cbb = init_localsbb;
8449
8450         if (cfg->gsharedvt && cfg->method == method) {
8451                 MonoGSharedVtMethodInfo *info;
8452                 MonoInst *var, *locals_var;
8453                 int dreg;
8454
8455                 info = (MonoGSharedVtMethodInfo *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoGSharedVtMethodInfo));
8456                 info->method = cfg->method;
8457                 info->count_entries = 16;
8458                 info->entries = (MonoRuntimeGenericContextInfoTemplate *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
8459                 cfg->gsharedvt_info = info;
8460
8461                 var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
8462                 /* prevent it from being register allocated */
8463                 //var->flags |= MONO_INST_VOLATILE;
8464                 cfg->gsharedvt_info_var = var;
8465
8466                 ins = emit_get_rgctx_gsharedvt_method (cfg, mini_method_check_context_used (cfg, method), method, info);
8467                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, var->dreg, ins->dreg);
8468
8469                 /* Allocate locals */
8470                 locals_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
8471                 /* prevent it from being register allocated */
8472                 //locals_var->flags |= MONO_INST_VOLATILE;
8473                 cfg->gsharedvt_locals_var = locals_var;
8474
8475                 dreg = alloc_ireg (cfg);
8476                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, dreg, var->dreg, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, locals_size));
8477
8478                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
8479                 ins->dreg = locals_var->dreg;
8480                 ins->sreg1 = dreg;
8481                 MONO_ADD_INS (cfg->cbb, ins);
8482                 cfg->gsharedvt_locals_var_ins = ins;
8483                 
8484                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
8485                 /*
8486                 if (init_locals)
8487                         ins->flags |= MONO_INST_INIT;
8488                 */
8489         }
8490
8491         if (mono_security_core_clr_enabled ()) {
8492                 /* check if this is native code, e.g. an icall or a p/invoke */
8493                 if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
8494                         MonoMethod *wrapped = mono_marshal_method_from_wrapper (method);
8495                         if (wrapped) {
8496                                 gboolean pinvk = (wrapped->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL);
8497                                 gboolean icall = (wrapped->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL);
8498
8499                                 /* if this ia a native call then it can only be JITted from platform code */
8500                                 if ((icall || pinvk) && method->klass && method->klass->image) {
8501                                         if (!mono_security_core_clr_is_platform_image (method->klass->image)) {
8502                                                 MonoException *ex = icall ? mono_get_exception_security () : 
8503                                                         mono_get_exception_method_access ();
8504                                                 emit_throw_exception (cfg, ex);
8505                                         }
8506                                 }
8507                         }
8508                 }
8509         }
8510
8511         CHECK_CFG_EXCEPTION;
8512
8513         if (header->code_size == 0)
8514                 UNVERIFIED;
8515
8516         if (get_basic_blocks (cfg, header, cfg->real_offset, ip, end, &err_pos)) {
8517                 ip = err_pos;
8518                 UNVERIFIED;
8519         }
8520
8521         if (cfg->method == method)
8522                 mono_debug_init_method (cfg, cfg->cbb, breakpoint_id);
8523
8524         for (n = 0; n < header->num_locals; ++n) {
8525                 if (header->locals [n]->type == MONO_TYPE_VOID && !header->locals [n]->byref)
8526                         UNVERIFIED;
8527         }
8528         class_inits = NULL;
8529
8530         /* We force the vtable variable here for all shared methods
8531            for the possibility that they might show up in a stack
8532            trace where their exact instantiation is needed. */
8533         if (cfg->gshared && method == cfg->method) {
8534                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
8535                                 mini_method_get_context (method)->method_inst ||
8536                                 method->klass->valuetype) {
8537                         mono_get_vtable_var (cfg);
8538                 } else {
8539                         /* FIXME: Is there a better way to do this?
8540                            We need the variable live for the duration
8541                            of the whole method. */
8542                         cfg->args [0]->flags |= MONO_INST_VOLATILE;
8543                 }
8544         }
8545
8546         /* add a check for this != NULL to inlined methods */
8547         if (is_virtual_call) {
8548                 MonoInst *arg_ins;
8549
8550                 NEW_ARGLOAD (cfg, arg_ins, 0);
8551                 MONO_ADD_INS (cfg->cbb, arg_ins);
8552                 MONO_EMIT_NEW_CHECK_THIS (cfg, arg_ins->dreg);
8553         }
8554
8555         skip_dead_blocks = !dont_verify;
8556         if (skip_dead_blocks) {
8557                 original_bb = bb = mono_basic_block_split (method, &cfg->error);
8558                 CHECK_CFG_ERROR;
8559                 g_assert (bb);
8560         }
8561
8562         /* we use a spare stack slot in SWITCH and NEWOBJ and others */
8563         stack_start = sp = (MonoInst **)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (header->max_stack + 1));
8564
8565         ins_flag = 0;
8566         start_new_bblock = 0;
8567         while (ip < end) {
8568                 if (cfg->method == method)
8569                         cfg->real_offset = ip - header->code;
8570                 else
8571                         cfg->real_offset = inline_offset;
8572                 cfg->ip = ip;
8573
8574                 context_used = 0;
8575
8576                 if (start_new_bblock) {
8577                         cfg->cbb->cil_length = ip - cfg->cbb->cil_code;
8578                         if (start_new_bblock == 2) {
8579                                 g_assert (ip == tblock->cil_code);
8580                         } else {
8581                                 GET_BBLOCK (cfg, tblock, ip);
8582                         }
8583                         cfg->cbb->next_bb = tblock;
8584                         cfg->cbb = tblock;
8585                         start_new_bblock = 0;
8586                         for (i = 0; i < cfg->cbb->in_scount; ++i) {
8587                                 if (cfg->verbose_level > 3)
8588                                         printf ("loading %d from temp %d\n", i, (int)cfg->cbb->in_stack [i]->inst_c0);
8589                                 EMIT_NEW_TEMPLOAD (cfg, ins, cfg->cbb->in_stack [i]->inst_c0);
8590                                 *sp++ = ins;
8591                         }
8592                         if (class_inits)
8593                                 g_slist_free (class_inits);
8594                         class_inits = NULL;
8595                 } else {
8596                         if ((tblock = cfg->cil_offset_to_bb [ip - cfg->cil_start]) && (tblock != cfg->cbb)) {
8597                                 link_bblock (cfg, cfg->cbb, tblock);
8598                                 if (sp != stack_start) {
8599                                         handle_stack_args (cfg, stack_start, sp - stack_start);
8600                                         sp = stack_start;
8601                                         CHECK_UNVERIFIABLE (cfg);
8602                                 }
8603                                 cfg->cbb->next_bb = tblock;
8604                                 cfg->cbb = tblock;
8605                                 for (i = 0; i < cfg->cbb->in_scount; ++i) {
8606                                         if (cfg->verbose_level > 3)
8607                                                 printf ("loading %d from temp %d\n", i, (int)cfg->cbb->in_stack [i]->inst_c0);
8608                                         EMIT_NEW_TEMPLOAD (cfg, ins, cfg->cbb->in_stack [i]->inst_c0);
8609                                         *sp++ = ins;
8610                                 }
8611                                 g_slist_free (class_inits);
8612                                 class_inits = NULL;
8613                         }
8614                 }
8615
8616                 if (skip_dead_blocks) {
8617                         int ip_offset = ip - header->code;
8618
8619                         if (ip_offset == bb->end)
8620                                 bb = bb->next;
8621
8622                         if (bb->dead) {
8623                                 int op_size = mono_opcode_size (ip, end);
8624                                 g_assert (op_size > 0); /*The BB formation pass must catch all bad ops*/
8625
8626                                 if (cfg->verbose_level > 3) printf ("SKIPPING DEAD OP at %x\n", ip_offset);
8627
8628                                 if (ip_offset + op_size == bb->end) {
8629                                         MONO_INST_NEW (cfg, ins, OP_NOP);
8630                                         MONO_ADD_INS (cfg->cbb, ins);
8631                                         start_new_bblock = 1;
8632                                 }
8633
8634                                 ip += op_size;
8635                                 continue;
8636                         }
8637                 }
8638                 /*
8639                  * Sequence points are points where the debugger can place a breakpoint.
8640                  * Currently, we generate these automatically at points where the IL
8641                  * stack is empty.
8642                  */
8643                 if (seq_points && ((!sym_seq_points && (sp == stack_start)) || (sym_seq_points && mono_bitset_test_fast (seq_point_locs, ip - header->code)))) {
8644                         /*
8645                          * Make methods interruptable at the beginning, and at the targets of
8646                          * backward branches.
8647                          * Also, do this at the start of every bblock in methods with clauses too,
8648                          * to be able to handle instructions with inprecise control flow like
8649                          * throw/endfinally.
8650                          * Backward branches are handled at the end of method-to-ir ().
8651                          */
8652                         gboolean intr_loc = ip == header->code || (!cfg->cbb->last_ins && cfg->header->num_clauses);
8653                         gboolean sym_seq_point = sym_seq_points && mono_bitset_test_fast (seq_point_locs, ip - header->code);
8654
8655                         /* Avoid sequence points on empty IL like .volatile */
8656                         // FIXME: Enable this
8657                         //if (!(cfg->cbb->last_ins && cfg->cbb->last_ins->opcode == OP_SEQ_POINT)) {
8658                         NEW_SEQ_POINT (cfg, ins, ip - header->code, intr_loc);
8659                         if ((sp != stack_start) && !sym_seq_point)
8660                                 ins->flags |= MONO_INST_NONEMPTY_STACK;
8661                         MONO_ADD_INS (cfg->cbb, ins);
8662
8663                         if (sym_seq_points)
8664                                 mono_bitset_set_fast (seq_point_set_locs, ip - header->code);
8665                 }
8666
8667                 cfg->cbb->real_offset = cfg->real_offset;
8668
8669                 if ((cfg->method == method) && cfg->coverage_info) {
8670                         guint32 cil_offset = ip - header->code;
8671                         cfg->coverage_info->data [cil_offset].cil_code = ip;
8672
8673                         /* TODO: Use an increment here */
8674 #if defined(TARGET_X86)
8675                         MONO_INST_NEW (cfg, ins, OP_STORE_MEM_IMM);
8676                         ins->inst_p0 = &(cfg->coverage_info->data [cil_offset].count);
8677                         ins->inst_imm = 1;
8678                         MONO_ADD_INS (cfg->cbb, ins);
8679 #else
8680                         EMIT_NEW_PCONST (cfg, ins, &(cfg->coverage_info->data [cil_offset].count));
8681                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, ins->dreg, 0, 1);
8682 #endif
8683                 }
8684
8685                 if (cfg->verbose_level > 3)
8686                         printf ("converting (in B%d: stack: %d) %s", cfg->cbb->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
8687
8688                 switch (*ip) {
8689                 case CEE_NOP:
8690                         if (seq_points && !sym_seq_points && sp != stack_start) {
8691                                 /*
8692                                  * The C# compiler uses these nops to notify the JIT that it should
8693                                  * insert seq points.
8694                                  */
8695                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, FALSE);
8696                                 MONO_ADD_INS (cfg->cbb, ins);
8697                         }
8698                         if (cfg->keep_cil_nops)
8699                                 MONO_INST_NEW (cfg, ins, OP_HARD_NOP);
8700                         else
8701                                 MONO_INST_NEW (cfg, ins, OP_NOP);
8702                         ip++;
8703                         MONO_ADD_INS (cfg->cbb, ins);
8704                         break;
8705                 case CEE_BREAK:
8706                         if (should_insert_brekpoint (cfg->method)) {
8707                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
8708                         } else {
8709                                 MONO_INST_NEW (cfg, ins, OP_NOP);
8710                         }
8711                         ip++;
8712                         MONO_ADD_INS (cfg->cbb, ins);
8713                         break;
8714                 case CEE_LDARG_0:
8715                 case CEE_LDARG_1:
8716                 case CEE_LDARG_2:
8717                 case CEE_LDARG_3:
8718                         CHECK_STACK_OVF (1);
8719                         n = (*ip)-CEE_LDARG_0;
8720                         CHECK_ARG (n);
8721                         EMIT_NEW_ARGLOAD (cfg, ins, n);
8722                         ip++;
8723                         *sp++ = ins;
8724                         break;
8725                 case CEE_LDLOC_0:
8726                 case CEE_LDLOC_1:
8727                 case CEE_LDLOC_2:
8728                 case CEE_LDLOC_3:
8729                         CHECK_STACK_OVF (1);
8730                         n = (*ip)-CEE_LDLOC_0;
8731                         CHECK_LOCAL (n);
8732                         EMIT_NEW_LOCLOAD (cfg, ins, n);
8733                         ip++;
8734                         *sp++ = ins;
8735                         break;
8736                 case CEE_STLOC_0:
8737                 case CEE_STLOC_1:
8738                 case CEE_STLOC_2:
8739                 case CEE_STLOC_3: {
8740                         CHECK_STACK (1);
8741                         n = (*ip)-CEE_STLOC_0;
8742                         CHECK_LOCAL (n);
8743                         --sp;
8744                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
8745                                 UNVERIFIED;
8746                         emit_stloc_ir (cfg, sp, header, n);
8747                         ++ip;
8748                         inline_costs += 1;
8749                         break;
8750                         }
8751                 case CEE_LDARG_S:
8752                         CHECK_OPSIZE (2);
8753                         CHECK_STACK_OVF (1);
8754                         n = ip [1];
8755                         CHECK_ARG (n);
8756                         EMIT_NEW_ARGLOAD (cfg, ins, n);
8757                         *sp++ = ins;
8758                         ip += 2;
8759                         break;
8760                 case CEE_LDARGA_S:
8761                         CHECK_OPSIZE (2);
8762                         CHECK_STACK_OVF (1);
8763                         n = ip [1];
8764                         CHECK_ARG (n);
8765                         NEW_ARGLOADA (cfg, ins, n);
8766                         MONO_ADD_INS (cfg->cbb, ins);
8767                         *sp++ = ins;
8768                         ip += 2;
8769                         break;
8770                 case CEE_STARG_S:
8771                         CHECK_OPSIZE (2);
8772                         CHECK_STACK (1);
8773                         --sp;
8774                         n = ip [1];
8775                         CHECK_ARG (n);
8776                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [ip [1]], *sp))
8777                                 UNVERIFIED;
8778                         EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
8779                         ip += 2;
8780                         break;
8781                 case CEE_LDLOC_S:
8782                         CHECK_OPSIZE (2);
8783                         CHECK_STACK_OVF (1);
8784                         n = ip [1];
8785                         CHECK_LOCAL (n);
8786                         EMIT_NEW_LOCLOAD (cfg, ins, n);
8787                         *sp++ = ins;
8788                         ip += 2;
8789                         break;
8790                 case CEE_LDLOCA_S: {
8791                         unsigned char *tmp_ip;
8792                         CHECK_OPSIZE (2);
8793                         CHECK_STACK_OVF (1);
8794                         CHECK_LOCAL (ip [1]);
8795
8796                         if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 1))) {
8797                                 ip = tmp_ip;
8798                                 inline_costs += 1;
8799                                 break;
8800                         }
8801
8802                         EMIT_NEW_LOCLOADA (cfg, ins, ip [1]);
8803                         *sp++ = ins;
8804                         ip += 2;
8805                         break;
8806                 }
8807                 case CEE_STLOC_S:
8808                         CHECK_OPSIZE (2);
8809                         CHECK_STACK (1);
8810                         --sp;
8811                         CHECK_LOCAL (ip [1]);
8812                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [ip [1]], *sp))
8813                                 UNVERIFIED;
8814                         emit_stloc_ir (cfg, sp, header, ip [1]);
8815                         ip += 2;
8816                         inline_costs += 1;
8817                         break;
8818                 case CEE_LDNULL:
8819                         CHECK_STACK_OVF (1);
8820                         EMIT_NEW_PCONST (cfg, ins, NULL);
8821                         ins->type = STACK_OBJ;
8822                         ++ip;
8823                         *sp++ = ins;
8824                         break;
8825                 case CEE_LDC_I4_M1:
8826                         CHECK_STACK_OVF (1);
8827                         EMIT_NEW_ICONST (cfg, ins, -1);
8828                         ++ip;
8829                         *sp++ = ins;
8830                         break;
8831                 case CEE_LDC_I4_0:
8832                 case CEE_LDC_I4_1:
8833                 case CEE_LDC_I4_2:
8834                 case CEE_LDC_I4_3:
8835                 case CEE_LDC_I4_4:
8836                 case CEE_LDC_I4_5:
8837                 case CEE_LDC_I4_6:
8838                 case CEE_LDC_I4_7:
8839                 case CEE_LDC_I4_8:
8840                         CHECK_STACK_OVF (1);
8841                         EMIT_NEW_ICONST (cfg, ins, (*ip) - CEE_LDC_I4_0);
8842                         ++ip;
8843                         *sp++ = ins;
8844                         break;
8845                 case CEE_LDC_I4_S:
8846                         CHECK_OPSIZE (2);
8847                         CHECK_STACK_OVF (1);
8848                         ++ip;
8849                         EMIT_NEW_ICONST (cfg, ins, *((signed char*)ip));
8850                         ++ip;
8851                         *sp++ = ins;
8852                         break;
8853                 case CEE_LDC_I4:
8854                         CHECK_OPSIZE (5);
8855                         CHECK_STACK_OVF (1);
8856                         EMIT_NEW_ICONST (cfg, ins, (gint32)read32 (ip + 1));
8857                         ip += 5;
8858                         *sp++ = ins;
8859                         break;
8860                 case CEE_LDC_I8:
8861                         CHECK_OPSIZE (9);
8862                         CHECK_STACK_OVF (1);
8863                         MONO_INST_NEW (cfg, ins, OP_I8CONST);
8864                         ins->type = STACK_I8;
8865                         ins->dreg = alloc_dreg (cfg, STACK_I8);
8866                         ++ip;
8867                         ins->inst_l = (gint64)read64 (ip);
8868                         MONO_ADD_INS (cfg->cbb, ins);
8869                         ip += 8;
8870                         *sp++ = ins;
8871                         break;
8872                 case CEE_LDC_R4: {
8873                         float *f;
8874                         gboolean use_aotconst = FALSE;
8875
8876 #ifdef TARGET_POWERPC
8877                         /* FIXME: Clean this up */
8878                         if (cfg->compile_aot)
8879                                 use_aotconst = TRUE;
8880 #endif
8881
8882                         /* FIXME: we should really allocate this only late in the compilation process */
8883                         f = (float *)mono_domain_alloc (cfg->domain, sizeof (float));
8884                         CHECK_OPSIZE (5);
8885                         CHECK_STACK_OVF (1);
8886
8887                         if (use_aotconst) {
8888                                 MonoInst *cons;
8889                                 int dreg;
8890
8891                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R4, f);
8892
8893                                 dreg = alloc_freg (cfg);
8894                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR4_MEMBASE, dreg, cons->dreg, 0);
8895                                 ins->type = cfg->r4_stack_type;
8896                         } else {
8897                                 MONO_INST_NEW (cfg, ins, OP_R4CONST);
8898                                 ins->type = cfg->r4_stack_type;
8899                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
8900                                 ins->inst_p0 = f;
8901                                 MONO_ADD_INS (cfg->cbb, ins);
8902                         }
8903                         ++ip;
8904                         readr4 (ip, f);
8905                         ip += 4;
8906                         *sp++ = ins;                    
8907                         break;
8908                 }
8909                 case CEE_LDC_R8: {
8910                         double *d;
8911                         gboolean use_aotconst = FALSE;
8912
8913 #ifdef TARGET_POWERPC
8914                         /* FIXME: Clean this up */
8915                         if (cfg->compile_aot)
8916                                 use_aotconst = TRUE;
8917 #endif
8918
8919                         /* FIXME: we should really allocate this only late in the compilation process */
8920                         d = (double *)mono_domain_alloc (cfg->domain, sizeof (double));
8921                         CHECK_OPSIZE (9);
8922                         CHECK_STACK_OVF (1);
8923
8924                         if (use_aotconst) {
8925                                 MonoInst *cons;
8926                                 int dreg;
8927
8928                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R8, d);
8929
8930                                 dreg = alloc_freg (cfg);
8931                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR8_MEMBASE, dreg, cons->dreg, 0);
8932                                 ins->type = STACK_R8;
8933                         } else {
8934                                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
8935                                 ins->type = STACK_R8;
8936                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
8937                                 ins->inst_p0 = d;
8938                                 MONO_ADD_INS (cfg->cbb, ins);
8939                         }
8940                         ++ip;
8941                         readr8 (ip, d);
8942                         ip += 8;
8943                         *sp++ = ins;
8944                         break;
8945                 }
8946                 case CEE_DUP: {
8947                         MonoInst *temp, *store;
8948                         CHECK_STACK (1);
8949                         CHECK_STACK_OVF (1);
8950                         sp--;
8951                         ins = *sp;
8952
8953                         temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
8954                         EMIT_NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
8955
8956                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
8957                         *sp++ = ins;
8958
8959                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
8960                         *sp++ = ins;
8961
8962                         ++ip;
8963                         inline_costs += 2;
8964                         break;
8965                 }
8966                 case CEE_POP:
8967                         CHECK_STACK (1);
8968                         ip++;
8969                         --sp;
8970
8971 #ifdef TARGET_X86
8972                         if (sp [0]->type == STACK_R8)
8973                                 /* we need to pop the value from the x86 FP stack */
8974                                 MONO_EMIT_NEW_UNALU (cfg, OP_X86_FPOP, -1, sp [0]->dreg);
8975 #endif
8976                         break;
8977                 case CEE_JMP: {
8978                         MonoCallInst *call;
8979                         MonoMethodSignature *fsig;
8980                         int i, n;
8981
8982                         INLINE_FAILURE ("jmp");
8983                         GSHAREDVT_FAILURE (*ip);
8984
8985                         CHECK_OPSIZE (5);
8986                         if (stack_start != sp)
8987                                 UNVERIFIED;
8988                         token = read32 (ip + 1);
8989                         /* FIXME: check the signature matches */
8990                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
8991                         CHECK_CFG_ERROR;
8992  
8993                         if (cfg->gshared && mono_method_check_context_used (cmethod))
8994                                 GENERIC_SHARING_FAILURE (CEE_JMP);
8995
8996                         emit_instrumentation_call (cfg, mono_profiler_method_leave);
8997
8998                         fsig = mono_method_signature (cmethod);
8999                         n = fsig->param_count + fsig->hasthis;
9000                         if (cfg->llvm_only) {
9001                                 MonoInst **args;
9002
9003                                 args = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * n);
9004                                 for (i = 0; i < n; ++i)
9005                                         EMIT_NEW_ARGLOAD (cfg, args [i], i);
9006                                 ins = mono_emit_method_call_full (cfg, cmethod, fsig, TRUE, args, NULL, NULL, NULL);
9007                                 /*
9008                                  * The code in mono-basic-block.c treats the rest of the code as dead, but we
9009                                  * have to emit a normal return since llvm expects it.
9010                                  */
9011                                 if (cfg->ret)
9012                                         emit_setret (cfg, ins);
9013                                 MONO_INST_NEW (cfg, ins, OP_BR);
9014                                 ins->inst_target_bb = end_bblock;
9015                                 MONO_ADD_INS (cfg->cbb, ins);
9016                                 link_bblock (cfg, cfg->cbb, end_bblock);
9017                                 ip += 5;
9018                                 break;
9019                         } else if (cfg->backend->have_op_tail_call) {
9020                                 /* Handle tail calls similarly to calls */
9021                                 DISABLE_AOT (cfg);
9022
9023                                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
9024                                 call->method = cmethod;
9025                                 call->tail_call = TRUE;
9026                                 call->signature = mono_method_signature (cmethod);
9027                                 call->args = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * n);
9028                                 call->inst.inst_p0 = cmethod;
9029                                 for (i = 0; i < n; ++i)
9030                                         EMIT_NEW_ARGLOAD (cfg, call->args [i], i);
9031
9032                                 mono_arch_emit_call (cfg, call);
9033                                 cfg->param_area = MAX(cfg->param_area, call->stack_usage);
9034                                 MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
9035                         } else {
9036                                 for (i = 0; i < num_args; ++i)
9037                                         /* Prevent arguments from being optimized away */
9038                                         arg_array [i]->flags |= MONO_INST_VOLATILE;
9039
9040                                 MONO_INST_NEW_CALL (cfg, call, OP_JMP);
9041                                 ins = (MonoInst*)call;
9042                                 ins->inst_p0 = cmethod;
9043                                 MONO_ADD_INS (cfg->cbb, ins);
9044                         }
9045
9046                         ip += 5;
9047                         start_new_bblock = 1;
9048                         break;
9049                 }
9050                 case CEE_CALLI: {
9051                         MonoInst *addr;
9052                         MonoMethodSignature *fsig;
9053
9054                         CHECK_OPSIZE (5);
9055                         token = read32 (ip + 1);
9056
9057                         ins = NULL;
9058
9059                         //GSHAREDVT_FAILURE (*ip);
9060                         cmethod = NULL;
9061                         CHECK_STACK (1);
9062                         --sp;
9063                         addr = *sp;
9064                         fsig = mini_get_signature (method, token, generic_context);
9065
9066                         if (method->dynamic && fsig->pinvoke) {
9067                                 MonoInst *args [3];
9068
9069                                 /*
9070                                  * This is a call through a function pointer using a pinvoke
9071                                  * signature. Have to create a wrapper and call that instead.
9072                                  * FIXME: This is very slow, need to create a wrapper at JIT time
9073                                  * instead based on the signature.
9074                                  */
9075                                 EMIT_NEW_IMAGECONST (cfg, args [0], method->klass->image);
9076                                 EMIT_NEW_PCONST (cfg, args [1], fsig);
9077                                 args [2] = addr;
9078                                 addr = mono_emit_jit_icall (cfg, mono_get_native_calli_wrapper, args);
9079                         }
9080
9081                         n = fsig->param_count + fsig->hasthis;
9082
9083                         CHECK_STACK (n);
9084
9085                         //g_assert (!virtual_ || fsig->hasthis);
9086
9087                         sp -= n;
9088
9089                         inline_costs += 10 * num_calls++;
9090
9091                         /*
9092                          * Making generic calls out of gsharedvt methods.
9093                          * This needs to be used for all generic calls, not just ones with a gsharedvt signature, to avoid
9094                          * patching gshared method addresses into a gsharedvt method.
9095                          */
9096                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) {
9097                                 /*
9098                                  * We pass the address to the gsharedvt trampoline in the rgctx reg
9099                                  */
9100                                 MonoInst *callee = addr;
9101
9102                                 if (method->wrapper_type != MONO_WRAPPER_DELEGATE_INVOKE)
9103                                         /* Not tested */
9104                                         GSHAREDVT_FAILURE (*ip);
9105
9106                                 if (cfg->llvm_only)
9107                                         // FIXME:
9108                                         GSHAREDVT_FAILURE (*ip);
9109
9110                                 addr = emit_get_rgctx_sig (cfg, context_used,
9111                                                                                           fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
9112                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, callee);
9113                                 goto calli_end;
9114                         }
9115
9116                         /* Prevent inlining of methods with indirect calls */
9117                         INLINE_FAILURE ("indirect call");
9118
9119                         if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST || addr->opcode == OP_GOT_ENTRY) {
9120                                 MonoJumpInfoType info_type;
9121                                 gpointer info_data;
9122
9123                                 /*
9124                                  * Instead of emitting an indirect call, emit a direct call
9125                                  * with the contents of the aotconst as the patch info.
9126                                  */
9127                                 if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST) {
9128                                         info_type = (MonoJumpInfoType)addr->inst_c1;
9129                                         info_data = addr->inst_p0;
9130                                 } else {
9131                                         info_type = (MonoJumpInfoType)addr->inst_right->inst_c1;
9132                                         info_data = addr->inst_right->inst_left;
9133                                 }
9134
9135                                 if (info_type == MONO_PATCH_INFO_ICALL_ADDR || info_type == MONO_PATCH_INFO_JIT_ICALL_ADDR) {
9136                                         ins = (MonoInst*)mono_emit_abs_call (cfg, info_type, info_data, fsig, sp);
9137                                         NULLIFY_INS (addr);
9138                                         goto calli_end;
9139                                 }
9140                         }
9141                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9142
9143                         calli_end:
9144
9145                         /* End of call, INS should contain the result of the call, if any */
9146
9147                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9148                                 g_assert (ins);
9149                                 *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
9150                         }
9151
9152                         CHECK_CFG_EXCEPTION;
9153
9154                         ip += 5;
9155                         ins_flag = 0;
9156                         constrained_class = NULL;
9157                         break;
9158                 }
9159                 case CEE_CALL:
9160                 case CEE_CALLVIRT: {
9161                         MonoInst *addr = NULL;
9162                         MonoMethodSignature *fsig = NULL;
9163                         int array_rank = 0;
9164                         int virtual_ = *ip == CEE_CALLVIRT;
9165                         gboolean pass_imt_from_rgctx = FALSE;
9166                         MonoInst *imt_arg = NULL;
9167                         MonoInst *keep_this_alive = NULL;
9168                         gboolean pass_vtable = FALSE;
9169                         gboolean pass_mrgctx = FALSE;
9170                         MonoInst *vtable_arg = NULL;
9171                         gboolean check_this = FALSE;
9172                         gboolean supported_tail_call = FALSE;
9173                         gboolean tail_call = FALSE;
9174                         gboolean need_seq_point = FALSE;
9175                         guint32 call_opcode = *ip;
9176                         gboolean emit_widen = TRUE;
9177                         gboolean push_res = TRUE;
9178                         gboolean skip_ret = FALSE;
9179                         gboolean delegate_invoke = FALSE;
9180                         gboolean direct_icall = FALSE;
9181                         gboolean constrained_partial_call = FALSE;
9182                         MonoMethod *cil_method;
9183
9184                         CHECK_OPSIZE (5);
9185                         token = read32 (ip + 1);
9186
9187                         ins = NULL;
9188
9189                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
9190                         CHECK_CFG_ERROR;
9191
9192                         cil_method = cmethod;
9193                                 
9194                         if (constrained_class) {
9195                                 if ((constrained_class->byval_arg.type == MONO_TYPE_VAR || constrained_class->byval_arg.type == MONO_TYPE_MVAR) && cfg->gshared) {
9196                                         if (!mini_is_gsharedvt_klass (constrained_class)) {
9197                                                 g_assert (!cmethod->klass->valuetype);
9198                                                 if (!mini_type_is_reference (&constrained_class->byval_arg))
9199                                                         constrained_partial_call = TRUE;
9200                                         }
9201                                 }
9202
9203                                 if (method->wrapper_type != MONO_WRAPPER_NONE) {
9204                                         if (cfg->verbose_level > 2)
9205                                                 printf ("DM Constrained call to %s\n", mono_type_get_full_name (constrained_class));
9206                                         if (!((constrained_class->byval_arg.type == MONO_TYPE_VAR ||
9207                                                    constrained_class->byval_arg.type == MONO_TYPE_MVAR) &&
9208                                                   cfg->gshared)) {
9209                                                 cmethod = mono_get_method_constrained_with_method (image, cil_method, constrained_class, generic_context, &cfg->error);
9210                                                 CHECK_CFG_ERROR;
9211                                         }
9212                                 } else {
9213                                         if (cfg->verbose_level > 2)
9214                                                 printf ("Constrained call to %s\n", mono_type_get_full_name (constrained_class));
9215
9216                                         if ((constrained_class->byval_arg.type == MONO_TYPE_VAR || constrained_class->byval_arg.type == MONO_TYPE_MVAR) && cfg->gshared) {
9217                                                 /* 
9218                                                  * This is needed since get_method_constrained can't find 
9219                                                  * the method in klass representing a type var.
9220                                                  * The type var is guaranteed to be a reference type in this
9221                                                  * case.
9222                                                  */
9223                                                 if (!mini_is_gsharedvt_klass (constrained_class))
9224                                                         g_assert (!cmethod->klass->valuetype);
9225                                         } else {
9226                                                 cmethod = mono_get_method_constrained_checked (image, token, constrained_class, generic_context, &cil_method, &cfg->error);
9227                                                 CHECK_CFG_ERROR;
9228                                         }
9229                                 }
9230                         }
9231                                         
9232                         if (!cmethod || mono_loader_get_last_error ()) {
9233                                 if (mono_loader_get_last_error ()) {
9234                                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
9235                                         mono_error_set_from_loader_error (&cfg->error);
9236                                         CHECK_CFG_ERROR;
9237                                 } else {
9238                                         LOAD_ERROR;
9239                                 }
9240                         }
9241                         if (!dont_verify && !cfg->skip_visibility) {
9242                                 MonoMethod *target_method = cil_method;
9243                                 if (method->is_inflated) {
9244                                         target_method = mini_get_method_allow_open (method, token, NULL, &(mono_method_get_generic_container (method_definition)->context), &cfg->error);
9245                                         CHECK_CFG_ERROR;
9246                                 }
9247                                 if (!mono_method_can_access_method (method_definition, target_method) &&
9248                                         !mono_method_can_access_method (method, cil_method))
9249                                         METHOD_ACCESS_FAILURE (method, cil_method);
9250                         }
9251
9252                         if (mono_security_core_clr_enabled ())
9253                                 ensure_method_is_allowed_to_call_method (cfg, method, cil_method);
9254
9255                         if (!virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_ABSTRACT))
9256                                 /* MS.NET seems to silently convert this to a callvirt */
9257                                 virtual_ = 1;
9258
9259                         {
9260                                 /*
9261                                  * MS.NET accepts non virtual calls to virtual final methods of transparent proxy classes and
9262                                  * converts to a callvirt.
9263                                  *
9264                                  * tests/bug-515884.il is an example of this behavior
9265                                  */
9266                                 const int test_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_STATIC;
9267                                 const int expected_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL;
9268                                 if (!virtual_ && mono_class_is_marshalbyref (cmethod->klass) && (cmethod->flags & test_flags) == expected_flags && cfg->method->wrapper_type == MONO_WRAPPER_NONE)
9269                                         virtual_ = 1;
9270                         }
9271
9272                         if (!cmethod->klass->inited)
9273                                 if (!mono_class_init (cmethod->klass))
9274                                         TYPE_LOAD_ERROR (cmethod->klass);
9275
9276                         fsig = mono_method_signature (cmethod);
9277                         if (!fsig)
9278                                 LOAD_ERROR;
9279                         if (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL &&
9280                                 mini_class_is_system_array (cmethod->klass)) {
9281                                 array_rank = cmethod->klass->rank;
9282                         } else if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && icall_is_direct_callable (cfg, cmethod)) {
9283                                 direct_icall = TRUE;
9284                         } else if (fsig->pinvoke) {
9285                                 MonoMethod *wrapper = mono_marshal_get_native_wrapper (cmethod, TRUE, cfg->compile_aot);
9286                                 fsig = mono_method_signature (wrapper);
9287                         } else if (constrained_class) {
9288                         } else {
9289                                 fsig = mono_method_get_signature_checked (cmethod, image, token, generic_context, &cfg->error);
9290                                 CHECK_CFG_ERROR;
9291                         }
9292
9293                         if (cfg->llvm_only && !cfg->method->wrapper_type)
9294                                 cfg->signatures = g_slist_prepend_mempool (cfg->mempool, cfg->signatures, fsig);
9295
9296                         /* See code below */
9297                         if (cmethod->klass == mono_defaults.monitor_class && !strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1) {
9298                                 MonoBasicBlock *tbb;
9299
9300                                 GET_BBLOCK (cfg, tbb, ip + 5);
9301                                 if (tbb->try_start && MONO_REGION_FLAGS(tbb->region) == MONO_EXCEPTION_CLAUSE_FINALLY) {
9302                                         /*
9303                                          * We want to extend the try block to cover the call, but we can't do it if the
9304                                          * call is made directly since its followed by an exception check.
9305                                          */
9306                                         direct_icall = FALSE;
9307                                 }
9308                         }
9309
9310                         mono_save_token_info (cfg, image, token, cil_method);
9311
9312                         if (!(seq_point_locs && mono_bitset_test_fast (seq_point_locs, ip + 5 - header->code)))
9313                                 need_seq_point = TRUE;
9314
9315                         /* Don't support calls made using type arguments for now */
9316                         /*
9317                           if (cfg->gsharedvt) {
9318                           if (mini_is_gsharedvt_signature (fsig))
9319                           GSHAREDVT_FAILURE (*ip);
9320                           }
9321                         */
9322
9323                         if (cmethod->string_ctor && method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE)
9324                                 g_assert_not_reached ();
9325
9326                         n = fsig->param_count + fsig->hasthis;
9327
9328                         if (!cfg->gshared && cmethod->klass->generic_container)
9329                                 UNVERIFIED;
9330
9331                         if (!cfg->gshared)
9332                                 g_assert (!mono_method_check_context_used (cmethod));
9333
9334                         CHECK_STACK (n);
9335
9336                         //g_assert (!virtual_ || fsig->hasthis);
9337
9338                         sp -= n;
9339
9340                         /*
9341                          * We have the `constrained.' prefix opcode.
9342                          */
9343                         if (constrained_class) {
9344                                 if (mini_is_gsharedvt_klass (constrained_class)) {
9345                                         if ((cmethod->klass != mono_defaults.object_class) && constrained_class->valuetype && cmethod->klass->valuetype) {
9346                                                 /* The 'Own method' case below */
9347                                         } else if (cmethod->klass->image != mono_defaults.corlib && !(cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) && !cmethod->klass->valuetype) {
9348                                                 /* 'The type parameter is instantiated as a reference type' case below. */
9349                                         } else {
9350                                                 ins = handle_constrained_gsharedvt_call (cfg, cmethod, fsig, sp, constrained_class, &emit_widen);
9351                                                 CHECK_CFG_EXCEPTION;
9352                                                 g_assert (ins);
9353                                                 goto call_end;
9354                                         }
9355                                 }
9356
9357                                 if (constrained_partial_call) {
9358                                         gboolean need_box = TRUE;
9359
9360                                         /*
9361                                          * The receiver is a valuetype, but the exact type is not known at compile time. This means the
9362                                          * called method is not known at compile time either. The called method could end up being
9363                                          * one of the methods on the parent classes (object/valuetype/enum), in which case we need
9364                                          * to box the receiver.
9365                                          * A simple solution would be to box always and make a normal virtual call, but that would
9366                                          * be bad performance wise.
9367                                          */
9368                                         if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE && cmethod->klass->generic_class) {
9369                                                 /*
9370                                                  * The parent classes implement no generic interfaces, so the called method will be a vtype method, so no boxing neccessary.
9371                                                  */
9372                                                 need_box = FALSE;
9373                                         }
9374
9375                                         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)) {
9376                                                 /* The called method is not virtual, i.e. Object:GetType (), the receiver is a vtype, has to box */
9377                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
9378                                                 ins->klass = constrained_class;
9379                                                 sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
9380                                                 CHECK_CFG_EXCEPTION;
9381                                         } else if (need_box) {
9382                                                 MonoInst *box_type;
9383                                                 MonoBasicBlock *is_ref_bb, *end_bb;
9384                                                 MonoInst *nonbox_call;
9385
9386                                                 /*
9387                                                  * Determine at runtime whenever the called method is defined on object/valuetype/enum, and emit a boxing call
9388                                                  * if needed.
9389                                                  * FIXME: It is possible to inline the called method in a lot of cases, i.e. for T_INT,
9390                                                  * the no-box case goes to a method in Int32, while the box case goes to a method in Enum.
9391                                                  */
9392                                                 addr = emit_get_rgctx_virt_method (cfg, mono_class_check_context_used (constrained_class), constrained_class, cmethod, MONO_RGCTX_INFO_VIRT_METHOD_CODE);
9393
9394                                                 NEW_BBLOCK (cfg, is_ref_bb);
9395                                                 NEW_BBLOCK (cfg, end_bb);
9396
9397                                                 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);
9398                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, box_type->dreg, MONO_GSHAREDVT_BOX_TYPE_REF);
9399                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
9400
9401                                                 /* Non-ref case */
9402                                                 nonbox_call = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9403
9404                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
9405
9406                                                 /* Ref case */
9407                                                 MONO_START_BB (cfg, is_ref_bb);
9408                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
9409                                                 ins->klass = constrained_class;
9410                                                 sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
9411                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9412
9413                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
9414
9415                                                 MONO_START_BB (cfg, end_bb);
9416                                                 cfg->cbb = end_bb;
9417
9418                                                 nonbox_call->dreg = ins->dreg;
9419                                                 goto call_end;
9420                                         } else {
9421                                                 g_assert (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE);
9422                                                 addr = emit_get_rgctx_virt_method (cfg, mono_class_check_context_used (constrained_class), constrained_class, cmethod, MONO_RGCTX_INFO_VIRT_METHOD_CODE);
9423                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9424                                                 goto call_end;
9425                                         }
9426                                 } else if (constrained_class->valuetype && (cmethod->klass == mono_defaults.object_class || cmethod->klass == mono_defaults.enum_class->parent || cmethod->klass == mono_defaults.enum_class)) {
9427                                         /*
9428                                          * The type parameter is instantiated as a valuetype,
9429                                          * but that type doesn't override the method we're
9430                                          * calling, so we need to box `this'.
9431                                          */
9432                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
9433                                         ins->klass = constrained_class;
9434                                         sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
9435                                         CHECK_CFG_EXCEPTION;
9436                                 } else if (!constrained_class->valuetype) {
9437                                         int dreg = alloc_ireg_ref (cfg);
9438
9439                                         /*
9440                                          * The type parameter is instantiated as a reference
9441                                          * type.  We have a managed pointer on the stack, so
9442                                          * we need to dereference it here.
9443                                          */
9444                                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, sp [0]->dreg, 0);
9445                                         ins->type = STACK_OBJ;
9446                                         sp [0] = ins;
9447                                 } else {
9448                                         if (cmethod->klass->valuetype) {
9449                                                 /* Own method */
9450                                         } else {
9451                                                 /* Interface method */
9452                                                 int ioffset, slot;
9453
9454                                                 mono_class_setup_vtable (constrained_class);
9455                                                 CHECK_TYPELOAD (constrained_class);
9456                                                 ioffset = mono_class_interface_offset (constrained_class, cmethod->klass);
9457                                                 if (ioffset == -1)
9458                                                         TYPE_LOAD_ERROR (constrained_class);
9459                                                 slot = mono_method_get_vtable_slot (cmethod);
9460                                                 if (slot == -1)
9461                                                         TYPE_LOAD_ERROR (cmethod->klass);
9462                                                 cmethod = constrained_class->vtable [ioffset + slot];
9463
9464                                                 if (cmethod->klass == mono_defaults.enum_class) {
9465                                                         /* Enum implements some interfaces, so treat this as the first case */
9466                                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
9467                                                         ins->klass = constrained_class;
9468                                                         sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
9469                                                         CHECK_CFG_EXCEPTION;
9470                                                 }
9471                                         }
9472                                         virtual_ = 0;
9473                                 }
9474                                 constrained_class = NULL;
9475                         }
9476
9477                         if (check_call_signature (cfg, fsig, sp))
9478                                 UNVERIFIED;
9479
9480                         if ((cmethod->klass->parent == mono_defaults.multicastdelegate_class) && !strcmp (cmethod->name, "Invoke"))
9481                                 delegate_invoke = TRUE;
9482
9483                         if ((cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_sharable_method (cfg, cmethod, fsig, sp))) {
9484                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9485                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
9486                                         emit_widen = FALSE;
9487                                 }
9488
9489                                 goto call_end;
9490                         }
9491
9492                         /* 
9493                          * If the callee is a shared method, then its static cctor
9494                          * might not get called after the call was patched.
9495                          */
9496                         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)) {
9497                                 emit_class_init (cfg, cmethod->klass);
9498                                 CHECK_TYPELOAD (cmethod->klass);
9499                         }
9500
9501                         check_method_sharing (cfg, cmethod, &pass_vtable, &pass_mrgctx);
9502
9503                         if (cfg->gshared) {
9504                                 MonoGenericContext *cmethod_context = mono_method_get_context (cmethod);
9505
9506                                 context_used = mini_method_check_context_used (cfg, cmethod);
9507
9508                                 if (context_used && (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
9509                                         /* Generic method interface
9510                                            calls are resolved via a
9511                                            helper function and don't
9512                                            need an imt. */
9513                                         if (!cmethod_context || !cmethod_context->method_inst)
9514                                                 pass_imt_from_rgctx = TRUE;
9515                                 }
9516
9517                                 /*
9518                                  * If a shared method calls another
9519                                  * shared method then the caller must
9520                                  * have a generic sharing context
9521                                  * because the magic trampoline
9522                                  * requires it.  FIXME: We shouldn't
9523                                  * have to force the vtable/mrgctx
9524                                  * variable here.  Instead there
9525                                  * should be a flag in the cfg to
9526                                  * request a generic sharing context.
9527                                  */
9528                                 if (context_used &&
9529                                                 ((method->flags & METHOD_ATTRIBUTE_STATIC) || method->klass->valuetype))
9530                                         mono_get_vtable_var (cfg);
9531                         }
9532
9533                         if (pass_vtable) {
9534                                 if (context_used) {
9535                                         vtable_arg = emit_get_rgctx_klass (cfg, context_used, cmethod->klass, MONO_RGCTX_INFO_VTABLE);
9536                                 } else {
9537                                         MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
9538
9539                                         CHECK_TYPELOAD (cmethod->klass);
9540                                         EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
9541                                 }
9542                         }
9543
9544                         if (pass_mrgctx) {
9545                                 g_assert (!vtable_arg);
9546
9547                                 if (!cfg->compile_aot) {
9548                                         /* 
9549                                          * emit_get_rgctx_method () calls mono_class_vtable () so check 
9550                                          * for type load errors before.
9551                                          */
9552                                         mono_class_setup_vtable (cmethod->klass);
9553                                         CHECK_TYPELOAD (cmethod->klass);
9554                                 }
9555
9556                                 vtable_arg = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
9557
9558                                 /* !marshalbyref is needed to properly handle generic methods + remoting */
9559                                 if ((!(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
9560                                          MONO_METHOD_IS_FINAL (cmethod)) &&
9561                                         !mono_class_is_marshalbyref (cmethod->klass)) {
9562                                         if (virtual_)
9563                                                 check_this = TRUE;
9564                                         virtual_ = 0;
9565                                 }
9566                         }
9567
9568                         if (pass_imt_from_rgctx) {
9569                                 g_assert (!pass_vtable);
9570
9571                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9572                                         cmethod, MONO_RGCTX_INFO_METHOD);
9573                         }
9574
9575                         if (check_this)
9576                                 MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
9577
9578                         /* Calling virtual generic methods */
9579                         if (virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) &&
9580                             !(MONO_METHOD_IS_FINAL (cmethod) && 
9581                               cmethod->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK) &&
9582                             fsig->generic_param_count && 
9583                                 !(cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) &&
9584                                 !cfg->llvm_only) {
9585                                 MonoInst *this_temp, *this_arg_temp, *store;
9586                                 MonoInst *iargs [4];
9587
9588                                 g_assert (fsig->is_inflated);
9589
9590                                 /* Prevent inlining of methods that contain indirect calls */
9591                                 INLINE_FAILURE ("virtual generic call");
9592
9593                                 if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig))
9594                                         GSHAREDVT_FAILURE (*ip);
9595
9596                                 if (cfg->backend->have_generalized_imt_thunk && cfg->backend->gshared_supported && cmethod->wrapper_type == MONO_WRAPPER_NONE) {
9597                                         g_assert (!imt_arg);
9598                                         if (!context_used)
9599                                                 g_assert (cmethod->is_inflated);
9600                                         imt_arg = emit_get_rgctx_method (cfg, context_used,
9601                                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
9602                                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, sp [0], imt_arg, NULL);
9603                                 } else {
9604                                         this_temp = mono_compile_create_var (cfg, type_from_stack_type (sp [0]), OP_LOCAL);
9605                                         NEW_TEMPSTORE (cfg, store, this_temp->inst_c0, sp [0]);
9606                                         MONO_ADD_INS (cfg->cbb, store);
9607
9608                                         /* FIXME: This should be a managed pointer */
9609                                         this_arg_temp = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
9610
9611                                         EMIT_NEW_TEMPLOAD (cfg, iargs [0], this_temp->inst_c0);
9612                                         iargs [1] = emit_get_rgctx_method (cfg, context_used,
9613                                                                                                            cmethod, MONO_RGCTX_INFO_METHOD);
9614                                         EMIT_NEW_TEMPLOADA (cfg, iargs [2], this_arg_temp->inst_c0);
9615                                         addr = mono_emit_jit_icall (cfg,
9616                                                                                                 mono_helper_compile_generic_method, iargs);
9617
9618                                         EMIT_NEW_TEMPLOAD (cfg, sp [0], this_arg_temp->inst_c0);
9619
9620                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9621                                 }
9622
9623                                 goto call_end;
9624                         }
9625
9626                         /*
9627                          * Implement a workaround for the inherent races involved in locking:
9628                          * Monitor.Enter ()
9629                          * try {
9630                          * } finally {
9631                          *    Monitor.Exit ()
9632                          * }
9633                          * If a thread abort happens between the call to Monitor.Enter () and the start of the
9634                          * try block, the Exit () won't be executed, see:
9635                          * http://www.bluebytesoftware.com/blog/2007/01/30/MonitorEnterThreadAbortsAndOrphanedLocks.aspx
9636                          * To work around this, we extend such try blocks to include the last x bytes
9637                          * of the Monitor.Enter () call.
9638                          */
9639                         if (cmethod->klass == mono_defaults.monitor_class && !strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1) {
9640                                 MonoBasicBlock *tbb;
9641
9642                                 GET_BBLOCK (cfg, tbb, ip + 5);
9643                                 /* 
9644                                  * Only extend try blocks with a finally, to avoid catching exceptions thrown
9645                                  * from Monitor.Enter like ArgumentNullException.
9646                                  */
9647                                 if (tbb->try_start && MONO_REGION_FLAGS(tbb->region) == MONO_EXCEPTION_CLAUSE_FINALLY) {
9648                                         /* Mark this bblock as needing to be extended */
9649                                         tbb->extend_try_block = TRUE;
9650                                 }
9651                         }
9652
9653                         /* Conversion to a JIT intrinsic */
9654                         if ((cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_method (cfg, cmethod, fsig, sp))) {
9655                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9656                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
9657                                         emit_widen = FALSE;
9658                                 }
9659                                 goto call_end;
9660                         }
9661
9662                         /* Inlining */
9663                         if ((cfg->opt & MONO_OPT_INLINE) &&
9664                                 (!virtual_ || !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) || MONO_METHOD_IS_FINAL (cmethod)) &&
9665                             mono_method_check_inlining (cfg, cmethod)) {
9666                                 int costs;
9667                                 gboolean always = FALSE;
9668
9669                                 if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
9670                                         (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
9671                                         /* Prevent inlining of methods that call wrappers */
9672                                         INLINE_FAILURE ("wrapper call");
9673                                         cmethod = mono_marshal_get_native_wrapper (cmethod, TRUE, FALSE);
9674                                         always = TRUE;
9675                                 }
9676
9677                                 costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, always);
9678                                 if (costs) {
9679                                         cfg->real_offset += 5;
9680
9681                                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9682                                                 /* *sp is already set by inline_method */
9683                                                 sp++;
9684                                                 push_res = FALSE;
9685                                         }
9686
9687                                         inline_costs += costs;
9688
9689                                         goto call_end;
9690                                 }
9691                         }
9692
9693                         /* Tail recursion elimination */
9694                         if ((cfg->opt & MONO_OPT_TAILC) && call_opcode == CEE_CALL && cmethod == method && ip [5] == CEE_RET && !vtable_arg) {
9695                                 gboolean has_vtargs = FALSE;
9696                                 int i;
9697
9698                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
9699                                 INLINE_FAILURE ("tail call");
9700
9701                                 /* keep it simple */
9702                                 for (i =  fsig->param_count - 1; i >= 0; i--) {
9703                                         if (MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->params [i])) 
9704                                                 has_vtargs = TRUE;
9705                                 }
9706
9707                                 if (!has_vtargs) {
9708                                         for (i = 0; i < n; ++i)
9709                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
9710                                         MONO_INST_NEW (cfg, ins, OP_BR);
9711                                         MONO_ADD_INS (cfg->cbb, ins);
9712                                         tblock = start_bblock->out_bb [0];
9713                                         link_bblock (cfg, cfg->cbb, tblock);
9714                                         ins->inst_target_bb = tblock;
9715                                         start_new_bblock = 1;
9716
9717                                         /* skip the CEE_RET, too */
9718                                         if (ip_in_bb (cfg, cfg->cbb, ip + 5))
9719                                                 skip_ret = TRUE;
9720                                         push_res = FALSE;
9721                                         goto call_end;
9722                                 }
9723                         }
9724
9725                         inline_costs += 10 * num_calls++;
9726
9727                         /*
9728                          * Making generic calls out of gsharedvt methods.
9729                          * This needs to be used for all generic calls, not just ones with a gsharedvt signature, to avoid
9730                          * patching gshared method addresses into a gsharedvt method.
9731                          */
9732                         if (cfg->gsharedvt && (mini_is_gsharedvt_signature (fsig) || cmethod->is_inflated || cmethod->klass->generic_class) &&
9733                                 !(cmethod->klass->rank && cmethod->klass->byval_arg.type != MONO_TYPE_SZARRAY) &&
9734                                 (!(cfg->llvm_only && virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL)))) {
9735                                 MonoRgctxInfoType info_type;
9736
9737                                 if (virtual_) {
9738                                         //if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)
9739                                                 //GSHAREDVT_FAILURE (*ip);
9740                                         // disable for possible remoting calls
9741                                         if (fsig->hasthis && (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class))
9742                                                 GSHAREDVT_FAILURE (*ip);
9743                                         if (fsig->generic_param_count) {
9744                                                 /* virtual generic call */
9745                                                 g_assert (!imt_arg);
9746                                                 /* Same as the virtual generic case above */
9747                                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9748                                                                                                                  cmethod, MONO_RGCTX_INFO_METHOD);
9749                                                 /* This is not needed, as the trampoline code will pass one, and it might be passed in the same reg as the imt arg */
9750                                                 vtable_arg = NULL;
9751                                         } else if ((cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) && !imt_arg) {
9752                                                 /* This can happen when we call a fully instantiated iface method */
9753                                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9754                                                                                                                  cmethod, MONO_RGCTX_INFO_METHOD);
9755                                                 vtable_arg = NULL;
9756                                         }
9757                                 }
9758
9759                                 if ((cmethod->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (cmethod->name, "Invoke")))
9760                                         keep_this_alive = sp [0];
9761
9762                                 if (virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))
9763                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
9764                                 else
9765                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE;
9766                                 addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, info_type);
9767
9768                                 if (cfg->llvm_only) {
9769                                         // FIXME: Avoid initializing vtable_arg
9770                                         ins = emit_llvmonly_calli (cfg, fsig, sp, addr);
9771                                 } else {
9772                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
9773                                 }
9774                                 goto call_end;
9775                         }
9776
9777                         /* Generic sharing */
9778
9779                         /*
9780                          * Use this if the callee is gsharedvt sharable too, since
9781                          * at runtime we might find an instantiation so the call cannot
9782                          * be patched (the 'no_patch' code path in mini-trampolines.c).
9783                          */
9784                         if (context_used && !imt_arg && !array_rank && !delegate_invoke &&
9785                                 (!mono_method_is_generic_sharable_full (cmethod, TRUE, FALSE, FALSE) ||
9786                                  !mono_class_generic_sharing_enabled (cmethod->klass)) &&
9787                                 (!virtual_ || MONO_METHOD_IS_FINAL (cmethod) ||
9788                                  !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))) {
9789                                 INLINE_FAILURE ("gshared");
9790
9791                                 g_assert (cfg->gshared && cmethod);
9792                                 g_assert (!addr);
9793
9794                                 /*
9795                                  * We are compiling a call to a
9796                                  * generic method from shared code,
9797                                  * which means that we have to look up
9798                                  * the method in the rgctx and do an
9799                                  * indirect call.
9800                                  */
9801                                 if (fsig->hasthis)
9802                                         MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
9803
9804                                 if (cfg->llvm_only) {
9805                                         if (cfg->gsharedvt && mini_is_gsharedvt_variable_signature (fsig))
9806                                                 addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER);
9807                                         else
9808                                                 addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
9809                                         // FIXME: Avoid initializing imt_arg/vtable_arg
9810                                         ins = emit_llvmonly_calli (cfg, fsig, sp, addr);
9811                                 } else {
9812                                         addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
9813                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
9814                                 }
9815                                 goto call_end;
9816                         }
9817
9818                         /* Direct calls to icalls */
9819                         if (direct_icall) {
9820                                 MonoMethod *wrapper;
9821                                 int costs;
9822
9823                                 /* Inline the wrapper */
9824                                 wrapper = mono_marshal_get_native_wrapper (cmethod, TRUE, cfg->compile_aot);
9825
9826                                 costs = inline_method (cfg, wrapper, fsig, sp, ip, cfg->real_offset, TRUE);
9827                                 g_assert (costs > 0);
9828                                 cfg->real_offset += 5;
9829
9830                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9831                                         /* *sp is already set by inline_method */
9832                                         sp++;
9833                                         push_res = FALSE;
9834                                 }
9835
9836                                 inline_costs += costs;
9837
9838                                 goto call_end;
9839                         }
9840                                         
9841                         /* Array methods */
9842                         if (array_rank) {
9843                                 MonoInst *addr;
9844
9845                                 if (strcmp (cmethod->name, "Set") == 0) { /* array Set */ 
9846                                         MonoInst *val = sp [fsig->param_count];
9847
9848                                         if (val->type == STACK_OBJ) {
9849                                                 MonoInst *iargs [2];
9850
9851                                                 iargs [0] = sp [0];
9852                                                 iargs [1] = val;
9853                                                 
9854                                                 mono_emit_jit_icall (cfg, mono_helper_stelem_ref_check, iargs);
9855                                         }
9856                                         
9857                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, TRUE);
9858                                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, fsig->params [fsig->param_count - 1], addr->dreg, 0, val->dreg);
9859                                         if (cfg->gen_write_barriers && val->type == STACK_OBJ && !(val->opcode == OP_PCONST && val->inst_c0 == 0))
9860                                                 emit_write_barrier (cfg, addr, val);
9861                                         if (cfg->gen_write_barriers && mini_is_gsharedvt_klass (cmethod->klass))
9862                                                 GSHAREDVT_FAILURE (*ip);
9863                                 } else if (strcmp (cmethod->name, "Get") == 0) { /* array Get */
9864                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
9865
9866                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, addr->dreg, 0);
9867                                 } else if (strcmp (cmethod->name, "Address") == 0) { /* array Address */
9868                                         if (!cmethod->klass->element_class->valuetype && !readonly)
9869                                                 mini_emit_check_array_type (cfg, sp [0], cmethod->klass);
9870                                         CHECK_TYPELOAD (cmethod->klass);
9871                                         
9872                                         readonly = FALSE;
9873                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
9874                                         ins = addr;
9875                                 } else {
9876                                         g_assert_not_reached ();
9877                                 }
9878
9879                                 emit_widen = FALSE;
9880                                 goto call_end;
9881                         }
9882
9883                         ins = mini_redirect_call (cfg, cmethod, fsig, sp, virtual_ ? sp [0] : NULL);
9884                         if (ins)
9885                                 goto call_end;
9886
9887                         /* Tail prefix / tail call optimization */
9888
9889                         /* FIXME: Enabling TAILC breaks some inlining/stack trace/etc tests */
9890                         /* FIXME: runtime generic context pointer for jumps? */
9891                         /* FIXME: handle this for generic sharing eventually */
9892                         if ((ins_flag & MONO_INST_TAILCALL) &&
9893                                 !vtable_arg && !cfg->gshared && is_supported_tail_call (cfg, method, cmethod, fsig, call_opcode))
9894                                 supported_tail_call = TRUE;
9895
9896                         if (supported_tail_call) {
9897                                 MonoCallInst *call;
9898
9899                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
9900                                 INLINE_FAILURE ("tail call");
9901
9902                                 //printf ("HIT: %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
9903
9904                                 if (cfg->backend->have_op_tail_call) {
9905                                         /* Handle tail calls similarly to normal calls */
9906                                         tail_call = TRUE;
9907                                 } else {
9908                                         emit_instrumentation_call (cfg, mono_profiler_method_leave);
9909
9910                                         MONO_INST_NEW_CALL (cfg, call, OP_JMP);
9911                                         call->tail_call = TRUE;
9912                                         call->method = cmethod;
9913                                         call->signature = mono_method_signature (cmethod);
9914
9915                                         /*
9916                                          * We implement tail calls by storing the actual arguments into the 
9917                                          * argument variables, then emitting a CEE_JMP.
9918                                          */
9919                                         for (i = 0; i < n; ++i) {
9920                                                 /* Prevent argument from being register allocated */
9921                                                 arg_array [i]->flags |= MONO_INST_VOLATILE;
9922                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
9923                                         }
9924                                         ins = (MonoInst*)call;
9925                                         ins->inst_p0 = cmethod;
9926                                         ins->inst_p1 = arg_array [0];
9927                                         MONO_ADD_INS (cfg->cbb, ins);
9928                                         link_bblock (cfg, cfg->cbb, end_bblock);
9929                                         start_new_bblock = 1;
9930
9931                                         // FIXME: Eliminate unreachable epilogs
9932
9933                                         /*
9934                                          * OP_TAILCALL has no return value, so skip the CEE_RET if it is
9935                                          * only reachable from this call.
9936                                          */
9937                                         GET_BBLOCK (cfg, tblock, ip + 5);
9938                                         if (tblock == cfg->cbb || tblock->in_count == 0)
9939                                                 skip_ret = TRUE;
9940                                         push_res = FALSE;
9941
9942                                         goto call_end;
9943                                 }
9944                         }
9945
9946                         /* 
9947                          * Synchronized wrappers.
9948                          * Its hard to determine where to replace a method with its synchronized
9949                          * wrapper without causing an infinite recursion. The current solution is
9950                          * to add the synchronized wrapper in the trampolines, and to
9951                          * change the called method to a dummy wrapper, and resolve that wrapper
9952                          * to the real method in mono_jit_compile_method ().
9953                          */
9954                         if (cfg->method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
9955                                 MonoMethod *orig = mono_marshal_method_from_wrapper (cfg->method);
9956                                 if (cmethod == orig || (cmethod->is_inflated && mono_method_get_declaring_generic_method (cmethod) == orig))
9957                                         cmethod = mono_marshal_get_synchronized_inner_wrapper (cmethod);
9958                         }
9959
9960                         /*
9961                          * Virtual calls in llvm-only mode.
9962                          */
9963                         if (cfg->llvm_only && virtual_ && cmethod && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
9964                                 ins = emit_llvmonly_virtual_call (cfg, cmethod, fsig, context_used, sp);
9965                                 goto call_end;
9966                         }
9967
9968                         /* Common call */
9969                         INLINE_FAILURE ("call");
9970                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, tail_call, sp, virtual_ ? sp [0] : NULL,
9971                                                                                           imt_arg, vtable_arg);
9972
9973                         if (tail_call && !cfg->llvm_only) {
9974                                 link_bblock (cfg, cfg->cbb, end_bblock);
9975                                 start_new_bblock = 1;
9976
9977                                 // FIXME: Eliminate unreachable epilogs
9978
9979                                 /*
9980                                  * OP_TAILCALL has no return value, so skip the CEE_RET if it is
9981                                  * only reachable from this call.
9982                                  */
9983                                 GET_BBLOCK (cfg, tblock, ip + 5);
9984                                 if (tblock == cfg->cbb || tblock->in_count == 0)
9985                                         skip_ret = TRUE;
9986                                 push_res = FALSE;
9987                         }
9988
9989                         call_end:
9990
9991                         /* End of call, INS should contain the result of the call, if any */
9992
9993                         if (push_res && !MONO_TYPE_IS_VOID (fsig->ret)) {
9994                                 g_assert (ins);
9995                                 if (emit_widen)
9996                                         *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
9997                                 else
9998                                         *sp++ = ins;
9999                         }
10000
10001                         if (keep_this_alive) {
10002                                 MonoInst *dummy_use;
10003
10004                                 /* See mono_emit_method_call_full () */
10005                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, keep_this_alive);
10006                         }
10007
10008                         CHECK_CFG_EXCEPTION;
10009
10010                         ip += 5;
10011                         if (skip_ret) {
10012                                 g_assert (*ip == CEE_RET);
10013                                 ip += 1;
10014                         }
10015                         ins_flag = 0;
10016                         constrained_class = NULL;
10017                         if (need_seq_point)
10018                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
10019                         break;
10020                 }
10021                 case CEE_RET:
10022                         if (cfg->method != method) {
10023                                 /* return from inlined method */
10024                                 /* 
10025                                  * If in_count == 0, that means the ret is unreachable due to
10026                                  * being preceeded by a throw. In that case, inline_method () will
10027                                  * handle setting the return value 
10028                                  * (test case: test_0_inline_throw ()).
10029                                  */
10030                                 if (return_var && cfg->cbb->in_count) {
10031                                         MonoType *ret_type = mono_method_signature (method)->ret;
10032
10033                                         MonoInst *store;
10034                                         CHECK_STACK (1);
10035                                         --sp;
10036
10037                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
10038                                                 UNVERIFIED;
10039
10040                                         //g_assert (returnvar != -1);
10041                                         EMIT_NEW_TEMPSTORE (cfg, store, return_var->inst_c0, *sp);
10042                                         cfg->ret_var_set = TRUE;
10043                                 } 
10044                         } else {
10045                                 emit_instrumentation_call (cfg, mono_profiler_method_leave);
10046
10047                                 if (cfg->lmf_var && cfg->cbb->in_count && !cfg->llvm_only)
10048                                         emit_pop_lmf (cfg);
10049
10050                                 if (cfg->ret) {
10051                                         MonoType *ret_type = mini_get_underlying_type (mono_method_signature (method)->ret);
10052
10053                                         if (seq_points && !sym_seq_points) {
10054                                                 /* 
10055                                                  * Place a seq point here too even through the IL stack is not
10056                                                  * empty, so a step over on
10057                                                  * call <FOO>
10058                                                  * ret
10059                                                  * will work correctly.
10060                                                  */
10061                                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, TRUE);
10062                                                 MONO_ADD_INS (cfg->cbb, ins);
10063                                         }
10064
10065                                         g_assert (!return_var);
10066                                         CHECK_STACK (1);
10067                                         --sp;
10068
10069                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
10070                                                 UNVERIFIED;
10071
10072                                         emit_setret (cfg, *sp);
10073                                 }
10074                         }
10075                         if (sp != stack_start)
10076                                 UNVERIFIED;
10077                         MONO_INST_NEW (cfg, ins, OP_BR);
10078                         ip++;
10079                         ins->inst_target_bb = end_bblock;
10080                         MONO_ADD_INS (cfg->cbb, ins);
10081                         link_bblock (cfg, cfg->cbb, end_bblock);
10082                         start_new_bblock = 1;
10083                         break;
10084                 case CEE_BR_S:
10085                         CHECK_OPSIZE (2);
10086                         MONO_INST_NEW (cfg, ins, OP_BR);
10087                         ip++;
10088                         target = ip + 1 + (signed char)(*ip);
10089                         ++ip;
10090                         GET_BBLOCK (cfg, tblock, target);
10091                         link_bblock (cfg, cfg->cbb, tblock);
10092                         ins->inst_target_bb = tblock;
10093                         if (sp != stack_start) {
10094                                 handle_stack_args (cfg, stack_start, sp - stack_start);
10095                                 sp = stack_start;
10096                                 CHECK_UNVERIFIABLE (cfg);
10097                         }
10098                         MONO_ADD_INS (cfg->cbb, ins);
10099                         start_new_bblock = 1;
10100                         inline_costs += BRANCH_COST;
10101                         break;
10102                 case CEE_BEQ_S:
10103                 case CEE_BGE_S:
10104                 case CEE_BGT_S:
10105                 case CEE_BLE_S:
10106                 case CEE_BLT_S:
10107                 case CEE_BNE_UN_S:
10108                 case CEE_BGE_UN_S:
10109                 case CEE_BGT_UN_S:
10110                 case CEE_BLE_UN_S:
10111                 case CEE_BLT_UN_S:
10112                         CHECK_OPSIZE (2);
10113                         CHECK_STACK (2);
10114                         MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
10115                         ip++;
10116                         target = ip + 1 + *(signed char*)ip;
10117                         ip++;
10118
10119                         ADD_BINCOND (NULL);
10120
10121                         sp = stack_start;
10122                         inline_costs += BRANCH_COST;
10123                         break;
10124                 case CEE_BR:
10125                         CHECK_OPSIZE (5);
10126                         MONO_INST_NEW (cfg, ins, OP_BR);
10127                         ip++;
10128
10129                         target = ip + 4 + (gint32)read32(ip);
10130                         ip += 4;
10131                         GET_BBLOCK (cfg, tblock, target);
10132                         link_bblock (cfg, cfg->cbb, tblock);
10133                         ins->inst_target_bb = tblock;
10134                         if (sp != stack_start) {
10135                                 handle_stack_args (cfg, stack_start, sp - stack_start);
10136                                 sp = stack_start;
10137                                 CHECK_UNVERIFIABLE (cfg);
10138                         }
10139
10140                         MONO_ADD_INS (cfg->cbb, ins);
10141
10142                         start_new_bblock = 1;
10143                         inline_costs += BRANCH_COST;
10144                         break;
10145                 case CEE_BRFALSE_S:
10146                 case CEE_BRTRUE_S:
10147                 case CEE_BRFALSE:
10148                 case CEE_BRTRUE: {
10149                         MonoInst *cmp;
10150                         gboolean is_short = ((*ip) == CEE_BRFALSE_S) || ((*ip) == CEE_BRTRUE_S);
10151                         gboolean is_true = ((*ip) == CEE_BRTRUE_S) || ((*ip) == CEE_BRTRUE);
10152                         guint32 opsize = is_short ? 1 : 4;
10153
10154                         CHECK_OPSIZE (opsize);
10155                         CHECK_STACK (1);
10156                         if (sp [-1]->type == STACK_VTYPE || sp [-1]->type == STACK_R8)
10157                                 UNVERIFIED;
10158                         ip ++;
10159                         target = ip + opsize + (is_short ? *(signed char*)ip : (gint32)read32(ip));
10160                         ip += opsize;
10161
10162                         sp--;
10163
10164                         GET_BBLOCK (cfg, tblock, target);
10165                         link_bblock (cfg, cfg->cbb, tblock);
10166                         GET_BBLOCK (cfg, tblock, ip);
10167                         link_bblock (cfg, cfg->cbb, tblock);
10168
10169                         if (sp != stack_start) {
10170                                 handle_stack_args (cfg, stack_start, sp - stack_start);
10171                                 CHECK_UNVERIFIABLE (cfg);
10172                         }
10173
10174                         MONO_INST_NEW(cfg, cmp, OP_ICOMPARE_IMM);
10175                         cmp->sreg1 = sp [0]->dreg;
10176                         type_from_op (cfg, cmp, sp [0], NULL);
10177                         CHECK_TYPE (cmp);
10178
10179 #if SIZEOF_REGISTER == 4
10180                         if (cmp->opcode == OP_LCOMPARE_IMM) {
10181                                 /* Convert it to OP_LCOMPARE */
10182                                 MONO_INST_NEW (cfg, ins, OP_I8CONST);
10183                                 ins->type = STACK_I8;
10184                                 ins->dreg = alloc_dreg (cfg, STACK_I8);
10185                                 ins->inst_l = 0;
10186                                 MONO_ADD_INS (cfg->cbb, ins);
10187                                 cmp->opcode = OP_LCOMPARE;
10188                                 cmp->sreg2 = ins->dreg;
10189                         }
10190 #endif
10191                         MONO_ADD_INS (cfg->cbb, cmp);
10192
10193                         MONO_INST_NEW (cfg, ins, is_true ? CEE_BNE_UN : CEE_BEQ);
10194                         type_from_op (cfg, ins, sp [0], NULL);
10195                         MONO_ADD_INS (cfg->cbb, ins);
10196                         ins->inst_many_bb = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);
10197                         GET_BBLOCK (cfg, tblock, target);
10198                         ins->inst_true_bb = tblock;
10199                         GET_BBLOCK (cfg, tblock, ip);
10200                         ins->inst_false_bb = tblock;
10201                         start_new_bblock = 2;
10202
10203                         sp = stack_start;
10204                         inline_costs += BRANCH_COST;
10205                         break;
10206                 }
10207                 case CEE_BEQ:
10208                 case CEE_BGE:
10209                 case CEE_BGT:
10210                 case CEE_BLE:
10211                 case CEE_BLT:
10212                 case CEE_BNE_UN:
10213                 case CEE_BGE_UN:
10214                 case CEE_BGT_UN:
10215                 case CEE_BLE_UN:
10216                 case CEE_BLT_UN:
10217                         CHECK_OPSIZE (5);
10218                         CHECK_STACK (2);
10219                         MONO_INST_NEW (cfg, ins, *ip);
10220                         ip++;
10221                         target = ip + 4 + (gint32)read32(ip);
10222                         ip += 4;
10223
10224                         ADD_BINCOND (NULL);
10225
10226                         sp = stack_start;
10227                         inline_costs += BRANCH_COST;
10228                         break;
10229                 case CEE_SWITCH: {
10230                         MonoInst *src1;
10231                         MonoBasicBlock **targets;
10232                         MonoBasicBlock *default_bblock;
10233                         MonoJumpInfoBBTable *table;
10234                         int offset_reg = alloc_preg (cfg);
10235                         int target_reg = alloc_preg (cfg);
10236                         int table_reg = alloc_preg (cfg);
10237                         int sum_reg = alloc_preg (cfg);
10238                         gboolean use_op_switch;
10239
10240                         CHECK_OPSIZE (5);
10241                         CHECK_STACK (1);
10242                         n = read32 (ip + 1);
10243                         --sp;
10244                         src1 = sp [0];
10245                         if ((src1->type != STACK_I4) && (src1->type != STACK_PTR)) 
10246                                 UNVERIFIED;
10247
10248                         ip += 5;
10249                         CHECK_OPSIZE (n * sizeof (guint32));
10250                         target = ip + n * sizeof (guint32);
10251
10252                         GET_BBLOCK (cfg, default_bblock, target);
10253                         default_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
10254
10255                         targets = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * n);
10256                         for (i = 0; i < n; ++i) {
10257                                 GET_BBLOCK (cfg, tblock, target + (gint32)read32(ip));
10258                                 targets [i] = tblock;
10259                                 targets [i]->flags |= BB_INDIRECT_JUMP_TARGET;
10260                                 ip += 4;
10261                         }
10262
10263                         if (sp != stack_start) {
10264                                 /* 
10265                                  * Link the current bb with the targets as well, so handle_stack_args
10266                                  * will set their in_stack correctly.
10267                                  */
10268                                 link_bblock (cfg, cfg->cbb, default_bblock);
10269                                 for (i = 0; i < n; ++i)
10270                                         link_bblock (cfg, cfg->cbb, targets [i]);
10271
10272                                 handle_stack_args (cfg, stack_start, sp - stack_start);
10273                                 sp = stack_start;
10274                                 CHECK_UNVERIFIABLE (cfg);
10275
10276                                 /* Undo the links */
10277                                 mono_unlink_bblock (cfg, cfg->cbb, default_bblock);
10278                                 for (i = 0; i < n; ++i)
10279                                         mono_unlink_bblock (cfg, cfg->cbb, targets [i]);
10280                         }
10281
10282                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, src1->dreg, n);
10283                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBGE_UN, default_bblock);
10284
10285                         for (i = 0; i < n; ++i)
10286                                 link_bblock (cfg, cfg->cbb, targets [i]);
10287
10288                         table = (MonoJumpInfoBBTable *)mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfoBBTable));
10289                         table->table = targets;
10290                         table->table_size = n;
10291
10292                         use_op_switch = FALSE;
10293 #ifdef TARGET_ARM
10294                         /* ARM implements SWITCH statements differently */
10295                         /* FIXME: Make it use the generic implementation */
10296                         if (!cfg->compile_aot)
10297                                 use_op_switch = TRUE;
10298 #endif
10299
10300                         if (COMPILE_LLVM (cfg))
10301                                 use_op_switch = TRUE;
10302
10303                         cfg->cbb->has_jump_table = 1;
10304
10305                         if (use_op_switch) {
10306                                 MONO_INST_NEW (cfg, ins, OP_SWITCH);
10307                                 ins->sreg1 = src1->dreg;
10308                                 ins->inst_p0 = table;
10309                                 ins->inst_many_bb = targets;
10310                                 ins->klass = (MonoClass *)GUINT_TO_POINTER (n);
10311                                 MONO_ADD_INS (cfg->cbb, ins);
10312                         } else {
10313                                 if (sizeof (gpointer) == 8)
10314                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 3);
10315                                 else
10316                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 2);
10317
10318 #if SIZEOF_REGISTER == 8
10319                                 /* The upper word might not be zero, and we add it to a 64 bit address later */
10320                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, offset_reg, offset_reg);
10321 #endif
10322
10323                                 if (cfg->compile_aot) {
10324                                         MONO_EMIT_NEW_AOTCONST (cfg, table_reg, table, MONO_PATCH_INFO_SWITCH);
10325                                 } else {
10326                                         MONO_INST_NEW (cfg, ins, OP_JUMP_TABLE);
10327                                         ins->inst_c1 = MONO_PATCH_INFO_SWITCH;
10328                                         ins->inst_p0 = table;
10329                                         ins->dreg = table_reg;
10330                                         MONO_ADD_INS (cfg->cbb, ins);
10331                                 }
10332
10333                                 /* FIXME: Use load_memindex */
10334                                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, table_reg, offset_reg);
10335                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, target_reg, sum_reg, 0);
10336                                 MONO_EMIT_NEW_UNALU (cfg, OP_BR_REG, -1, target_reg);
10337                         }
10338                         start_new_bblock = 1;
10339                         inline_costs += (BRANCH_COST * 2);
10340                         break;
10341                 }
10342                 case CEE_LDIND_I1:
10343                 case CEE_LDIND_U1:
10344                 case CEE_LDIND_I2:
10345                 case CEE_LDIND_U2:
10346                 case CEE_LDIND_I4:
10347                 case CEE_LDIND_U4:
10348                 case CEE_LDIND_I8:
10349                 case CEE_LDIND_I:
10350                 case CEE_LDIND_R4:
10351                 case CEE_LDIND_R8:
10352                 case CEE_LDIND_REF:
10353                         CHECK_STACK (1);
10354                         --sp;
10355
10356                         switch (*ip) {
10357                         case CEE_LDIND_R4:
10358                         case CEE_LDIND_R8:
10359                                 dreg = alloc_freg (cfg);
10360                                 break;
10361                         case CEE_LDIND_I8:
10362                                 dreg = alloc_lreg (cfg);
10363                                 break;
10364                         case CEE_LDIND_REF:
10365                                 dreg = alloc_ireg_ref (cfg);
10366                                 break;
10367                         default:
10368                                 dreg = alloc_preg (cfg);
10369                         }
10370
10371                         NEW_LOAD_MEMBASE (cfg, ins, ldind_to_load_membase (*ip), dreg, sp [0]->dreg, 0);
10372                         ins->type = ldind_type [*ip - CEE_LDIND_I1];
10373                         if (*ip == CEE_LDIND_R4)
10374                                 ins->type = cfg->r4_stack_type;
10375                         ins->flags |= ins_flag;
10376                         MONO_ADD_INS (cfg->cbb, ins);
10377                         *sp++ = ins;
10378                         if (ins_flag & MONO_INST_VOLATILE) {
10379                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10380                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10381                         }
10382                         ins_flag = 0;
10383                         ++ip;
10384                         break;
10385                 case CEE_STIND_REF:
10386                 case CEE_STIND_I1:
10387                 case CEE_STIND_I2:
10388                 case CEE_STIND_I4:
10389                 case CEE_STIND_I8:
10390                 case CEE_STIND_R4:
10391                 case CEE_STIND_R8:
10392                 case CEE_STIND_I:
10393                         CHECK_STACK (2);
10394                         sp -= 2;
10395
10396                         if (ins_flag & MONO_INST_VOLATILE) {
10397                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
10398                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
10399                         }
10400
10401                         NEW_STORE_MEMBASE (cfg, ins, stind_to_store_membase (*ip), sp [0]->dreg, 0, sp [1]->dreg);
10402                         ins->flags |= ins_flag;
10403                         ins_flag = 0;
10404
10405                         MONO_ADD_INS (cfg->cbb, ins);
10406
10407                         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)))
10408                                 emit_write_barrier (cfg, sp [0], sp [1]);
10409
10410                         inline_costs += 1;
10411                         ++ip;
10412                         break;
10413
10414                 case CEE_MUL:
10415                         CHECK_STACK (2);
10416
10417                         MONO_INST_NEW (cfg, ins, (*ip));
10418                         sp -= 2;
10419                         ins->sreg1 = sp [0]->dreg;
10420                         ins->sreg2 = sp [1]->dreg;
10421                         type_from_op (cfg, ins, sp [0], sp [1]);
10422                         CHECK_TYPE (ins);
10423                         ins->dreg = alloc_dreg ((cfg), (MonoStackType)(ins)->type);
10424
10425                         /* Use the immediate opcodes if possible */
10426                         if ((sp [1]->opcode == OP_ICONST) && mono_arch_is_inst_imm (sp [1]->inst_c0)) {
10427                                 int imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
10428                                 if (imm_opcode != -1) {
10429                                         ins->opcode = imm_opcode;
10430                                         ins->inst_p1 = (gpointer)(gssize)(sp [1]->inst_c0);
10431                                         ins->sreg2 = -1;
10432
10433                                         NULLIFY_INS (sp [1]);
10434                                 }
10435                         }
10436
10437                         MONO_ADD_INS ((cfg)->cbb, (ins));
10438
10439                         *sp++ = mono_decompose_opcode (cfg, ins);
10440                         ip++;
10441                         break;
10442                 case CEE_ADD:
10443                 case CEE_SUB:
10444                 case CEE_DIV:
10445                 case CEE_DIV_UN:
10446                 case CEE_REM:
10447                 case CEE_REM_UN:
10448                 case CEE_AND:
10449                 case CEE_OR:
10450                 case CEE_XOR:
10451                 case CEE_SHL:
10452                 case CEE_SHR:
10453                 case CEE_SHR_UN:
10454                         CHECK_STACK (2);
10455
10456                         MONO_INST_NEW (cfg, ins, (*ip));
10457                         sp -= 2;
10458                         ins->sreg1 = sp [0]->dreg;
10459                         ins->sreg2 = sp [1]->dreg;
10460                         type_from_op (cfg, ins, sp [0], sp [1]);
10461                         CHECK_TYPE (ins);
10462                         add_widen_op (cfg, ins, &sp [0], &sp [1]);
10463                         ins->dreg = alloc_dreg ((cfg), (MonoStackType)(ins)->type);
10464
10465                         /* FIXME: Pass opcode to is_inst_imm */
10466
10467                         /* Use the immediate opcodes if possible */
10468                         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)) {
10469                                 int imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
10470                                 if (imm_opcode != -1) {
10471                                         ins->opcode = imm_opcode;
10472                                         if (sp [1]->opcode == OP_I8CONST) {
10473 #if SIZEOF_REGISTER == 8
10474                                                 ins->inst_imm = sp [1]->inst_l;
10475 #else
10476                                                 ins->inst_ls_word = sp [1]->inst_ls_word;
10477                                                 ins->inst_ms_word = sp [1]->inst_ms_word;
10478 #endif
10479                                         }
10480                                         else
10481                                                 ins->inst_imm = (gssize)(sp [1]->inst_c0);
10482                                         ins->sreg2 = -1;
10483
10484                                         /* Might be followed by an instruction added by add_widen_op */
10485                                         if (sp [1]->next == NULL)
10486                                                 NULLIFY_INS (sp [1]);
10487                                 }
10488                         }
10489                         MONO_ADD_INS ((cfg)->cbb, (ins));
10490
10491                         *sp++ = mono_decompose_opcode (cfg, ins);
10492                         ip++;
10493                         break;
10494                 case CEE_NEG:
10495                 case CEE_NOT:
10496                 case CEE_CONV_I1:
10497                 case CEE_CONV_I2:
10498                 case CEE_CONV_I4:
10499                 case CEE_CONV_R4:
10500                 case CEE_CONV_R8:
10501                 case CEE_CONV_U4:
10502                 case CEE_CONV_I8:
10503                 case CEE_CONV_U8:
10504                 case CEE_CONV_OVF_I8:
10505                 case CEE_CONV_OVF_U8:
10506                 case CEE_CONV_R_UN:
10507                         CHECK_STACK (1);
10508
10509                         /* Special case this earlier so we have long constants in the IR */
10510                         if ((((*ip) == CEE_CONV_I8) || ((*ip) == CEE_CONV_U8)) && (sp [-1]->opcode == OP_ICONST)) {
10511                                 int data = sp [-1]->inst_c0;
10512                                 sp [-1]->opcode = OP_I8CONST;
10513                                 sp [-1]->type = STACK_I8;
10514 #if SIZEOF_REGISTER == 8
10515                                 if ((*ip) == CEE_CONV_U8)
10516                                         sp [-1]->inst_c0 = (guint32)data;
10517                                 else
10518                                         sp [-1]->inst_c0 = data;
10519 #else
10520                                 sp [-1]->inst_ls_word = data;
10521                                 if ((*ip) == CEE_CONV_U8)
10522                                         sp [-1]->inst_ms_word = 0;
10523                                 else
10524                                         sp [-1]->inst_ms_word = (data < 0) ? -1 : 0;
10525 #endif
10526                                 sp [-1]->dreg = alloc_dreg (cfg, STACK_I8);
10527                         }
10528                         else {
10529                                 ADD_UNOP (*ip);
10530                         }
10531                         ip++;
10532                         break;
10533                 case CEE_CONV_OVF_I4:
10534                 case CEE_CONV_OVF_I1:
10535                 case CEE_CONV_OVF_I2:
10536                 case CEE_CONV_OVF_I:
10537                 case CEE_CONV_OVF_U:
10538                         CHECK_STACK (1);
10539
10540                         if (sp [-1]->type == STACK_R8 || sp [-1]->type == STACK_R4) {
10541                                 ADD_UNOP (CEE_CONV_OVF_I8);
10542                                 ADD_UNOP (*ip);
10543                         } else {
10544                                 ADD_UNOP (*ip);
10545                         }
10546                         ip++;
10547                         break;
10548                 case CEE_CONV_OVF_U1:
10549                 case CEE_CONV_OVF_U2:
10550                 case CEE_CONV_OVF_U4:
10551                         CHECK_STACK (1);
10552
10553                         if (sp [-1]->type == STACK_R8 || sp [-1]->type == STACK_R4) {
10554                                 ADD_UNOP (CEE_CONV_OVF_U8);
10555                                 ADD_UNOP (*ip);
10556                         } else {
10557                                 ADD_UNOP (*ip);
10558                         }
10559                         ip++;
10560                         break;
10561                 case CEE_CONV_OVF_I1_UN:
10562                 case CEE_CONV_OVF_I2_UN:
10563                 case CEE_CONV_OVF_I4_UN:
10564                 case CEE_CONV_OVF_I8_UN:
10565                 case CEE_CONV_OVF_U1_UN:
10566                 case CEE_CONV_OVF_U2_UN:
10567                 case CEE_CONV_OVF_U4_UN:
10568                 case CEE_CONV_OVF_U8_UN:
10569                 case CEE_CONV_OVF_I_UN:
10570                 case CEE_CONV_OVF_U_UN:
10571                 case CEE_CONV_U2:
10572                 case CEE_CONV_U1:
10573                 case CEE_CONV_I:
10574                 case CEE_CONV_U:
10575                         CHECK_STACK (1);
10576                         ADD_UNOP (*ip);
10577                         CHECK_CFG_EXCEPTION;
10578                         ip++;
10579                         break;
10580                 case CEE_ADD_OVF:
10581                 case CEE_ADD_OVF_UN:
10582                 case CEE_MUL_OVF:
10583                 case CEE_MUL_OVF_UN:
10584                 case CEE_SUB_OVF:
10585                 case CEE_SUB_OVF_UN:
10586                         CHECK_STACK (2);
10587                         ADD_BINOP (*ip);
10588                         ip++;
10589                         break;
10590                 case CEE_CPOBJ:
10591                         GSHAREDVT_FAILURE (*ip);
10592                         CHECK_OPSIZE (5);
10593                         CHECK_STACK (2);
10594                         token = read32 (ip + 1);
10595                         klass = mini_get_class (method, token, generic_context);
10596                         CHECK_TYPELOAD (klass);
10597                         sp -= 2;
10598                         if (generic_class_is_reference_type (cfg, klass)) {
10599                                 MonoInst *store, *load;
10600                                 int dreg = alloc_ireg_ref (cfg);
10601
10602                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, dreg, sp [1]->dreg, 0);
10603                                 load->flags |= ins_flag;
10604                                 MONO_ADD_INS (cfg->cbb, load);
10605
10606                                 NEW_STORE_MEMBASE (cfg, store, OP_STORE_MEMBASE_REG, sp [0]->dreg, 0, dreg);
10607                                 store->flags |= ins_flag;
10608                                 MONO_ADD_INS (cfg->cbb, store);
10609
10610                                 if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER)
10611                                         emit_write_barrier (cfg, sp [0], sp [1]);
10612                         } else {
10613                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
10614                         }
10615                         ins_flag = 0;
10616                         ip += 5;
10617                         break;
10618                 case CEE_LDOBJ: {
10619                         int loc_index = -1;
10620                         int stloc_len = 0;
10621
10622                         CHECK_OPSIZE (5);
10623                         CHECK_STACK (1);
10624                         --sp;
10625                         token = read32 (ip + 1);
10626                         klass = mini_get_class (method, token, generic_context);
10627                         CHECK_TYPELOAD (klass);
10628
10629                         /* Optimize the common ldobj+stloc combination */
10630                         switch (ip [5]) {
10631                         case CEE_STLOC_S:
10632                                 loc_index = ip [6];
10633                                 stloc_len = 2;
10634                                 break;
10635                         case CEE_STLOC_0:
10636                         case CEE_STLOC_1:
10637                         case CEE_STLOC_2:
10638                         case CEE_STLOC_3:
10639                                 loc_index = ip [5] - CEE_STLOC_0;
10640                                 stloc_len = 1;
10641                                 break;
10642                         default:
10643                                 break;
10644                         }
10645
10646                         if ((loc_index != -1) && ip_in_bb (cfg, cfg->cbb, ip + 5)) {
10647                                 CHECK_LOCAL (loc_index);
10648
10649                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
10650                                 ins->dreg = cfg->locals [loc_index]->dreg;
10651                                 ins->flags |= ins_flag;
10652                                 ip += 5;
10653                                 ip += stloc_len;
10654                                 if (ins_flag & MONO_INST_VOLATILE) {
10655                                         /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10656                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10657                                 }
10658                                 ins_flag = 0;
10659                                 break;
10660                         }
10661
10662                         /* Optimize the ldobj+stobj combination */
10663                         /* The reference case ends up being a load+store anyway */
10664                         /* Skip this if the operation is volatile. */
10665                         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)) {
10666                                 CHECK_STACK (1);
10667
10668                                 sp --;
10669
10670                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
10671
10672                                 ip += 5 + 5;
10673                                 ins_flag = 0;
10674                                 break;
10675                         }
10676
10677                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
10678                         ins->flags |= ins_flag;
10679                         *sp++ = ins;
10680
10681                         if (ins_flag & MONO_INST_VOLATILE) {
10682                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10683                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10684                         }
10685
10686                         ip += 5;
10687                         ins_flag = 0;
10688                         inline_costs += 1;
10689                         break;
10690                 }
10691                 case CEE_LDSTR:
10692                         CHECK_STACK_OVF (1);
10693                         CHECK_OPSIZE (5);
10694                         n = read32 (ip + 1);
10695
10696                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
10697                                 EMIT_NEW_PCONST (cfg, ins, mono_method_get_wrapper_data (method, n));
10698                                 ins->type = STACK_OBJ;
10699                                 *sp = ins;
10700                         }
10701                         else if (method->wrapper_type != MONO_WRAPPER_NONE) {
10702                                 MonoInst *iargs [1];
10703                                 char *str = (char *)mono_method_get_wrapper_data (method, n);
10704
10705                                 if (cfg->compile_aot)
10706                                         EMIT_NEW_LDSTRLITCONST (cfg, iargs [0], str);
10707                                 else
10708                                         EMIT_NEW_PCONST (cfg, iargs [0], str);
10709                                 *sp = mono_emit_jit_icall (cfg, mono_string_new_wrapper, iargs);
10710                         } else {
10711                                 if (cfg->opt & MONO_OPT_SHARED) {
10712                                         MonoInst *iargs [3];
10713
10714                                         if (cfg->compile_aot) {
10715                                                 cfg->ldstr_list = g_list_prepend (cfg->ldstr_list, GINT_TO_POINTER (n));
10716                                         }
10717                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
10718                                         EMIT_NEW_IMAGECONST (cfg, iargs [1], image);
10719                                         EMIT_NEW_ICONST (cfg, iargs [2], mono_metadata_token_index (n));
10720                                         *sp = mono_emit_jit_icall (cfg, mono_ldstr, iargs);
10721                                         mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
10722                                 } else {
10723                                         if (cfg->cbb->out_of_line) {
10724                                                 MonoInst *iargs [2];
10725
10726                                                 if (image == mono_defaults.corlib) {
10727                                                         /* 
10728                                                          * Avoid relocations in AOT and save some space by using a 
10729                                                          * version of helper_ldstr specialized to mscorlib.
10730                                                          */
10731                                                         EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (n));
10732                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr_mscorlib, iargs);
10733                                                 } else {
10734                                                         /* Avoid creating the string object */
10735                                                         EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
10736                                                         EMIT_NEW_ICONST (cfg, iargs [1], mono_metadata_token_index (n));
10737                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr, iargs);
10738                                                 }
10739                                         } 
10740                                         else
10741                                         if (cfg->compile_aot) {
10742                                                 NEW_LDSTRCONST (cfg, ins, image, n);
10743                                                 *sp = ins;
10744                                                 MONO_ADD_INS (cfg->cbb, ins);
10745                                         } 
10746                                         else {
10747                                                 NEW_PCONST (cfg, ins, NULL);
10748                                                 ins->type = STACK_OBJ;
10749                                                 ins->inst_p0 = mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
10750                                                 if (!ins->inst_p0)
10751                                                         OUT_OF_MEMORY_FAILURE;
10752
10753                                                 *sp = ins;
10754                                                 MONO_ADD_INS (cfg->cbb, ins);
10755                                         }
10756                                 }
10757                         }
10758
10759                         sp++;
10760                         ip += 5;
10761                         break;
10762                 case CEE_NEWOBJ: {
10763                         MonoInst *iargs [2];
10764                         MonoMethodSignature *fsig;
10765                         MonoInst this_ins;
10766                         MonoInst *alloc;
10767                         MonoInst *vtable_arg = NULL;
10768
10769                         CHECK_OPSIZE (5);
10770                         token = read32 (ip + 1);
10771                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
10772                         CHECK_CFG_ERROR;
10773
10774                         fsig = mono_method_get_signature_checked (cmethod, image, token, generic_context, &cfg->error);
10775                         CHECK_CFG_ERROR;
10776
10777                         mono_save_token_info (cfg, image, token, cmethod);
10778
10779                         if (!mono_class_init (cmethod->klass))
10780                                 TYPE_LOAD_ERROR (cmethod->klass);
10781
10782                         context_used = mini_method_check_context_used (cfg, cmethod);
10783
10784                         if (mono_security_core_clr_enabled ())
10785                                 ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
10786
10787                         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)) {
10788                                 emit_class_init (cfg, cmethod->klass);
10789                                 CHECK_TYPELOAD (cmethod->klass);
10790                         }
10791
10792                         /*
10793                         if (cfg->gsharedvt) {
10794                                 if (mini_is_gsharedvt_variable_signature (sig))
10795                                         GSHAREDVT_FAILURE (*ip);
10796                         }
10797                         */
10798
10799                         n = fsig->param_count;
10800                         CHECK_STACK (n);
10801
10802                         /* 
10803                          * Generate smaller code for the common newobj <exception> instruction in
10804                          * argument checking code.
10805                          */
10806                         if (cfg->cbb->out_of_line && cmethod->klass->image == mono_defaults.corlib &&
10807                                 is_exception_class (cmethod->klass) && n <= 2 &&
10808                                 ((n < 1) || (!fsig->params [0]->byref && fsig->params [0]->type == MONO_TYPE_STRING)) && 
10809                                 ((n < 2) || (!fsig->params [1]->byref && fsig->params [1]->type == MONO_TYPE_STRING))) {
10810                                 MonoInst *iargs [3];
10811
10812                                 sp -= n;
10813
10814                                 EMIT_NEW_ICONST (cfg, iargs [0], cmethod->klass->type_token);
10815                                 switch (n) {
10816                                 case 0:
10817                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_0, iargs);
10818                                         break;
10819                                 case 1:
10820                                         iargs [1] = sp [0];
10821                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_1, iargs);
10822                                         break;
10823                                 case 2:
10824                                         iargs [1] = sp [0];
10825                                         iargs [2] = sp [1];
10826                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_2, iargs);
10827                                         break;
10828                                 default:
10829                                         g_assert_not_reached ();
10830                                 }
10831
10832                                 ip += 5;
10833                                 inline_costs += 5;
10834                                 break;
10835                         }
10836
10837                         /* move the args to allow room for 'this' in the first position */
10838                         while (n--) {
10839                                 --sp;
10840                                 sp [1] = sp [0];
10841                         }
10842
10843                         /* check_call_signature () requires sp[0] to be set */
10844                         this_ins.type = STACK_OBJ;
10845                         sp [0] = &this_ins;
10846                         if (check_call_signature (cfg, fsig, sp))
10847                                 UNVERIFIED;
10848
10849                         iargs [0] = NULL;
10850
10851                         if (mini_class_is_system_array (cmethod->klass)) {
10852                                 *sp = emit_get_rgctx_method (cfg, context_used,
10853                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
10854
10855                                 /* Avoid varargs in the common case */
10856                                 if (fsig->param_count == 1)
10857                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_1, sp);
10858                                 else if (fsig->param_count == 2)
10859                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_2, sp);
10860                                 else if (fsig->param_count == 3)
10861                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_3, sp);
10862                                 else if (fsig->param_count == 4)
10863                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_4, sp);
10864                                 else
10865                                         alloc = handle_array_new (cfg, fsig->param_count, sp, ip);
10866                         } else if (cmethod->string_ctor) {
10867                                 g_assert (!context_used);
10868                                 g_assert (!vtable_arg);
10869                                 /* we simply pass a null pointer */
10870                                 EMIT_NEW_PCONST (cfg, *sp, NULL); 
10871                                 /* now call the string ctor */
10872                                 alloc = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, NULL, NULL, NULL);
10873                         } else {
10874                                 if (cmethod->klass->valuetype) {
10875                                         iargs [0] = mono_compile_create_var (cfg, &cmethod->klass->byval_arg, OP_LOCAL);
10876                                         emit_init_rvar (cfg, iargs [0]->dreg, &cmethod->klass->byval_arg);
10877                                         EMIT_NEW_TEMPLOADA (cfg, *sp, iargs [0]->inst_c0);
10878
10879                                         alloc = NULL;
10880
10881                                         /* 
10882                                          * The code generated by mini_emit_virtual_call () expects
10883                                          * iargs [0] to be a boxed instance, but luckily the vcall
10884                                          * will be transformed into a normal call there.
10885                                          */
10886                                 } else if (context_used) {
10887                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, context_used);
10888                                         *sp = alloc;
10889                                 } else {
10890                                         MonoVTable *vtable = NULL;
10891
10892                                         if (!cfg->compile_aot)
10893                                                 vtable = mono_class_vtable (cfg->domain, cmethod->klass);
10894                                         CHECK_TYPELOAD (cmethod->klass);
10895
10896                                         /*
10897                                          * TypeInitializationExceptions thrown from the mono_runtime_class_init
10898                                          * call in mono_jit_runtime_invoke () can abort the finalizer thread.
10899                                          * As a workaround, we call class cctors before allocating objects.
10900                                          */
10901                                         if (mini_field_access_needs_cctor_run (cfg, method, cmethod->klass, vtable) && !(g_slist_find (class_inits, cmethod->klass))) {
10902                                                 emit_class_init (cfg, cmethod->klass);
10903                                                 if (cfg->verbose_level > 2)
10904                                                         printf ("class %s.%s needs init call for ctor\n", cmethod->klass->name_space, cmethod->klass->name);
10905                                                 class_inits = g_slist_prepend (class_inits, cmethod->klass);
10906                                         }
10907
10908                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, 0);
10909                                         *sp = alloc;
10910                                 }
10911                                 CHECK_CFG_EXCEPTION; /*for handle_alloc*/
10912
10913                                 if (alloc)
10914                                         MONO_EMIT_NEW_UNALU (cfg, OP_NOT_NULL, -1, alloc->dreg);
10915
10916                                 /* Now call the actual ctor */
10917                                 handle_ctor_call (cfg, cmethod, fsig, context_used, sp, ip, &inline_costs);
10918                                 CHECK_CFG_EXCEPTION;
10919                         }
10920
10921                         if (alloc == NULL) {
10922                                 /* Valuetype */
10923                                 EMIT_NEW_TEMPLOAD (cfg, ins, iargs [0]->inst_c0);
10924                                 type_to_eval_stack_type (cfg, &ins->klass->byval_arg, ins);
10925                                 *sp++= ins;
10926                         } else {
10927                                 *sp++ = alloc;
10928                         }
10929                         
10930                         ip += 5;
10931                         inline_costs += 5;
10932                         if (!(seq_point_locs && mono_bitset_test_fast (seq_point_locs, ip - header->code)))
10933                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
10934                         break;
10935                 }
10936                 case CEE_CASTCLASS:
10937                         CHECK_STACK (1);
10938                         --sp;
10939                         CHECK_OPSIZE (5);
10940                         token = read32 (ip + 1);
10941                         klass = mini_get_class (method, token, generic_context);
10942                         CHECK_TYPELOAD (klass);
10943                         if (sp [0]->type != STACK_OBJ)
10944                                 UNVERIFIED;
10945
10946                         ins = handle_castclass (cfg, klass, *sp, ip, &inline_costs);
10947                         CHECK_CFG_EXCEPTION;
10948
10949                         *sp ++ = ins;
10950                         ip += 5;
10951                         break;
10952                 case CEE_ISINST: {
10953                         CHECK_STACK (1);
10954                         --sp;
10955                         CHECK_OPSIZE (5);
10956                         token = read32 (ip + 1);
10957                         klass = mini_get_class (method, token, generic_context);
10958                         CHECK_TYPELOAD (klass);
10959                         if (sp [0]->type != STACK_OBJ)
10960                                 UNVERIFIED;
10961  
10962                         context_used = mini_class_check_context_used (cfg, klass);
10963
10964                         if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
10965                                 MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
10966                                 MonoInst *args [3];
10967                                 int idx;
10968
10969                                 /* obj */
10970                                 args [0] = *sp;
10971
10972                                 /* klass */
10973                                 EMIT_NEW_CLASSCONST (cfg, args [1], klass);
10974
10975                                 /* inline cache*/
10976                                 idx = get_castclass_cache_idx (cfg);
10977                                 args [2] = emit_runtime_constant (cfg, MONO_PATCH_INFO_CASTCLASS_CACHE, GINT_TO_POINTER (idx));
10978
10979                                 *sp++ = mono_emit_method_call (cfg, mono_isinst, args, NULL);
10980                                 ip += 5;
10981                                 inline_costs += 2;
10982                         } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
10983                                 MonoMethod *mono_isinst;
10984                                 MonoInst *iargs [1];
10985                                 int costs;
10986
10987                                 mono_isinst = mono_marshal_get_isinst (klass); 
10988                                 iargs [0] = sp [0];
10989
10990                                 costs = inline_method (cfg, mono_isinst, mono_method_signature (mono_isinst), 
10991                                                                            iargs, ip, cfg->real_offset, TRUE);
10992                                 CHECK_CFG_EXCEPTION;
10993                                 g_assert (costs > 0);
10994                                 
10995                                 ip += 5;
10996                                 cfg->real_offset += 5;
10997
10998                                 *sp++= iargs [0];
10999
11000                                 inline_costs += costs;
11001                         }
11002                         else {
11003                                 ins = handle_isinst (cfg, klass, *sp, context_used);
11004                                 CHECK_CFG_EXCEPTION;
11005                                 *sp ++ = ins;
11006                                 ip += 5;
11007                         }
11008                         break;
11009                 }
11010                 case CEE_UNBOX_ANY: {
11011                         MonoInst *res, *addr;
11012
11013                         CHECK_STACK (1);
11014                         --sp;
11015                         CHECK_OPSIZE (5);
11016                         token = read32 (ip + 1);
11017                         klass = mini_get_class (method, token, generic_context);
11018                         CHECK_TYPELOAD (klass);
11019
11020                         mono_save_token_info (cfg, image, token, klass);
11021
11022                         context_used = mini_class_check_context_used (cfg, klass);
11023
11024                         if (mini_is_gsharedvt_klass (klass)) {
11025                                 res = handle_unbox_gsharedvt (cfg, klass, *sp);
11026                                 inline_costs += 2;
11027                         } else if (generic_class_is_reference_type (cfg, klass)) {
11028                                 res = handle_castclass (cfg, klass, *sp, ip, &inline_costs);
11029                                 CHECK_CFG_EXCEPTION;
11030                         } else if (mono_class_is_nullable (klass)) {
11031                                 res = handle_unbox_nullable (cfg, *sp, klass, context_used);
11032                         } else {
11033                                 addr = handle_unbox (cfg, klass, sp, context_used);
11034                                 /* LDOBJ */
11035                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
11036                                 res = ins;
11037                                 inline_costs += 2;
11038                         }
11039
11040                         *sp ++ = res;
11041                         ip += 5;
11042                         break;
11043                 }
11044                 case CEE_BOX: {
11045                         MonoInst *val;
11046                         MonoClass *enum_class;
11047                         MonoMethod *has_flag;
11048
11049                         CHECK_STACK (1);
11050                         --sp;
11051                         val = *sp;
11052                         CHECK_OPSIZE (5);
11053                         token = read32 (ip + 1);
11054                         klass = mini_get_class (method, token, generic_context);
11055                         CHECK_TYPELOAD (klass);
11056
11057                         mono_save_token_info (cfg, image, token, klass);
11058
11059                         context_used = mini_class_check_context_used (cfg, klass);
11060
11061                         if (generic_class_is_reference_type (cfg, klass)) {
11062                                 *sp++ = val;
11063                                 ip += 5;
11064                                 break;
11065                         }
11066
11067                         if (klass == mono_defaults.void_class)
11068                                 UNVERIFIED;
11069                         if (target_type_is_incompatible (cfg, &klass->byval_arg, *sp))
11070                                 UNVERIFIED;
11071                         /* frequent check in generic code: box (struct), brtrue */
11072
11073                         /*
11074                          * Look for:
11075                          *
11076                          *   <push int/long ptr>
11077                          *   <push int/long>
11078                          *   box MyFlags
11079                          *   constrained. MyFlags
11080                          *   callvirt instace bool class [mscorlib] System.Enum::HasFlag (class [mscorlib] System.Enum)
11081                          *
11082                          * If we find this sequence and the operand types on box and constrained
11083                          * are equal, we can emit a specialized instruction sequence instead of
11084                          * the very slow HasFlag () call.
11085                          */
11086                         if ((cfg->opt & MONO_OPT_INTRINS) &&
11087                             /* Cheap checks first. */
11088                             ip + 5 + 6 + 5 < end &&
11089                             ip [5] == CEE_PREFIX1 &&
11090                             ip [6] == CEE_CONSTRAINED_ &&
11091                             ip [11] == CEE_CALLVIRT &&
11092                             ip_in_bb (cfg, cfg->cbb, ip + 5 + 6 + 5) &&
11093                             mono_class_is_enum (klass) &&
11094                             (enum_class = mini_get_class (method, read32 (ip + 7), generic_context)) &&
11095                             (has_flag = mini_get_method (cfg, method, read32 (ip + 12), NULL, generic_context)) &&
11096                             has_flag->klass == mono_defaults.enum_class &&
11097                             !strcmp (has_flag->name, "HasFlag") &&
11098                             has_flag->signature->hasthis &&
11099                             has_flag->signature->param_count == 1) {
11100                                 CHECK_TYPELOAD (enum_class);
11101
11102                                 if (enum_class == klass) {
11103                                         MonoInst *enum_this, *enum_flag;
11104
11105                                         ip += 5 + 6 + 5;
11106                                         --sp;
11107
11108                                         enum_this = sp [0];
11109                                         enum_flag = sp [1];
11110
11111                                         *sp++ = handle_enum_has_flag (cfg, klass, enum_this, enum_flag);
11112                                         break;
11113                                 }
11114                         }
11115
11116                         // FIXME: LLVM can't handle the inconsistent bb linking
11117                         if (!mono_class_is_nullable (klass) &&
11118                                 !mini_is_gsharedvt_klass (klass) &&
11119                                 ip + 5 < end && ip_in_bb (cfg, cfg->cbb, ip + 5) &&
11120                                 (ip [5] == CEE_BRTRUE || 
11121                                  ip [5] == CEE_BRTRUE_S ||
11122                                  ip [5] == CEE_BRFALSE ||
11123                                  ip [5] == CEE_BRFALSE_S)) {
11124                                 gboolean is_true = ip [5] == CEE_BRTRUE || ip [5] == CEE_BRTRUE_S;
11125                                 int dreg;
11126                                 MonoBasicBlock *true_bb, *false_bb;
11127
11128                                 ip += 5;
11129
11130                                 if (cfg->verbose_level > 3) {
11131                                         printf ("converting (in B%d: stack: %d) %s", cfg->cbb->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
11132                                         printf ("<box+brtrue opt>\n");
11133                                 }
11134
11135                                 switch (*ip) {
11136                                 case CEE_BRTRUE_S:
11137                                 case CEE_BRFALSE_S:
11138                                         CHECK_OPSIZE (2);
11139                                         ip++;
11140                                         target = ip + 1 + (signed char)(*ip);
11141                                         ip++;
11142                                         break;
11143                                 case CEE_BRTRUE:
11144                                 case CEE_BRFALSE:
11145                                         CHECK_OPSIZE (5);
11146                                         ip++;
11147                                         target = ip + 4 + (gint)(read32 (ip));
11148                                         ip += 4;
11149                                         break;
11150                                 default:
11151                                         g_assert_not_reached ();
11152                                 }
11153
11154                                 /* 
11155                                  * We need to link both bblocks, since it is needed for handling stack
11156                                  * arguments correctly (See test_0_box_brtrue_opt_regress_81102).
11157                                  * Branching to only one of them would lead to inconsistencies, so
11158                                  * generate an ICONST+BRTRUE, the branch opts will get rid of them.
11159                                  */
11160                                 GET_BBLOCK (cfg, true_bb, target);
11161                                 GET_BBLOCK (cfg, false_bb, ip);
11162
11163                                 mono_link_bblock (cfg, cfg->cbb, true_bb);
11164                                 mono_link_bblock (cfg, cfg->cbb, false_bb);
11165
11166                                 if (sp != stack_start) {
11167                                         handle_stack_args (cfg, stack_start, sp - stack_start);
11168                                         sp = stack_start;
11169                                         CHECK_UNVERIFIABLE (cfg);
11170                                 }
11171
11172                                 if (COMPILE_LLVM (cfg)) {
11173                                         dreg = alloc_ireg (cfg);
11174                                         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
11175                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, dreg, is_true ? 0 : 1);
11176
11177                                         MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, OP_IBEQ, true_bb, false_bb);
11178                                 } else {
11179                                         /* The JIT can't eliminate the iconst+compare */
11180                                         MONO_INST_NEW (cfg, ins, OP_BR);
11181                                         ins->inst_target_bb = is_true ? true_bb : false_bb;
11182                                         MONO_ADD_INS (cfg->cbb, ins);
11183                                 }
11184
11185                                 start_new_bblock = 1;
11186                                 break;
11187                         }
11188
11189                         *sp++ = handle_box (cfg, val, klass, context_used);
11190
11191                         CHECK_CFG_EXCEPTION;
11192                         ip += 5;
11193                         inline_costs += 1;
11194                         break;
11195                 }
11196                 case CEE_UNBOX: {
11197                         CHECK_STACK (1);
11198                         --sp;
11199                         CHECK_OPSIZE (5);
11200                         token = read32 (ip + 1);
11201                         klass = mini_get_class (method, token, generic_context);
11202                         CHECK_TYPELOAD (klass);
11203
11204                         mono_save_token_info (cfg, image, token, klass);
11205
11206                         context_used = mini_class_check_context_used (cfg, klass);
11207
11208                         if (mono_class_is_nullable (klass)) {
11209                                 MonoInst *val;
11210
11211                                 val = handle_unbox_nullable (cfg, *sp, klass, context_used);
11212                                 EMIT_NEW_VARLOADA (cfg, ins, get_vreg_to_inst (cfg, val->dreg), &val->klass->byval_arg);
11213
11214                                 *sp++= ins;
11215                         } else {
11216                                 ins = handle_unbox (cfg, klass, sp, context_used);
11217                                 *sp++ = ins;
11218                         }
11219                         ip += 5;
11220                         inline_costs += 2;
11221                         break;
11222                 }
11223                 case CEE_LDFLD:
11224                 case CEE_LDFLDA:
11225                 case CEE_STFLD:
11226                 case CEE_LDSFLD:
11227                 case CEE_LDSFLDA:
11228                 case CEE_STSFLD: {
11229                         MonoClassField *field;
11230 #ifndef DISABLE_REMOTING
11231                         int costs;
11232 #endif
11233                         guint foffset;
11234                         gboolean is_instance;
11235                         int op;
11236                         gpointer addr = NULL;
11237                         gboolean is_special_static;
11238                         MonoType *ftype;
11239                         MonoInst *store_val = NULL;
11240                         MonoInst *thread_ins;
11241
11242                         op = *ip;
11243                         is_instance = (op == CEE_LDFLD || op == CEE_LDFLDA || op == CEE_STFLD);
11244                         if (is_instance) {
11245                                 if (op == CEE_STFLD) {
11246                                         CHECK_STACK (2);
11247                                         sp -= 2;
11248                                         store_val = sp [1];
11249                                 } else {
11250                                         CHECK_STACK (1);
11251                                         --sp;
11252                                 }
11253                                 if (sp [0]->type == STACK_I4 || sp [0]->type == STACK_I8 || sp [0]->type == STACK_R8)
11254                                         UNVERIFIED;
11255                                 if (*ip != CEE_LDFLD && sp [0]->type == STACK_VTYPE)
11256                                         UNVERIFIED;
11257                         } else {
11258                                 if (op == CEE_STSFLD) {
11259                                         CHECK_STACK (1);
11260                                         sp--;
11261                                         store_val = sp [0];
11262                                 }
11263                         }
11264
11265                         CHECK_OPSIZE (5);
11266                         token = read32 (ip + 1);
11267                         if (method->wrapper_type != MONO_WRAPPER_NONE) {
11268                                 field = (MonoClassField *)mono_method_get_wrapper_data (method, token);
11269                                 klass = field->parent;
11270                         }
11271                         else {
11272                                 field = mono_field_from_token_checked (image, token, &klass, generic_context, &cfg->error);
11273                                 CHECK_CFG_ERROR;
11274                         }
11275                         if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_field (method, field))
11276                                 FIELD_ACCESS_FAILURE (method, field);
11277                         mono_class_init (klass);
11278
11279                         /* if the class is Critical then transparent code cannot access it's fields */
11280                         if (!is_instance && mono_security_core_clr_enabled ())
11281                                 ensure_method_is_allowed_to_access_field (cfg, method, field);
11282
11283                         /* XXX this is technically required but, so far (SL2), no [SecurityCritical] types (not many exists) have
11284                            any visible *instance* field  (in fact there's a single case for a static field in Marshal) XXX
11285                         if (mono_security_core_clr_enabled ())
11286                                 ensure_method_is_allowed_to_access_field (cfg, method, field);
11287                         */
11288
11289                         ftype = mono_field_get_type (field);
11290
11291                         /*
11292                          * LDFLD etc. is usable on static fields as well, so convert those cases to
11293                          * the static case.
11294                          */
11295                         if (is_instance && ftype->attrs & FIELD_ATTRIBUTE_STATIC) {
11296                                 switch (op) {
11297                                 case CEE_LDFLD:
11298                                         op = CEE_LDSFLD;
11299                                         break;
11300                                 case CEE_STFLD:
11301                                         op = CEE_STSFLD;
11302                                         break;
11303                                 case CEE_LDFLDA:
11304                                         op = CEE_LDSFLDA;
11305                                         break;
11306                                 default:
11307                                         g_assert_not_reached ();
11308                                 }
11309                                 is_instance = FALSE;
11310                         }
11311
11312                         context_used = mini_class_check_context_used (cfg, klass);
11313
11314                         /* INSTANCE CASE */
11315
11316                         foffset = klass->valuetype? field->offset - sizeof (MonoObject): field->offset;
11317                         if (op == CEE_STFLD) {
11318                                 if (target_type_is_incompatible (cfg, field->type, sp [1]))
11319                                         UNVERIFIED;
11320 #ifndef DISABLE_REMOTING
11321                                 if ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class) {
11322                                         MonoMethod *stfld_wrapper = mono_marshal_get_stfld_wrapper (field->type); 
11323                                         MonoInst *iargs [5];
11324
11325                                         GSHAREDVT_FAILURE (op);
11326
11327                                         iargs [0] = sp [0];
11328                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
11329                                         EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
11330                                         EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : 
11331                                                     field->offset);
11332                                         iargs [4] = sp [1];
11333
11334                                         if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
11335                                                 costs = inline_method (cfg, stfld_wrapper, mono_method_signature (stfld_wrapper), 
11336                                                                                            iargs, ip, cfg->real_offset, TRUE);
11337                                                 CHECK_CFG_EXCEPTION;
11338                                                 g_assert (costs > 0);
11339                                                       
11340                                                 cfg->real_offset += 5;
11341
11342                                                 inline_costs += costs;
11343                                         } else {
11344                                                 mono_emit_method_call (cfg, stfld_wrapper, iargs, NULL);
11345                                         }
11346                                 } else
11347 #endif
11348                                 {
11349                                         MonoInst *store;
11350
11351                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
11352
11353                                         if (mini_is_gsharedvt_klass (klass)) {
11354                                                 MonoInst *offset_ins;
11355
11356                                                 context_used = mini_class_check_context_used (cfg, klass);
11357
11358                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11359                                                 /* The value is offset by 1 */
11360                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
11361                                                 dreg = alloc_ireg_mp (cfg);
11362                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
11363                                                 /* The decomposition will call mini_emit_stobj () which will emit a wbarrier if needed */
11364                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, dreg, 0, sp [1]->dreg);
11365                                         } else {
11366                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, sp [0]->dreg, foffset, sp [1]->dreg);
11367                                         }
11368                                         if (sp [0]->opcode != OP_LDADDR)
11369                                                 store->flags |= MONO_INST_FAULT;
11370
11371                                 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)) {
11372                                         /* insert call to write barrier */
11373                                         MonoInst *ptr;
11374                                         int dreg;
11375
11376                                         dreg = alloc_ireg_mp (cfg);
11377                                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
11378                                         emit_write_barrier (cfg, ptr, sp [1]);
11379                                 }
11380
11381                                         store->flags |= ins_flag;
11382                                 }
11383                                 ins_flag = 0;
11384                                 ip += 5;
11385                                 break;
11386                         }
11387
11388 #ifndef DISABLE_REMOTING
11389                         if (is_instance && ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class)) {
11390                                 MonoMethod *wrapper = (op == CEE_LDFLDA) ? mono_marshal_get_ldflda_wrapper (field->type) : mono_marshal_get_ldfld_wrapper (field->type); 
11391                                 MonoInst *iargs [4];
11392
11393                                 GSHAREDVT_FAILURE (op);
11394
11395                                 iargs [0] = sp [0];
11396                                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
11397                                 EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
11398                                 EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset);
11399                                 if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
11400                                         costs = inline_method (cfg, wrapper, mono_method_signature (wrapper), 
11401                                                                                    iargs, ip, cfg->real_offset, TRUE);
11402                                         CHECK_CFG_EXCEPTION;
11403                                         g_assert (costs > 0);
11404                                                       
11405                                         cfg->real_offset += 5;
11406
11407                                         *sp++ = iargs [0];
11408
11409                                         inline_costs += costs;
11410                                 } else {
11411                                         ins = mono_emit_method_call (cfg, wrapper, iargs, NULL);
11412                                         *sp++ = ins;
11413                                 }
11414                         } else 
11415 #endif
11416                         if (is_instance) {
11417                                 if (sp [0]->type == STACK_VTYPE) {
11418                                         MonoInst *var;
11419
11420                                         /* Have to compute the address of the variable */
11421
11422                                         var = get_vreg_to_inst (cfg, sp [0]->dreg);
11423                                         if (!var)
11424                                                 var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, sp [0]->dreg);
11425                                         else
11426                                                 g_assert (var->klass == klass);
11427                                         
11428                                         EMIT_NEW_VARLOADA (cfg, ins, var, &var->klass->byval_arg);
11429                                         sp [0] = ins;
11430                                 }
11431
11432                                 if (op == CEE_LDFLDA) {
11433                                         if (sp [0]->type == STACK_OBJ) {
11434                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, sp [0]->dreg, 0);
11435                                                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "NullReferenceException");
11436                                         }
11437
11438                                         dreg = alloc_ireg_mp (cfg);
11439
11440                                         if (mini_is_gsharedvt_klass (klass)) {
11441                                                 MonoInst *offset_ins;
11442
11443                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11444                                                 /* The value is offset by 1 */
11445                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
11446                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
11447                                         } else {
11448                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
11449                                         }
11450                                         ins->klass = mono_class_from_mono_type (field->type);
11451                                         ins->type = STACK_MP;
11452                                         *sp++ = ins;
11453                                 } else {
11454                                         MonoInst *load;
11455
11456                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
11457
11458                                         if (mini_is_gsharedvt_klass (klass)) {
11459                                                 MonoInst *offset_ins;
11460
11461                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11462                                                 /* The value is offset by 1 */
11463                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
11464                                                 dreg = alloc_ireg_mp (cfg);
11465                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
11466                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, dreg, 0);
11467                                         } else {
11468                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, sp [0]->dreg, foffset);
11469                                         }
11470                                         load->flags |= ins_flag;
11471                                         if (sp [0]->opcode != OP_LDADDR)
11472                                                 load->flags |= MONO_INST_FAULT;
11473                                         *sp++ = load;
11474                                 }
11475                         }
11476
11477                         if (is_instance) {
11478                                 ins_flag = 0;
11479                                 ip += 5;
11480                                 break;
11481                         }
11482
11483                         /* STATIC CASE */
11484                         context_used = mini_class_check_context_used (cfg, klass);
11485
11486                         if (ftype->attrs & FIELD_ATTRIBUTE_LITERAL)
11487                                 UNVERIFIED;
11488
11489                         /* The special_static_fields field is init'd in mono_class_vtable, so it needs
11490                          * to be called here.
11491                          */
11492                         if (!context_used && !(cfg->opt & MONO_OPT_SHARED)) {
11493                                 mono_class_vtable (cfg->domain, klass);
11494                                 CHECK_TYPELOAD (klass);
11495                         }
11496                         mono_domain_lock (cfg->domain);
11497                         if (cfg->domain->special_static_fields)
11498                                 addr = g_hash_table_lookup (cfg->domain->special_static_fields, field);
11499                         mono_domain_unlock (cfg->domain);
11500
11501                         is_special_static = mono_class_field_is_special_static (field);
11502
11503                         if (is_special_static && ((gsize)addr & 0x80000000) == 0)
11504                                 thread_ins = mono_get_thread_intrinsic (cfg);
11505                         else
11506                                 thread_ins = NULL;
11507
11508                         /* Generate IR to compute the field address */
11509                         if (is_special_static && ((gsize)addr & 0x80000000) == 0 && thread_ins && !(cfg->opt & MONO_OPT_SHARED) && !context_used) {
11510                                 /*
11511                                  * Fast access to TLS data
11512                                  * Inline version of get_thread_static_data () in
11513                                  * threads.c.
11514                                  */
11515                                 guint32 offset;
11516                                 int idx, static_data_reg, array_reg, dreg;
11517
11518                                 GSHAREDVT_FAILURE (op);
11519
11520                                 MONO_ADD_INS (cfg->cbb, thread_ins);
11521                                 static_data_reg = alloc_ireg (cfg);
11522                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, static_data_reg, thread_ins->dreg, MONO_STRUCT_OFFSET (MonoInternalThread, static_data));
11523
11524                                 if (cfg->compile_aot) {
11525                                         int offset_reg, offset2_reg, idx_reg;
11526
11527                                         /* For TLS variables, this will return the TLS offset */
11528                                         EMIT_NEW_SFLDACONST (cfg, ins, field);
11529                                         offset_reg = ins->dreg;
11530                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset_reg, offset_reg, 0x7fffffff);
11531                                         idx_reg = alloc_ireg (cfg);
11532                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, idx_reg, offset_reg, 0x3f);
11533                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHL_IMM, idx_reg, idx_reg, sizeof (gpointer) == 8 ? 3 : 2);
11534                                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, static_data_reg, static_data_reg, idx_reg);
11535                                         array_reg = alloc_ireg (cfg);
11536                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, 0);
11537                                         offset2_reg = alloc_ireg (cfg);
11538                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, offset2_reg, offset_reg, 6);
11539                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset2_reg, offset2_reg, 0x1ffffff);
11540                                         dreg = alloc_ireg (cfg);
11541                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, array_reg, offset2_reg);
11542                                 } else {
11543                                         offset = (gsize)addr & 0x7fffffff;
11544                                         idx = offset & 0x3f;
11545
11546                                         array_reg = alloc_ireg (cfg);
11547                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, idx * sizeof (gpointer));
11548                                         dreg = alloc_ireg (cfg);
11549                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_ADD_IMM, dreg, array_reg, ((offset >> 6) & 0x1ffffff));
11550                                 }
11551                         } else if ((cfg->opt & MONO_OPT_SHARED) ||
11552                                         (cfg->compile_aot && is_special_static) ||
11553                                         (context_used && is_special_static)) {
11554                                 MonoInst *iargs [2];
11555
11556                                 g_assert (field->parent);
11557                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11558                                 if (context_used) {
11559                                         iargs [1] = emit_get_rgctx_field (cfg, context_used,
11560                                                 field, MONO_RGCTX_INFO_CLASS_FIELD);
11561                                 } else {
11562                                         EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
11563                                 }
11564                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
11565                         } else if (context_used) {
11566                                 MonoInst *static_data;
11567
11568                                 /*
11569                                 g_print ("sharing static field access in %s.%s.%s - depth %d offset %d\n",
11570                                         method->klass->name_space, method->klass->name, method->name,
11571                                         depth, field->offset);
11572                                 */
11573
11574                                 if (mono_class_needs_cctor_run (klass, method))
11575                                         emit_class_init (cfg, klass);
11576
11577                                 /*
11578                                  * The pointer we're computing here is
11579                                  *
11580                                  *   super_info.static_data + field->offset
11581                                  */
11582                                 static_data = emit_get_rgctx_klass (cfg, context_used,
11583                                         klass, MONO_RGCTX_INFO_STATIC_DATA);
11584
11585                                 if (mini_is_gsharedvt_klass (klass)) {
11586                                         MonoInst *offset_ins;
11587
11588                                         offset_ins = emit_get_rgctx_field (cfg, context_used, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11589                                         /* The value is offset by 1 */
11590                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
11591                                         dreg = alloc_ireg_mp (cfg);
11592                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, static_data->dreg, offset_ins->dreg);
11593                                 } else if (field->offset == 0) {
11594                                         ins = static_data;
11595                                 } else {
11596                                         int addr_reg = mono_alloc_preg (cfg);
11597                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, addr_reg, static_data->dreg, field->offset);
11598                                 }
11599                                 } else if ((cfg->opt & MONO_OPT_SHARED) || (cfg->compile_aot && addr)) {
11600                                 MonoInst *iargs [2];
11601
11602                                 g_assert (field->parent);
11603                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11604                                 EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
11605                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
11606                         } else {
11607                                 MonoVTable *vtable = NULL;
11608
11609                                 if (!cfg->compile_aot)
11610                                         vtable = mono_class_vtable (cfg->domain, klass);
11611                                 CHECK_TYPELOAD (klass);
11612
11613                                 if (!addr) {
11614                                         if (mini_field_access_needs_cctor_run (cfg, method, klass, vtable)) {
11615                                                 if (!(g_slist_find (class_inits, klass))) {
11616                                                         emit_class_init (cfg, klass);
11617                                                         if (cfg->verbose_level > 2)
11618                                                                 printf ("class %s.%s needs init call for %s\n", klass->name_space, klass->name, mono_field_get_name (field));
11619                                                         class_inits = g_slist_prepend (class_inits, klass);
11620                                                 }
11621                                         } else {
11622                                                 if (cfg->run_cctors) {
11623                                                         MonoException *ex;
11624                                                         /* This makes so that inline cannot trigger */
11625                                                         /* .cctors: too many apps depend on them */
11626                                                         /* running with a specific order... */
11627                                                         g_assert (vtable);
11628                                                         if (! vtable->initialized)
11629                                                                 INLINE_FAILURE ("class init");
11630                                                         ex = mono_runtime_class_init_full (vtable, FALSE);
11631                                                         if (ex) {
11632                                                                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
11633                                                                 mono_error_set_exception_instance (&cfg->error, ex);
11634                                                                 g_assert_not_reached ();
11635                                                                 goto exception_exit;
11636                                                         }
11637                                                 }
11638                                         }
11639                                         if (cfg->compile_aot)
11640                                                 EMIT_NEW_SFLDACONST (cfg, ins, field);
11641                                         else {
11642                                                 g_assert (vtable);
11643                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
11644                                                 g_assert (addr);
11645                                                 EMIT_NEW_PCONST (cfg, ins, addr);
11646                                         }
11647                                 } else {
11648                                         MonoInst *iargs [1];
11649                                         EMIT_NEW_ICONST (cfg, iargs [0], GPOINTER_TO_UINT (addr));
11650                                         ins = mono_emit_jit_icall (cfg, mono_get_special_static_data, iargs);
11651                                 }
11652                         }
11653
11654                         /* Generate IR to do the actual load/store operation */
11655
11656                         if ((op == CEE_STFLD || op == CEE_STSFLD) && (ins_flag & MONO_INST_VOLATILE)) {
11657                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
11658                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
11659                         }
11660
11661                         if (op == CEE_LDSFLDA) {
11662                                 ins->klass = mono_class_from_mono_type (ftype);
11663                                 ins->type = STACK_PTR;
11664                                 *sp++ = ins;
11665                         } else if (op == CEE_STSFLD) {
11666                                 MonoInst *store;
11667
11668                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, ftype, ins->dreg, 0, store_val->dreg);
11669                                 store->flags |= ins_flag;
11670                         } else {
11671                                 gboolean is_const = FALSE;
11672                                 MonoVTable *vtable = NULL;
11673                                 gpointer addr = NULL;
11674
11675                                 if (!context_used) {
11676                                         vtable = mono_class_vtable (cfg->domain, klass);
11677                                         CHECK_TYPELOAD (klass);
11678                                 }
11679                                 if ((ftype->attrs & FIELD_ATTRIBUTE_INIT_ONLY) && (((addr = mono_aot_readonly_field_override (field)) != NULL) ||
11680                                                 (!context_used && !((cfg->opt & MONO_OPT_SHARED) || cfg->compile_aot) && vtable->initialized))) {
11681                                         int ro_type = ftype->type;
11682                                         if (!addr)
11683                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
11684                                         if (ro_type == MONO_TYPE_VALUETYPE && ftype->data.klass->enumtype) {
11685                                                 ro_type = mono_class_enum_basetype (ftype->data.klass)->type;
11686                                         }
11687
11688                                         GSHAREDVT_FAILURE (op);
11689
11690                                         /* printf ("RO-FIELD %s.%s:%s\n", klass->name_space, klass->name, mono_field_get_name (field));*/
11691                                         is_const = TRUE;
11692                                         switch (ro_type) {
11693                                         case MONO_TYPE_BOOLEAN:
11694                                         case MONO_TYPE_U1:
11695                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint8 *)addr));
11696                                                 sp++;
11697                                                 break;
11698                                         case MONO_TYPE_I1:
11699                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint8 *)addr));
11700                                                 sp++;
11701                                                 break;                                          
11702                                         case MONO_TYPE_CHAR:
11703                                         case MONO_TYPE_U2:
11704                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint16 *)addr));
11705                                                 sp++;
11706                                                 break;
11707                                         case MONO_TYPE_I2:
11708                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint16 *)addr));
11709                                                 sp++;
11710                                                 break;
11711                                                 break;
11712                                         case MONO_TYPE_I4:
11713                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint32 *)addr));
11714                                                 sp++;
11715                                                 break;                                          
11716                                         case MONO_TYPE_U4:
11717                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint32 *)addr));
11718                                                 sp++;
11719                                                 break;
11720                                         case MONO_TYPE_I:
11721                                         case MONO_TYPE_U:
11722                                         case MONO_TYPE_PTR:
11723                                         case MONO_TYPE_FNPTR:
11724                                                 EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
11725                                                 type_to_eval_stack_type ((cfg), field->type, *sp);
11726                                                 sp++;
11727                                                 break;
11728                                         case MONO_TYPE_STRING:
11729                                         case MONO_TYPE_OBJECT:
11730                                         case MONO_TYPE_CLASS:
11731                                         case MONO_TYPE_SZARRAY:
11732                                         case MONO_TYPE_ARRAY:
11733                                                 if (!mono_gc_is_moving ()) {
11734                                                         EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
11735                                                         type_to_eval_stack_type ((cfg), field->type, *sp);
11736                                                         sp++;
11737                                                 } else {
11738                                                         is_const = FALSE;
11739                                                 }
11740                                                 break;
11741                                         case MONO_TYPE_I8:
11742                                         case MONO_TYPE_U8:
11743                                                 EMIT_NEW_I8CONST (cfg, *sp, *((gint64 *)addr));
11744                                                 sp++;
11745                                                 break;
11746                                         case MONO_TYPE_R4:
11747                                         case MONO_TYPE_R8:
11748                                         case MONO_TYPE_VALUETYPE:
11749                                         default:
11750                                                 is_const = FALSE;
11751                                                 break;
11752                                         }
11753                                 }
11754
11755                                 if (!is_const) {
11756                                         MonoInst *load;
11757
11758                                         CHECK_STACK_OVF (1);
11759
11760                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, ins->dreg, 0);
11761                                         load->flags |= ins_flag;
11762                                         ins_flag = 0;
11763                                         *sp++ = load;
11764                                 }
11765                         }
11766
11767                         if ((op == CEE_LDFLD || op == CEE_LDSFLD) && (ins_flag & MONO_INST_VOLATILE)) {
11768                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
11769                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
11770                         }
11771
11772                         ins_flag = 0;
11773                         ip += 5;
11774                         break;
11775                 }
11776                 case CEE_STOBJ:
11777                         CHECK_STACK (2);
11778                         sp -= 2;
11779                         CHECK_OPSIZE (5);
11780                         token = read32 (ip + 1);
11781                         klass = mini_get_class (method, token, generic_context);
11782                         CHECK_TYPELOAD (klass);
11783                         if (ins_flag & MONO_INST_VOLATILE) {
11784                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
11785                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
11786                         }
11787                         /* FIXME: should check item at sp [1] is compatible with the type of the store. */
11788                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0, sp [1]->dreg);
11789                         ins->flags |= ins_flag;
11790                         if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER &&
11791                                         generic_class_is_reference_type (cfg, klass)) {
11792                                 /* insert call to write barrier */
11793                                 emit_write_barrier (cfg, sp [0], sp [1]);
11794                         }
11795                         ins_flag = 0;
11796                         ip += 5;
11797                         inline_costs += 1;
11798                         break;
11799
11800                         /*
11801                          * Array opcodes
11802                          */
11803                 case CEE_NEWARR: {
11804                         MonoInst *len_ins;
11805                         const char *data_ptr;
11806                         int data_size = 0;
11807                         guint32 field_token;
11808
11809                         CHECK_STACK (1);
11810                         --sp;
11811
11812                         CHECK_OPSIZE (5);
11813                         token = read32 (ip + 1);
11814
11815                         klass = mini_get_class (method, token, generic_context);
11816                         CHECK_TYPELOAD (klass);
11817
11818                         context_used = mini_class_check_context_used (cfg, klass);
11819
11820                         if (sp [0]->type == STACK_I8 || (SIZEOF_VOID_P == 8 && sp [0]->type == STACK_PTR)) {
11821                                 MONO_INST_NEW (cfg, ins, OP_LCONV_TO_OVF_U4);
11822                                 ins->sreg1 = sp [0]->dreg;
11823                                 ins->type = STACK_I4;
11824                                 ins->dreg = alloc_ireg (cfg);
11825                                 MONO_ADD_INS (cfg->cbb, ins);
11826                                 *sp = mono_decompose_opcode (cfg, ins);
11827                         }
11828
11829                         if (context_used) {
11830                                 MonoInst *args [3];
11831                                 MonoClass *array_class = mono_array_class_get (klass, 1);
11832                                 MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (array_class);
11833
11834                                 /* FIXME: Use OP_NEWARR and decompose later to help abcrem */
11835
11836                                 /* vtable */
11837                                 args [0] = emit_get_rgctx_klass (cfg, context_used,
11838                                         array_class, MONO_RGCTX_INFO_VTABLE);
11839                                 /* array len */
11840                                 args [1] = sp [0];
11841
11842                                 if (managed_alloc)
11843                                         ins = mono_emit_method_call (cfg, managed_alloc, args, NULL);
11844                                 else
11845                                         ins = mono_emit_jit_icall (cfg, ves_icall_array_new_specific, args);
11846                         } else {
11847                                 if (cfg->opt & MONO_OPT_SHARED) {
11848                                         /* Decompose now to avoid problems with references to the domainvar */
11849                                         MonoInst *iargs [3];
11850
11851                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11852                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
11853                                         iargs [2] = sp [0];
11854
11855                                         ins = mono_emit_jit_icall (cfg, mono_array_new, iargs);
11856                                 } else {
11857                                         /* Decompose later since it is needed by abcrem */
11858                                         MonoClass *array_type = mono_array_class_get (klass, 1);
11859                                         mono_class_vtable (cfg->domain, array_type);
11860                                         CHECK_TYPELOAD (array_type);
11861
11862                                         MONO_INST_NEW (cfg, ins, OP_NEWARR);
11863                                         ins->dreg = alloc_ireg_ref (cfg);
11864                                         ins->sreg1 = sp [0]->dreg;
11865                                         ins->inst_newa_class = klass;
11866                                         ins->type = STACK_OBJ;
11867                                         ins->klass = array_type;
11868                                         MONO_ADD_INS (cfg->cbb, ins);
11869                                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
11870                                         cfg->cbb->has_array_access = TRUE;
11871
11872                                         /* Needed so mono_emit_load_get_addr () gets called */
11873                                         mono_get_got_var (cfg);
11874                                 }
11875                         }
11876
11877                         len_ins = sp [0];
11878                         ip += 5;
11879                         *sp++ = ins;
11880                         inline_costs += 1;
11881
11882                         /* 
11883                          * we inline/optimize the initialization sequence if possible.
11884                          * we should also allocate the array as not cleared, since we spend as much time clearing to 0 as initializing
11885                          * for small sizes open code the memcpy
11886                          * ensure the rva field is big enough
11887                          */
11888                         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))) {
11889                                 MonoMethod *memcpy_method = get_memcpy_method ();
11890                                 MonoInst *iargs [3];
11891                                 int add_reg = alloc_ireg_mp (cfg);
11892
11893                                 EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, add_reg, ins->dreg, MONO_STRUCT_OFFSET (MonoArray, vector));
11894                                 if (cfg->compile_aot) {
11895                                         EMIT_NEW_AOTCONST_TOKEN (cfg, iargs [1], MONO_PATCH_INFO_RVA, method->klass->image, GPOINTER_TO_UINT(field_token), STACK_PTR, NULL);
11896                                 } else {
11897                                         EMIT_NEW_PCONST (cfg, iargs [1], (char*)data_ptr);
11898                                 }
11899                                 EMIT_NEW_ICONST (cfg, iargs [2], data_size);
11900                                 mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
11901                                 ip += 11;
11902                         }
11903
11904                         break;
11905                 }
11906                 case CEE_LDLEN:
11907                         CHECK_STACK (1);
11908                         --sp;
11909                         if (sp [0]->type != STACK_OBJ)
11910                                 UNVERIFIED;
11911
11912                         MONO_INST_NEW (cfg, ins, OP_LDLEN);
11913                         ins->dreg = alloc_preg (cfg);
11914                         ins->sreg1 = sp [0]->dreg;
11915                         ins->type = STACK_I4;
11916                         /* This flag will be inherited by the decomposition */
11917                         ins->flags |= MONO_INST_FAULT;
11918                         MONO_ADD_INS (cfg->cbb, ins);
11919                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
11920                         cfg->cbb->has_array_access = TRUE;
11921                         ip ++;
11922                         *sp++ = ins;
11923                         break;
11924                 case CEE_LDELEMA:
11925                         CHECK_STACK (2);
11926                         sp -= 2;
11927                         CHECK_OPSIZE (5);
11928                         if (sp [0]->type != STACK_OBJ)
11929                                 UNVERIFIED;
11930
11931                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11932
11933                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
11934                         CHECK_TYPELOAD (klass);
11935                         /* we need to make sure that this array is exactly the type it needs
11936                          * to be for correctness. the wrappers are lax with their usage
11937                          * so we need to ignore them here
11938                          */
11939                         if (!klass->valuetype && method->wrapper_type == MONO_WRAPPER_NONE && !readonly) {
11940                                 MonoClass *array_class = mono_array_class_get (klass, 1);
11941                                 mini_emit_check_array_type (cfg, sp [0], array_class);
11942                                 CHECK_TYPELOAD (array_class);
11943                         }
11944
11945                         readonly = FALSE;
11946                         ins = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11947                         *sp++ = ins;
11948                         ip += 5;
11949                         break;
11950                 case CEE_LDELEM:
11951                 case CEE_LDELEM_I1:
11952                 case CEE_LDELEM_U1:
11953                 case CEE_LDELEM_I2:
11954                 case CEE_LDELEM_U2:
11955                 case CEE_LDELEM_I4:
11956                 case CEE_LDELEM_U4:
11957                 case CEE_LDELEM_I8:
11958                 case CEE_LDELEM_I:
11959                 case CEE_LDELEM_R4:
11960                 case CEE_LDELEM_R8:
11961                 case CEE_LDELEM_REF: {
11962                         MonoInst *addr;
11963
11964                         CHECK_STACK (2);
11965                         sp -= 2;
11966
11967                         if (*ip == CEE_LDELEM) {
11968                                 CHECK_OPSIZE (5);
11969                                 token = read32 (ip + 1);
11970                                 klass = mini_get_class (method, token, generic_context);
11971                                 CHECK_TYPELOAD (klass);
11972                                 mono_class_init (klass);
11973                         }
11974                         else
11975                                 klass = array_access_to_klass (*ip);
11976
11977                         if (sp [0]->type != STACK_OBJ)
11978                                 UNVERIFIED;
11979
11980                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11981
11982                         if (mini_is_gsharedvt_variable_klass (klass)) {
11983                                 // FIXME-VT: OP_ICONST optimization
11984                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11985                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
11986                                 ins->opcode = OP_LOADV_MEMBASE;
11987                         } else if (sp [1]->opcode == OP_ICONST) {
11988                                 int array_reg = sp [0]->dreg;
11989                                 int index_reg = sp [1]->dreg;
11990                                 int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + MONO_STRUCT_OFFSET (MonoArray, vector);
11991
11992                                 if (SIZEOF_REGISTER == 8 && COMPILE_LLVM (cfg))
11993                                         MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, index_reg, index_reg);
11994
11995                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
11996                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset);
11997                         } else {
11998                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11999                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
12000                         }
12001                         *sp++ = ins;
12002                         if (*ip == CEE_LDELEM)
12003                                 ip += 5;
12004                         else
12005                                 ++ip;
12006                         break;
12007                 }
12008                 case CEE_STELEM_I:
12009                 case CEE_STELEM_I1:
12010                 case CEE_STELEM_I2:
12011                 case CEE_STELEM_I4:
12012                 case CEE_STELEM_I8:
12013                 case CEE_STELEM_R4:
12014                 case CEE_STELEM_R8:
12015                 case CEE_STELEM_REF:
12016                 case CEE_STELEM: {
12017                         CHECK_STACK (3);
12018                         sp -= 3;
12019
12020                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
12021
12022                         if (*ip == CEE_STELEM) {
12023                                 CHECK_OPSIZE (5);
12024                                 token = read32 (ip + 1);
12025                                 klass = mini_get_class (method, token, generic_context);
12026                                 CHECK_TYPELOAD (klass);
12027                                 mono_class_init (klass);
12028                         }
12029                         else
12030                                 klass = array_access_to_klass (*ip);
12031
12032                         if (sp [0]->type != STACK_OBJ)
12033                                 UNVERIFIED;
12034
12035                         emit_array_store (cfg, klass, sp, TRUE);
12036
12037                         if (*ip == CEE_STELEM)
12038                                 ip += 5;
12039                         else
12040                                 ++ip;
12041                         inline_costs += 1;
12042                         break;
12043                 }
12044                 case CEE_CKFINITE: {
12045                         CHECK_STACK (1);
12046                         --sp;
12047
12048                         if (cfg->llvm_only) {
12049                                 MonoInst *iargs [1];
12050
12051                                 iargs [0] = sp [0];
12052                                 *sp++ = mono_emit_jit_icall (cfg, mono_ckfinite, iargs);
12053                         } else  {
12054                                 MONO_INST_NEW (cfg, ins, OP_CKFINITE);
12055                                 ins->sreg1 = sp [0]->dreg;
12056                                 ins->dreg = alloc_freg (cfg);
12057                                 ins->type = STACK_R8;
12058                                 MONO_ADD_INS (cfg->cbb, ins);
12059
12060                                 *sp++ = mono_decompose_opcode (cfg, ins);
12061                         }
12062
12063                         ++ip;
12064                         break;
12065                 }
12066                 case CEE_REFANYVAL: {
12067                         MonoInst *src_var, *src;
12068
12069                         int klass_reg = alloc_preg (cfg);
12070                         int dreg = alloc_preg (cfg);
12071
12072                         GSHAREDVT_FAILURE (*ip);
12073
12074                         CHECK_STACK (1);
12075                         MONO_INST_NEW (cfg, ins, *ip);
12076                         --sp;
12077                         CHECK_OPSIZE (5);
12078                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
12079                         CHECK_TYPELOAD (klass);
12080
12081                         context_used = mini_class_check_context_used (cfg, klass);
12082
12083                         // FIXME:
12084                         src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
12085                         if (!src_var)
12086                                 src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
12087                         EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
12088                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass));
12089
12090                         if (context_used) {
12091                                 MonoInst *klass_ins;
12092
12093                                 klass_ins = emit_get_rgctx_klass (cfg, context_used,
12094                                                 klass, MONO_RGCTX_INFO_KLASS);
12095
12096                                 // FIXME:
12097                                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_ins->dreg);
12098                                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
12099                         } else {
12100                                 mini_emit_class_check (cfg, klass_reg, klass);
12101                         }
12102                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, value));
12103                         ins->type = STACK_MP;
12104                         ins->klass = klass;
12105                         *sp++ = ins;
12106                         ip += 5;
12107                         break;
12108                 }
12109                 case CEE_MKREFANY: {
12110                         MonoInst *loc, *addr;
12111
12112                         GSHAREDVT_FAILURE (*ip);
12113
12114                         CHECK_STACK (1);
12115                         MONO_INST_NEW (cfg, ins, *ip);
12116                         --sp;
12117                         CHECK_OPSIZE (5);
12118                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
12119                         CHECK_TYPELOAD (klass);
12120
12121                         context_used = mini_class_check_context_used (cfg, klass);
12122
12123                         loc = mono_compile_create_var (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL);
12124                         EMIT_NEW_TEMPLOADA (cfg, addr, loc->inst_c0);
12125
12126                         if (context_used) {
12127                                 MonoInst *const_ins;
12128                                 int type_reg = alloc_preg (cfg);
12129
12130                                 const_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
12131                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), const_ins->dreg);
12132                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_ins->dreg, MONO_STRUCT_OFFSET (MonoClass, byval_arg));
12133                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
12134                         } else if (cfg->compile_aot) {
12135                                 int const_reg = alloc_preg (cfg);
12136                                 int type_reg = alloc_preg (cfg);
12137
12138                                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
12139                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), const_reg);
12140                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_reg, MONO_STRUCT_OFFSET (MonoClass, byval_arg));
12141                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
12142                         } else {
12143                                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), &klass->byval_arg);
12144                                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), klass);
12145                         }
12146                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, value), sp [0]->dreg);
12147
12148                         EMIT_NEW_TEMPLOAD (cfg, ins, loc->inst_c0);
12149                         ins->type = STACK_VTYPE;
12150                         ins->klass = mono_defaults.typed_reference_class;
12151                         *sp++ = ins;
12152                         ip += 5;
12153                         break;
12154                 }
12155                 case CEE_LDTOKEN: {
12156                         gpointer handle;
12157                         MonoClass *handle_class;
12158
12159                         CHECK_STACK_OVF (1);
12160
12161                         CHECK_OPSIZE (5);
12162                         n = read32 (ip + 1);
12163
12164                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD ||
12165                                         method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
12166                                 handle = mono_method_get_wrapper_data (method, n);
12167                                 handle_class = (MonoClass *)mono_method_get_wrapper_data (method, n + 1);
12168                                 if (handle_class == mono_defaults.typehandle_class)
12169                                         handle = &((MonoClass*)handle)->byval_arg;
12170                         }
12171                         else {
12172                                 handle = mono_ldtoken_checked (image, n, &handle_class, generic_context, &cfg->error);
12173                                 CHECK_CFG_ERROR;
12174                         }
12175                         if (!handle)
12176                                 LOAD_ERROR;
12177                         mono_class_init (handle_class);
12178                         if (cfg->gshared) {
12179                                 if (mono_metadata_token_table (n) == MONO_TABLE_TYPEDEF ||
12180                                                 mono_metadata_token_table (n) == MONO_TABLE_TYPEREF) {
12181                                         /* This case handles ldtoken
12182                                            of an open type, like for
12183                                            typeof(Gen<>). */
12184                                         context_used = 0;
12185                                 } else if (handle_class == mono_defaults.typehandle_class) {
12186                                         context_used = mini_class_check_context_used (cfg, mono_class_from_mono_type ((MonoType *)handle));
12187                                 } else if (handle_class == mono_defaults.fieldhandle_class)
12188                                         context_used = mini_class_check_context_used (cfg, ((MonoClassField*)handle)->parent);
12189                                 else if (handle_class == mono_defaults.methodhandle_class)
12190                                         context_used = mini_method_check_context_used (cfg, (MonoMethod *)handle);
12191                                 else
12192                                         g_assert_not_reached ();
12193                         }
12194
12195                         if ((cfg->opt & MONO_OPT_SHARED) &&
12196                                         method->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD &&
12197                                         method->wrapper_type != MONO_WRAPPER_SYNCHRONIZED) {
12198                                 MonoInst *addr, *vtvar, *iargs [3];
12199                                 int method_context_used;
12200
12201                                 method_context_used = mini_method_check_context_used (cfg, method);
12202
12203                                 vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL); 
12204
12205                                 EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
12206                                 EMIT_NEW_ICONST (cfg, iargs [1], n);
12207                                 if (method_context_used) {
12208                                         iargs [2] = emit_get_rgctx_method (cfg, method_context_used,
12209                                                 method, MONO_RGCTX_INFO_METHOD);
12210                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper_generic_shared, iargs);
12211                                 } else {
12212                                         EMIT_NEW_PCONST (cfg, iargs [2], generic_context);
12213                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper, iargs);
12214                                 }
12215                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
12216
12217                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
12218
12219                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
12220                         } else {
12221                                 if ((ip + 5 < end) && ip_in_bb (cfg, cfg->cbb, ip + 5) && 
12222                                         ((ip [5] == CEE_CALL) || (ip [5] == CEE_CALLVIRT)) && 
12223                                         (cmethod = mini_get_method (cfg, method, read32 (ip + 6), NULL, generic_context)) &&
12224                                         (cmethod->klass == mono_defaults.systemtype_class) &&
12225                                         (strcmp (cmethod->name, "GetTypeFromHandle") == 0)) {
12226                                         MonoClass *tclass = mono_class_from_mono_type ((MonoType *)handle);
12227
12228                                         mono_class_init (tclass);
12229                                         if (context_used) {
12230                                                 ins = emit_get_rgctx_klass (cfg, context_used,
12231                                                         tclass, MONO_RGCTX_INFO_REFLECTION_TYPE);
12232                                         } else if (cfg->compile_aot) {
12233                                                 if (method->wrapper_type) {
12234                                                         mono_error_init (&error); //got to do it since there are multiple conditionals below
12235                                                         if (mono_class_get_checked (tclass->image, tclass->type_token, &error) == tclass && !generic_context) {
12236                                                                 /* Special case for static synchronized wrappers */
12237                                                                 EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, tclass->image, tclass->type_token, generic_context);
12238                                                         } else {
12239                                                                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
12240                                                                 /* FIXME: n is not a normal token */
12241                                                                 DISABLE_AOT (cfg);
12242                                                                 EMIT_NEW_PCONST (cfg, ins, NULL);
12243                                                         }
12244                                                 } else {
12245                                                         EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, image, n, generic_context);
12246                                                 }
12247                                         } else {
12248                                                 MonoError error;
12249                                                 MonoReflectionType *rt = mono_type_get_object_checked (cfg->domain, (MonoType *)handle, &error);
12250                                                 mono_error_raise_exception (&error); /* FIXME don't raise here */
12251
12252                                                 EMIT_NEW_PCONST (cfg, ins, rt);
12253                                         }
12254                                         ins->type = STACK_OBJ;
12255                                         ins->klass = cmethod->klass;
12256                                         ip += 5;
12257                                 } else {
12258                                         MonoInst *addr, *vtvar;
12259
12260                                         vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL);
12261
12262                                         if (context_used) {
12263                                                 if (handle_class == mono_defaults.typehandle_class) {
12264                                                         ins = emit_get_rgctx_klass (cfg, context_used,
12265                                                                         mono_class_from_mono_type ((MonoType *)handle),
12266                                                                         MONO_RGCTX_INFO_TYPE);
12267                                                 } else if (handle_class == mono_defaults.methodhandle_class) {
12268                                                         ins = emit_get_rgctx_method (cfg, context_used,
12269                                                                         (MonoMethod *)handle, MONO_RGCTX_INFO_METHOD);
12270                                                 } else if (handle_class == mono_defaults.fieldhandle_class) {
12271                                                         ins = emit_get_rgctx_field (cfg, context_used,
12272                                                                         (MonoClassField *)handle, MONO_RGCTX_INFO_CLASS_FIELD);
12273                                                 } else {
12274                                                         g_assert_not_reached ();
12275                                                 }
12276                                         } else if (cfg->compile_aot) {
12277                                                 EMIT_NEW_LDTOKENCONST (cfg, ins, image, n, generic_context);
12278                                         } else {
12279                                                 EMIT_NEW_PCONST (cfg, ins, handle);
12280                                         }
12281                                         EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
12282                                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
12283                                         EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
12284                                 }
12285                         }
12286
12287                         *sp++ = ins;
12288                         ip += 5;
12289                         break;
12290                 }
12291                 case CEE_THROW:
12292                         CHECK_STACK (1);
12293                         MONO_INST_NEW (cfg, ins, OP_THROW);
12294                         --sp;
12295                         ins->sreg1 = sp [0]->dreg;
12296                         ip++;
12297                         cfg->cbb->out_of_line = TRUE;
12298                         MONO_ADD_INS (cfg->cbb, ins);
12299                         MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
12300                         MONO_ADD_INS (cfg->cbb, ins);
12301                         sp = stack_start;
12302                         
12303                         link_bblock (cfg, cfg->cbb, end_bblock);
12304                         start_new_bblock = 1;
12305                         /* This can complicate code generation for llvm since the return value might not be defined */
12306                         if (COMPILE_LLVM (cfg))
12307                                 INLINE_FAILURE ("throw");
12308                         break;
12309                 case CEE_ENDFINALLY:
12310                         /* mono_save_seq_point_info () depends on this */
12311                         if (sp != stack_start)
12312                                 emit_seq_point (cfg, method, ip, FALSE, FALSE);
12313                         MONO_INST_NEW (cfg, ins, OP_ENDFINALLY);
12314                         MONO_ADD_INS (cfg->cbb, ins);
12315                         ip++;
12316                         start_new_bblock = 1;
12317
12318                         /*
12319                          * Control will leave the method so empty the stack, otherwise
12320                          * the next basic block will start with a nonempty stack.
12321                          */
12322                         while (sp != stack_start) {
12323                                 sp--;
12324                         }
12325                         break;
12326                 case CEE_LEAVE:
12327                 case CEE_LEAVE_S: {
12328                         GList *handlers;
12329
12330                         if (*ip == CEE_LEAVE) {
12331                                 CHECK_OPSIZE (5);
12332                                 target = ip + 5 + (gint32)read32(ip + 1);
12333                         } else {
12334                                 CHECK_OPSIZE (2);
12335                                 target = ip + 2 + (signed char)(ip [1]);
12336                         }
12337
12338                         /* empty the stack */
12339                         while (sp != stack_start) {
12340                                 sp--;
12341                         }
12342
12343                         /* 
12344                          * If this leave statement is in a catch block, check for a
12345                          * pending exception, and rethrow it if necessary.
12346                          * We avoid doing this in runtime invoke wrappers, since those are called
12347                          * by native code which excepts the wrapper to catch all exceptions.
12348                          */
12349                         for (i = 0; i < header->num_clauses; ++i) {
12350                                 MonoExceptionClause *clause = &header->clauses [i];
12351
12352                                 /* 
12353                                  * Use <= in the final comparison to handle clauses with multiple
12354                                  * leave statements, like in bug #78024.
12355                                  * The ordering of the exception clauses guarantees that we find the
12356                                  * innermost clause.
12357                                  */
12358                                 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) {
12359                                         MonoInst *exc_ins;
12360                                         MonoBasicBlock *dont_throw;
12361
12362                                         /*
12363                                           MonoInst *load;
12364
12365                                           NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, clause->handler_offset)->inst_c0);
12366                                         */
12367
12368                                         exc_ins = mono_emit_jit_icall (cfg, mono_thread_get_undeniable_exception, NULL);
12369
12370                                         NEW_BBLOCK (cfg, dont_throw);
12371
12372                                         /*
12373                                          * Currently, we always rethrow the abort exception, despite the 
12374                                          * fact that this is not correct. See thread6.cs for an example. 
12375                                          * But propagating the abort exception is more important than 
12376                                          * getting the sematics right.
12377                                          */
12378                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, exc_ins->dreg, 0);
12379                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, dont_throw);
12380                                         MONO_EMIT_NEW_UNALU (cfg, OP_THROW, -1, exc_ins->dreg);
12381
12382                                         MONO_START_BB (cfg, dont_throw);
12383                                 }
12384                         }
12385
12386 #ifdef ENABLE_LLVM
12387                         cfg->cbb->try_end = (intptr_t)(ip - header->code);
12388 #endif
12389
12390                         if ((handlers = mono_find_final_block (cfg, ip, target, MONO_EXCEPTION_CLAUSE_FINALLY))) {
12391                                 GList *tmp;
12392                                 MonoExceptionClause *clause;
12393
12394                                 for (tmp = handlers; tmp; tmp = tmp->next) {
12395                                         clause = (MonoExceptionClause *)tmp->data;
12396                                         tblock = cfg->cil_offset_to_bb [clause->handler_offset];
12397                                         g_assert (tblock);
12398                                         link_bblock (cfg, cfg->cbb, tblock);
12399                                         MONO_INST_NEW (cfg, ins, OP_CALL_HANDLER);
12400                                         ins->inst_target_bb = tblock;
12401                                         ins->inst_eh_block = clause;
12402                                         MONO_ADD_INS (cfg->cbb, ins);
12403                                         cfg->cbb->has_call_handler = 1;
12404                                         if (COMPILE_LLVM (cfg)) {
12405                                                 MonoBasicBlock *target_bb;
12406
12407                                                 /* 
12408                                                  * Link the finally bblock with the target, since it will
12409                                                  * conceptually branch there.
12410                                                  */
12411                                                 GET_BBLOCK (cfg, tblock, cfg->cil_start + clause->handler_offset + clause->handler_len - 1);
12412                                                 GET_BBLOCK (cfg, target_bb, target);
12413                                                 link_bblock (cfg, tblock, target_bb);
12414                                         }
12415                                 }
12416                                 g_list_free (handlers);
12417                         } 
12418
12419                         MONO_INST_NEW (cfg, ins, OP_BR);
12420                         MONO_ADD_INS (cfg->cbb, ins);
12421                         GET_BBLOCK (cfg, tblock, target);
12422                         link_bblock (cfg, cfg->cbb, tblock);
12423                         ins->inst_target_bb = tblock;
12424
12425                         start_new_bblock = 1;
12426
12427                         if (*ip == CEE_LEAVE)
12428                                 ip += 5;
12429                         else
12430                                 ip += 2;
12431
12432                         break;
12433                 }
12434
12435                         /*
12436                          * Mono specific opcodes
12437                          */
12438                 case MONO_CUSTOM_PREFIX: {
12439
12440                         g_assert (method->wrapper_type != MONO_WRAPPER_NONE);
12441
12442                         CHECK_OPSIZE (2);
12443                         switch (ip [1]) {
12444                         case CEE_MONO_ICALL: {
12445                                 gpointer func;
12446                                 MonoJitICallInfo *info;
12447
12448                                 token = read32 (ip + 2);
12449                                 func = mono_method_get_wrapper_data (method, token);
12450                                 info = mono_find_jit_icall_by_addr (func);
12451                                 if (!info)
12452                                         g_error ("Could not find icall address in wrapper %s", mono_method_full_name (method, 1));
12453                                 g_assert (info);
12454
12455                                 CHECK_STACK (info->sig->param_count);
12456                                 sp -= info->sig->param_count;
12457
12458                                 ins = mono_emit_jit_icall (cfg, info->func, sp);
12459                                 if (!MONO_TYPE_IS_VOID (info->sig->ret))
12460                                         *sp++ = ins;
12461
12462                                 ip += 6;
12463                                 inline_costs += 10 * num_calls++;
12464
12465                                 break;
12466                         }
12467                         case CEE_MONO_LDPTR_CARD_TABLE:
12468                         case CEE_MONO_LDPTR_NURSERY_START:
12469                         case CEE_MONO_LDPTR_NURSERY_BITS:
12470                         case CEE_MONO_LDPTR_INT_REQ_FLAG: {
12471                                 CHECK_STACK_OVF (1);
12472
12473                                 switch (ip [1]) {
12474                                         case CEE_MONO_LDPTR_CARD_TABLE:
12475                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_CARD_TABLE_ADDR, NULL);
12476                                                 break;
12477                                         case CEE_MONO_LDPTR_NURSERY_START:
12478                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_NURSERY_START, NULL);
12479                                                 break;
12480                                         case CEE_MONO_LDPTR_NURSERY_BITS:
12481                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_NURSERY_BITS, NULL);
12482                                                 break;
12483                                         case CEE_MONO_LDPTR_INT_REQ_FLAG:
12484                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG, NULL);
12485                                                 break;
12486                                 }
12487
12488                                 *sp++ = ins;
12489                                 ip += 2;
12490                                 inline_costs += 10 * num_calls++;
12491                                 break;
12492                         }
12493                         case CEE_MONO_LDPTR: {
12494                                 gpointer ptr;
12495
12496                                 CHECK_STACK_OVF (1);
12497                                 CHECK_OPSIZE (6);
12498                                 token = read32 (ip + 2);
12499
12500                                 ptr = mono_method_get_wrapper_data (method, token);
12501                                 EMIT_NEW_PCONST (cfg, ins, ptr);
12502                                 *sp++ = ins;
12503                                 ip += 6;
12504                                 inline_costs += 10 * num_calls++;
12505                                 /* Can't embed random pointers into AOT code */
12506                                 DISABLE_AOT (cfg);
12507                                 break;
12508                         }
12509                         case CEE_MONO_JIT_ICALL_ADDR: {
12510                                 MonoJitICallInfo *callinfo;
12511                                 gpointer ptr;
12512
12513                                 CHECK_STACK_OVF (1);
12514                                 CHECK_OPSIZE (6);
12515                                 token = read32 (ip + 2);
12516
12517                                 ptr = mono_method_get_wrapper_data (method, token);
12518                                 callinfo = mono_find_jit_icall_by_addr (ptr);
12519                                 g_assert (callinfo);
12520                                 EMIT_NEW_JIT_ICALL_ADDRCONST (cfg, ins, (char*)callinfo->name);
12521                                 *sp++ = ins;
12522                                 ip += 6;
12523                                 inline_costs += 10 * num_calls++;
12524                                 break;
12525                         }
12526                         case CEE_MONO_ICALL_ADDR: {
12527                                 MonoMethod *cmethod;
12528                                 gpointer ptr;
12529
12530                                 CHECK_STACK_OVF (1);
12531                                 CHECK_OPSIZE (6);
12532                                 token = read32 (ip + 2);
12533
12534                                 cmethod = (MonoMethod *)mono_method_get_wrapper_data (method, token);
12535
12536                                 if (cfg->compile_aot) {
12537                                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_ICALL_ADDR, cmethod);
12538                                 } else {
12539                                         ptr = mono_lookup_internal_call (cmethod);
12540                                         g_assert (ptr);
12541                                         EMIT_NEW_PCONST (cfg, ins, ptr);
12542                                 }
12543                                 *sp++ = ins;
12544                                 ip += 6;
12545                                 break;
12546                         }
12547                         case CEE_MONO_VTADDR: {
12548                                 MonoInst *src_var, *src;
12549
12550                                 CHECK_STACK (1);
12551                                 --sp;
12552
12553                                 // FIXME:
12554                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
12555                                 EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
12556                                 *sp++ = src;
12557                                 ip += 2;
12558                                 break;
12559                         }
12560                         case CEE_MONO_NEWOBJ: {
12561                                 MonoInst *iargs [2];
12562
12563                                 CHECK_STACK_OVF (1);
12564                                 CHECK_OPSIZE (6);
12565                                 token = read32 (ip + 2);
12566                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12567                                 mono_class_init (klass);
12568                                 NEW_DOMAINCONST (cfg, iargs [0]);
12569                                 MONO_ADD_INS (cfg->cbb, iargs [0]);
12570                                 NEW_CLASSCONST (cfg, iargs [1], klass);
12571                                 MONO_ADD_INS (cfg->cbb, iargs [1]);
12572                                 *sp++ = mono_emit_jit_icall (cfg, ves_icall_object_new, iargs);
12573                                 ip += 6;
12574                                 inline_costs += 10 * num_calls++;
12575                                 break;
12576                         }
12577                         case CEE_MONO_OBJADDR:
12578                                 CHECK_STACK (1);
12579                                 --sp;
12580                                 MONO_INST_NEW (cfg, ins, OP_MOVE);
12581                                 ins->dreg = alloc_ireg_mp (cfg);
12582                                 ins->sreg1 = sp [0]->dreg;
12583                                 ins->type = STACK_MP;
12584                                 MONO_ADD_INS (cfg->cbb, ins);
12585                                 *sp++ = ins;
12586                                 ip += 2;
12587                                 break;
12588                         case CEE_MONO_LDNATIVEOBJ:
12589                                 /*
12590                                  * Similar to LDOBJ, but instead load the unmanaged 
12591                                  * representation of the vtype to the stack.
12592                                  */
12593                                 CHECK_STACK (1);
12594                                 CHECK_OPSIZE (6);
12595                                 --sp;
12596                                 token = read32 (ip + 2);
12597                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12598                                 g_assert (klass->valuetype);
12599                                 mono_class_init (klass);
12600
12601                                 {
12602                                         MonoInst *src, *dest, *temp;
12603
12604                                         src = sp [0];
12605                                         temp = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
12606                                         temp->backend.is_pinvoke = 1;
12607                                         EMIT_NEW_TEMPLOADA (cfg, dest, temp->inst_c0);
12608                                         mini_emit_stobj (cfg, dest, src, klass, TRUE);
12609
12610                                         EMIT_NEW_TEMPLOAD (cfg, dest, temp->inst_c0);
12611                                         dest->type = STACK_VTYPE;
12612                                         dest->klass = klass;
12613
12614                                         *sp ++ = dest;
12615                                         ip += 6;
12616                                 }
12617                                 break;
12618                         case CEE_MONO_RETOBJ: {
12619                                 /*
12620                                  * Same as RET, but return the native representation of a vtype
12621                                  * to the caller.
12622                                  */
12623                                 g_assert (cfg->ret);
12624                                 g_assert (mono_method_signature (method)->pinvoke); 
12625                                 CHECK_STACK (1);
12626                                 --sp;
12627                                 
12628                                 CHECK_OPSIZE (6);
12629                                 token = read32 (ip + 2);    
12630                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12631
12632                                 if (!cfg->vret_addr) {
12633                                         g_assert (cfg->ret_var_is_local);
12634
12635                                         EMIT_NEW_VARLOADA (cfg, ins, cfg->ret, cfg->ret->inst_vtype);
12636                                 } else {
12637                                         EMIT_NEW_RETLOADA (cfg, ins);
12638                                 }
12639                                 mini_emit_stobj (cfg, ins, sp [0], klass, TRUE);
12640                                 
12641                                 if (sp != stack_start)
12642                                         UNVERIFIED;
12643                                 
12644                                 MONO_INST_NEW (cfg, ins, OP_BR);
12645                                 ins->inst_target_bb = end_bblock;
12646                                 MONO_ADD_INS (cfg->cbb, ins);
12647                                 link_bblock (cfg, cfg->cbb, end_bblock);
12648                                 start_new_bblock = 1;
12649                                 ip += 6;
12650                                 break;
12651                         }
12652                         case CEE_MONO_CISINST:
12653                         case CEE_MONO_CCASTCLASS: {
12654                                 int token;
12655                                 CHECK_STACK (1);
12656                                 --sp;
12657                                 CHECK_OPSIZE (6);
12658                                 token = read32 (ip + 2);
12659                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12660                                 if (ip [1] == CEE_MONO_CISINST)
12661                                         ins = handle_cisinst (cfg, klass, sp [0]);
12662                                 else
12663                                         ins = handle_ccastclass (cfg, klass, sp [0]);
12664                                 *sp++ = ins;
12665                                 ip += 6;
12666                                 break;
12667                         }
12668                         case CEE_MONO_SAVE_LMF:
12669                         case CEE_MONO_RESTORE_LMF:
12670                                 ip += 2;
12671                                 break;
12672                         case CEE_MONO_CLASSCONST:
12673                                 CHECK_STACK_OVF (1);
12674                                 CHECK_OPSIZE (6);
12675                                 token = read32 (ip + 2);
12676                                 EMIT_NEW_CLASSCONST (cfg, ins, mono_method_get_wrapper_data (method, token));
12677                                 *sp++ = ins;
12678                                 ip += 6;
12679                                 inline_costs += 10 * num_calls++;
12680                                 break;
12681                         case CEE_MONO_NOT_TAKEN:
12682                                 cfg->cbb->out_of_line = TRUE;
12683                                 ip += 2;
12684                                 break;
12685                         case CEE_MONO_TLS: {
12686                                 MonoTlsKey key;
12687
12688                                 CHECK_STACK_OVF (1);
12689                                 CHECK_OPSIZE (6);
12690                                 key = (MonoTlsKey)read32 (ip + 2);
12691                                 g_assert (key < TLS_KEY_NUM);
12692
12693                                 ins = mono_create_tls_get (cfg, key);
12694                                 if (!ins) {
12695                                         if (cfg->compile_aot) {
12696                                                 DISABLE_AOT (cfg);
12697                                                 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
12698                                                 ins->dreg = alloc_preg (cfg);
12699                                                 ins->type = STACK_PTR;
12700                                         } else {
12701                                                 g_assert_not_reached ();
12702                                         }
12703                                 }
12704                                 ins->type = STACK_PTR;
12705                                 MONO_ADD_INS (cfg->cbb, ins);
12706                                 *sp++ = ins;
12707                                 ip += 6;
12708                                 break;
12709                         }
12710                         case CEE_MONO_DYN_CALL: {
12711                                 MonoCallInst *call;
12712
12713                                 /* It would be easier to call a trampoline, but that would put an
12714                                  * extra frame on the stack, confusing exception handling. So
12715                                  * implement it inline using an opcode for now.
12716                                  */
12717
12718                                 if (!cfg->dyn_call_var) {
12719                                         cfg->dyn_call_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
12720                                         /* prevent it from being register allocated */
12721                                         cfg->dyn_call_var->flags |= MONO_INST_VOLATILE;
12722                                 }
12723
12724                                 /* Has to use a call inst since it local regalloc expects it */
12725                                 MONO_INST_NEW_CALL (cfg, call, OP_DYN_CALL);
12726                                 ins = (MonoInst*)call;
12727                                 sp -= 2;
12728                                 ins->sreg1 = sp [0]->dreg;
12729                                 ins->sreg2 = sp [1]->dreg;
12730                                 MONO_ADD_INS (cfg->cbb, ins);
12731
12732                                 cfg->param_area = MAX (cfg->param_area, cfg->backend->dyn_call_param_area);
12733
12734                                 ip += 2;
12735                                 inline_costs += 10 * num_calls++;
12736
12737                                 break;
12738                         }
12739                         case CEE_MONO_MEMORY_BARRIER: {
12740                                 CHECK_OPSIZE (6);
12741                                 emit_memory_barrier (cfg, (int)read32 (ip + 2));
12742                                 ip += 6;
12743                                 break;
12744                         }
12745                         case CEE_MONO_JIT_ATTACH: {
12746                                 MonoInst *args [16], *domain_ins;
12747                                 MonoInst *ad_ins, *jit_tls_ins;
12748                                 MonoBasicBlock *next_bb = NULL, *call_bb = NULL;
12749
12750                                 cfg->orig_domain_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
12751
12752                                 EMIT_NEW_PCONST (cfg, ins, NULL);
12753                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
12754
12755                                 ad_ins = mono_get_domain_intrinsic (cfg);
12756                                 jit_tls_ins = mono_get_jit_tls_intrinsic (cfg);
12757
12758                                 if (cfg->backend->have_tls_get && ad_ins && jit_tls_ins) {
12759                                         NEW_BBLOCK (cfg, next_bb);
12760                                         NEW_BBLOCK (cfg, call_bb);
12761
12762                                         if (cfg->compile_aot) {
12763                                                 /* AOT code is only used in the root domain */
12764                                                 EMIT_NEW_PCONST (cfg, domain_ins, NULL);
12765                                         } else {
12766                                                 EMIT_NEW_PCONST (cfg, domain_ins, cfg->domain);
12767                                         }
12768                                         MONO_ADD_INS (cfg->cbb, ad_ins);
12769                                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, ad_ins->dreg, domain_ins->dreg);
12770                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, call_bb);
12771
12772                                         MONO_ADD_INS (cfg->cbb, jit_tls_ins);
12773                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, jit_tls_ins->dreg, 0);
12774                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, call_bb);
12775
12776                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, next_bb);
12777                                         MONO_START_BB (cfg, call_bb);
12778                                 }
12779
12780                                 if (cfg->compile_aot) {
12781                                         /* AOT code is only used in the root domain */
12782                                         EMIT_NEW_PCONST (cfg, args [0], NULL);
12783                                 } else {
12784                                         EMIT_NEW_PCONST (cfg, args [0], cfg->domain);
12785                                 }
12786                                 ins = mono_emit_jit_icall (cfg, mono_jit_thread_attach, args);
12787                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
12788
12789                                 if (next_bb)
12790                                         MONO_START_BB (cfg, next_bb);
12791                                 ip += 2;
12792                                 break;
12793                         }
12794                         case CEE_MONO_JIT_DETACH: {
12795                                 MonoInst *args [16];
12796
12797                                 /* Restore the original domain */
12798                                 dreg = alloc_ireg (cfg);
12799                                 EMIT_NEW_UNALU (cfg, args [0], OP_MOVE, dreg, cfg->orig_domain_var->dreg);
12800                                 mono_emit_jit_icall (cfg, mono_jit_set_domain, args);
12801                                 ip += 2;
12802                                 break;
12803                         }
12804                         case CEE_MONO_CALLI_EXTRA_ARG: {
12805                                 MonoInst *addr;
12806                                 MonoMethodSignature *fsig;
12807                                 MonoInst *arg;
12808
12809                                 /*
12810                                  * This is the same as CEE_CALLI, but passes an additional argument
12811                                  * to the called method in llvmonly mode.
12812                                  * This is only used by delegate invoke wrappers to call the
12813                                  * actual delegate method.
12814                                  */
12815                                 g_assert (method->wrapper_type == MONO_WRAPPER_DELEGATE_INVOKE);
12816
12817                                 CHECK_OPSIZE (6);
12818                                 token = read32 (ip + 2);
12819
12820                                 ins = NULL;
12821
12822                                 cmethod = NULL;
12823                                 CHECK_STACK (1);
12824                                 --sp;
12825                                 addr = *sp;
12826                                 fsig = mini_get_signature (method, token, generic_context);
12827
12828                                 if (cfg->llvm_only)
12829                                         cfg->signatures = g_slist_prepend_mempool (cfg->mempool, cfg->signatures, fsig);
12830
12831                                 n = fsig->param_count + fsig->hasthis + 1;
12832
12833                                 CHECK_STACK (n);
12834
12835                                 sp -= n;
12836                                 arg = sp [n - 1];
12837
12838                                 if (cfg->llvm_only) {
12839                                         /*
12840                                          * The lowest bit of 'arg' determines whenever the callee uses the gsharedvt
12841                                          * cconv. This is set by mono_init_delegate ().
12842                                          */
12843                                         if (cfg->gsharedvt && mini_is_gsharedvt_variable_signature (fsig)) {
12844                                                 MonoInst *callee = addr;
12845                                                 MonoInst *call, *localloc_ins;
12846                                                 MonoBasicBlock *is_gsharedvt_bb, *end_bb;
12847                                                 int low_bit_reg = alloc_preg (cfg);
12848
12849                                                 NEW_BBLOCK (cfg, is_gsharedvt_bb);
12850                                                 NEW_BBLOCK (cfg, end_bb);
12851
12852                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, low_bit_reg, arg->dreg, 1);
12853                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_bit_reg, 0);
12854                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, is_gsharedvt_bb);
12855
12856                                                 /* Normal case: callee uses a normal cconv, have to add an out wrapper */
12857                                                 addr = emit_get_rgctx_sig (cfg, context_used,
12858                                                                                                    fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
12859                                                 /*
12860                                                  * ADDR points to a gsharedvt-out wrapper, have to pass <callee, arg> as an extra arg.
12861                                                  */
12862                                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
12863                                                 ins->dreg = alloc_preg (cfg);
12864                                                 ins->inst_imm = 2 * SIZEOF_VOID_P;
12865                                                 MONO_ADD_INS (cfg->cbb, ins);
12866                                                 localloc_ins = ins;
12867                                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
12868                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, 0, callee->dreg);
12869                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, SIZEOF_VOID_P, arg->dreg);
12870
12871                                                 call = emit_extra_arg_calli (cfg, fsig, sp, localloc_ins->dreg, addr);
12872                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
12873
12874                                                 /* Gsharedvt case: callee uses a gsharedvt cconv, no conversion is needed */
12875                                                 MONO_START_BB (cfg, is_gsharedvt_bb);
12876                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PXOR_IMM, arg->dreg, arg->dreg, 1);
12877                                                 ins = emit_extra_arg_calli (cfg, fsig, sp, arg->dreg, callee);
12878                                                 ins->dreg = call->dreg;
12879
12880                                                 MONO_START_BB (cfg, end_bb);
12881                                         } else {
12882                                                 /* Caller uses a normal calling conv */
12883
12884                                                 MonoInst *callee = addr;
12885                                                 MonoInst *call, *localloc_ins;
12886                                                 MonoBasicBlock *is_gsharedvt_bb, *end_bb;
12887                                                 int low_bit_reg = alloc_preg (cfg);
12888
12889                                                 NEW_BBLOCK (cfg, is_gsharedvt_bb);
12890                                                 NEW_BBLOCK (cfg, end_bb);
12891
12892                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, low_bit_reg, arg->dreg, 1);
12893                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_bit_reg, 0);
12894                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, is_gsharedvt_bb);
12895
12896                                                 /* Normal case: callee uses a normal cconv, no conversion is needed */
12897                                                 call = emit_extra_arg_calli (cfg, fsig, sp, arg->dreg, callee);
12898                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
12899                                                 /* Gsharedvt case: callee uses a gsharedvt cconv, have to add an in wrapper */
12900                                                 MONO_START_BB (cfg, is_gsharedvt_bb);
12901                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PXOR_IMM, arg->dreg, arg->dreg, 1);
12902                                                 NEW_AOTCONST (cfg, addr, MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER, fsig);
12903                                                 MONO_ADD_INS (cfg->cbb, addr);
12904                                                 /*
12905                                                  * ADDR points to a gsharedvt-in wrapper, have to pass <callee, arg> as an extra arg.
12906                                                  */
12907                                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
12908                                                 ins->dreg = alloc_preg (cfg);
12909                                                 ins->inst_imm = 2 * SIZEOF_VOID_P;
12910                                                 MONO_ADD_INS (cfg->cbb, ins);
12911                                                 localloc_ins = ins;
12912                                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
12913                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, 0, callee->dreg);
12914                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, SIZEOF_VOID_P, arg->dreg);
12915
12916                                                 ins = emit_extra_arg_calli (cfg, fsig, sp, localloc_ins->dreg, addr);
12917                                                 ins->dreg = call->dreg;
12918                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
12919
12920                                                 MONO_START_BB (cfg, end_bb);
12921                                         }
12922                                 } else {
12923                                         /* Same as CEE_CALLI */
12924                                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) {
12925                                                 /*
12926                                                  * We pass the address to the gsharedvt trampoline in the rgctx reg
12927                                                  */
12928                                                 MonoInst *callee = addr;
12929
12930                                                 addr = emit_get_rgctx_sig (cfg, context_used,
12931                                                                                                    fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
12932                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, callee);
12933                                         } else {
12934                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
12935                                         }
12936                                 }
12937
12938                                 if (!MONO_TYPE_IS_VOID (fsig->ret))
12939                                         *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
12940
12941                                 CHECK_CFG_EXCEPTION;
12942
12943                                 ip += 6;
12944                                 ins_flag = 0;
12945                                 constrained_class = NULL;
12946                                 break;
12947                         }
12948                         default:
12949                                 g_error ("opcode 0x%02x 0x%02x not handled", MONO_CUSTOM_PREFIX, ip [1]);
12950                                 break;
12951                         }
12952                         break;
12953                 }
12954
12955                 case CEE_PREFIX1: {
12956                         CHECK_OPSIZE (2);
12957                         switch (ip [1]) {
12958                         case CEE_ARGLIST: {
12959                                 /* somewhat similar to LDTOKEN */
12960                                 MonoInst *addr, *vtvar;
12961                                 CHECK_STACK_OVF (1);
12962                                 vtvar = mono_compile_create_var (cfg, &mono_defaults.argumenthandle_class->byval_arg, OP_LOCAL); 
12963
12964                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
12965                                 EMIT_NEW_UNALU (cfg, ins, OP_ARGLIST, -1, addr->dreg);
12966
12967                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
12968                                 ins->type = STACK_VTYPE;
12969                                 ins->klass = mono_defaults.argumenthandle_class;
12970                                 *sp++ = ins;
12971                                 ip += 2;
12972                                 break;
12973                         }
12974                         case CEE_CEQ:
12975                         case CEE_CGT:
12976                         case CEE_CGT_UN:
12977                         case CEE_CLT:
12978                         case CEE_CLT_UN: {
12979                                 MonoInst *cmp, *arg1, *arg2;
12980
12981                                 CHECK_STACK (2);
12982                                 sp -= 2;
12983                                 arg1 = sp [0];
12984                                 arg2 = sp [1];
12985
12986                                 /*
12987                                  * The following transforms:
12988                                  *    CEE_CEQ    into OP_CEQ
12989                                  *    CEE_CGT    into OP_CGT
12990                                  *    CEE_CGT_UN into OP_CGT_UN
12991                                  *    CEE_CLT    into OP_CLT
12992                                  *    CEE_CLT_UN into OP_CLT_UN
12993                                  */
12994                                 MONO_INST_NEW (cfg, cmp, (OP_CEQ - CEE_CEQ) + ip [1]);
12995
12996                                 MONO_INST_NEW (cfg, ins, cmp->opcode);
12997                                 cmp->sreg1 = arg1->dreg;
12998                                 cmp->sreg2 = arg2->dreg;
12999                                 type_from_op (cfg, cmp, arg1, arg2);
13000                                 CHECK_TYPE (cmp);
13001                                 add_widen_op (cfg, cmp, &arg1, &arg2);
13002                                 if ((arg1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((arg1->type == STACK_PTR) || (arg1->type == STACK_OBJ) || (arg1->type == STACK_MP))))
13003                                         cmp->opcode = OP_LCOMPARE;
13004                                 else if (arg1->type == STACK_R4)
13005                                         cmp->opcode = OP_RCOMPARE;
13006                                 else if (arg1->type == STACK_R8)
13007                                         cmp->opcode = OP_FCOMPARE;
13008                                 else
13009                                         cmp->opcode = OP_ICOMPARE;
13010                                 MONO_ADD_INS (cfg->cbb, cmp);
13011                                 ins->type = STACK_I4;
13012                                 ins->dreg = alloc_dreg (cfg, (MonoStackType)ins->type);
13013                                 type_from_op (cfg, ins, arg1, arg2);
13014
13015                                 if (cmp->opcode == OP_FCOMPARE || cmp->opcode == OP_RCOMPARE) {
13016                                         /*
13017                                          * The backends expect the fceq opcodes to do the
13018                                          * comparison too.
13019                                          */
13020                                         ins->sreg1 = cmp->sreg1;
13021                                         ins->sreg2 = cmp->sreg2;
13022                                         NULLIFY_INS (cmp);
13023                                 }
13024                                 MONO_ADD_INS (cfg->cbb, ins);
13025                                 *sp++ = ins;
13026                                 ip += 2;
13027                                 break;
13028                         }
13029                         case CEE_LDFTN: {
13030                                 MonoInst *argconst;
13031                                 MonoMethod *cil_method;
13032
13033                                 CHECK_STACK_OVF (1);
13034                                 CHECK_OPSIZE (6);
13035                                 n = read32 (ip + 2);
13036                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
13037                                 CHECK_CFG_ERROR;
13038
13039                                 mono_class_init (cmethod->klass);
13040
13041                                 mono_save_token_info (cfg, image, n, cmethod);
13042
13043                                 context_used = mini_method_check_context_used (cfg, cmethod);
13044
13045                                 cil_method = cmethod;
13046                                 if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_method (method, cmethod))
13047                                         METHOD_ACCESS_FAILURE (method, cil_method);
13048
13049                                 if (mono_security_core_clr_enabled ())
13050                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
13051
13052                                 /* 
13053                                  * Optimize the common case of ldftn+delegate creation
13054                                  */
13055                                 if ((sp > stack_start) && (ip + 6 + 5 < end) && ip_in_bb (cfg, cfg->cbb, ip + 6) && (ip [6] == CEE_NEWOBJ)) {
13056                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
13057                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
13058                                                 MonoInst *target_ins, *handle_ins;
13059                                                 MonoMethod *invoke;
13060                                                 int invoke_context_used;
13061
13062                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
13063                                                 if (!invoke || !mono_method_signature (invoke))
13064                                                         LOAD_ERROR;
13065
13066                                                 invoke_context_used = mini_method_check_context_used (cfg, invoke);
13067
13068                                                 target_ins = sp [-1];
13069
13070                                                 if (mono_security_core_clr_enabled ())
13071                                                         ensure_method_is_allowed_to_call_method (cfg, method, ctor_method);
13072
13073                                                 if (!(cmethod->flags & METHOD_ATTRIBUTE_STATIC)) {
13074                                                         /*LAME IMPL: We must not add a null check for virtual invoke delegates.*/
13075                                                         if (mono_method_signature (invoke)->param_count == mono_method_signature (cmethod)->param_count) {
13076                                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, target_ins->dreg, 0);
13077                                                                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "ArgumentException");
13078                                                         }
13079                                                 }
13080
13081                                                 /* FIXME: SGEN support */
13082                                                 if (invoke_context_used == 0 || cfg->llvm_only) {
13083                                                         ip += 6;
13084                                                         if (cfg->verbose_level > 3)
13085                                                                 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));
13086                                                         if ((handle_ins = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used, FALSE))) {
13087                                                                 sp --;
13088                                                                 *sp = handle_ins;
13089                                                                 CHECK_CFG_EXCEPTION;
13090                                                                 ip += 5;
13091                                                                 sp ++;
13092                                                                 break;
13093                                                         }
13094                                                         ip -= 6;
13095                                                 }
13096                                         }
13097                                 }
13098
13099                                 argconst = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD);
13100                                 ins = mono_emit_jit_icall (cfg, mono_ldftn, &argconst);
13101                                 *sp++ = ins;
13102                                 
13103                                 ip += 6;
13104                                 inline_costs += 10 * num_calls++;
13105                                 break;
13106                         }
13107                         case CEE_LDVIRTFTN: {
13108                                 MonoInst *args [2];
13109
13110                                 CHECK_STACK (1);
13111                                 CHECK_OPSIZE (6);
13112                                 n = read32 (ip + 2);
13113                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
13114                                 CHECK_CFG_ERROR;
13115
13116                                 mono_class_init (cmethod->klass);
13117  
13118                                 context_used = mini_method_check_context_used (cfg, cmethod);
13119
13120                                 if (mono_security_core_clr_enabled ())
13121                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
13122
13123                                 /*
13124                                  * Optimize the common case of ldvirtftn+delegate creation
13125                                  */
13126                                 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)) {
13127                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
13128                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
13129                                                 MonoInst *target_ins, *handle_ins;
13130                                                 MonoMethod *invoke;
13131                                                 int invoke_context_used;
13132                                                 gboolean is_virtual = cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL;
13133
13134                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
13135                                                 if (!invoke || !mono_method_signature (invoke))
13136                                                         LOAD_ERROR;
13137
13138                                                 invoke_context_used = mini_method_check_context_used (cfg, invoke);
13139
13140                                                 target_ins = sp [-1];
13141
13142                                                 if (mono_security_core_clr_enabled ())
13143                                                         ensure_method_is_allowed_to_call_method (cfg, method, ctor_method);
13144
13145                                                 /* FIXME: SGEN support */
13146                                                 if (invoke_context_used == 0 || cfg->llvm_only) {
13147                                                         ip += 6;
13148                                                         if (cfg->verbose_level > 3)
13149                                                                 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));
13150                                                         if ((handle_ins = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used, is_virtual))) {
13151                                                                 sp -= 2;
13152                                                                 *sp = handle_ins;
13153                                                                 CHECK_CFG_EXCEPTION;
13154                                                                 ip += 5;
13155                                                                 sp ++;
13156                                                                 break;
13157                                                         }
13158                                                         ip -= 6;
13159                                                 }
13160                                         }
13161                                 }
13162
13163                                 --sp;
13164                                 args [0] = *sp;
13165
13166                                 args [1] = emit_get_rgctx_method (cfg, context_used,
13167                                                                                                   cmethod, MONO_RGCTX_INFO_METHOD);
13168
13169                                 if (context_used)
13170                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn_gshared, args);
13171                                 else
13172                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn, args);
13173
13174                                 ip += 6;
13175                                 inline_costs += 10 * num_calls++;
13176                                 break;
13177                         }
13178                         case CEE_LDARG:
13179                                 CHECK_STACK_OVF (1);
13180                                 CHECK_OPSIZE (4);
13181                                 n = read16 (ip + 2);
13182                                 CHECK_ARG (n);
13183                                 EMIT_NEW_ARGLOAD (cfg, ins, n);
13184                                 *sp++ = ins;
13185                                 ip += 4;
13186                                 break;
13187                         case CEE_LDARGA:
13188                                 CHECK_STACK_OVF (1);
13189                                 CHECK_OPSIZE (4);
13190                                 n = read16 (ip + 2);
13191                                 CHECK_ARG (n);
13192                                 NEW_ARGLOADA (cfg, ins, n);
13193                                 MONO_ADD_INS (cfg->cbb, ins);
13194                                 *sp++ = ins;
13195                                 ip += 4;
13196                                 break;
13197                         case CEE_STARG:
13198                                 CHECK_STACK (1);
13199                                 --sp;
13200                                 CHECK_OPSIZE (4);
13201                                 n = read16 (ip + 2);
13202                                 CHECK_ARG (n);
13203                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [n], *sp))
13204                                         UNVERIFIED;
13205                                 EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
13206                                 ip += 4;
13207                                 break;
13208                         case CEE_LDLOC:
13209                                 CHECK_STACK_OVF (1);
13210                                 CHECK_OPSIZE (4);
13211                                 n = read16 (ip + 2);
13212                                 CHECK_LOCAL (n);
13213                                 EMIT_NEW_LOCLOAD (cfg, ins, n);
13214                                 *sp++ = ins;
13215                                 ip += 4;
13216                                 break;
13217                         case CEE_LDLOCA: {
13218                                 unsigned char *tmp_ip;
13219                                 CHECK_STACK_OVF (1);
13220                                 CHECK_OPSIZE (4);
13221                                 n = read16 (ip + 2);
13222                                 CHECK_LOCAL (n);
13223
13224                                 if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 2))) {
13225                                         ip = tmp_ip;
13226                                         inline_costs += 1;
13227                                         break;
13228                                 }                       
13229                                 
13230                                 EMIT_NEW_LOCLOADA (cfg, ins, n);
13231                                 *sp++ = ins;
13232                                 ip += 4;
13233                                 break;
13234                         }
13235                         case CEE_STLOC:
13236                                 CHECK_STACK (1);
13237                                 --sp;
13238                                 CHECK_OPSIZE (4);
13239                                 n = read16 (ip + 2);
13240                                 CHECK_LOCAL (n);
13241                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
13242                                         UNVERIFIED;
13243                                 emit_stloc_ir (cfg, sp, header, n);
13244                                 ip += 4;
13245                                 inline_costs += 1;
13246                                 break;
13247                         case CEE_LOCALLOC:
13248                                 CHECK_STACK (1);
13249                                 --sp;
13250                                 if (sp != stack_start) 
13251                                         UNVERIFIED;
13252                                 if (cfg->method != method) 
13253                                         /* 
13254                                          * Inlining this into a loop in a parent could lead to 
13255                                          * stack overflows which is different behavior than the
13256                                          * non-inlined case, thus disable inlining in this case.
13257                                          */
13258                                         INLINE_FAILURE("localloc");
13259
13260                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
13261                                 ins->dreg = alloc_preg (cfg);
13262                                 ins->sreg1 = sp [0]->dreg;
13263                                 ins->type = STACK_PTR;
13264                                 MONO_ADD_INS (cfg->cbb, ins);
13265
13266                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
13267                                 if (init_locals)
13268                                         ins->flags |= MONO_INST_INIT;
13269
13270                                 *sp++ = ins;
13271                                 ip += 2;
13272                                 break;
13273                         case CEE_ENDFILTER: {
13274                                 MonoExceptionClause *clause, *nearest;
13275                                 int cc;
13276
13277                                 CHECK_STACK (1);
13278                                 --sp;
13279                                 if ((sp != stack_start) || (sp [0]->type != STACK_I4)) 
13280                                         UNVERIFIED;
13281                                 MONO_INST_NEW (cfg, ins, OP_ENDFILTER);
13282                                 ins->sreg1 = (*sp)->dreg;
13283                                 MONO_ADD_INS (cfg->cbb, ins);
13284                                 start_new_bblock = 1;
13285                                 ip += 2;
13286
13287                                 nearest = NULL;
13288                                 for (cc = 0; cc < header->num_clauses; ++cc) {
13289                                         clause = &header->clauses [cc];
13290                                         if ((clause->flags & MONO_EXCEPTION_CLAUSE_FILTER) &&
13291                                                 ((ip - header->code) > clause->data.filter_offset && (ip - header->code) <= clause->handler_offset) &&
13292                                             (!nearest || (clause->data.filter_offset < nearest->data.filter_offset)))
13293                                                 nearest = clause;
13294                                 }
13295                                 g_assert (nearest);
13296                                 if ((ip - header->code) != nearest->handler_offset)
13297                                         UNVERIFIED;
13298
13299                                 break;
13300                         }
13301                         case CEE_UNALIGNED_:
13302                                 ins_flag |= MONO_INST_UNALIGNED;
13303                                 /* FIXME: record alignment? we can assume 1 for now */
13304                                 CHECK_OPSIZE (3);
13305                                 ip += 3;
13306                                 break;
13307                         case CEE_VOLATILE_:
13308                                 ins_flag |= MONO_INST_VOLATILE;
13309                                 ip += 2;
13310                                 break;
13311                         case CEE_TAIL_:
13312                                 ins_flag   |= MONO_INST_TAILCALL;
13313                                 cfg->flags |= MONO_CFG_HAS_TAIL;
13314                                 /* Can't inline tail calls at this time */
13315                                 inline_costs += 100000;
13316                                 ip += 2;
13317                                 break;
13318                         case CEE_INITOBJ:
13319                                 CHECK_STACK (1);
13320                                 --sp;
13321                                 CHECK_OPSIZE (6);
13322                                 token = read32 (ip + 2);
13323                                 klass = mini_get_class (method, token, generic_context);
13324                                 CHECK_TYPELOAD (klass);
13325                                 if (generic_class_is_reference_type (cfg, klass))
13326                                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, sp [0]->dreg, 0, 0);
13327                                 else
13328                                         mini_emit_initobj (cfg, *sp, NULL, klass);
13329                                 ip += 6;
13330                                 inline_costs += 1;
13331                                 break;
13332                         case CEE_CONSTRAINED_:
13333                                 CHECK_OPSIZE (6);
13334                                 token = read32 (ip + 2);
13335                                 constrained_class = mini_get_class (method, token, generic_context);
13336                                 CHECK_TYPELOAD (constrained_class);
13337                                 ip += 6;
13338                                 break;
13339                         case CEE_CPBLK:
13340                         case CEE_INITBLK: {
13341                                 MonoInst *iargs [3];
13342                                 CHECK_STACK (3);
13343                                 sp -= 3;
13344
13345                                 /* Skip optimized paths for volatile operations. */
13346                                 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)) {
13347                                         mini_emit_memcpy (cfg, sp [0]->dreg, 0, sp [1]->dreg, 0, sp [2]->inst_c0, 0);
13348                                 } 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)) {
13349                                         /* emit_memset only works when val == 0 */
13350                                         mini_emit_memset (cfg, sp [0]->dreg, 0, sp [2]->inst_c0, sp [1]->inst_c0, 0);
13351                                 } else {
13352                                         MonoInst *call;
13353                                         iargs [0] = sp [0];
13354                                         iargs [1] = sp [1];
13355                                         iargs [2] = sp [2];
13356                                         if (ip [1] == CEE_CPBLK) {
13357                                                 /*
13358                                                  * FIXME: It's unclear whether we should be emitting both the acquire
13359                                                  * and release barriers for cpblk. It is technically both a load and
13360                                                  * store operation, so it seems like that's the sensible thing to do.
13361                                                  *
13362                                                  * FIXME: We emit full barriers on both sides of the operation for
13363                                                  * simplicity. We should have a separate atomic memcpy method instead.
13364                                                  */
13365                                                 MonoMethod *memcpy_method = get_memcpy_method ();
13366
13367                                                 if (ins_flag & MONO_INST_VOLATILE)
13368                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
13369
13370                                                 call = mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
13371                                                 call->flags |= ins_flag;
13372
13373                                                 if (ins_flag & MONO_INST_VOLATILE)
13374                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
13375                                         } else {
13376                                                 MonoMethod *memset_method = get_memset_method ();
13377                                                 if (ins_flag & MONO_INST_VOLATILE) {
13378                                                         /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
13379                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
13380                                                 }
13381                                                 call = mono_emit_method_call (cfg, memset_method, iargs, NULL);
13382                                                 call->flags |= ins_flag;
13383                                         }
13384                                 }
13385                                 ip += 2;
13386                                 ins_flag = 0;
13387                                 inline_costs += 1;
13388                                 break;
13389                         }
13390                         case CEE_NO_:
13391                                 CHECK_OPSIZE (3);
13392                                 if (ip [2] & 0x1)
13393                                         ins_flag |= MONO_INST_NOTYPECHECK;
13394                                 if (ip [2] & 0x2)
13395                                         ins_flag |= MONO_INST_NORANGECHECK;
13396                                 /* we ignore the no-nullcheck for now since we
13397                                  * really do it explicitly only when doing callvirt->call
13398                                  */
13399                                 ip += 3;
13400                                 break;
13401                         case CEE_RETHROW: {
13402                                 MonoInst *load;
13403                                 int handler_offset = -1;
13404
13405                                 for (i = 0; i < header->num_clauses; ++i) {
13406                                         MonoExceptionClause *clause = &header->clauses [i];
13407                                         if (MONO_OFFSET_IN_HANDLER (clause, ip - header->code) && !(clause->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
13408                                                 handler_offset = clause->handler_offset;
13409                                                 break;
13410                                         }
13411                                 }
13412
13413                                 cfg->cbb->flags |= BB_EXCEPTION_UNSAFE;
13414
13415                                 if (handler_offset == -1)
13416                                         UNVERIFIED;
13417
13418                                 EMIT_NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, handler_offset)->inst_c0);
13419                                 MONO_INST_NEW (cfg, ins, OP_RETHROW);
13420                                 ins->sreg1 = load->dreg;
13421                                 MONO_ADD_INS (cfg->cbb, ins);
13422
13423                                 MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
13424                                 MONO_ADD_INS (cfg->cbb, ins);
13425
13426                                 sp = stack_start;
13427                                 link_bblock (cfg, cfg->cbb, end_bblock);
13428                                 start_new_bblock = 1;
13429                                 ip += 2;
13430                                 break;
13431                         }
13432                         case CEE_SIZEOF: {
13433                                 guint32 val;
13434                                 int ialign;
13435
13436                                 CHECK_STACK_OVF (1);
13437                                 CHECK_OPSIZE (6);
13438                                 token = read32 (ip + 2);
13439                                 if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC && !image_is_dynamic (method->klass->image) && !generic_context) {
13440                                         MonoType *type = mono_type_create_from_typespec_checked (image, token, &cfg->error);
13441                                         CHECK_CFG_ERROR;
13442
13443                                         val = mono_type_size (type, &ialign);
13444                                 } else {
13445                                         MonoClass *klass = mini_get_class (method, token, generic_context);
13446                                         CHECK_TYPELOAD (klass);
13447
13448                                         val = mono_type_size (&klass->byval_arg, &ialign);
13449
13450                                         if (mini_is_gsharedvt_klass (klass))
13451                                                 GSHAREDVT_FAILURE (*ip);
13452                                 }
13453                                 EMIT_NEW_ICONST (cfg, ins, val);
13454                                 *sp++= ins;
13455                                 ip += 6;
13456                                 break;
13457                         }
13458                         case CEE_REFANYTYPE: {
13459                                 MonoInst *src_var, *src;
13460
13461                                 GSHAREDVT_FAILURE (*ip);
13462
13463                                 CHECK_STACK (1);
13464                                 --sp;
13465
13466                                 // FIXME:
13467                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
13468                                 if (!src_var)
13469                                         src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
13470                                 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
13471                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &mono_defaults.typehandle_class->byval_arg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type));
13472                                 *sp++ = ins;
13473                                 ip += 2;
13474                                 break;
13475                         }
13476                         case CEE_READONLY_:
13477                                 readonly = TRUE;
13478                                 ip += 2;
13479                                 break;
13480
13481                         case CEE_UNUSED56:
13482                         case CEE_UNUSED57:
13483                         case CEE_UNUSED70:
13484                         case CEE_UNUSED:
13485                         case CEE_UNUSED99:
13486                                 UNVERIFIED;
13487                                 
13488                         default:
13489                                 g_warning ("opcode 0xfe 0x%02x not handled", ip [1]);
13490                                 UNVERIFIED;
13491                         }
13492                         break;
13493                 }
13494                 case CEE_UNUSED58:
13495                 case CEE_UNUSED1:
13496                         UNVERIFIED;
13497
13498                 default:
13499                         g_warning ("opcode 0x%02x not handled", *ip);
13500                         UNVERIFIED;
13501                 }
13502         }
13503         if (start_new_bblock != 1)
13504                 UNVERIFIED;
13505
13506         cfg->cbb->cil_length = ip - cfg->cbb->cil_code;
13507         if (cfg->cbb->next_bb) {
13508                 /* This could already be set because of inlining, #693905 */
13509                 MonoBasicBlock *bb = cfg->cbb;
13510
13511                 while (bb->next_bb)
13512                         bb = bb->next_bb;
13513                 bb->next_bb = end_bblock;
13514         } else {
13515                 cfg->cbb->next_bb = end_bblock;
13516         }
13517
13518         if (cfg->method == method && cfg->domainvar) {
13519                 MonoInst *store;
13520                 MonoInst *get_domain;
13521
13522                 cfg->cbb = init_localsbb;
13523
13524                 if ((get_domain = mono_get_domain_intrinsic (cfg))) {
13525                         MONO_ADD_INS (cfg->cbb, get_domain);
13526                 } else {
13527                         get_domain = mono_emit_jit_icall (cfg, mono_domain_get, NULL);
13528                 }
13529                 NEW_TEMPSTORE (cfg, store, cfg->domainvar->inst_c0, get_domain);
13530                 MONO_ADD_INS (cfg->cbb, store);
13531         }
13532
13533 #if defined(TARGET_POWERPC) || defined(TARGET_X86)
13534         if (cfg->compile_aot)
13535                 /* FIXME: The plt slots require a GOT var even if the method doesn't use it */
13536                 mono_get_got_var (cfg);
13537 #endif
13538
13539         if (cfg->method == method && cfg->got_var)
13540                 mono_emit_load_got_addr (cfg);
13541
13542         if (init_localsbb) {
13543                 cfg->cbb = init_localsbb;
13544                 cfg->ip = NULL;
13545                 for (i = 0; i < header->num_locals; ++i) {
13546                         emit_init_local (cfg, i, header->locals [i], init_locals);
13547                 }
13548         }
13549
13550         if (cfg->init_ref_vars && cfg->method == method) {
13551                 /* Emit initialization for ref vars */
13552                 // FIXME: Avoid duplication initialization for IL locals.
13553                 for (i = 0; i < cfg->num_varinfo; ++i) {
13554                         MonoInst *ins = cfg->varinfo [i];
13555
13556                         if (ins->opcode == OP_LOCAL && ins->type == STACK_OBJ)
13557                                 MONO_EMIT_NEW_PCONST (cfg, ins->dreg, NULL);
13558                 }
13559         }
13560
13561         if (cfg->lmf_var && cfg->method == method && !cfg->llvm_only) {
13562                 cfg->cbb = init_localsbb;
13563                 emit_push_lmf (cfg);
13564         }
13565
13566         cfg->cbb = init_localsbb;
13567         emit_instrumentation_call (cfg, mono_profiler_method_enter);
13568
13569         if (seq_points) {
13570                 MonoBasicBlock *bb;
13571
13572                 /*
13573                  * Make seq points at backward branch targets interruptable.
13574                  */
13575                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
13576                         if (bb->code && bb->in_count > 1 && bb->code->opcode == OP_SEQ_POINT)
13577                                 bb->code->flags |= MONO_INST_SINGLE_STEP_LOC;
13578         }
13579
13580         /* Add a sequence point for method entry/exit events */
13581         if (seq_points && cfg->gen_sdb_seq_points) {
13582                 NEW_SEQ_POINT (cfg, ins, METHOD_ENTRY_IL_OFFSET, FALSE);
13583                 MONO_ADD_INS (init_localsbb, ins);
13584                 NEW_SEQ_POINT (cfg, ins, METHOD_EXIT_IL_OFFSET, FALSE);
13585                 MONO_ADD_INS (cfg->bb_exit, ins);
13586         }
13587
13588         /*
13589          * Add seq points for IL offsets which have line number info, but wasn't generated a seq point during JITting because
13590          * the code they refer to was dead (#11880).
13591          */
13592         if (sym_seq_points) {
13593                 for (i = 0; i < header->code_size; ++i) {
13594                         if (mono_bitset_test_fast (seq_point_locs, i) && !mono_bitset_test_fast (seq_point_set_locs, i)) {
13595                                 MonoInst *ins;
13596
13597                                 NEW_SEQ_POINT (cfg, ins, i, FALSE);
13598                                 mono_add_seq_point (cfg, NULL, ins, SEQ_POINT_NATIVE_OFFSET_DEAD_CODE);
13599                         }
13600                 }
13601         }
13602
13603         cfg->ip = NULL;
13604
13605         if (cfg->method == method) {
13606                 MonoBasicBlock *bb;
13607                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
13608                         bb->region = mono_find_block_region (cfg, bb->real_offset);
13609                         if (cfg->spvars)
13610                                 mono_create_spvar_for_region (cfg, bb->region);
13611                         if (cfg->verbose_level > 2)
13612                                 printf ("REGION BB%d IL_%04x ID_%08X\n", bb->block_num, bb->real_offset, bb->region);
13613                 }
13614         }
13615
13616         if (inline_costs < 0) {
13617                 char *mname;
13618
13619                 /* Method is too large */
13620                 mname = mono_method_full_name (method, TRUE);
13621                 mono_cfg_set_exception_invalid_program (cfg, g_strdup_printf ("Method %s is too complex.", mname));
13622                 g_free (mname);
13623         }
13624
13625         if ((cfg->verbose_level > 2) && (cfg->method == method)) 
13626                 mono_print_code (cfg, "AFTER METHOD-TO-IR");
13627
13628         goto cleanup;
13629
13630 mono_error_exit:
13631         g_assert (!mono_error_ok (&cfg->error));
13632         goto cleanup;
13633  
13634  exception_exit:
13635         g_assert (cfg->exception_type != MONO_EXCEPTION_NONE);
13636         goto cleanup;
13637
13638  unverified:
13639         set_exception_type_from_invalid_il (cfg, method, ip);
13640         goto cleanup;
13641
13642  cleanup:
13643         g_slist_free (class_inits);
13644         mono_basic_block_free (original_bb);
13645         cfg->dont_inline = g_list_remove (cfg->dont_inline, method);
13646         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
13647         if (cfg->exception_type)
13648                 return -1;
13649         else
13650                 return inline_costs;
13651 }
13652
13653 static int
13654 store_membase_reg_to_store_membase_imm (int opcode)
13655 {
13656         switch (opcode) {
13657         case OP_STORE_MEMBASE_REG:
13658                 return OP_STORE_MEMBASE_IMM;
13659         case OP_STOREI1_MEMBASE_REG:
13660                 return OP_STOREI1_MEMBASE_IMM;
13661         case OP_STOREI2_MEMBASE_REG:
13662                 return OP_STOREI2_MEMBASE_IMM;
13663         case OP_STOREI4_MEMBASE_REG:
13664                 return OP_STOREI4_MEMBASE_IMM;
13665         case OP_STOREI8_MEMBASE_REG:
13666                 return OP_STOREI8_MEMBASE_IMM;
13667         default:
13668                 g_assert_not_reached ();
13669         }
13670
13671         return -1;
13672 }               
13673
13674 int
13675 mono_op_to_op_imm (int opcode)
13676 {
13677         switch (opcode) {
13678         case OP_IADD:
13679                 return OP_IADD_IMM;
13680         case OP_ISUB:
13681                 return OP_ISUB_IMM;
13682         case OP_IDIV:
13683                 return OP_IDIV_IMM;
13684         case OP_IDIV_UN:
13685                 return OP_IDIV_UN_IMM;
13686         case OP_IREM:
13687                 return OP_IREM_IMM;
13688         case OP_IREM_UN:
13689                 return OP_IREM_UN_IMM;
13690         case OP_IMUL:
13691                 return OP_IMUL_IMM;
13692         case OP_IAND:
13693                 return OP_IAND_IMM;
13694         case OP_IOR:
13695                 return OP_IOR_IMM;
13696         case OP_IXOR:
13697                 return OP_IXOR_IMM;
13698         case OP_ISHL:
13699                 return OP_ISHL_IMM;
13700         case OP_ISHR:
13701                 return OP_ISHR_IMM;
13702         case OP_ISHR_UN:
13703                 return OP_ISHR_UN_IMM;
13704
13705         case OP_LADD:
13706                 return OP_LADD_IMM;
13707         case OP_LSUB:
13708                 return OP_LSUB_IMM;
13709         case OP_LAND:
13710                 return OP_LAND_IMM;
13711         case OP_LOR:
13712                 return OP_LOR_IMM;
13713         case OP_LXOR:
13714                 return OP_LXOR_IMM;
13715         case OP_LSHL:
13716                 return OP_LSHL_IMM;
13717         case OP_LSHR:
13718                 return OP_LSHR_IMM;
13719         case OP_LSHR_UN:
13720                 return OP_LSHR_UN_IMM;
13721 #if SIZEOF_REGISTER == 8
13722         case OP_LREM:
13723                 return OP_LREM_IMM;
13724 #endif
13725
13726         case OP_COMPARE:
13727                 return OP_COMPARE_IMM;
13728         case OP_ICOMPARE:
13729                 return OP_ICOMPARE_IMM;
13730         case OP_LCOMPARE:
13731                 return OP_LCOMPARE_IMM;
13732
13733         case OP_STORE_MEMBASE_REG:
13734                 return OP_STORE_MEMBASE_IMM;
13735         case OP_STOREI1_MEMBASE_REG:
13736                 return OP_STOREI1_MEMBASE_IMM;
13737         case OP_STOREI2_MEMBASE_REG:
13738                 return OP_STOREI2_MEMBASE_IMM;
13739         case OP_STOREI4_MEMBASE_REG:
13740                 return OP_STOREI4_MEMBASE_IMM;
13741
13742 #if defined(TARGET_X86) || defined (TARGET_AMD64)
13743         case OP_X86_PUSH:
13744                 return OP_X86_PUSH_IMM;
13745         case OP_X86_COMPARE_MEMBASE_REG:
13746                 return OP_X86_COMPARE_MEMBASE_IMM;
13747 #endif
13748 #if defined(TARGET_AMD64)
13749         case OP_AMD64_ICOMPARE_MEMBASE_REG:
13750                 return OP_AMD64_ICOMPARE_MEMBASE_IMM;
13751 #endif
13752         case OP_VOIDCALL_REG:
13753                 return OP_VOIDCALL;
13754         case OP_CALL_REG:
13755                 return OP_CALL;
13756         case OP_LCALL_REG:
13757                 return OP_LCALL;
13758         case OP_FCALL_REG:
13759                 return OP_FCALL;
13760         case OP_LOCALLOC:
13761                 return OP_LOCALLOC_IMM;
13762         }
13763
13764         return -1;
13765 }
13766
13767 static int
13768 ldind_to_load_membase (int opcode)
13769 {
13770         switch (opcode) {
13771         case CEE_LDIND_I1:
13772                 return OP_LOADI1_MEMBASE;
13773         case CEE_LDIND_U1:
13774                 return OP_LOADU1_MEMBASE;
13775         case CEE_LDIND_I2:
13776                 return OP_LOADI2_MEMBASE;
13777         case CEE_LDIND_U2:
13778                 return OP_LOADU2_MEMBASE;
13779         case CEE_LDIND_I4:
13780                 return OP_LOADI4_MEMBASE;
13781         case CEE_LDIND_U4:
13782                 return OP_LOADU4_MEMBASE;
13783         case CEE_LDIND_I:
13784                 return OP_LOAD_MEMBASE;
13785         case CEE_LDIND_REF:
13786                 return OP_LOAD_MEMBASE;
13787         case CEE_LDIND_I8:
13788                 return OP_LOADI8_MEMBASE;
13789         case CEE_LDIND_R4:
13790                 return OP_LOADR4_MEMBASE;
13791         case CEE_LDIND_R8:
13792                 return OP_LOADR8_MEMBASE;
13793         default:
13794                 g_assert_not_reached ();
13795         }
13796
13797         return -1;
13798 }
13799
13800 static int
13801 stind_to_store_membase (int opcode)
13802 {
13803         switch (opcode) {
13804         case CEE_STIND_I1:
13805                 return OP_STOREI1_MEMBASE_REG;
13806         case CEE_STIND_I2:
13807                 return OP_STOREI2_MEMBASE_REG;
13808         case CEE_STIND_I4:
13809                 return OP_STOREI4_MEMBASE_REG;
13810         case CEE_STIND_I:
13811         case CEE_STIND_REF:
13812                 return OP_STORE_MEMBASE_REG;
13813         case CEE_STIND_I8:
13814                 return OP_STOREI8_MEMBASE_REG;
13815         case CEE_STIND_R4:
13816                 return OP_STORER4_MEMBASE_REG;
13817         case CEE_STIND_R8:
13818                 return OP_STORER8_MEMBASE_REG;
13819         default:
13820                 g_assert_not_reached ();
13821         }
13822
13823         return -1;
13824 }
13825
13826 int
13827 mono_load_membase_to_load_mem (int opcode)
13828 {
13829         // FIXME: Add a MONO_ARCH_HAVE_LOAD_MEM macro
13830 #if defined(TARGET_X86) || defined(TARGET_AMD64)
13831         switch (opcode) {
13832         case OP_LOAD_MEMBASE:
13833                 return OP_LOAD_MEM;
13834         case OP_LOADU1_MEMBASE:
13835                 return OP_LOADU1_MEM;
13836         case OP_LOADU2_MEMBASE:
13837                 return OP_LOADU2_MEM;
13838         case OP_LOADI4_MEMBASE:
13839                 return OP_LOADI4_MEM;
13840         case OP_LOADU4_MEMBASE:
13841                 return OP_LOADU4_MEM;
13842 #if SIZEOF_REGISTER == 8
13843         case OP_LOADI8_MEMBASE:
13844                 return OP_LOADI8_MEM;
13845 #endif
13846         }
13847 #endif
13848
13849         return -1;
13850 }
13851
13852 static inline int
13853 op_to_op_dest_membase (int store_opcode, int opcode)
13854 {
13855 #if defined(TARGET_X86)
13856         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG)))
13857                 return -1;
13858
13859         switch (opcode) {
13860         case OP_IADD:
13861                 return OP_X86_ADD_MEMBASE_REG;
13862         case OP_ISUB:
13863                 return OP_X86_SUB_MEMBASE_REG;
13864         case OP_IAND:
13865                 return OP_X86_AND_MEMBASE_REG;
13866         case OP_IOR:
13867                 return OP_X86_OR_MEMBASE_REG;
13868         case OP_IXOR:
13869                 return OP_X86_XOR_MEMBASE_REG;
13870         case OP_ADD_IMM:
13871         case OP_IADD_IMM:
13872                 return OP_X86_ADD_MEMBASE_IMM;
13873         case OP_SUB_IMM:
13874         case OP_ISUB_IMM:
13875                 return OP_X86_SUB_MEMBASE_IMM;
13876         case OP_AND_IMM:
13877         case OP_IAND_IMM:
13878                 return OP_X86_AND_MEMBASE_IMM;
13879         case OP_OR_IMM:
13880         case OP_IOR_IMM:
13881                 return OP_X86_OR_MEMBASE_IMM;
13882         case OP_XOR_IMM:
13883         case OP_IXOR_IMM:
13884                 return OP_X86_XOR_MEMBASE_IMM;
13885         case OP_MOVE:
13886                 return OP_NOP;
13887         }
13888 #endif
13889
13890 #if defined(TARGET_AMD64)
13891         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG) || (store_opcode == OP_STOREI8_MEMBASE_REG)))
13892                 return -1;
13893
13894         switch (opcode) {
13895         case OP_IADD:
13896                 return OP_X86_ADD_MEMBASE_REG;
13897         case OP_ISUB:
13898                 return OP_X86_SUB_MEMBASE_REG;
13899         case OP_IAND:
13900                 return OP_X86_AND_MEMBASE_REG;
13901         case OP_IOR:
13902                 return OP_X86_OR_MEMBASE_REG;
13903         case OP_IXOR:
13904                 return OP_X86_XOR_MEMBASE_REG;
13905         case OP_IADD_IMM:
13906                 return OP_X86_ADD_MEMBASE_IMM;
13907         case OP_ISUB_IMM:
13908                 return OP_X86_SUB_MEMBASE_IMM;
13909         case OP_IAND_IMM:
13910                 return OP_X86_AND_MEMBASE_IMM;
13911         case OP_IOR_IMM:
13912                 return OP_X86_OR_MEMBASE_IMM;
13913         case OP_IXOR_IMM:
13914                 return OP_X86_XOR_MEMBASE_IMM;
13915         case OP_LADD:
13916                 return OP_AMD64_ADD_MEMBASE_REG;
13917         case OP_LSUB:
13918                 return OP_AMD64_SUB_MEMBASE_REG;
13919         case OP_LAND:
13920                 return OP_AMD64_AND_MEMBASE_REG;
13921         case OP_LOR:
13922                 return OP_AMD64_OR_MEMBASE_REG;
13923         case OP_LXOR:
13924                 return OP_AMD64_XOR_MEMBASE_REG;
13925         case OP_ADD_IMM:
13926         case OP_LADD_IMM:
13927                 return OP_AMD64_ADD_MEMBASE_IMM;
13928         case OP_SUB_IMM:
13929         case OP_LSUB_IMM:
13930                 return OP_AMD64_SUB_MEMBASE_IMM;
13931         case OP_AND_IMM:
13932         case OP_LAND_IMM:
13933                 return OP_AMD64_AND_MEMBASE_IMM;
13934         case OP_OR_IMM:
13935         case OP_LOR_IMM:
13936                 return OP_AMD64_OR_MEMBASE_IMM;
13937         case OP_XOR_IMM:
13938         case OP_LXOR_IMM:
13939                 return OP_AMD64_XOR_MEMBASE_IMM;
13940         case OP_MOVE:
13941                 return OP_NOP;
13942         }
13943 #endif
13944
13945         return -1;
13946 }
13947
13948 static inline int
13949 op_to_op_store_membase (int store_opcode, int opcode)
13950 {
13951 #if defined(TARGET_X86) || defined(TARGET_AMD64)
13952         switch (opcode) {
13953         case OP_ICEQ:
13954                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
13955                         return OP_X86_SETEQ_MEMBASE;
13956         case OP_CNE:
13957                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
13958                         return OP_X86_SETNE_MEMBASE;
13959         }
13960 #endif
13961
13962         return -1;
13963 }
13964
13965 static inline int
13966 op_to_op_src1_membase (MonoCompile *cfg, int load_opcode, int opcode)
13967 {
13968 #ifdef TARGET_X86
13969         /* FIXME: This has sign extension issues */
13970         /*
13971         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
13972                 return OP_X86_COMPARE_MEMBASE8_IMM;
13973         */
13974
13975         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
13976                 return -1;
13977
13978         switch (opcode) {
13979         case OP_X86_PUSH:
13980                 return OP_X86_PUSH_MEMBASE;
13981         case OP_COMPARE_IMM:
13982         case OP_ICOMPARE_IMM:
13983                 return OP_X86_COMPARE_MEMBASE_IMM;
13984         case OP_COMPARE:
13985         case OP_ICOMPARE:
13986                 return OP_X86_COMPARE_MEMBASE_REG;
13987         }
13988 #endif
13989
13990 #ifdef TARGET_AMD64
13991         /* FIXME: This has sign extension issues */
13992         /*
13993         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
13994                 return OP_X86_COMPARE_MEMBASE8_IMM;
13995         */
13996
13997         switch (opcode) {
13998         case OP_X86_PUSH:
13999                 if ((load_opcode == OP_LOAD_MEMBASE && !cfg->backend->ilp32) || (load_opcode == OP_LOADI8_MEMBASE))
14000                         return OP_X86_PUSH_MEMBASE;
14001                 break;
14002                 /* FIXME: This only works for 32 bit immediates
14003         case OP_COMPARE_IMM:
14004         case OP_LCOMPARE_IMM:
14005                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
14006                         return OP_AMD64_COMPARE_MEMBASE_IMM;
14007                 */
14008         case OP_ICOMPARE_IMM:
14009                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
14010                         return OP_AMD64_ICOMPARE_MEMBASE_IMM;
14011                 break;
14012         case OP_COMPARE:
14013         case OP_LCOMPARE:
14014                 if (cfg->backend->ilp32 && load_opcode == OP_LOAD_MEMBASE)
14015                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
14016                 if ((load_opcode == OP_LOAD_MEMBASE && !cfg->backend->ilp32) || (load_opcode == OP_LOADI8_MEMBASE))
14017                         return OP_AMD64_COMPARE_MEMBASE_REG;
14018                 break;
14019         case OP_ICOMPARE:
14020                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
14021                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
14022                 break;
14023         }
14024 #endif
14025
14026         return -1;
14027 }
14028
14029 static inline int
14030 op_to_op_src2_membase (MonoCompile *cfg, int load_opcode, int opcode)
14031 {
14032 #ifdef TARGET_X86
14033         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
14034                 return -1;
14035         
14036         switch (opcode) {
14037         case OP_COMPARE:
14038         case OP_ICOMPARE:
14039                 return OP_X86_COMPARE_REG_MEMBASE;
14040         case OP_IADD:
14041                 return OP_X86_ADD_REG_MEMBASE;
14042         case OP_ISUB:
14043                 return OP_X86_SUB_REG_MEMBASE;
14044         case OP_IAND:
14045                 return OP_X86_AND_REG_MEMBASE;
14046         case OP_IOR:
14047                 return OP_X86_OR_REG_MEMBASE;
14048         case OP_IXOR:
14049                 return OP_X86_XOR_REG_MEMBASE;
14050         }
14051 #endif
14052
14053 #ifdef TARGET_AMD64
14054         if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE && cfg->backend->ilp32)) {
14055                 switch (opcode) {
14056                 case OP_ICOMPARE:
14057                         return OP_AMD64_ICOMPARE_REG_MEMBASE;
14058                 case OP_IADD:
14059                         return OP_X86_ADD_REG_MEMBASE;
14060                 case OP_ISUB:
14061                         return OP_X86_SUB_REG_MEMBASE;
14062                 case OP_IAND:
14063                         return OP_X86_AND_REG_MEMBASE;
14064                 case OP_IOR:
14065                         return OP_X86_OR_REG_MEMBASE;
14066                 case OP_IXOR:
14067                         return OP_X86_XOR_REG_MEMBASE;
14068                 }
14069         } else if ((load_opcode == OP_LOADI8_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE && !cfg->backend->ilp32)) {
14070                 switch (opcode) {
14071                 case OP_COMPARE:
14072                 case OP_LCOMPARE:
14073                         return OP_AMD64_COMPARE_REG_MEMBASE;
14074                 case OP_LADD:
14075                         return OP_AMD64_ADD_REG_MEMBASE;
14076                 case OP_LSUB:
14077                         return OP_AMD64_SUB_REG_MEMBASE;
14078                 case OP_LAND:
14079                         return OP_AMD64_AND_REG_MEMBASE;
14080                 case OP_LOR:
14081                         return OP_AMD64_OR_REG_MEMBASE;
14082                 case OP_LXOR:
14083                         return OP_AMD64_XOR_REG_MEMBASE;
14084                 }
14085         }
14086 #endif
14087
14088         return -1;
14089 }
14090
14091 int
14092 mono_op_to_op_imm_noemul (int opcode)
14093 {
14094         switch (opcode) {
14095 #if SIZEOF_REGISTER == 4 && !defined(MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS)
14096         case OP_LSHR:
14097         case OP_LSHL:
14098         case OP_LSHR_UN:
14099                 return -1;
14100 #endif
14101 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
14102         case OP_IDIV:
14103         case OP_IDIV_UN:
14104         case OP_IREM:
14105         case OP_IREM_UN:
14106                 return -1;
14107 #endif
14108 #if defined(MONO_ARCH_EMULATE_MUL_DIV)
14109         case OP_IMUL:
14110                 return -1;
14111 #endif
14112         default:
14113                 return mono_op_to_op_imm (opcode);
14114         }
14115 }
14116
14117 /**
14118  * mono_handle_global_vregs:
14119  *
14120  *   Make vregs used in more than one bblock 'global', i.e. allocate a variable
14121  * for them.
14122  */
14123 void
14124 mono_handle_global_vregs (MonoCompile *cfg)
14125 {
14126         gint32 *vreg_to_bb;
14127         MonoBasicBlock *bb;
14128         int i, pos;
14129
14130         vreg_to_bb = (gint32 *)mono_mempool_alloc0 (cfg->mempool, sizeof (gint32*) * cfg->next_vreg + 1);
14131
14132 #ifdef MONO_ARCH_SIMD_INTRINSICS
14133         if (cfg->uses_simd_intrinsics)
14134                 mono_simd_simplify_indirection (cfg);
14135 #endif
14136
14137         /* Find local vregs used in more than one bb */
14138         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
14139                 MonoInst *ins = bb->code;       
14140                 int block_num = bb->block_num;
14141
14142                 if (cfg->verbose_level > 2)
14143                         printf ("\nHANDLE-GLOBAL-VREGS BLOCK %d:\n", bb->block_num);
14144
14145                 cfg->cbb = bb;
14146                 for (; ins; ins = ins->next) {
14147                         const char *spec = INS_INFO (ins->opcode);
14148                         int regtype = 0, regindex;
14149                         gint32 prev_bb;
14150
14151                         if (G_UNLIKELY (cfg->verbose_level > 2))
14152                                 mono_print_ins (ins);
14153
14154                         g_assert (ins->opcode >= MONO_CEE_LAST);
14155
14156                         for (regindex = 0; regindex < 4; regindex ++) {
14157                                 int vreg = 0;
14158
14159                                 if (regindex == 0) {
14160                                         regtype = spec [MONO_INST_DEST];
14161                                         if (regtype == ' ')
14162                                                 continue;
14163                                         vreg = ins->dreg;
14164                                 } else if (regindex == 1) {
14165                                         regtype = spec [MONO_INST_SRC1];
14166                                         if (regtype == ' ')
14167                                                 continue;
14168                                         vreg = ins->sreg1;
14169                                 } else if (regindex == 2) {
14170                                         regtype = spec [MONO_INST_SRC2];
14171                                         if (regtype == ' ')
14172                                                 continue;
14173                                         vreg = ins->sreg2;
14174                                 } else if (regindex == 3) {
14175                                         regtype = spec [MONO_INST_SRC3];
14176                                         if (regtype == ' ')
14177                                                 continue;
14178                                         vreg = ins->sreg3;
14179                                 }
14180
14181 #if SIZEOF_REGISTER == 4
14182                                 /* In the LLVM case, the long opcodes are not decomposed */
14183                                 if (regtype == 'l' && !COMPILE_LLVM (cfg)) {
14184                                         /*
14185                                          * Since some instructions reference the original long vreg,
14186                                          * and some reference the two component vregs, it is quite hard
14187                                          * to determine when it needs to be global. So be conservative.
14188                                          */
14189                                         if (!get_vreg_to_inst (cfg, vreg)) {
14190                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
14191
14192                                                 if (cfg->verbose_level > 2)
14193                                                         printf ("LONG VREG R%d made global.\n", vreg);
14194                                         }
14195
14196                                         /*
14197                                          * Make the component vregs volatile since the optimizations can
14198                                          * get confused otherwise.
14199                                          */
14200                                         get_vreg_to_inst (cfg, MONO_LVREG_LS (vreg))->flags |= MONO_INST_VOLATILE;
14201                                         get_vreg_to_inst (cfg, MONO_LVREG_MS (vreg))->flags |= MONO_INST_VOLATILE;
14202                                 }
14203 #endif
14204
14205                                 g_assert (vreg != -1);
14206
14207                                 prev_bb = vreg_to_bb [vreg];
14208                                 if (prev_bb == 0) {
14209                                         /* 0 is a valid block num */
14210                                         vreg_to_bb [vreg] = block_num + 1;
14211                                 } else if ((prev_bb != block_num + 1) && (prev_bb != -1)) {
14212                                         if (((regtype == 'i' && (vreg < MONO_MAX_IREGS))) || (regtype == 'f' && (vreg < MONO_MAX_FREGS)))
14213                                                 continue;
14214
14215                                         if (!get_vreg_to_inst (cfg, vreg)) {
14216                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
14217                                                         printf ("VREG R%d used in BB%d and BB%d made global.\n", vreg, vreg_to_bb [vreg], block_num);
14218
14219                                                 switch (regtype) {
14220                                                 case 'i':
14221                                                         if (vreg_is_ref (cfg, vreg))
14222                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL, vreg);
14223                                                         else
14224                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL, vreg);
14225                                                         break;
14226                                                 case 'l':
14227                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
14228                                                         break;
14229                                                 case 'f':
14230                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.double_class->byval_arg, OP_LOCAL, vreg);
14231                                                         break;
14232                                                 case 'v':
14233                                                         mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, vreg);
14234                                                         break;
14235                                                 default:
14236                                                         g_assert_not_reached ();
14237                                                 }
14238                                         }
14239
14240                                         /* Flag as having been used in more than one bb */
14241                                         vreg_to_bb [vreg] = -1;
14242                                 }
14243                         }
14244                 }
14245         }
14246
14247         /* If a variable is used in only one bblock, convert it into a local vreg */
14248         for (i = 0; i < cfg->num_varinfo; i++) {
14249                 MonoInst *var = cfg->varinfo [i];
14250                 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
14251
14252                 switch (var->type) {
14253                 case STACK_I4:
14254                 case STACK_OBJ:
14255                 case STACK_PTR:
14256                 case STACK_MP:
14257                 case STACK_VTYPE:
14258 #if SIZEOF_REGISTER == 8
14259                 case STACK_I8:
14260 #endif
14261 #if !defined(TARGET_X86)
14262                 /* Enabling this screws up the fp stack on x86 */
14263                 case STACK_R8:
14264 #endif
14265                         if (mono_arch_is_soft_float ())
14266                                 break;
14267
14268                         /*
14269                         if (var->type == STACK_VTYPE && cfg->gsharedvt && mini_is_gsharedvt_variable_type (var->inst_vtype))
14270                                 break;
14271                         */
14272
14273                         /* Arguments are implicitly global */
14274                         /* Putting R4 vars into registers doesn't work currently */
14275                         /* The gsharedvt vars are implicitly referenced by ldaddr opcodes, but those opcodes are only generated later */
14276                         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) {
14277                                 /* 
14278                                  * Make that the variable's liveness interval doesn't contain a call, since
14279                                  * that would cause the lvreg to be spilled, making the whole optimization
14280                                  * useless.
14281                                  */
14282                                 /* This is too slow for JIT compilation */
14283 #if 0
14284                                 if (cfg->compile_aot && vreg_to_bb [var->dreg]) {
14285                                         MonoInst *ins;
14286                                         int def_index, call_index, ins_index;
14287                                         gboolean spilled = FALSE;
14288
14289                                         def_index = -1;
14290                                         call_index = -1;
14291                                         ins_index = 0;
14292                                         for (ins = vreg_to_bb [var->dreg]->code; ins; ins = ins->next) {
14293                                                 const char *spec = INS_INFO (ins->opcode);
14294
14295                                                 if ((spec [MONO_INST_DEST] != ' ') && (ins->dreg == var->dreg))
14296                                                         def_index = ins_index;
14297
14298                                                 if (((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg)) ||
14299                                                         ((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg))) {
14300                                                         if (call_index > def_index) {
14301                                                                 spilled = TRUE;
14302                                                                 break;
14303                                                         }
14304                                                 }
14305
14306                                                 if (MONO_IS_CALL (ins))
14307                                                         call_index = ins_index;
14308
14309                                                 ins_index ++;
14310                                         }
14311
14312                                         if (spilled)
14313                                                 break;
14314                                 }
14315 #endif
14316
14317                                 if (G_UNLIKELY (cfg->verbose_level > 2))
14318                                         printf ("CONVERTED R%d(%d) TO VREG.\n", var->dreg, vmv->idx);
14319                                 var->flags |= MONO_INST_IS_DEAD;
14320                                 cfg->vreg_to_inst [var->dreg] = NULL;
14321                         }
14322                         break;
14323                 }
14324         }
14325
14326         /* 
14327          * Compress the varinfo and vars tables so the liveness computation is faster and
14328          * takes up less space.
14329          */
14330         pos = 0;
14331         for (i = 0; i < cfg->num_varinfo; ++i) {
14332                 MonoInst *var = cfg->varinfo [i];
14333                 if (pos < i && cfg->locals_start == i)
14334                         cfg->locals_start = pos;
14335                 if (!(var->flags & MONO_INST_IS_DEAD)) {
14336                         if (pos < i) {
14337                                 cfg->varinfo [pos] = cfg->varinfo [i];
14338                                 cfg->varinfo [pos]->inst_c0 = pos;
14339                                 memcpy (&cfg->vars [pos], &cfg->vars [i], sizeof (MonoMethodVar));
14340                                 cfg->vars [pos].idx = pos;
14341 #if SIZEOF_REGISTER == 4
14342                                 if (cfg->varinfo [pos]->type == STACK_I8) {
14343                                         /* Modify the two component vars too */
14344                                         MonoInst *var1;
14345
14346                                         var1 = get_vreg_to_inst (cfg, MONO_LVREG_LS (cfg->varinfo [pos]->dreg));
14347                                         var1->inst_c0 = pos;
14348                                         var1 = get_vreg_to_inst (cfg, MONO_LVREG_MS (cfg->varinfo [pos]->dreg));
14349                                         var1->inst_c0 = pos;
14350                                 }
14351 #endif
14352                         }
14353                         pos ++;
14354                 }
14355         }
14356         cfg->num_varinfo = pos;
14357         if (cfg->locals_start > cfg->num_varinfo)
14358                 cfg->locals_start = cfg->num_varinfo;
14359 }
14360
14361 /*
14362  * mono_allocate_gsharedvt_vars:
14363  *
14364  *   Allocate variables with gsharedvt types to entries in the MonoGSharedVtMethodRuntimeInfo.entries array.
14365  * Initialize cfg->gsharedvt_vreg_to_idx with the mapping between vregs and indexes.
14366  */
14367 void
14368 mono_allocate_gsharedvt_vars (MonoCompile *cfg)
14369 {
14370         int i;
14371
14372         cfg->gsharedvt_vreg_to_idx = (int *)mono_mempool_alloc0 (cfg->mempool, sizeof (int) * cfg->next_vreg);
14373
14374         for (i = 0; i < cfg->num_varinfo; ++i) {
14375                 MonoInst *ins = cfg->varinfo [i];
14376                 int idx;
14377
14378                 if (mini_is_gsharedvt_variable_type (ins->inst_vtype)) {
14379                         if (i >= cfg->locals_start) {
14380                                 /* Local */
14381                                 idx = get_gsharedvt_info_slot (cfg, ins->inst_vtype, MONO_RGCTX_INFO_LOCAL_OFFSET);
14382                                 cfg->gsharedvt_vreg_to_idx [ins->dreg] = idx + 1;
14383                                 ins->opcode = OP_GSHAREDVT_LOCAL;
14384                                 ins->inst_imm = idx;
14385                         } else {
14386                                 /* Arg */
14387                                 cfg->gsharedvt_vreg_to_idx [ins->dreg] = -1;
14388                                 ins->opcode = OP_GSHAREDVT_ARG_REGOFFSET;
14389                         }
14390                 }
14391         }
14392 }
14393
14394 /**
14395  * mono_spill_global_vars:
14396  *
14397  *   Generate spill code for variables which are not allocated to registers, 
14398  * and replace vregs with their allocated hregs. *need_local_opts is set to TRUE if
14399  * code is generated which could be optimized by the local optimization passes.
14400  */
14401 void
14402 mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
14403 {
14404         MonoBasicBlock *bb;
14405         char spec2 [16];
14406         int orig_next_vreg;
14407         guint32 *vreg_to_lvreg;
14408         guint32 *lvregs;
14409         guint32 i, lvregs_len;
14410         gboolean dest_has_lvreg = FALSE;
14411         MonoStackType stacktypes [128];
14412         MonoInst **live_range_start, **live_range_end;
14413         MonoBasicBlock **live_range_start_bb, **live_range_end_bb;
14414
14415         *need_local_opts = FALSE;
14416
14417         memset (spec2, 0, sizeof (spec2));
14418
14419         /* FIXME: Move this function to mini.c */
14420         stacktypes ['i'] = STACK_PTR;
14421         stacktypes ['l'] = STACK_I8;
14422         stacktypes ['f'] = STACK_R8;
14423 #ifdef MONO_ARCH_SIMD_INTRINSICS
14424         stacktypes ['x'] = STACK_VTYPE;
14425 #endif
14426
14427 #if SIZEOF_REGISTER == 4
14428         /* Create MonoInsts for longs */
14429         for (i = 0; i < cfg->num_varinfo; i++) {
14430                 MonoInst *ins = cfg->varinfo [i];
14431
14432                 if ((ins->opcode != OP_REGVAR) && !(ins->flags & MONO_INST_IS_DEAD)) {
14433                         switch (ins->type) {
14434                         case STACK_R8:
14435                         case STACK_I8: {
14436                                 MonoInst *tree;
14437
14438                                 if (ins->type == STACK_R8 && !COMPILE_SOFT_FLOAT (cfg))
14439                                         break;
14440
14441                                 g_assert (ins->opcode == OP_REGOFFSET);
14442
14443                                 tree = get_vreg_to_inst (cfg, MONO_LVREG_LS (ins->dreg));
14444                                 g_assert (tree);
14445                                 tree->opcode = OP_REGOFFSET;
14446                                 tree->inst_basereg = ins->inst_basereg;
14447                                 tree->inst_offset = ins->inst_offset + MINI_LS_WORD_OFFSET;
14448
14449                                 tree = get_vreg_to_inst (cfg, MONO_LVREG_MS (ins->dreg));
14450                                 g_assert (tree);
14451                                 tree->opcode = OP_REGOFFSET;
14452                                 tree->inst_basereg = ins->inst_basereg;
14453                                 tree->inst_offset = ins->inst_offset + MINI_MS_WORD_OFFSET;
14454                                 break;
14455                         }
14456                         default:
14457                                 break;
14458                         }
14459                 }
14460         }
14461 #endif
14462
14463         if (cfg->compute_gc_maps) {
14464                 /* registers need liveness info even for !non refs */
14465                 for (i = 0; i < cfg->num_varinfo; i++) {
14466                         MonoInst *ins = cfg->varinfo [i];
14467
14468                         if (ins->opcode == OP_REGVAR)
14469                                 ins->flags |= MONO_INST_GC_TRACK;
14470                 }
14471         }
14472                 
14473         /* FIXME: widening and truncation */
14474
14475         /*
14476          * As an optimization, when a variable allocated to the stack is first loaded into 
14477          * an lvreg, we will remember the lvreg and use it the next time instead of loading
14478          * the variable again.
14479          */
14480         orig_next_vreg = cfg->next_vreg;
14481         vreg_to_lvreg = (guint32 *)mono_mempool_alloc0 (cfg->mempool, sizeof (guint32) * cfg->next_vreg);
14482         lvregs = (guint32 *)mono_mempool_alloc (cfg->mempool, sizeof (guint32) * 1024);
14483         lvregs_len = 0;
14484
14485         /* 
14486          * These arrays contain the first and last instructions accessing a given
14487          * variable.
14488          * Since we emit bblocks in the same order we process them here, and we
14489          * don't split live ranges, these will precisely describe the live range of
14490          * the variable, i.e. the instruction range where a valid value can be found
14491          * in the variables location.
14492          * The live range is computed using the liveness info computed by the liveness pass.
14493          * We can't use vmv->range, since that is an abstract live range, and we need
14494          * one which is instruction precise.
14495          * FIXME: Variables used in out-of-line bblocks have a hole in their live range.
14496          */
14497         /* FIXME: Only do this if debugging info is requested */
14498         live_range_start = g_new0 (MonoInst*, cfg->next_vreg);
14499         live_range_end = g_new0 (MonoInst*, cfg->next_vreg);
14500         live_range_start_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
14501         live_range_end_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
14502         
14503         /* Add spill loads/stores */
14504         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
14505                 MonoInst *ins;
14506
14507                 if (cfg->verbose_level > 2)
14508                         printf ("\nSPILL BLOCK %d:\n", bb->block_num);
14509
14510                 /* Clear vreg_to_lvreg array */
14511                 for (i = 0; i < lvregs_len; i++)
14512                         vreg_to_lvreg [lvregs [i]] = 0;
14513                 lvregs_len = 0;
14514
14515                 cfg->cbb = bb;
14516                 MONO_BB_FOR_EACH_INS (bb, ins) {
14517                         const char *spec = INS_INFO (ins->opcode);
14518                         int regtype, srcindex, sreg, tmp_reg, prev_dreg, num_sregs;
14519                         gboolean store, no_lvreg;
14520                         int sregs [MONO_MAX_SRC_REGS];
14521
14522                         if (G_UNLIKELY (cfg->verbose_level > 2))
14523                                 mono_print_ins (ins);
14524
14525                         if (ins->opcode == OP_NOP)
14526                                 continue;
14527
14528                         /* 
14529                          * We handle LDADDR here as well, since it can only be decomposed
14530                          * when variable addresses are known.
14531                          */
14532                         if (ins->opcode == OP_LDADDR) {
14533                                 MonoInst *var = (MonoInst *)ins->inst_p0;
14534
14535                                 if (var->opcode == OP_VTARG_ADDR) {
14536                                         /* Happens on SPARC/S390 where vtypes are passed by reference */
14537                                         MonoInst *vtaddr = var->inst_left;
14538                                         if (vtaddr->opcode == OP_REGVAR) {
14539                                                 ins->opcode = OP_MOVE;
14540                                                 ins->sreg1 = vtaddr->dreg;
14541                                         }
14542                                         else if (var->inst_left->opcode == OP_REGOFFSET) {
14543                                                 ins->opcode = OP_LOAD_MEMBASE;
14544                                                 ins->inst_basereg = vtaddr->inst_basereg;
14545                                                 ins->inst_offset = vtaddr->inst_offset;
14546                                         } else
14547                                                 NOT_IMPLEMENTED;
14548                                 } else if (cfg->gsharedvt && cfg->gsharedvt_vreg_to_idx [var->dreg] < 0) {
14549                                         /* gsharedvt arg passed by ref */
14550                                         g_assert (var->opcode == OP_GSHAREDVT_ARG_REGOFFSET);
14551
14552                                         ins->opcode = OP_LOAD_MEMBASE;
14553                                         ins->inst_basereg = var->inst_basereg;
14554                                         ins->inst_offset = var->inst_offset;
14555                                 } else if (cfg->gsharedvt && cfg->gsharedvt_vreg_to_idx [var->dreg]) {
14556                                         MonoInst *load, *load2, *load3;
14557                                         int idx = cfg->gsharedvt_vreg_to_idx [var->dreg] - 1;
14558                                         int reg1, reg2, reg3;
14559                                         MonoInst *info_var = cfg->gsharedvt_info_var;
14560                                         MonoInst *locals_var = cfg->gsharedvt_locals_var;
14561
14562                                         /*
14563                                          * gsharedvt local.
14564                                          * Compute the address of the local as gsharedvt_locals_var + gsharedvt_info_var->locals_offsets [idx].
14565                                          */
14566
14567                                         g_assert (var->opcode == OP_GSHAREDVT_LOCAL);
14568
14569                                         g_assert (info_var);
14570                                         g_assert (locals_var);
14571
14572                                         /* Mark the instruction used to compute the locals var as used */
14573                                         cfg->gsharedvt_locals_var_ins = NULL;
14574
14575                                         /* Load the offset */
14576                                         if (info_var->opcode == OP_REGOFFSET) {
14577                                                 reg1 = alloc_ireg (cfg);
14578                                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, reg1, info_var->inst_basereg, info_var->inst_offset);
14579                                         } else if (info_var->opcode == OP_REGVAR) {
14580                                                 load = NULL;
14581                                                 reg1 = info_var->dreg;
14582                                         } else {
14583                                                 g_assert_not_reached ();
14584                                         }
14585                                         reg2 = alloc_ireg (cfg);
14586                                         NEW_LOAD_MEMBASE (cfg, load2, OP_LOADI4_MEMBASE, reg2, reg1, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, entries) + (idx * sizeof (gpointer)));
14587                                         /* Load the locals area address */
14588                                         reg3 = alloc_ireg (cfg);
14589                                         if (locals_var->opcode == OP_REGOFFSET) {
14590                                                 NEW_LOAD_MEMBASE (cfg, load3, OP_LOAD_MEMBASE, reg3, locals_var->inst_basereg, locals_var->inst_offset);
14591                                         } else if (locals_var->opcode == OP_REGVAR) {
14592                                                 NEW_UNALU (cfg, load3, OP_MOVE, reg3, locals_var->dreg);
14593                                         } else {
14594                                                 g_assert_not_reached ();
14595                                         }
14596                                         /* Compute the address */
14597                                         ins->opcode = OP_PADD;
14598                                         ins->sreg1 = reg3;
14599                                         ins->sreg2 = reg2;
14600
14601                                         mono_bblock_insert_before_ins (bb, ins, load3);
14602                                         mono_bblock_insert_before_ins (bb, load3, load2);
14603                                         if (load)
14604                                                 mono_bblock_insert_before_ins (bb, load2, load);
14605                                 } else {
14606                                         g_assert (var->opcode == OP_REGOFFSET);
14607
14608                                         ins->opcode = OP_ADD_IMM;
14609                                         ins->sreg1 = var->inst_basereg;
14610                                         ins->inst_imm = var->inst_offset;
14611                                 }
14612
14613                                 *need_local_opts = TRUE;
14614                                 spec = INS_INFO (ins->opcode);
14615                         }
14616
14617                         if (ins->opcode < MONO_CEE_LAST) {
14618                                 mono_print_ins (ins);
14619                                 g_assert_not_reached ();
14620                         }
14621
14622                         /*
14623                          * Store opcodes have destbasereg in the dreg, but in reality, it is an
14624                          * src register.
14625                          * FIXME:
14626                          */
14627                         if (MONO_IS_STORE_MEMBASE (ins)) {
14628                                 tmp_reg = ins->dreg;
14629                                 ins->dreg = ins->sreg2;
14630                                 ins->sreg2 = tmp_reg;
14631                                 store = TRUE;
14632
14633                                 spec2 [MONO_INST_DEST] = ' ';
14634                                 spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
14635                                 spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
14636                                 spec2 [MONO_INST_SRC3] = ' ';
14637                                 spec = spec2;
14638                         } else if (MONO_IS_STORE_MEMINDEX (ins))
14639                                 g_assert_not_reached ();
14640                         else
14641                                 store = FALSE;
14642                         no_lvreg = FALSE;
14643
14644                         if (G_UNLIKELY (cfg->verbose_level > 2)) {
14645                                 printf ("\t %.3s %d", spec, ins->dreg);
14646                                 num_sregs = mono_inst_get_src_registers (ins, sregs);
14647                                 for (srcindex = 0; srcindex < num_sregs; ++srcindex)
14648                                         printf (" %d", sregs [srcindex]);
14649                                 printf ("\n");
14650                         }
14651
14652                         /***************/
14653                         /*    DREG     */
14654                         /***************/
14655                         regtype = spec [MONO_INST_DEST];
14656                         g_assert (((ins->dreg == -1) && (regtype == ' ')) || ((ins->dreg != -1) && (regtype != ' ')));
14657                         prev_dreg = -1;
14658
14659                         if ((ins->dreg != -1) && get_vreg_to_inst (cfg, ins->dreg)) {
14660                                 MonoInst *var = get_vreg_to_inst (cfg, ins->dreg);
14661                                 MonoInst *store_ins;
14662                                 int store_opcode;
14663                                 MonoInst *def_ins = ins;
14664                                 int dreg = ins->dreg; /* The original vreg */
14665
14666                                 store_opcode = mono_type_to_store_membase (cfg, var->inst_vtype);
14667
14668                                 if (var->opcode == OP_REGVAR) {
14669                                         ins->dreg = var->dreg;
14670                                 } 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)) {
14671                                         /* 
14672                                          * Instead of emitting a load+store, use a _membase opcode.
14673                                          */
14674                                         g_assert (var->opcode == OP_REGOFFSET);
14675                                         if (ins->opcode == OP_MOVE) {
14676                                                 NULLIFY_INS (ins);
14677                                                 def_ins = NULL;
14678                                         } else {
14679                                                 ins->opcode = op_to_op_dest_membase (store_opcode, ins->opcode);
14680                                                 ins->inst_basereg = var->inst_basereg;
14681                                                 ins->inst_offset = var->inst_offset;
14682                                                 ins->dreg = -1;
14683                                         }
14684                                         spec = INS_INFO (ins->opcode);
14685                                 } else {
14686                                         guint32 lvreg;
14687
14688                                         g_assert (var->opcode == OP_REGOFFSET);
14689
14690                                         prev_dreg = ins->dreg;
14691
14692                                         /* Invalidate any previous lvreg for this vreg */
14693                                         vreg_to_lvreg [ins->dreg] = 0;
14694
14695                                         lvreg = 0;
14696
14697                                         if (COMPILE_SOFT_FLOAT (cfg) && store_opcode == OP_STORER8_MEMBASE_REG) {
14698                                                 regtype = 'l';
14699                                                 store_opcode = OP_STOREI8_MEMBASE_REG;
14700                                         }
14701
14702                                         ins->dreg = alloc_dreg (cfg, stacktypes [regtype]);
14703
14704 #if SIZEOF_REGISTER != 8
14705                                         if (regtype == 'l') {
14706                                                 NEW_STORE_MEMBASE (cfg, store_ins, OP_STOREI4_MEMBASE_REG, var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET, MONO_LVREG_LS (ins->dreg));
14707                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
14708                                                 NEW_STORE_MEMBASE (cfg, store_ins, OP_STOREI4_MEMBASE_REG, var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET, MONO_LVREG_MS (ins->dreg));
14709                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
14710                                                 def_ins = store_ins;
14711                                         }
14712                                         else
14713 #endif
14714                                         {
14715                                                 g_assert (store_opcode != OP_STOREV_MEMBASE);
14716
14717                                                 /* Try to fuse the store into the instruction itself */
14718                                                 /* FIXME: Add more instructions */
14719                                                 if (!lvreg && ((ins->opcode == OP_ICONST) || ((ins->opcode == OP_I8CONST) && (ins->inst_c0 == 0)))) {
14720                                                         ins->opcode = store_membase_reg_to_store_membase_imm (store_opcode);
14721                                                         ins->inst_imm = ins->inst_c0;
14722                                                         ins->inst_destbasereg = var->inst_basereg;
14723                                                         ins->inst_offset = var->inst_offset;
14724                                                         spec = INS_INFO (ins->opcode);
14725                                                 } else if (!lvreg && ((ins->opcode == OP_MOVE) || (ins->opcode == OP_FMOVE) || (ins->opcode == OP_LMOVE) || (ins->opcode == OP_RMOVE))) {
14726                                                         ins->opcode = store_opcode;
14727                                                         ins->inst_destbasereg = var->inst_basereg;
14728                                                         ins->inst_offset = var->inst_offset;
14729
14730                                                         no_lvreg = TRUE;
14731
14732                                                         tmp_reg = ins->dreg;
14733                                                         ins->dreg = ins->sreg2;
14734                                                         ins->sreg2 = tmp_reg;
14735                                                         store = TRUE;
14736
14737                                                         spec2 [MONO_INST_DEST] = ' ';
14738                                                         spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
14739                                                         spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
14740                                                         spec2 [MONO_INST_SRC3] = ' ';
14741                                                         spec = spec2;
14742                                                 } else if (!lvreg && (op_to_op_store_membase (store_opcode, ins->opcode) != -1)) {
14743                                                         // FIXME: The backends expect the base reg to be in inst_basereg
14744                                                         ins->opcode = op_to_op_store_membase (store_opcode, ins->opcode);
14745                                                         ins->dreg = -1;
14746                                                         ins->inst_basereg = var->inst_basereg;
14747                                                         ins->inst_offset = var->inst_offset;
14748                                                         spec = INS_INFO (ins->opcode);
14749                                                 } else {
14750                                                         /* printf ("INS: "); mono_print_ins (ins); */
14751                                                         /* Create a store instruction */
14752                                                         NEW_STORE_MEMBASE (cfg, store_ins, store_opcode, var->inst_basereg, var->inst_offset, ins->dreg);
14753
14754                                                         /* Insert it after the instruction */
14755                                                         mono_bblock_insert_after_ins (bb, ins, store_ins);
14756
14757                                                         def_ins = store_ins;
14758
14759                                                         /* 
14760                                                          * We can't assign ins->dreg to var->dreg here, since the
14761                                                          * sregs could use it. So set a flag, and do it after
14762                                                          * the sregs.
14763                                                          */
14764                                                         if ((!cfg->backend->use_fpstack || ((store_opcode != OP_STORER8_MEMBASE_REG) && (store_opcode != OP_STORER4_MEMBASE_REG))) && !((var)->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT)))
14765                                                                 dest_has_lvreg = TRUE;
14766                                                 }
14767                                         }
14768                                 }
14769
14770                                 if (def_ins && !live_range_start [dreg]) {
14771                                         live_range_start [dreg] = def_ins;
14772                                         live_range_start_bb [dreg] = bb;
14773                                 }
14774
14775                                 if (cfg->compute_gc_maps && def_ins && (var->flags & MONO_INST_GC_TRACK)) {
14776                                         MonoInst *tmp;
14777
14778                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_DEF);
14779                                         tmp->inst_c1 = dreg;
14780                                         mono_bblock_insert_after_ins (bb, def_ins, tmp);
14781                                 }
14782                         }
14783
14784                         /************/
14785                         /*  SREGS   */
14786                         /************/
14787                         num_sregs = mono_inst_get_src_registers (ins, sregs);
14788                         for (srcindex = 0; srcindex < 3; ++srcindex) {
14789                                 regtype = spec [MONO_INST_SRC1 + srcindex];
14790                                 sreg = sregs [srcindex];
14791
14792                                 g_assert (((sreg == -1) && (regtype == ' ')) || ((sreg != -1) && (regtype != ' ')));
14793                                 if ((sreg != -1) && get_vreg_to_inst (cfg, sreg)) {
14794                                         MonoInst *var = get_vreg_to_inst (cfg, sreg);
14795                                         MonoInst *use_ins = ins;
14796                                         MonoInst *load_ins;
14797                                         guint32 load_opcode;
14798
14799                                         if (var->opcode == OP_REGVAR) {
14800                                                 sregs [srcindex] = var->dreg;
14801                                                 //mono_inst_set_src_registers (ins, sregs);
14802                                                 live_range_end [sreg] = use_ins;
14803                                                 live_range_end_bb [sreg] = bb;
14804
14805                                                 if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
14806                                                         MonoInst *tmp;
14807
14808                                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
14809                                                         /* var->dreg is a hreg */
14810                                                         tmp->inst_c1 = sreg;
14811                                                         mono_bblock_insert_after_ins (bb, ins, tmp);
14812                                                 }
14813
14814                                                 continue;
14815                                         }
14816
14817                                         g_assert (var->opcode == OP_REGOFFSET);
14818                                                 
14819                                         load_opcode = mono_type_to_load_membase (cfg, var->inst_vtype);
14820
14821                                         g_assert (load_opcode != OP_LOADV_MEMBASE);
14822
14823                                         if (vreg_to_lvreg [sreg]) {
14824                                                 g_assert (vreg_to_lvreg [sreg] != -1);
14825
14826                                                 /* The variable is already loaded to an lvreg */
14827                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
14828                                                         printf ("\t\tUse lvreg R%d for R%d.\n", vreg_to_lvreg [sreg], sreg);
14829                                                 sregs [srcindex] = vreg_to_lvreg [sreg];
14830                                                 //mono_inst_set_src_registers (ins, sregs);
14831                                                 continue;
14832                                         }
14833
14834                                         /* Try to fuse the load into the instruction */
14835                                         if ((srcindex == 0) && (op_to_op_src1_membase (cfg, load_opcode, ins->opcode) != -1)) {
14836                                                 ins->opcode = op_to_op_src1_membase (cfg, load_opcode, ins->opcode);
14837                                                 sregs [0] = var->inst_basereg;
14838                                                 //mono_inst_set_src_registers (ins, sregs);
14839                                                 ins->inst_offset = var->inst_offset;
14840                                         } else if ((srcindex == 1) && (op_to_op_src2_membase (cfg, load_opcode, ins->opcode) != -1)) {
14841                                                 ins->opcode = op_to_op_src2_membase (cfg, load_opcode, ins->opcode);
14842                                                 sregs [1] = var->inst_basereg;
14843                                                 //mono_inst_set_src_registers (ins, sregs);
14844                                                 ins->inst_offset = var->inst_offset;
14845                                         } else {
14846                                                 if (MONO_IS_REAL_MOVE (ins)) {
14847                                                         ins->opcode = OP_NOP;
14848                                                         sreg = ins->dreg;
14849                                                 } else {
14850                                                         //printf ("%d ", srcindex); mono_print_ins (ins);
14851
14852                                                         sreg = alloc_dreg (cfg, stacktypes [regtype]);
14853
14854                                                         if ((!cfg->backend->use_fpstack || ((load_opcode != OP_LOADR8_MEMBASE) && (load_opcode != OP_LOADR4_MEMBASE))) && !((var)->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT)) && !no_lvreg) {
14855                                                                 if (var->dreg == prev_dreg) {
14856                                                                         /*
14857                                                                          * sreg refers to the value loaded by the load
14858                                                                          * emitted below, but we need to use ins->dreg
14859                                                                          * since it refers to the store emitted earlier.
14860                                                                          */
14861                                                                         sreg = ins->dreg;
14862                                                                 }
14863                                                                 g_assert (sreg != -1);
14864                                                                 vreg_to_lvreg [var->dreg] = sreg;
14865                                                                 g_assert (lvregs_len < 1024);
14866                                                                 lvregs [lvregs_len ++] = var->dreg;
14867                                                         }
14868                                                 }
14869
14870                                                 sregs [srcindex] = sreg;
14871                                                 //mono_inst_set_src_registers (ins, sregs);
14872
14873 #if SIZEOF_REGISTER != 8
14874                                                 if (regtype == 'l') {
14875                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, MONO_LVREG_MS (sreg), var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET);
14876                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14877                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, MONO_LVREG_LS (sreg), var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET);
14878                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14879                                                         use_ins = load_ins;
14880                                                 }
14881                                                 else
14882 #endif
14883                                                 {
14884 #if SIZEOF_REGISTER == 4
14885                                                         g_assert (load_opcode != OP_LOADI8_MEMBASE);
14886 #endif
14887                                                         NEW_LOAD_MEMBASE (cfg, load_ins, load_opcode, sreg, var->inst_basereg, var->inst_offset);
14888                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14889                                                         use_ins = load_ins;
14890                                                 }
14891                                         }
14892
14893                                         if (var->dreg < orig_next_vreg) {
14894                                                 live_range_end [var->dreg] = use_ins;
14895                                                 live_range_end_bb [var->dreg] = bb;
14896                                         }
14897
14898                                         if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
14899                                                 MonoInst *tmp;
14900
14901                                                 MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
14902                                                 tmp->inst_c1 = var->dreg;
14903                                                 mono_bblock_insert_after_ins (bb, ins, tmp);
14904                                         }
14905                                 }
14906                         }
14907                         mono_inst_set_src_registers (ins, sregs);
14908
14909                         if (dest_has_lvreg) {
14910                                 g_assert (ins->dreg != -1);
14911                                 vreg_to_lvreg [prev_dreg] = ins->dreg;
14912                                 g_assert (lvregs_len < 1024);
14913                                 lvregs [lvregs_len ++] = prev_dreg;
14914                                 dest_has_lvreg = FALSE;
14915                         }
14916
14917                         if (store) {
14918                                 tmp_reg = ins->dreg;
14919                                 ins->dreg = ins->sreg2;
14920                                 ins->sreg2 = tmp_reg;
14921                         }
14922
14923                         if (MONO_IS_CALL (ins)) {
14924                                 /* Clear vreg_to_lvreg array */
14925                                 for (i = 0; i < lvregs_len; i++)
14926                                         vreg_to_lvreg [lvregs [i]] = 0;
14927                                 lvregs_len = 0;
14928                         } else if (ins->opcode == OP_NOP) {
14929                                 ins->dreg = -1;
14930                                 MONO_INST_NULLIFY_SREGS (ins);
14931                         }
14932
14933                         if (cfg->verbose_level > 2)
14934                                 mono_print_ins_index (1, ins);
14935                 }
14936
14937                 /* Extend the live range based on the liveness info */
14938                 if (cfg->compute_precise_live_ranges && bb->live_out_set && bb->code) {
14939                         for (i = 0; i < cfg->num_varinfo; i ++) {
14940                                 MonoMethodVar *vi = MONO_VARINFO (cfg, i);
14941
14942                                 if (vreg_is_volatile (cfg, vi->vreg))
14943                                         /* The liveness info is incomplete */
14944                                         continue;
14945
14946                                 if (mono_bitset_test_fast (bb->live_in_set, i) && !live_range_start [vi->vreg]) {
14947                                         /* Live from at least the first ins of this bb */
14948                                         live_range_start [vi->vreg] = bb->code;
14949                                         live_range_start_bb [vi->vreg] = bb;
14950                                 }
14951
14952                                 if (mono_bitset_test_fast (bb->live_out_set, i)) {
14953                                         /* Live at least until the last ins of this bb */
14954                                         live_range_end [vi->vreg] = bb->last_ins;
14955                                         live_range_end_bb [vi->vreg] = bb;
14956                                 }
14957                         }
14958                 }
14959         }
14960         
14961         /*
14962          * Emit LIVERANGE_START/LIVERANGE_END opcodes, the backend will implement them
14963          * by storing the current native offset into MonoMethodVar->live_range_start/end.
14964          */
14965         if (cfg->backend->have_liverange_ops && cfg->compute_precise_live_ranges && cfg->comp_done & MONO_COMP_LIVENESS) {
14966                 for (i = 0; i < cfg->num_varinfo; ++i) {
14967                         int vreg = MONO_VARINFO (cfg, i)->vreg;
14968                         MonoInst *ins;
14969
14970                         if (live_range_start [vreg]) {
14971                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_START);
14972                                 ins->inst_c0 = i;
14973                                 ins->inst_c1 = vreg;
14974                                 mono_bblock_insert_after_ins (live_range_start_bb [vreg], live_range_start [vreg], ins);
14975                         }
14976                         if (live_range_end [vreg]) {
14977                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_END);
14978                                 ins->inst_c0 = i;
14979                                 ins->inst_c1 = vreg;
14980                                 if (live_range_end [vreg] == live_range_end_bb [vreg]->last_ins)
14981                                         mono_add_ins_to_end (live_range_end_bb [vreg], ins);
14982                                 else
14983                                         mono_bblock_insert_after_ins (live_range_end_bb [vreg], live_range_end [vreg], ins);
14984                         }
14985                 }
14986         }
14987
14988         if (cfg->gsharedvt_locals_var_ins) {
14989                 /* Nullify if unused */
14990                 cfg->gsharedvt_locals_var_ins->opcode = OP_PCONST;
14991                 cfg->gsharedvt_locals_var_ins->inst_imm = 0;
14992         }
14993
14994         g_free (live_range_start);
14995         g_free (live_range_end);
14996         g_free (live_range_start_bb);
14997         g_free (live_range_end_bb);
14998 }
14999
15000 /**
15001  * FIXME:
15002  * - use 'iadd' instead of 'int_add'
15003  * - handling ovf opcodes: decompose in method_to_ir.
15004  * - unify iregs/fregs
15005  *   -> partly done, the missing parts are:
15006  *   - a more complete unification would involve unifying the hregs as well, so
15007  *     code wouldn't need if (fp) all over the place. but that would mean the hregs
15008  *     would no longer map to the machine hregs, so the code generators would need to
15009  *     be modified. Also, on ia64 for example, niregs + nfregs > 256 -> bitmasks
15010  *     wouldn't work any more. Duplicating the code in mono_local_regalloc () into
15011  *     fp/non-fp branches speeds it up by about 15%.
15012  * - use sext/zext opcodes instead of shifts
15013  * - add OP_ICALL
15014  * - get rid of TEMPLOADs if possible and use vregs instead
15015  * - clean up usage of OP_P/OP_ opcodes
15016  * - cleanup usage of DUMMY_USE
15017  * - cleanup the setting of ins->type for MonoInst's which are pushed on the 
15018  *   stack
15019  * - set the stack type and allocate a dreg in the EMIT_NEW macros
15020  * - get rid of all the <foo>2 stuff when the new JIT is ready.
15021  * - make sure handle_stack_args () is called before the branch is emitted
15022  * - when the new IR is done, get rid of all unused stuff
15023  * - COMPARE/BEQ as separate instructions or unify them ?
15024  *   - keeping them separate allows specialized compare instructions like
15025  *     compare_imm, compare_membase
15026  *   - most back ends unify fp compare+branch, fp compare+ceq
15027  * - integrate mono_save_args into inline_method
15028  * - get rid of the empty bblocks created by MONO_EMIT_NEW_BRACH_BLOCK2
15029  * - handle long shift opts on 32 bit platforms somehow: they require 
15030  *   3 sregs (2 for arg1 and 1 for arg2)
15031  * - make byref a 'normal' type.
15032  * - use vregs for bb->out_stacks if possible, handle_global_vreg will make them a
15033  *   variable if needed.
15034  * - do not start a new IL level bblock when cfg->cbb is changed by a function call
15035  *   like inline_method.
15036  * - remove inlining restrictions
15037  * - fix LNEG and enable cfold of INEG
15038  * - generalize x86 optimizations like ldelema as a peephole optimization
15039  * - add store_mem_imm for amd64
15040  * - optimize the loading of the interruption flag in the managed->native wrappers
15041  * - avoid special handling of OP_NOP in passes
15042  * - move code inserting instructions into one function/macro.
15043  * - try a coalescing phase after liveness analysis
15044  * - add float -> vreg conversion + local optimizations on !x86
15045  * - figure out how to handle decomposed branches during optimizations, ie.
15046  *   compare+branch, op_jump_table+op_br etc.
15047  * - promote RuntimeXHandles to vregs
15048  * - vtype cleanups:
15049  *   - add a NEW_VARLOADA_VREG macro
15050  * - the vtype optimizations are blocked by the LDADDR opcodes generated for 
15051  *   accessing vtype fields.
15052  * - get rid of I8CONST on 64 bit platforms
15053  * - dealing with the increase in code size due to branches created during opcode
15054  *   decomposition:
15055  *   - use extended basic blocks
15056  *     - all parts of the JIT
15057  *     - handle_global_vregs () && local regalloc
15058  *   - avoid introducing global vregs during decomposition, like 'vtable' in isinst
15059  * - sources of increase in code size:
15060  *   - vtypes
15061  *   - long compares
15062  *   - isinst and castclass
15063  *   - lvregs not allocated to global registers even if used multiple times
15064  * - call cctors outside the JIT, to make -v output more readable and JIT timings more
15065  *   meaningful.
15066  * - check for fp stack leakage in other opcodes too. (-> 'exceptions' optimization)
15067  * - add all micro optimizations from the old JIT
15068  * - put tree optimizations into the deadce pass
15069  * - decompose op_start_handler/op_endfilter/op_endfinally earlier using an arch
15070  *   specific function.
15071  * - unify the float comparison opcodes with the other comparison opcodes, i.e.
15072  *   fcompare + branchCC.
15073  * - create a helper function for allocating a stack slot, taking into account 
15074  *   MONO_CFG_HAS_SPILLUP.
15075  * - merge r68207.
15076  * - merge the ia64 switch changes.
15077  * - optimize mono_regstate2_alloc_int/float.
15078  * - fix the pessimistic handling of variables accessed in exception handler blocks.
15079  * - need to write a tree optimization pass, but the creation of trees is difficult, i.e.
15080  *   parts of the tree could be separated by other instructions, killing the tree
15081  *   arguments, or stores killing loads etc. Also, should we fold loads into other
15082  *   instructions if the result of the load is used multiple times ?
15083  * - make the REM_IMM optimization in mini-x86.c arch-independent.
15084  * - LAST MERGE: 108395.
15085  * - when returning vtypes in registers, generate IR and append it to the end of the
15086  *   last bb instead of doing it in the epilog.
15087  * - change the store opcodes so they use sreg1 instead of dreg to store the base register.
15088  */
15089
15090 /*
15091
15092 NOTES
15093 -----
15094
15095 - When to decompose opcodes:
15096   - earlier: this makes some optimizations hard to implement, since the low level IR
15097   no longer contains the neccessary information. But it is easier to do.
15098   - later: harder to implement, enables more optimizations.
15099 - Branches inside bblocks:
15100   - created when decomposing complex opcodes. 
15101     - branches to another bblock: harmless, but not tracked by the branch 
15102       optimizations, so need to branch to a label at the start of the bblock.
15103     - branches to inside the same bblock: very problematic, trips up the local
15104       reg allocator. Can be fixed by spitting the current bblock, but that is a
15105       complex operation, since some local vregs can become global vregs etc.
15106 - Local/global vregs:
15107   - local vregs: temporary vregs used inside one bblock. Assigned to hregs by the
15108     local register allocator.
15109   - global vregs: used in more than one bblock. Have an associated MonoMethodVar
15110     structure, created by mono_create_var (). Assigned to hregs or the stack by
15111     the global register allocator.
15112 - When to do optimizations like alu->alu_imm:
15113   - earlier -> saves work later on since the IR will be smaller/simpler
15114   - later -> can work on more instructions
15115 - Handling of valuetypes:
15116   - When a vtype is pushed on the stack, a new temporary is created, an 
15117     instruction computing its address (LDADDR) is emitted and pushed on
15118     the stack. Need to optimize cases when the vtype is used immediately as in
15119     argument passing, stloc etc.
15120 - Instead of the to_end stuff in the old JIT, simply call the function handling
15121   the values on the stack before emitting the last instruction of the bb.
15122 */
15123
15124 #endif /* DISABLE_JIT */