Merge pull request #2536 from lambdageek/monoerror-mono_field_get_object
[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/debug-mono-symfile.h>
60 #include <mono/utils/mono-compiler.h>
61 #include <mono/utils/mono-memory-model.h>
62 #include <mono/metadata/mono-basic-block.h>
63 #include <mono/metadata/reflection-internals.h>
64
65 #include "trace.h"
66
67 #include "ir-emit.h"
68
69 #include "jit-icalls.h"
70 #include "jit.h"
71 #include "debugger-agent.h"
72 #include "seq-points.h"
73 #include "aot-compiler.h"
74 #include "mini-llvm.h"
75
76 #define BRANCH_COST 10
77 #define INLINE_LENGTH_LIMIT 20
78
79 /* These have 'cfg' as an implicit argument */
80 #define INLINE_FAILURE(msg) do {                                                                        \
81         if ((cfg->method != cfg->current_method) && (cfg->current_method->wrapper_type == MONO_WRAPPER_NONE)) { \
82                 inline_failure (cfg, msg);                                                                              \
83                 goto exception_exit;                                                                                    \
84         } \
85         } while (0)
86 #define CHECK_CFG_EXCEPTION do {\
87                 if (cfg->exception_type != MONO_EXCEPTION_NONE) \
88                         goto exception_exit;                                            \
89         } while (0)
90 #define METHOD_ACCESS_FAILURE(method, cmethod) do {                     \
91                 method_access_failure ((cfg), (method), (cmethod));                     \
92                 goto exception_exit;                                                                            \
93         } while (0)
94 #define FIELD_ACCESS_FAILURE(method, field) do {                                        \
95                 field_access_failure ((cfg), (method), (field));                        \
96                 goto exception_exit;    \
97         } while (0)
98 #define GENERIC_SHARING_FAILURE(opcode) do {            \
99                 if (cfg->gshared) {                                                                     \
100                         gshared_failure (cfg, opcode, __FILE__, __LINE__);      \
101                         goto exception_exit;    \
102                 }                       \
103         } while (0)
104 #define GSHAREDVT_FAILURE(opcode) do {          \
105         if (cfg->gsharedvt) {                                                                                           \
106                 gsharedvt_failure (cfg, opcode, __FILE__, __LINE__);                    \
107                 goto exception_exit;                                                                                    \
108         }                                                                                                                                       \
109         } while (0)
110 #define OUT_OF_MEMORY_FAILURE do {      \
111                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);                \
112                 mono_error_set_out_of_memory (&cfg->error, "");                                 \
113                 goto exception_exit;    \
114         } while (0)
115 #define DISABLE_AOT(cfg) do { \
116                 if ((cfg)->verbose_level >= 2)                                            \
117                         printf ("AOT disabled: %s:%d\n", __FILE__, __LINE__);   \
118                 (cfg)->disable_aot = TRUE;                                                        \
119         } while (0)
120 #define LOAD_ERROR do { \
121                 break_on_unverified ();                                                         \
122                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD); \
123                 goto exception_exit;                                                                    \
124         } while (0)
125
126 #define TYPE_LOAD_ERROR(klass) do { \
127                 cfg->exception_ptr = klass; \
128                 LOAD_ERROR;                                     \
129         } while (0)
130
131 #define CHECK_CFG_ERROR do {\
132                 if (!mono_error_ok (&cfg->error)) { \
133                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);        \
134                         goto mono_error_exit; \
135                 } \
136         } while (0)
137
138 /* Determine whenever 'ins' represents a load of the 'this' argument */
139 #define MONO_CHECK_THIS(ins) (mono_method_signature (cfg->method)->hasthis && ((ins)->opcode == OP_MOVE) && ((ins)->sreg1 == cfg->args [0]->dreg))
140
141 static int ldind_to_load_membase (int opcode);
142 static int stind_to_store_membase (int opcode);
143
144 int mono_op_to_op_imm (int opcode);
145 int mono_op_to_op_imm_noemul (int opcode);
146
147 MONO_API MonoInst* mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig, MonoInst **args);
148
149 static int inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp,
150                                                   guchar *ip, guint real_offset, gboolean inline_always);
151 static MonoInst*
152 emit_llvmonly_virtual_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, int context_used, MonoInst **sp);
153
154 /* helper methods signatures */
155 static MonoMethodSignature *helper_sig_domain_get;
156 static MonoMethodSignature *helper_sig_rgctx_lazy_fetch_trampoline;
157 static MonoMethodSignature *helper_sig_llvmonly_imt_thunk;
158
159 /*
160  * Instruction metadata
161  */
162 #ifdef MINI_OP
163 #undef MINI_OP
164 #endif
165 #ifdef MINI_OP3
166 #undef MINI_OP3
167 #endif
168 #define MINI_OP(a,b,dest,src1,src2) dest, src1, src2, ' ',
169 #define MINI_OP3(a,b,dest,src1,src2,src3) dest, src1, src2, src3,
170 #define NONE ' '
171 #define IREG 'i'
172 #define FREG 'f'
173 #define VREG 'v'
174 #define XREG 'x'
175 #if SIZEOF_REGISTER == 8 && SIZEOF_REGISTER == SIZEOF_VOID_P
176 #define LREG IREG
177 #else
178 #define LREG 'l'
179 #endif
180 /* keep in sync with the enum in mini.h */
181 const char
182 ins_info[] = {
183 #include "mini-ops.h"
184 };
185 #undef MINI_OP
186 #undef MINI_OP3
187
188 #define MINI_OP(a,b,dest,src1,src2) ((src2) != NONE ? 2 : ((src1) != NONE ? 1 : 0)),
189 #define MINI_OP3(a,b,dest,src1,src2,src3) ((src3) != NONE ? 3 : ((src2) != NONE ? 2 : ((src1) != NONE ? 1 : 0))),
190 /* 
191  * This should contain the index of the last sreg + 1. This is not the same
192  * as the number of sregs for opcodes like IA64_CMP_EQ_IMM.
193  */
194 const gint8 ins_sreg_counts[] = {
195 #include "mini-ops.h"
196 };
197 #undef MINI_OP
198 #undef MINI_OP3
199
200 #define MONO_INIT_VARINFO(vi,id) do { \
201         (vi)->range.first_use.pos.bid = 0xffff; \
202         (vi)->reg = -1; \
203         (vi)->idx = (id); \
204 } while (0)
205
206 guint32
207 mono_alloc_ireg (MonoCompile *cfg)
208 {
209         return alloc_ireg (cfg);
210 }
211
212 guint32
213 mono_alloc_lreg (MonoCompile *cfg)
214 {
215         return alloc_lreg (cfg);
216 }
217
218 guint32
219 mono_alloc_freg (MonoCompile *cfg)
220 {
221         return alloc_freg (cfg);
222 }
223
224 guint32
225 mono_alloc_preg (MonoCompile *cfg)
226 {
227         return alloc_preg (cfg);
228 }
229
230 guint32
231 mono_alloc_dreg (MonoCompile *cfg, MonoStackType stack_type)
232 {
233         return alloc_dreg (cfg, stack_type);
234 }
235
236 /*
237  * mono_alloc_ireg_ref:
238  *
239  *   Allocate an IREG, and mark it as holding a GC ref.
240  */
241 guint32
242 mono_alloc_ireg_ref (MonoCompile *cfg)
243 {
244         return alloc_ireg_ref (cfg);
245 }
246
247 /*
248  * mono_alloc_ireg_mp:
249  *
250  *   Allocate an IREG, and mark it as holding a managed pointer.
251  */
252 guint32
253 mono_alloc_ireg_mp (MonoCompile *cfg)
254 {
255         return alloc_ireg_mp (cfg);
256 }
257
258 /*
259  * mono_alloc_ireg_copy:
260  *
261  *   Allocate an IREG with the same GC type as VREG.
262  */
263 guint32
264 mono_alloc_ireg_copy (MonoCompile *cfg, guint32 vreg)
265 {
266         if (vreg_is_ref (cfg, vreg))
267                 return alloc_ireg_ref (cfg);
268         else if (vreg_is_mp (cfg, vreg))
269                 return alloc_ireg_mp (cfg);
270         else
271                 return alloc_ireg (cfg);
272 }
273
274 guint
275 mono_type_to_regmove (MonoCompile *cfg, MonoType *type)
276 {
277         if (type->byref)
278                 return OP_MOVE;
279
280         type = mini_get_underlying_type (type);
281 handle_enum:
282         switch (type->type) {
283         case MONO_TYPE_I1:
284         case MONO_TYPE_U1:
285                 return OP_MOVE;
286         case MONO_TYPE_I2:
287         case MONO_TYPE_U2:
288                 return OP_MOVE;
289         case MONO_TYPE_I4:
290         case MONO_TYPE_U4:
291                 return OP_MOVE;
292         case MONO_TYPE_I:
293         case MONO_TYPE_U:
294         case MONO_TYPE_PTR:
295         case MONO_TYPE_FNPTR:
296                 return OP_MOVE;
297         case MONO_TYPE_CLASS:
298         case MONO_TYPE_STRING:
299         case MONO_TYPE_OBJECT:
300         case MONO_TYPE_SZARRAY:
301         case MONO_TYPE_ARRAY:    
302                 return OP_MOVE;
303         case MONO_TYPE_I8:
304         case MONO_TYPE_U8:
305 #if SIZEOF_REGISTER == 8
306                 return OP_MOVE;
307 #else
308                 return OP_LMOVE;
309 #endif
310         case MONO_TYPE_R4:
311                 return cfg->r4fp ? OP_RMOVE : OP_FMOVE;
312         case MONO_TYPE_R8:
313                 return OP_FMOVE;
314         case MONO_TYPE_VALUETYPE:
315                 if (type->data.klass->enumtype) {
316                         type = mono_class_enum_basetype (type->data.klass);
317                         goto handle_enum;
318                 }
319                 if (MONO_CLASS_IS_SIMD (cfg, mono_class_from_mono_type (type)))
320                         return OP_XMOVE;
321                 return OP_VMOVE;
322         case MONO_TYPE_TYPEDBYREF:
323                 return OP_VMOVE;
324         case MONO_TYPE_GENERICINST:
325                 type = &type->data.generic_class->container_class->byval_arg;
326                 goto handle_enum;
327         case MONO_TYPE_VAR:
328         case MONO_TYPE_MVAR:
329                 g_assert (cfg->gshared);
330                 if (mini_type_var_is_vt (type))
331                         return OP_VMOVE;
332                 else
333                         return mono_type_to_regmove (cfg, mini_get_underlying_type (type));
334         default:
335                 g_error ("unknown type 0x%02x in type_to_regstore", type->type);
336         }
337         return -1;
338 }
339
340 void
341 mono_print_bb (MonoBasicBlock *bb, const char *msg)
342 {
343         int i;
344         MonoInst *tree;
345
346         printf ("\n%s %d: [IN: ", msg, bb->block_num);
347         for (i = 0; i < bb->in_count; ++i)
348                 printf (" BB%d(%d)", bb->in_bb [i]->block_num, bb->in_bb [i]->dfn);
349         printf (", OUT: ");
350         for (i = 0; i < bb->out_count; ++i)
351                 printf (" BB%d(%d)", bb->out_bb [i]->block_num, bb->out_bb [i]->dfn);
352         printf (" ]\n");
353         for (tree = bb->code; tree; tree = tree->next)
354                 mono_print_ins_index (-1, tree);
355 }
356
357 void
358 mono_create_helper_signatures (void)
359 {
360         helper_sig_domain_get = mono_create_icall_signature ("ptr");
361         helper_sig_rgctx_lazy_fetch_trampoline = mono_create_icall_signature ("ptr ptr");
362         helper_sig_llvmonly_imt_thunk = mono_create_icall_signature ("ptr ptr ptr");
363 }
364
365 static MONO_NEVER_INLINE void
366 break_on_unverified (void)
367 {
368         if (mini_get_debug_options ()->break_on_unverified)
369                 G_BREAKPOINT ();
370 }
371
372 static MONO_NEVER_INLINE void
373 method_access_failure (MonoCompile *cfg, MonoMethod *method, MonoMethod *cil_method)
374 {
375         char *method_fname = mono_method_full_name (method, TRUE);
376         char *cil_method_fname = mono_method_full_name (cil_method, TRUE);
377         mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
378         mono_error_set_generic_error (&cfg->error, "System", "MethodAccessException", "Method `%s' is inaccessible from method `%s'\n", cil_method_fname, method_fname);
379         g_free (method_fname);
380         g_free (cil_method_fname);
381 }
382
383 static MONO_NEVER_INLINE void
384 field_access_failure (MonoCompile *cfg, MonoMethod *method, MonoClassField *field)
385 {
386         char *method_fname = mono_method_full_name (method, TRUE);
387         char *field_fname = mono_field_full_name (field);
388         mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
389         mono_error_set_generic_error (&cfg->error, "System", "FieldAccessException", "Field `%s' is inaccessible from method `%s'\n", field_fname, method_fname);
390         g_free (method_fname);
391         g_free (field_fname);
392 }
393
394 static MONO_NEVER_INLINE void
395 inline_failure (MonoCompile *cfg, const char *msg)
396 {
397         if (cfg->verbose_level >= 2)
398                 printf ("inline failed: %s\n", msg);
399         mono_cfg_set_exception (cfg, MONO_EXCEPTION_INLINE_FAILED);
400 }
401
402 static MONO_NEVER_INLINE void
403 gshared_failure (MonoCompile *cfg, int opcode, const char *file, int line)
404 {
405         if (cfg->verbose_level > 2)                                                                                     \
406                 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);
407         mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED);
408 }
409
410 static MONO_NEVER_INLINE void
411 gsharedvt_failure (MonoCompile *cfg, int opcode, const char *file, int line)
412 {
413         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);
414         if (cfg->verbose_level >= 2)
415                 printf ("%s\n", cfg->exception_message);
416         mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED);
417 }
418
419 /*
420  * When using gsharedvt, some instatiations might be verifiable, and some might be not. i.e. 
421  * foo<T> (int i) { ldarg.0; box T; }
422  */
423 #define UNVERIFIED do { \
424         if (cfg->gsharedvt) { \
425                 if (cfg->verbose_level > 2)                                                                     \
426                         printf ("gsharedvt method failed to verify, falling back to instantiation.\n"); \
427                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED); \
428                 goto exception_exit;                                                                                    \
429         }                                                                                                                                       \
430         break_on_unverified ();                                                                                         \
431         goto unverified;                                                                                                        \
432 } while (0)
433
434 #define GET_BBLOCK(cfg,tblock,ip) do {  \
435                 (tblock) = cfg->cil_offset_to_bb [(ip) - cfg->cil_start]; \
436                 if (!(tblock)) {        \
437                         if ((ip) >= end || (ip) < header->code) UNVERIFIED; \
438             NEW_BBLOCK (cfg, (tblock)); \
439                         (tblock)->cil_code = (ip);      \
440                         ADD_BBLOCK (cfg, (tblock));     \
441                 } \
442         } while (0)
443
444 #if defined(TARGET_X86) || defined(TARGET_AMD64)
445 #define EMIT_NEW_X86_LEA(cfg,dest,sr1,sr2,shift,imm) do { \
446                 MONO_INST_NEW (cfg, dest, OP_X86_LEA); \
447                 (dest)->dreg = alloc_ireg_mp ((cfg)); \
448                 (dest)->sreg1 = (sr1); \
449                 (dest)->sreg2 = (sr2); \
450                 (dest)->inst_imm = (imm); \
451                 (dest)->backend.shift_amount = (shift); \
452                 MONO_ADD_INS ((cfg)->cbb, (dest)); \
453         } while (0)
454 #endif
455
456 /* Emit conversions so both operands of a binary opcode are of the same type */
457 static void
458 add_widen_op (MonoCompile *cfg, MonoInst *ins, MonoInst **arg1_ref, MonoInst **arg2_ref)
459 {
460         MonoInst *arg1 = *arg1_ref;
461         MonoInst *arg2 = *arg2_ref;
462
463         if (cfg->r4fp &&
464                 ((arg1->type == STACK_R4 && arg2->type == STACK_R8) ||
465                  (arg1->type == STACK_R8 && arg2->type == STACK_R4))) {
466                 MonoInst *conv;
467
468                 /* Mixing r4/r8 is allowed by the spec */
469                 if (arg1->type == STACK_R4) {
470                         int dreg = alloc_freg (cfg);
471
472                         EMIT_NEW_UNALU (cfg, conv, OP_RCONV_TO_R8, dreg, arg1->dreg);
473                         conv->type = STACK_R8;
474                         ins->sreg1 = dreg;
475                         *arg1_ref = conv;
476                 }
477                 if (arg2->type == STACK_R4) {
478                         int dreg = alloc_freg (cfg);
479
480                         EMIT_NEW_UNALU (cfg, conv, OP_RCONV_TO_R8, dreg, arg2->dreg);
481                         conv->type = STACK_R8;
482                         ins->sreg2 = dreg;
483                         *arg2_ref = conv;
484                 }
485         }
486
487 #if SIZEOF_REGISTER == 8
488         /* FIXME: Need to add many more cases */
489         if ((arg1)->type == STACK_PTR && (arg2)->type == STACK_I4) {
490                 MonoInst *widen;
491
492                 int dr = alloc_preg (cfg);
493                 EMIT_NEW_UNALU (cfg, widen, OP_SEXT_I4, dr, (arg2)->dreg);
494                 (ins)->sreg2 = widen->dreg;
495         }
496 #endif
497 }
498
499 #define ADD_BINOP(op) do {      \
500                 MONO_INST_NEW (cfg, ins, (op)); \
501                 sp -= 2;        \
502                 ins->sreg1 = sp [0]->dreg;      \
503                 ins->sreg2 = sp [1]->dreg;      \
504                 type_from_op (cfg, ins, sp [0], sp [1]);        \
505                 CHECK_TYPE (ins);       \
506                 /* Have to insert a widening op */               \
507         add_widen_op (cfg, ins, &sp [0], &sp [1]);               \
508         ins->dreg = alloc_dreg ((cfg), (MonoStackType)(ins)->type); \
509         MONO_ADD_INS ((cfg)->cbb, (ins)); \
510         *sp++ = mono_decompose_opcode ((cfg), (ins));   \
511         } while (0)
512
513 #define ADD_UNOP(op) do {       \
514                 MONO_INST_NEW (cfg, ins, (op)); \
515                 sp--;   \
516                 ins->sreg1 = sp [0]->dreg;      \
517                 type_from_op (cfg, ins, sp [0], NULL);  \
518                 CHECK_TYPE (ins);       \
519         (ins)->dreg = alloc_dreg ((cfg), (MonoStackType)(ins)->type); \
520         MONO_ADD_INS ((cfg)->cbb, (ins)); \
521                 *sp++ = mono_decompose_opcode (cfg, ins);       \
522         } while (0)
523
524 #define ADD_BINCOND(next_block) do {    \
525                 MonoInst *cmp;  \
526                 sp -= 2; \
527                 MONO_INST_NEW(cfg, cmp, OP_COMPARE);    \
528                 cmp->sreg1 = sp [0]->dreg;      \
529                 cmp->sreg2 = sp [1]->dreg;      \
530                 type_from_op (cfg, cmp, sp [0], sp [1]);        \
531                 CHECK_TYPE (cmp);       \
532                 add_widen_op (cfg, cmp, &sp [0], &sp [1]);                                              \
533                 type_from_op (cfg, ins, sp [0], sp [1]);                                                        \
534                 ins->inst_many_bb = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);   \
535                 GET_BBLOCK (cfg, tblock, target);               \
536                 link_bblock (cfg, cfg->cbb, tblock);    \
537                 ins->inst_true_bb = tblock;     \
538                 if ((next_block)) {     \
539                         link_bblock (cfg, cfg->cbb, (next_block));      \
540                         ins->inst_false_bb = (next_block);      \
541                         start_new_bblock = 1;   \
542                 } else {        \
543                         GET_BBLOCK (cfg, tblock, ip);           \
544                         link_bblock (cfg, cfg->cbb, tblock);    \
545                         ins->inst_false_bb = tblock;    \
546                         start_new_bblock = 2;   \
547                 }       \
548                 if (sp != stack_start) {                                                                        \
549                     handle_stack_args (cfg, stack_start, sp - stack_start); \
550                         CHECK_UNVERIFIABLE (cfg); \
551                 } \
552         MONO_ADD_INS (cfg->cbb, cmp); \
553                 MONO_ADD_INS (cfg->cbb, ins);   \
554         } while (0)
555
556 /* *
557  * link_bblock: Links two basic blocks
558  *
559  * links two basic blocks in the control flow graph, the 'from'
560  * argument is the starting block and the 'to' argument is the block
561  * the control flow ends to after 'from'.
562  */
563 static void
564 link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
565 {
566         MonoBasicBlock **newa;
567         int i, found;
568
569 #if 0
570         if (from->cil_code) {
571                 if (to->cil_code)
572                         printf ("edge from IL%04x to IL_%04x\n", from->cil_code - cfg->cil_code, to->cil_code - cfg->cil_code);
573                 else
574                         printf ("edge from IL%04x to exit\n", from->cil_code - cfg->cil_code);
575         } else {
576                 if (to->cil_code)
577                         printf ("edge from entry to IL_%04x\n", to->cil_code - cfg->cil_code);
578                 else
579                         printf ("edge from entry to exit\n");
580         }
581 #endif
582
583         found = FALSE;
584         for (i = 0; i < from->out_count; ++i) {
585                 if (to == from->out_bb [i]) {
586                         found = TRUE;
587                         break;
588                 }
589         }
590         if (!found) {
591                 newa = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (from->out_count + 1));
592                 for (i = 0; i < from->out_count; ++i) {
593                         newa [i] = from->out_bb [i];
594                 }
595                 newa [i] = to;
596                 from->out_count++;
597                 from->out_bb = newa;
598         }
599
600         found = FALSE;
601         for (i = 0; i < to->in_count; ++i) {
602                 if (from == to->in_bb [i]) {
603                         found = TRUE;
604                         break;
605                 }
606         }
607         if (!found) {
608                 newa = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (to->in_count + 1));
609                 for (i = 0; i < to->in_count; ++i) {
610                         newa [i] = to->in_bb [i];
611                 }
612                 newa [i] = from;
613                 to->in_count++;
614                 to->in_bb = newa;
615         }
616 }
617
618 void
619 mono_link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
620 {
621         link_bblock (cfg, from, to);
622 }
623
624 /**
625  * mono_find_block_region:
626  *
627  *   We mark each basic block with a region ID. We use that to avoid BB
628  *   optimizations when blocks are in different regions.
629  *
630  * Returns:
631  *   A region token that encodes where this region is, and information
632  *   about the clause owner for this block.
633  *
634  *   The region encodes the try/catch/filter clause that owns this block
635  *   as well as the type.  -1 is a special value that represents a block
636  *   that is in none of try/catch/filter.
637  */
638 static int
639 mono_find_block_region (MonoCompile *cfg, int offset)
640 {
641         MonoMethodHeader *header = cfg->header;
642         MonoExceptionClause *clause;
643         int i;
644
645         for (i = 0; i < header->num_clauses; ++i) {
646                 clause = &header->clauses [i];
647                 if ((clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) && (offset >= clause->data.filter_offset) &&
648                     (offset < (clause->handler_offset)))
649                         return ((i + 1) << 8) | MONO_REGION_FILTER | clause->flags;
650                            
651                 if (MONO_OFFSET_IN_HANDLER (clause, offset)) {
652                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY)
653                                 return ((i + 1) << 8) | MONO_REGION_FINALLY | clause->flags;
654                         else if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
655                                 return ((i + 1) << 8) | MONO_REGION_FAULT | clause->flags;
656                         else
657                                 return ((i + 1) << 8) | MONO_REGION_CATCH | clause->flags;
658                 }
659         }
660         for (i = 0; i < header->num_clauses; ++i) {
661                 clause = &header->clauses [i];
662
663                 if (MONO_OFFSET_IN_CLAUSE (clause, offset))
664                         return ((i + 1) << 8) | clause->flags;
665         }
666
667         return -1;
668 }
669
670 static GList*
671 mono_find_final_block (MonoCompile *cfg, unsigned char *ip, unsigned char *target, int type)
672 {
673         MonoMethodHeader *header = cfg->header;
674         MonoExceptionClause *clause;
675         int i;
676         GList *res = NULL;
677
678         for (i = 0; i < header->num_clauses; ++i) {
679                 clause = &header->clauses [i];
680                 if (MONO_OFFSET_IN_CLAUSE (clause, (ip - header->code)) && 
681                     (!MONO_OFFSET_IN_CLAUSE (clause, (target - header->code)))) {
682                         if (clause->flags == type)
683                                 res = g_list_append (res, clause);
684                 }
685         }
686         return res;
687 }
688
689 static void
690 mono_create_spvar_for_region (MonoCompile *cfg, int region)
691 {
692         MonoInst *var;
693
694         var = (MonoInst *)g_hash_table_lookup (cfg->spvars, GINT_TO_POINTER (region));
695         if (var)
696                 return;
697
698         var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
699         /* prevent it from being register allocated */
700         var->flags |= MONO_INST_VOLATILE;
701
702         g_hash_table_insert (cfg->spvars, GINT_TO_POINTER (region), var);
703 }
704
705 MonoInst *
706 mono_find_exvar_for_offset (MonoCompile *cfg, int offset)
707 {
708         return (MonoInst *)g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
709 }
710
711 static MonoInst*
712 mono_create_exvar_for_offset (MonoCompile *cfg, int offset)
713 {
714         MonoInst *var;
715
716         var = (MonoInst *)g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
717         if (var)
718                 return var;
719
720         var = mono_compile_create_var (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL);
721         /* prevent it from being register allocated */
722         var->flags |= MONO_INST_VOLATILE;
723
724         g_hash_table_insert (cfg->exvars, GINT_TO_POINTER (offset), var);
725
726         return var;
727 }
728
729 /*
730  * Returns the type used in the eval stack when @type is loaded.
731  * FIXME: return a MonoType/MonoClass for the byref and VALUETYPE cases.
732  */
733 void
734 type_to_eval_stack_type (MonoCompile *cfg, MonoType *type, MonoInst *inst)
735 {
736         MonoClass *klass;
737
738         type = mini_get_underlying_type (type);
739         inst->klass = klass = mono_class_from_mono_type (type);
740         if (type->byref) {
741                 inst->type = STACK_MP;
742                 return;
743         }
744
745 handle_enum:
746         switch (type->type) {
747         case MONO_TYPE_VOID:
748                 inst->type = STACK_INV;
749                 return;
750         case MONO_TYPE_I1:
751         case MONO_TYPE_U1:
752         case MONO_TYPE_I2:
753         case MONO_TYPE_U2:
754         case MONO_TYPE_I4:
755         case MONO_TYPE_U4:
756                 inst->type = STACK_I4;
757                 return;
758         case MONO_TYPE_I:
759         case MONO_TYPE_U:
760         case MONO_TYPE_PTR:
761         case MONO_TYPE_FNPTR:
762                 inst->type = STACK_PTR;
763                 return;
764         case MONO_TYPE_CLASS:
765         case MONO_TYPE_STRING:
766         case MONO_TYPE_OBJECT:
767         case MONO_TYPE_SZARRAY:
768         case MONO_TYPE_ARRAY:    
769                 inst->type = STACK_OBJ;
770                 return;
771         case MONO_TYPE_I8:
772         case MONO_TYPE_U8:
773                 inst->type = STACK_I8;
774                 return;
775         case MONO_TYPE_R4:
776                 inst->type = cfg->r4_stack_type;
777                 break;
778         case MONO_TYPE_R8:
779                 inst->type = STACK_R8;
780                 return;
781         case MONO_TYPE_VALUETYPE:
782                 if (type->data.klass->enumtype) {
783                         type = mono_class_enum_basetype (type->data.klass);
784                         goto handle_enum;
785                 } else {
786                         inst->klass = klass;
787                         inst->type = STACK_VTYPE;
788                         return;
789                 }
790         case MONO_TYPE_TYPEDBYREF:
791                 inst->klass = mono_defaults.typed_reference_class;
792                 inst->type = STACK_VTYPE;
793                 return;
794         case MONO_TYPE_GENERICINST:
795                 type = &type->data.generic_class->container_class->byval_arg;
796                 goto handle_enum;
797         case MONO_TYPE_VAR:
798         case MONO_TYPE_MVAR:
799                 g_assert (cfg->gshared);
800                 if (mini_is_gsharedvt_type (type)) {
801                         g_assert (cfg->gsharedvt);
802                         inst->type = STACK_VTYPE;
803                 } else {
804                         type_to_eval_stack_type (cfg, mini_get_underlying_type (type), inst);
805                 }
806                 return;
807         default:
808                 g_error ("unknown type 0x%02x in eval stack type", type->type);
809         }
810 }
811
812 /*
813  * The following tables are used to quickly validate the IL code in type_from_op ().
814  */
815 static const char
816 bin_num_table [STACK_MAX] [STACK_MAX] = {
817         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
818         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
819         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
820         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
821         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_R8,  STACK_INV, STACK_INV, STACK_INV, STACK_R8},
822         {STACK_INV, STACK_MP,  STACK_INV, STACK_MP,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV},
823         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, 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_R8, STACK_INV, STACK_INV, STACK_INV, STACK_R4}
826 };
827
828 static const char 
829 neg_table [] = {
830         STACK_INV, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_INV, STACK_INV, STACK_INV, STACK_R4
831 };
832
833 /* reduce the size of this table */
834 static const char
835 bin_int_table [STACK_MAX] [STACK_MAX] = {
836         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
837         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
838         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
839         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
840         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, 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 };
845
846 static const char
847 bin_comp_table [STACK_MAX] [STACK_MAX] = {
848 /*      Inv i  L  p  F  &  O  vt r4 */
849         {0},
850         {0, 1, 0, 1, 0, 0, 0, 0}, /* i, int32 */
851         {0, 0, 1, 0, 0, 0, 0, 0}, /* L, int64 */
852         {0, 1, 0, 1, 0, 2, 4, 0}, /* p, ptr */
853         {0, 0, 0, 0, 1, 0, 0, 0, 1}, /* F, R8 */
854         {0, 0, 0, 2, 0, 1, 0, 0}, /* &, managed pointer */
855         {0, 0, 0, 4, 0, 0, 3, 0}, /* O, reference */
856         {0, 0, 0, 0, 0, 0, 0, 0}, /* vt value type */
857         {0, 0, 0, 0, 1, 0, 0, 0, 1}, /* r, r4 */
858 };
859
860 /* reduce the size of this table */
861 static const char
862 shift_table [STACK_MAX] [STACK_MAX] = {
863         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
864         {STACK_INV, STACK_I4,  STACK_INV, STACK_I4,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
865         {STACK_INV, STACK_I8,  STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
866         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
867         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, 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 };
872
873 /*
874  * Tables to map from the non-specific opcode to the matching
875  * type-specific opcode.
876  */
877 /* handles from CEE_ADD to CEE_SHR_UN (CEE_REM_UN for floats) */
878 static const guint16
879 binops_op_map [STACK_MAX] = {
880         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
881 };
882
883 /* handles from CEE_NEG to CEE_CONV_U8 */
884 static const guint16
885 unops_op_map [STACK_MAX] = {
886         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
887 };
888
889 /* handles from CEE_CONV_U2 to CEE_SUB_OVF_UN */
890 static const guint16
891 ovfops_op_map [STACK_MAX] = {
892         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
893 };
894
895 /* handles from CEE_CONV_OVF_I1_UN to CEE_CONV_OVF_U_UN */
896 static const guint16
897 ovf2ops_op_map [STACK_MAX] = {
898         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
899 };
900
901 /* handles from CEE_CONV_OVF_I1 to CEE_CONV_OVF_U8 */
902 static const guint16
903 ovf3ops_op_map [STACK_MAX] = {
904         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
905 };
906
907 /* handles from CEE_BEQ to CEE_BLT_UN */
908 static const guint16
909 beqops_op_map [STACK_MAX] = {
910         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
911 };
912
913 /* handles from CEE_CEQ to CEE_CLT_UN */
914 static const guint16
915 ceqops_op_map [STACK_MAX] = {
916         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
917 };
918
919 /*
920  * Sets ins->type (the type on the eval stack) according to the
921  * type of the opcode and the arguments to it.
922  * Invalid IL code is marked by setting ins->type to the invalid value STACK_INV.
923  *
924  * FIXME: this function sets ins->type unconditionally in some cases, but
925  * it should set it to invalid for some types (a conv.x on an object)
926  */
927 static void
928 type_from_op (MonoCompile *cfg, MonoInst *ins, MonoInst *src1, MonoInst *src2)
929 {
930         switch (ins->opcode) {
931         /* binops */
932         case CEE_ADD:
933         case CEE_SUB:
934         case CEE_MUL:
935         case CEE_DIV:
936         case CEE_REM:
937                 /* FIXME: check unverifiable args for STACK_MP */
938                 ins->type = bin_num_table [src1->type] [src2->type];
939                 ins->opcode += binops_op_map [ins->type];
940                 break;
941         case CEE_DIV_UN:
942         case CEE_REM_UN:
943         case CEE_AND:
944         case CEE_OR:
945         case CEE_XOR:
946                 ins->type = bin_int_table [src1->type] [src2->type];
947                 ins->opcode += binops_op_map [ins->type];
948                 break;
949         case CEE_SHL:
950         case CEE_SHR:
951         case CEE_SHR_UN:
952                 ins->type = shift_table [src1->type] [src2->type];
953                 ins->opcode += binops_op_map [ins->type];
954                 break;
955         case OP_COMPARE:
956         case OP_LCOMPARE:
957         case OP_ICOMPARE:
958                 ins->type = bin_comp_table [src1->type] [src2->type] ? STACK_I4: STACK_INV;
959                 if ((src1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((src1->type == STACK_PTR) || (src1->type == STACK_OBJ) || (src1->type == STACK_MP))))
960                         ins->opcode = OP_LCOMPARE;
961                 else if (src1->type == STACK_R4)
962                         ins->opcode = OP_RCOMPARE;
963                 else if (src1->type == STACK_R8)
964                         ins->opcode = OP_FCOMPARE;
965                 else
966                         ins->opcode = OP_ICOMPARE;
967                 break;
968         case OP_ICOMPARE_IMM:
969                 ins->type = bin_comp_table [src1->type] [src1->type] ? STACK_I4 : STACK_INV;
970                 if ((src1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((src1->type == STACK_PTR) || (src1->type == STACK_OBJ) || (src1->type == STACK_MP))))
971                         ins->opcode = OP_LCOMPARE_IMM;          
972                 break;
973         case CEE_BEQ:
974         case CEE_BGE:
975         case CEE_BGT:
976         case CEE_BLE:
977         case CEE_BLT:
978         case CEE_BNE_UN:
979         case CEE_BGE_UN:
980         case CEE_BGT_UN:
981         case CEE_BLE_UN:
982         case CEE_BLT_UN:
983                 ins->opcode += beqops_op_map [src1->type];
984                 break;
985         case OP_CEQ:
986                 ins->type = bin_comp_table [src1->type] [src2->type] ? STACK_I4: STACK_INV;
987                 ins->opcode += ceqops_op_map [src1->type];
988                 break;
989         case OP_CGT:
990         case OP_CGT_UN:
991         case OP_CLT:
992         case OP_CLT_UN:
993                 ins->type = (bin_comp_table [src1->type] [src2->type] & 1) ? STACK_I4: STACK_INV;
994                 ins->opcode += ceqops_op_map [src1->type];
995                 break;
996         /* unops */
997         case CEE_NEG:
998                 ins->type = neg_table [src1->type];
999                 ins->opcode += unops_op_map [ins->type];
1000                 break;
1001         case CEE_NOT:
1002                 if (src1->type >= STACK_I4 && src1->type <= STACK_PTR)
1003                         ins->type = src1->type;
1004                 else
1005                         ins->type = STACK_INV;
1006                 ins->opcode += unops_op_map [ins->type];
1007                 break;
1008         case CEE_CONV_I1:
1009         case CEE_CONV_I2:
1010         case CEE_CONV_I4:
1011         case CEE_CONV_U4:
1012                 ins->type = STACK_I4;
1013                 ins->opcode += unops_op_map [src1->type];
1014                 break;
1015         case CEE_CONV_R_UN:
1016                 ins->type = STACK_R8;
1017                 switch (src1->type) {
1018                 case STACK_I4:
1019                 case STACK_PTR:
1020                         ins->opcode = OP_ICONV_TO_R_UN;
1021                         break;
1022                 case STACK_I8:
1023                         ins->opcode = OP_LCONV_TO_R_UN; 
1024                         break;
1025                 }
1026                 break;
1027         case CEE_CONV_OVF_I1:
1028         case CEE_CONV_OVF_U1:
1029         case CEE_CONV_OVF_I2:
1030         case CEE_CONV_OVF_U2:
1031         case CEE_CONV_OVF_I4:
1032         case CEE_CONV_OVF_U4:
1033                 ins->type = STACK_I4;
1034                 ins->opcode += ovf3ops_op_map [src1->type];
1035                 break;
1036         case CEE_CONV_OVF_I_UN:
1037         case CEE_CONV_OVF_U_UN:
1038                 ins->type = STACK_PTR;
1039                 ins->opcode += ovf2ops_op_map [src1->type];
1040                 break;
1041         case CEE_CONV_OVF_I1_UN:
1042         case CEE_CONV_OVF_I2_UN:
1043         case CEE_CONV_OVF_I4_UN:
1044         case CEE_CONV_OVF_U1_UN:
1045         case CEE_CONV_OVF_U2_UN:
1046         case CEE_CONV_OVF_U4_UN:
1047                 ins->type = STACK_I4;
1048                 ins->opcode += ovf2ops_op_map [src1->type];
1049                 break;
1050         case CEE_CONV_U:
1051                 ins->type = STACK_PTR;
1052                 switch (src1->type) {
1053                 case STACK_I4:
1054                         ins->opcode = OP_ICONV_TO_U;
1055                         break;
1056                 case STACK_PTR:
1057                 case STACK_MP:
1058 #if SIZEOF_VOID_P == 8
1059                         ins->opcode = OP_LCONV_TO_U;
1060 #else
1061                         ins->opcode = OP_MOVE;
1062 #endif
1063                         break;
1064                 case STACK_I8:
1065                         ins->opcode = OP_LCONV_TO_U;
1066                         break;
1067                 case STACK_R8:
1068                         ins->opcode = OP_FCONV_TO_U;
1069                         break;
1070                 }
1071                 break;
1072         case CEE_CONV_I8:
1073         case CEE_CONV_U8:
1074                 ins->type = STACK_I8;
1075                 ins->opcode += unops_op_map [src1->type];
1076                 break;
1077         case CEE_CONV_OVF_I8:
1078         case CEE_CONV_OVF_U8:
1079                 ins->type = STACK_I8;
1080                 ins->opcode += ovf3ops_op_map [src1->type];
1081                 break;
1082         case CEE_CONV_OVF_U8_UN:
1083         case CEE_CONV_OVF_I8_UN:
1084                 ins->type = STACK_I8;
1085                 ins->opcode += ovf2ops_op_map [src1->type];
1086                 break;
1087         case CEE_CONV_R4:
1088                 ins->type = cfg->r4_stack_type;
1089                 ins->opcode += unops_op_map [src1->type];
1090                 break;
1091         case CEE_CONV_R8:
1092                 ins->type = STACK_R8;
1093                 ins->opcode += unops_op_map [src1->type];
1094                 break;
1095         case OP_CKFINITE:
1096                 ins->type = STACK_R8;           
1097                 break;
1098         case CEE_CONV_U2:
1099         case CEE_CONV_U1:
1100                 ins->type = STACK_I4;
1101                 ins->opcode += ovfops_op_map [src1->type];
1102                 break;
1103         case CEE_CONV_I:
1104         case CEE_CONV_OVF_I:
1105         case CEE_CONV_OVF_U:
1106                 ins->type = STACK_PTR;
1107                 ins->opcode += ovfops_op_map [src1->type];
1108                 break;
1109         case CEE_ADD_OVF:
1110         case CEE_ADD_OVF_UN:
1111         case CEE_MUL_OVF:
1112         case CEE_MUL_OVF_UN:
1113         case CEE_SUB_OVF:
1114         case CEE_SUB_OVF_UN:
1115                 ins->type = bin_num_table [src1->type] [src2->type];
1116                 ins->opcode += ovfops_op_map [src1->type];
1117                 if (ins->type == STACK_R8)
1118                         ins->type = STACK_INV;
1119                 break;
1120         case OP_LOAD_MEMBASE:
1121                 ins->type = STACK_PTR;
1122                 break;
1123         case OP_LOADI1_MEMBASE:
1124         case OP_LOADU1_MEMBASE:
1125         case OP_LOADI2_MEMBASE:
1126         case OP_LOADU2_MEMBASE:
1127         case OP_LOADI4_MEMBASE:
1128         case OP_LOADU4_MEMBASE:
1129                 ins->type = STACK_PTR;
1130                 break;
1131         case OP_LOADI8_MEMBASE:
1132                 ins->type = STACK_I8;
1133                 break;
1134         case OP_LOADR4_MEMBASE:
1135                 ins->type = cfg->r4_stack_type;
1136                 break;
1137         case OP_LOADR8_MEMBASE:
1138                 ins->type = STACK_R8;
1139                 break;
1140         default:
1141                 g_error ("opcode 0x%04x not handled in type from op", ins->opcode);
1142                 break;
1143         }
1144
1145         if (ins->type == STACK_MP)
1146                 ins->klass = mono_defaults.object_class;
1147 }
1148
1149 static const char 
1150 ldind_type [] = {
1151         STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_R8, STACK_OBJ
1152 };
1153
1154 #if 0
1155
1156 static const char
1157 param_table [STACK_MAX] [STACK_MAX] = {
1158         {0},
1159 };
1160
1161 static int
1162 check_values_to_signature (MonoInst *args, MonoType *this_ins, MonoMethodSignature *sig)
1163 {
1164         int i;
1165
1166         if (sig->hasthis) {
1167                 switch (args->type) {
1168                 case STACK_I4:
1169                 case STACK_I8:
1170                 case STACK_R8:
1171                 case STACK_VTYPE:
1172                 case STACK_INV:
1173                         return 0;
1174                 }
1175                 args++;
1176         }
1177         for (i = 0; i < sig->param_count; ++i) {
1178                 switch (args [i].type) {
1179                 case STACK_INV:
1180                         return 0;
1181                 case STACK_MP:
1182                         if (!sig->params [i]->byref)
1183                                 return 0;
1184                         continue;
1185                 case STACK_OBJ:
1186                         if (sig->params [i]->byref)
1187                                 return 0;
1188                         switch (sig->params [i]->type) {
1189                         case MONO_TYPE_CLASS:
1190                         case MONO_TYPE_STRING:
1191                         case MONO_TYPE_OBJECT:
1192                         case MONO_TYPE_SZARRAY:
1193                         case MONO_TYPE_ARRAY:
1194                                 break;
1195                         default:
1196                                 return 0;
1197                         }
1198                         continue;
1199                 case STACK_R8:
1200                         if (sig->params [i]->byref)
1201                                 return 0;
1202                         if (sig->params [i]->type != MONO_TYPE_R4 && sig->params [i]->type != MONO_TYPE_R8)
1203                                 return 0;
1204                         continue;
1205                 case STACK_PTR:
1206                 case STACK_I4:
1207                 case STACK_I8:
1208                 case STACK_VTYPE:
1209                         break;
1210                 }
1211                 /*if (!param_table [args [i].type] [sig->params [i]->type])
1212                         return 0;*/
1213         }
1214         return 1;
1215 }
1216 #endif
1217
1218 /*
1219  * When we need a pointer to the current domain many times in a method, we
1220  * call mono_domain_get() once and we store the result in a local variable.
1221  * This function returns the variable that represents the MonoDomain*.
1222  */
1223 inline static MonoInst *
1224 mono_get_domainvar (MonoCompile *cfg)
1225 {
1226         if (!cfg->domainvar)
1227                 cfg->domainvar = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1228         return cfg->domainvar;
1229 }
1230
1231 /*
1232  * The got_var contains the address of the Global Offset Table when AOT 
1233  * compiling.
1234  */
1235 MonoInst *
1236 mono_get_got_var (MonoCompile *cfg)
1237 {
1238         if (!cfg->compile_aot || !cfg->backend->need_got_var)
1239                 return NULL;
1240         if (!cfg->got_var) {
1241                 cfg->got_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1242         }
1243         return cfg->got_var;
1244 }
1245
1246 static MonoInst *
1247 mono_get_vtable_var (MonoCompile *cfg)
1248 {
1249         g_assert (cfg->gshared);
1250
1251         if (!cfg->rgctx_var) {
1252                 cfg->rgctx_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1253                 /* force the var to be stack allocated */
1254                 cfg->rgctx_var->flags |= MONO_INST_VOLATILE;
1255         }
1256
1257         return cfg->rgctx_var;
1258 }
1259
1260 static MonoType*
1261 type_from_stack_type (MonoInst *ins) {
1262         switch (ins->type) {
1263         case STACK_I4: return &mono_defaults.int32_class->byval_arg;
1264         case STACK_I8: return &mono_defaults.int64_class->byval_arg;
1265         case STACK_PTR: return &mono_defaults.int_class->byval_arg;
1266         case STACK_R4: return &mono_defaults.single_class->byval_arg;
1267         case STACK_R8: return &mono_defaults.double_class->byval_arg;
1268         case STACK_MP:
1269                 return &ins->klass->this_arg;
1270         case STACK_OBJ: return &mono_defaults.object_class->byval_arg;
1271         case STACK_VTYPE: return &ins->klass->byval_arg;
1272         default:
1273                 g_error ("stack type %d to monotype not handled\n", ins->type);
1274         }
1275         return NULL;
1276 }
1277
1278 static G_GNUC_UNUSED int
1279 type_to_stack_type (MonoCompile *cfg, MonoType *t)
1280 {
1281         t = mono_type_get_underlying_type (t);
1282         switch (t->type) {
1283         case MONO_TYPE_I1:
1284         case MONO_TYPE_U1:
1285         case MONO_TYPE_I2:
1286         case MONO_TYPE_U2:
1287         case MONO_TYPE_I4:
1288         case MONO_TYPE_U4:
1289                 return STACK_I4;
1290         case MONO_TYPE_I:
1291         case MONO_TYPE_U:
1292         case MONO_TYPE_PTR:
1293         case MONO_TYPE_FNPTR:
1294                 return STACK_PTR;
1295         case MONO_TYPE_CLASS:
1296         case MONO_TYPE_STRING:
1297         case MONO_TYPE_OBJECT:
1298         case MONO_TYPE_SZARRAY:
1299         case MONO_TYPE_ARRAY:    
1300                 return STACK_OBJ;
1301         case MONO_TYPE_I8:
1302         case MONO_TYPE_U8:
1303                 return STACK_I8;
1304         case MONO_TYPE_R4:
1305                 return cfg->r4_stack_type;
1306         case MONO_TYPE_R8:
1307                 return STACK_R8;
1308         case MONO_TYPE_VALUETYPE:
1309         case MONO_TYPE_TYPEDBYREF:
1310                 return STACK_VTYPE;
1311         case MONO_TYPE_GENERICINST:
1312                 if (mono_type_generic_inst_is_valuetype (t))
1313                         return STACK_VTYPE;
1314                 else
1315                         return STACK_OBJ;
1316                 break;
1317         default:
1318                 g_assert_not_reached ();
1319         }
1320
1321         return -1;
1322 }
1323
1324 static MonoClass*
1325 array_access_to_klass (int opcode)
1326 {
1327         switch (opcode) {
1328         case CEE_LDELEM_U1:
1329                 return mono_defaults.byte_class;
1330         case CEE_LDELEM_U2:
1331                 return mono_defaults.uint16_class;
1332         case CEE_LDELEM_I:
1333         case CEE_STELEM_I:
1334                 return mono_defaults.int_class;
1335         case CEE_LDELEM_I1:
1336         case CEE_STELEM_I1:
1337                 return mono_defaults.sbyte_class;
1338         case CEE_LDELEM_I2:
1339         case CEE_STELEM_I2:
1340                 return mono_defaults.int16_class;
1341         case CEE_LDELEM_I4:
1342         case CEE_STELEM_I4:
1343                 return mono_defaults.int32_class;
1344         case CEE_LDELEM_U4:
1345                 return mono_defaults.uint32_class;
1346         case CEE_LDELEM_I8:
1347         case CEE_STELEM_I8:
1348                 return mono_defaults.int64_class;
1349         case CEE_LDELEM_R4:
1350         case CEE_STELEM_R4:
1351                 return mono_defaults.single_class;
1352         case CEE_LDELEM_R8:
1353         case CEE_STELEM_R8:
1354                 return mono_defaults.double_class;
1355         case CEE_LDELEM_REF:
1356         case CEE_STELEM_REF:
1357                 return mono_defaults.object_class;
1358         default:
1359                 g_assert_not_reached ();
1360         }
1361         return NULL;
1362 }
1363
1364 /*
1365  * We try to share variables when possible
1366  */
1367 static MonoInst *
1368 mono_compile_get_interface_var (MonoCompile *cfg, int slot, MonoInst *ins)
1369 {
1370         MonoInst *res;
1371         int pos, vnum;
1372
1373         /* inlining can result in deeper stacks */ 
1374         if (slot >= cfg->header->max_stack)
1375                 return mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1376
1377         pos = ins->type - 1 + slot * STACK_MAX;
1378
1379         switch (ins->type) {
1380         case STACK_I4:
1381         case STACK_I8:
1382         case STACK_R8:
1383         case STACK_PTR:
1384         case STACK_MP:
1385         case STACK_OBJ:
1386                 if ((vnum = cfg->intvars [pos]))
1387                         return cfg->varinfo [vnum];
1388                 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1389                 cfg->intvars [pos] = res->inst_c0;
1390                 break;
1391         default:
1392                 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1393         }
1394         return res;
1395 }
1396
1397 static void
1398 mono_save_token_info (MonoCompile *cfg, MonoImage *image, guint32 token, gpointer key)
1399 {
1400         /* 
1401          * Don't use this if a generic_context is set, since that means AOT can't
1402          * look up the method using just the image+token.
1403          * table == 0 means this is a reference made from a wrapper.
1404          */
1405         if (cfg->compile_aot && !cfg->generic_context && (mono_metadata_token_table (token) > 0)) {
1406                 MonoJumpInfoToken *jump_info_token = (MonoJumpInfoToken *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoToken));
1407                 jump_info_token->image = image;
1408                 jump_info_token->token = token;
1409                 g_hash_table_insert (cfg->token_info_hash, key, jump_info_token);
1410         }
1411 }
1412
1413 /*
1414  * This function is called to handle items that are left on the evaluation stack
1415  * at basic block boundaries. What happens is that we save the values to local variables
1416  * and we reload them later when first entering the target basic block (with the
1417  * handle_loaded_temps () function).
1418  * A single joint point will use the same variables (stored in the array bb->out_stack or
1419  * bb->in_stack, if the basic block is before or after the joint point).
1420  *
1421  * This function needs to be called _before_ emitting the last instruction of
1422  * the bb (i.e. before emitting a branch).
1423  * If the stack merge fails at a join point, cfg->unverifiable is set.
1424  */
1425 static void
1426 handle_stack_args (MonoCompile *cfg, MonoInst **sp, int count)
1427 {
1428         int i, bindex;
1429         MonoBasicBlock *bb = cfg->cbb;
1430         MonoBasicBlock *outb;
1431         MonoInst *inst, **locals;
1432         gboolean found;
1433
1434         if (!count)
1435                 return;
1436         if (cfg->verbose_level > 3)
1437                 printf ("%d item(s) on exit from B%d\n", count, bb->block_num);
1438         if (!bb->out_scount) {
1439                 bb->out_scount = count;
1440                 //printf ("bblock %d has out:", bb->block_num);
1441                 found = FALSE;
1442                 for (i = 0; i < bb->out_count; ++i) {
1443                         outb = bb->out_bb [i];
1444                         /* exception handlers are linked, but they should not be considered for stack args */
1445                         if (outb->flags & BB_EXCEPTION_HANDLER)
1446                                 continue;
1447                         //printf (" %d", outb->block_num);
1448                         if (outb->in_stack) {
1449                                 found = TRUE;
1450                                 bb->out_stack = outb->in_stack;
1451                                 break;
1452                         }
1453                 }
1454                 //printf ("\n");
1455                 if (!found) {
1456                         bb->out_stack = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * count);
1457                         for (i = 0; i < count; ++i) {
1458                                 /* 
1459                                  * try to reuse temps already allocated for this purpouse, if they occupy the same
1460                                  * stack slot and if they are of the same type.
1461                                  * This won't cause conflicts since if 'local' is used to 
1462                                  * store one of the values in the in_stack of a bblock, then
1463                                  * the same variable will be used for the same outgoing stack 
1464                                  * slot as well. 
1465                                  * This doesn't work when inlining methods, since the bblocks
1466                                  * in the inlined methods do not inherit their in_stack from
1467                                  * the bblock they are inlined to. See bug #58863 for an
1468                                  * example.
1469                                  */
1470                                 if (cfg->inlined_method)
1471                                         bb->out_stack [i] = mono_compile_create_var (cfg, type_from_stack_type (sp [i]), OP_LOCAL);
1472                                 else
1473                                         bb->out_stack [i] = mono_compile_get_interface_var (cfg, i, sp [i]);
1474                         }
1475                 }
1476         }
1477
1478         for (i = 0; i < bb->out_count; ++i) {
1479                 outb = bb->out_bb [i];
1480                 /* exception handlers are linked, but they should not be considered for stack args */
1481                 if (outb->flags & BB_EXCEPTION_HANDLER)
1482                         continue;
1483                 if (outb->in_scount) {
1484                         if (outb->in_scount != bb->out_scount) {
1485                                 cfg->unverifiable = TRUE;
1486                                 return;
1487                         }
1488                         continue; /* check they are the same locals */
1489                 }
1490                 outb->in_scount = count;
1491                 outb->in_stack = bb->out_stack;
1492         }
1493
1494         locals = bb->out_stack;
1495         cfg->cbb = bb;
1496         for (i = 0; i < count; ++i) {
1497                 EMIT_NEW_TEMPSTORE (cfg, inst, locals [i]->inst_c0, sp [i]);
1498                 inst->cil_code = sp [i]->cil_code;
1499                 sp [i] = locals [i];
1500                 if (cfg->verbose_level > 3)
1501                         printf ("storing %d to temp %d\n", i, (int)locals [i]->inst_c0);
1502         }
1503
1504         /*
1505          * It is possible that the out bblocks already have in_stack assigned, and
1506          * the in_stacks differ. In this case, we will store to all the different 
1507          * in_stacks.
1508          */
1509
1510         found = TRUE;
1511         bindex = 0;
1512         while (found) {
1513                 /* Find a bblock which has a different in_stack */
1514                 found = FALSE;
1515                 while (bindex < bb->out_count) {
1516                         outb = bb->out_bb [bindex];
1517                         /* exception handlers are linked, but they should not be considered for stack args */
1518                         if (outb->flags & BB_EXCEPTION_HANDLER) {
1519                                 bindex++;
1520                                 continue;
1521                         }
1522                         if (outb->in_stack != locals) {
1523                                 for (i = 0; i < count; ++i) {
1524                                         EMIT_NEW_TEMPSTORE (cfg, inst, outb->in_stack [i]->inst_c0, sp [i]);
1525                                         inst->cil_code = sp [i]->cil_code;
1526                                         sp [i] = locals [i];
1527                                         if (cfg->verbose_level > 3)
1528                                                 printf ("storing %d to temp %d\n", i, (int)outb->in_stack [i]->inst_c0);
1529                                 }
1530                                 locals = outb->in_stack;
1531                                 found = TRUE;
1532                                 break;
1533                         }
1534                         bindex ++;
1535                 }
1536         }
1537 }
1538
1539 static MonoInst*
1540 emit_runtime_constant (MonoCompile *cfg, MonoJumpInfoType patch_type, gpointer data)
1541 {
1542         MonoInst *ins;
1543
1544         if (cfg->compile_aot) {
1545                 EMIT_NEW_AOTCONST (cfg, ins, patch_type, data);
1546         } else {
1547                 MonoJumpInfo ji;
1548                 gpointer target;
1549
1550                 ji.type = patch_type;
1551                 ji.data.target = data;
1552                 target = mono_resolve_patch_target (NULL, cfg->domain, NULL, &ji, FALSE);
1553
1554                 EMIT_NEW_PCONST (cfg, ins, target);
1555         }
1556         return ins;
1557 }
1558
1559 static void
1560 mini_emit_interface_bitmap_check (MonoCompile *cfg, int intf_bit_reg, int base_reg, int offset, MonoClass *klass)
1561 {
1562         int ibitmap_reg = alloc_preg (cfg);
1563 #ifdef COMPRESSED_INTERFACE_BITMAP
1564         MonoInst *args [2];
1565         MonoInst *res, *ins;
1566         NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, ibitmap_reg, base_reg, offset);
1567         MONO_ADD_INS (cfg->cbb, ins);
1568         args [0] = ins;
1569         args [1] = emit_runtime_constant (cfg, MONO_PATCH_INFO_IID, klass);
1570         res = mono_emit_jit_icall (cfg, mono_class_interface_match, args);
1571         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, intf_bit_reg, res->dreg);
1572 #else
1573         int ibitmap_byte_reg = alloc_preg (cfg);
1574
1575         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, ibitmap_reg, base_reg, offset);
1576
1577         if (cfg->compile_aot) {
1578                 int iid_reg = alloc_preg (cfg);
1579                 int shifted_iid_reg = alloc_preg (cfg);
1580                 int ibitmap_byte_address_reg = alloc_preg (cfg);
1581                 int masked_iid_reg = alloc_preg (cfg);
1582                 int iid_one_bit_reg = alloc_preg (cfg);
1583                 int iid_bit_reg = alloc_preg (cfg);
1584                 MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_IID);
1585                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, shifted_iid_reg, iid_reg, 3);
1586                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, ibitmap_byte_address_reg, ibitmap_reg, shifted_iid_reg);
1587                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, ibitmap_byte_reg, ibitmap_byte_address_reg, 0);
1588                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, masked_iid_reg, iid_reg, 7);
1589                 MONO_EMIT_NEW_ICONST (cfg, iid_one_bit_reg, 1);
1590                 MONO_EMIT_NEW_BIALU (cfg, OP_ISHL, iid_bit_reg, iid_one_bit_reg, masked_iid_reg);
1591                 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, intf_bit_reg, ibitmap_byte_reg, iid_bit_reg);
1592         } else {
1593                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, ibitmap_byte_reg, ibitmap_reg, klass->interface_id >> 3);
1594                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, intf_bit_reg, ibitmap_byte_reg, 1 << (klass->interface_id & 7));
1595         }
1596 #endif
1597 }
1598
1599 /* 
1600  * Emit code which loads into "intf_bit_reg" a nonzero value if the MonoClass
1601  * stored in "klass_reg" implements the interface "klass".
1602  */
1603 static void
1604 mini_emit_load_intf_bit_reg_class (MonoCompile *cfg, int intf_bit_reg, int klass_reg, MonoClass *klass)
1605 {
1606         mini_emit_interface_bitmap_check (cfg, intf_bit_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, interface_bitmap), klass);
1607 }
1608
1609 /* 
1610  * Emit code which loads into "intf_bit_reg" a nonzero value if the MonoVTable
1611  * stored in "vtable_reg" implements the interface "klass".
1612  */
1613 static void
1614 mini_emit_load_intf_bit_reg_vtable (MonoCompile *cfg, int intf_bit_reg, int vtable_reg, MonoClass *klass)
1615 {
1616         mini_emit_interface_bitmap_check (cfg, intf_bit_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, interface_bitmap), klass);
1617 }
1618
1619 /* 
1620  * Emit code which checks whenever the interface id of @klass is smaller than
1621  * than the value given by max_iid_reg.
1622 */
1623 static void
1624 mini_emit_max_iid_check (MonoCompile *cfg, int max_iid_reg, MonoClass *klass,
1625                                                  MonoBasicBlock *false_target)
1626 {
1627         if (cfg->compile_aot) {
1628                 int iid_reg = alloc_preg (cfg);
1629                 MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_IID);
1630                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, max_iid_reg, iid_reg);
1631         }
1632         else
1633                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, max_iid_reg, klass->interface_id);
1634         if (false_target)
1635                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBLT_UN, false_target);
1636         else
1637                 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "InvalidCastException");
1638 }
1639
1640 /* Same as above, but obtains max_iid from a vtable */
1641 static void
1642 mini_emit_max_iid_check_vtable (MonoCompile *cfg, int vtable_reg, MonoClass *klass,
1643                                                                  MonoBasicBlock *false_target)
1644 {
1645         int max_iid_reg = alloc_preg (cfg);
1646                 
1647         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, max_iid_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, max_interface_id));
1648         mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target);
1649 }
1650
1651 /* Same as above, but obtains max_iid from a klass */
1652 static void
1653 mini_emit_max_iid_check_class (MonoCompile *cfg, int klass_reg, MonoClass *klass,
1654                                                                  MonoBasicBlock *false_target)
1655 {
1656         int max_iid_reg = alloc_preg (cfg);
1657
1658         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, max_iid_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, max_interface_id));
1659         mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target);
1660 }
1661
1662 static void
1663 mini_emit_isninst_cast_inst (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoInst *klass_ins, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1664 {
1665         int idepth_reg = alloc_preg (cfg);
1666         int stypes_reg = alloc_preg (cfg);
1667         int stype = alloc_preg (cfg);
1668
1669         mono_class_setup_supertypes (klass);
1670
1671         if (klass->idepth > MONO_DEFAULT_SUPERTABLE_SIZE) {
1672                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, idepth_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, idepth));
1673                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, idepth_reg, klass->idepth);
1674                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBLT_UN, false_target);
1675         }
1676         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stypes_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, supertypes));
1677         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stype, stypes_reg, ((klass->idepth - 1) * SIZEOF_VOID_P));
1678         if (klass_ins) {
1679                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, stype, klass_ins->dreg);
1680         } else if (cfg->compile_aot) {
1681                 int const_reg = alloc_preg (cfg);
1682                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
1683                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, stype, const_reg);
1684         } else {
1685                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, stype, klass);
1686         }
1687         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, true_target);
1688 }
1689
1690 static void
1691 mini_emit_isninst_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1692 {
1693         mini_emit_isninst_cast_inst (cfg, klass_reg, klass, NULL, false_target, true_target);
1694 }
1695
1696 static void
1697 mini_emit_iface_cast (MonoCompile *cfg, int vtable_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1698 {
1699         int intf_reg = alloc_preg (cfg);
1700
1701         mini_emit_max_iid_check_vtable (cfg, vtable_reg, klass, false_target);
1702         mini_emit_load_intf_bit_reg_vtable (cfg, intf_reg, vtable_reg, klass);
1703         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, intf_reg, 0);
1704         if (true_target)
1705                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, true_target);
1706         else
1707                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");               
1708 }
1709
1710 /*
1711  * Variant of the above that takes a register to the class, not the vtable.
1712  */
1713 static void
1714 mini_emit_iface_class_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1715 {
1716         int intf_bit_reg = alloc_preg (cfg);
1717
1718         mini_emit_max_iid_check_class (cfg, klass_reg, klass, false_target);
1719         mini_emit_load_intf_bit_reg_class (cfg, intf_bit_reg, klass_reg, klass);
1720         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, intf_bit_reg, 0);
1721         if (true_target)
1722                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, true_target);
1723         else
1724                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
1725 }
1726
1727 static inline void
1728 mini_emit_class_check_inst (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoInst *klass_inst)
1729 {
1730         if (klass_inst) {
1731                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_inst->dreg);
1732         } else {
1733                 MonoInst *ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_CLASS, klass);
1734                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, ins->dreg);
1735         }
1736         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1737 }
1738
1739 static inline void
1740 mini_emit_class_check (MonoCompile *cfg, int klass_reg, MonoClass *klass)
1741 {
1742         mini_emit_class_check_inst (cfg, klass_reg, klass, NULL);
1743 }
1744
1745 static inline void
1746 mini_emit_class_check_branch (MonoCompile *cfg, int klass_reg, MonoClass *klass, int branch_op, MonoBasicBlock *target)
1747 {
1748         if (cfg->compile_aot) {
1749                 int const_reg = alloc_preg (cfg);
1750                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
1751                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, const_reg);
1752         } else {
1753                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
1754         }
1755         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, branch_op, target);
1756 }
1757
1758 static void
1759 mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoBasicBlock *object_is_null);
1760         
1761 static void
1762 mini_emit_castclass_inst (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoInst *klass_inst, MonoBasicBlock *object_is_null)
1763 {
1764         if (klass->rank) {
1765                 int rank_reg = alloc_preg (cfg);
1766                 int eclass_reg = alloc_preg (cfg);
1767
1768                 g_assert (!klass_inst);
1769                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, rank));
1770                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank);
1771                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1772                 //              MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
1773                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, cast_class));
1774                 if (klass->cast_class == mono_defaults.object_class) {
1775                         int parent_reg = alloc_preg (cfg);
1776                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, parent_reg, eclass_reg, MONO_STRUCT_OFFSET (MonoClass, parent));
1777                         mini_emit_class_check_branch (cfg, parent_reg, mono_defaults.enum_class->parent, OP_PBNE_UN, object_is_null);
1778                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1779                 } else if (klass->cast_class == mono_defaults.enum_class->parent) {
1780                         mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class->parent, OP_PBEQ, object_is_null);
1781                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1782                 } else if (klass->cast_class == mono_defaults.enum_class) {
1783                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1784                 } else if (klass->cast_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1785                         mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, NULL, NULL);
1786                 } else {
1787                         // Pass -1 as obj_reg to skip the check below for arrays of arrays
1788                         mini_emit_castclass (cfg, -1, eclass_reg, klass->cast_class, object_is_null);
1789                 }
1790
1791                 if ((klass->rank == 1) && (klass->byval_arg.type == MONO_TYPE_SZARRAY) && (obj_reg != -1)) {
1792                         /* Check that the object is a vector too */
1793                         int bounds_reg = alloc_preg (cfg);
1794                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, obj_reg, MONO_STRUCT_OFFSET (MonoArray, bounds));
1795                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
1796                         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1797                 }
1798         } else {
1799                 int idepth_reg = alloc_preg (cfg);
1800                 int stypes_reg = alloc_preg (cfg);
1801                 int stype = alloc_preg (cfg);
1802
1803                 mono_class_setup_supertypes (klass);
1804
1805                 if (klass->idepth > MONO_DEFAULT_SUPERTABLE_SIZE) {
1806                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, idepth_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, idepth));
1807                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, idepth_reg, klass->idepth);
1808                         MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "InvalidCastException");
1809                 }
1810                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stypes_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, supertypes));
1811                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stype, stypes_reg, ((klass->idepth - 1) * SIZEOF_VOID_P));
1812                 mini_emit_class_check_inst (cfg, stype, klass, klass_inst);
1813         }
1814 }
1815
1816 static void
1817 mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoBasicBlock *object_is_null)
1818 {
1819         mini_emit_castclass_inst (cfg, obj_reg, klass_reg, klass, NULL, object_is_null);
1820 }
1821
1822 static void 
1823 mini_emit_memset (MonoCompile *cfg, int destreg, int offset, int size, int val, int align)
1824 {
1825         int val_reg;
1826
1827         g_assert (val == 0);
1828
1829         if (align == 0)
1830                 align = 4;
1831
1832         if ((size <= SIZEOF_REGISTER) && (size <= align)) {
1833                 switch (size) {
1834                 case 1:
1835                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, destreg, offset, val);
1836                         return;
1837                 case 2:
1838                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI2_MEMBASE_IMM, destreg, offset, val);
1839                         return;
1840                 case 4:
1841                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI4_MEMBASE_IMM, destreg, offset, val);
1842                         return;
1843 #if SIZEOF_REGISTER == 8
1844                 case 8:
1845                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI8_MEMBASE_IMM, destreg, offset, val);
1846                         return;
1847 #endif
1848                 }
1849         }
1850
1851         val_reg = alloc_preg (cfg);
1852
1853         if (SIZEOF_REGISTER == 8)
1854                 MONO_EMIT_NEW_I8CONST (cfg, val_reg, val);
1855         else
1856                 MONO_EMIT_NEW_ICONST (cfg, val_reg, val);
1857
1858         if (align < 4) {
1859                 /* This could be optimized further if neccesary */
1860                 while (size >= 1) {
1861                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
1862                         offset += 1;
1863                         size -= 1;
1864                 }
1865                 return;
1866         }       
1867
1868         if (!cfg->backend->no_unaligned_access && SIZEOF_REGISTER == 8) {
1869                 if (offset % 8) {
1870                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
1871                         offset += 4;
1872                         size -= 4;
1873                 }
1874                 while (size >= 8) {
1875                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, destreg, offset, val_reg);
1876                         offset += 8;
1877                         size -= 8;
1878                 }
1879         }       
1880
1881         while (size >= 4) {
1882                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
1883                 offset += 4;
1884                 size -= 4;
1885         }
1886         while (size >= 2) {
1887                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, offset, val_reg);
1888                 offset += 2;
1889                 size -= 2;
1890         }
1891         while (size >= 1) {
1892                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
1893                 offset += 1;
1894                 size -= 1;
1895         }
1896 }
1897
1898 void 
1899 mini_emit_memcpy (MonoCompile *cfg, int destreg, int doffset, int srcreg, int soffset, int size, int align)
1900 {
1901         int cur_reg;
1902
1903         if (align == 0)
1904                 align = 4;
1905
1906         /*FIXME arbitrary hack to avoid unbound code expansion.*/
1907         g_assert (size < 10000);
1908
1909         if (align < 4) {
1910                 /* This could be optimized further if neccesary */
1911                 while (size >= 1) {
1912                         cur_reg = alloc_preg (cfg);
1913                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, cur_reg, srcreg, soffset);
1914                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, doffset, cur_reg);
1915                         doffset += 1;
1916                         soffset += 1;
1917                         size -= 1;
1918                 }
1919         }
1920
1921         if (!cfg->backend->no_unaligned_access && SIZEOF_REGISTER == 8) {
1922                 while (size >= 8) {
1923                         cur_reg = alloc_preg (cfg);
1924                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI8_MEMBASE, cur_reg, srcreg, soffset);
1925                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, destreg, doffset, cur_reg);
1926                         doffset += 8;
1927                         soffset += 8;
1928                         size -= 8;
1929                 }
1930         }       
1931
1932         while (size >= 4) {
1933                 cur_reg = alloc_preg (cfg);
1934                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, cur_reg, srcreg, soffset);
1935                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, doffset, cur_reg);
1936                 doffset += 4;
1937                 soffset += 4;
1938                 size -= 4;
1939         }
1940         while (size >= 2) {
1941                 cur_reg = alloc_preg (cfg);
1942                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, cur_reg, srcreg, soffset);
1943                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, doffset, cur_reg);
1944                 doffset += 2;
1945                 soffset += 2;
1946                 size -= 2;
1947         }
1948         while (size >= 1) {
1949                 cur_reg = alloc_preg (cfg);
1950                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, cur_reg, srcreg, soffset);
1951                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, doffset, cur_reg);
1952                 doffset += 1;
1953                 soffset += 1;
1954                 size -= 1;
1955         }
1956 }
1957
1958 static void
1959 emit_tls_set (MonoCompile *cfg, int sreg1, MonoTlsKey tls_key)
1960 {
1961         MonoInst *ins, *c;
1962
1963         if (cfg->compile_aot) {
1964                 EMIT_NEW_TLS_OFFSETCONST (cfg, c, tls_key);
1965                 MONO_INST_NEW (cfg, ins, OP_TLS_SET_REG);
1966                 ins->sreg1 = sreg1;
1967                 ins->sreg2 = c->dreg;
1968                 MONO_ADD_INS (cfg->cbb, ins);
1969         } else {
1970                 MONO_INST_NEW (cfg, ins, OP_TLS_SET);
1971                 ins->sreg1 = sreg1;
1972                 ins->inst_offset = mini_get_tls_offset (tls_key);
1973                 MONO_ADD_INS (cfg->cbb, ins);
1974         }
1975 }
1976
1977 /*
1978  * emit_push_lmf:
1979  *
1980  *   Emit IR to push the current LMF onto the LMF stack.
1981  */
1982 static void
1983 emit_push_lmf (MonoCompile *cfg)
1984 {
1985         /*
1986          * Emit IR to push the LMF:
1987          * lmf_addr = <lmf_addr from tls>
1988          * lmf->lmf_addr = lmf_addr
1989          * lmf->prev_lmf = *lmf_addr
1990          * *lmf_addr = lmf
1991          */
1992         int lmf_reg, prev_lmf_reg;
1993         MonoInst *ins, *lmf_ins;
1994
1995         if (!cfg->lmf_ir)
1996                 return;
1997
1998         if (cfg->lmf_ir_mono_lmf && mini_tls_get_supported (cfg, TLS_KEY_LMF)) {
1999                 /* Load current lmf */
2000                 lmf_ins = mono_get_lmf_intrinsic (cfg);
2001                 g_assert (lmf_ins);
2002                 MONO_ADD_INS (cfg->cbb, lmf_ins);
2003                 EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
2004                 lmf_reg = ins->dreg;
2005                 /* Save previous_lmf */
2006                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf), lmf_ins->dreg);
2007                 /* Set new LMF */
2008                 emit_tls_set (cfg, lmf_reg, TLS_KEY_LMF);
2009         } else {
2010                 /*
2011                  * Store lmf_addr in a variable, so it can be allocated to a global register.
2012                  */
2013                 if (!cfg->lmf_addr_var)
2014                         cfg->lmf_addr_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2015
2016 #ifdef HOST_WIN32
2017                 ins = mono_get_jit_tls_intrinsic (cfg);
2018                 if (ins) {
2019                         int jit_tls_dreg = ins->dreg;
2020
2021                         MONO_ADD_INS (cfg->cbb, ins);
2022                         lmf_reg = alloc_preg (cfg);
2023                         EMIT_NEW_BIALU_IMM (cfg, lmf_ins, OP_PADD_IMM, lmf_reg, jit_tls_dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, lmf));
2024                 } else {
2025                         lmf_ins = mono_emit_jit_icall (cfg, mono_get_lmf_addr, NULL);
2026                 }
2027 #else
2028                 lmf_ins = mono_get_lmf_addr_intrinsic (cfg);
2029                 if (lmf_ins) {
2030                         MONO_ADD_INS (cfg->cbb, lmf_ins);
2031                 } else {
2032 #ifdef TARGET_IOS
2033                         MonoInst *args [16], *jit_tls_ins, *ins;
2034
2035                         /* Inline mono_get_lmf_addr () */
2036                         /* jit_tls = pthread_getspecific (mono_jit_tls_id); lmf_addr = &jit_tls->lmf; */
2037
2038                         /* Load mono_jit_tls_id */
2039                         if (cfg->compile_aot)
2040                                 EMIT_NEW_AOTCONST (cfg, args [0], MONO_PATCH_INFO_JIT_TLS_ID, NULL);
2041                         else
2042                                 EMIT_NEW_ICONST (cfg, args [0], mono_jit_tls_id);
2043                         /* call pthread_getspecific () */
2044                         jit_tls_ins = mono_emit_jit_icall (cfg, pthread_getspecific, args);
2045                         /* lmf_addr = &jit_tls->lmf */
2046                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, cfg->lmf_addr_var->dreg, jit_tls_ins->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, lmf));
2047                         lmf_ins = ins;
2048 #else
2049                         lmf_ins = mono_emit_jit_icall (cfg, mono_get_lmf_addr, NULL);
2050 #endif
2051                 }
2052 #endif
2053                 lmf_ins->dreg = cfg->lmf_addr_var->dreg;
2054
2055                 EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
2056                 lmf_reg = ins->dreg;
2057
2058                 prev_lmf_reg = alloc_preg (cfg);
2059                 /* Save previous_lmf */
2060                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, cfg->lmf_addr_var->dreg, 0);
2061                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf), prev_lmf_reg);
2062                 /* Set new lmf */
2063                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, cfg->lmf_addr_var->dreg, 0, lmf_reg);
2064         }
2065 }
2066
2067 /*
2068  * emit_pop_lmf:
2069  *
2070  *   Emit IR to pop the current LMF from the LMF stack.
2071  */
2072 static void
2073 emit_pop_lmf (MonoCompile *cfg)
2074 {
2075         int lmf_reg, lmf_addr_reg, prev_lmf_reg;
2076         MonoInst *ins;
2077
2078         if (!cfg->lmf_ir)
2079                 return;
2080
2081         EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
2082         lmf_reg = ins->dreg;
2083
2084         if (cfg->lmf_ir_mono_lmf && mini_tls_get_supported (cfg, TLS_KEY_LMF)) {
2085                 /* Load previous_lmf */
2086                 prev_lmf_reg = alloc_preg (cfg);
2087                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf));
2088                 /* Set new LMF */
2089                 emit_tls_set (cfg, prev_lmf_reg, TLS_KEY_LMF);
2090         } else {
2091                 /*
2092                  * Emit IR to pop the LMF:
2093                  * *(lmf->lmf_addr) = lmf->prev_lmf
2094                  */
2095                 /* This could be called before emit_push_lmf () */
2096                 if (!cfg->lmf_addr_var)
2097                         cfg->lmf_addr_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2098                 lmf_addr_reg = cfg->lmf_addr_var->dreg;
2099
2100                 prev_lmf_reg = alloc_preg (cfg);
2101                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf));
2102                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_addr_reg, 0, prev_lmf_reg);
2103         }
2104 }
2105
2106 static void
2107 emit_instrumentation_call (MonoCompile *cfg, void *func)
2108 {
2109         MonoInst *iargs [1];
2110
2111         /*
2112          * Avoid instrumenting inlined methods since it can
2113          * distort profiling results.
2114          */
2115         if (cfg->method != cfg->current_method)
2116                 return;
2117
2118         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE) {
2119                 EMIT_NEW_METHODCONST (cfg, iargs [0], cfg->method);
2120                 mono_emit_jit_icall (cfg, func, iargs);
2121         }
2122 }
2123
2124 static int
2125 ret_type_to_call_opcode (MonoCompile *cfg, MonoType *type, int calli, int virt)
2126 {
2127 handle_enum:
2128         type = mini_get_underlying_type (type);
2129         switch (type->type) {
2130         case MONO_TYPE_VOID:
2131                 return calli? OP_VOIDCALL_REG: virt? OP_VOIDCALL_MEMBASE: OP_VOIDCALL;
2132         case MONO_TYPE_I1:
2133         case MONO_TYPE_U1:
2134         case MONO_TYPE_I2:
2135         case MONO_TYPE_U2:
2136         case MONO_TYPE_I4:
2137         case MONO_TYPE_U4:
2138                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2139         case MONO_TYPE_I:
2140         case MONO_TYPE_U:
2141         case MONO_TYPE_PTR:
2142         case MONO_TYPE_FNPTR:
2143                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2144         case MONO_TYPE_CLASS:
2145         case MONO_TYPE_STRING:
2146         case MONO_TYPE_OBJECT:
2147         case MONO_TYPE_SZARRAY:
2148         case MONO_TYPE_ARRAY:    
2149                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2150         case MONO_TYPE_I8:
2151         case MONO_TYPE_U8:
2152                 return calli? OP_LCALL_REG: virt? OP_LCALL_MEMBASE: OP_LCALL;
2153         case MONO_TYPE_R4:
2154                 if (cfg->r4fp)
2155                         return calli? OP_RCALL_REG: virt? OP_RCALL_MEMBASE: OP_RCALL;
2156                 else
2157                         return calli? OP_FCALL_REG: virt? OP_FCALL_MEMBASE: OP_FCALL;
2158         case MONO_TYPE_R8:
2159                 return calli? OP_FCALL_REG: virt? OP_FCALL_MEMBASE: OP_FCALL;
2160         case MONO_TYPE_VALUETYPE:
2161                 if (type->data.klass->enumtype) {
2162                         type = mono_class_enum_basetype (type->data.klass);
2163                         goto handle_enum;
2164                 } else
2165                         return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2166         case MONO_TYPE_TYPEDBYREF:
2167                 return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2168         case MONO_TYPE_GENERICINST:
2169                 type = &type->data.generic_class->container_class->byval_arg;
2170                 goto handle_enum;
2171         case MONO_TYPE_VAR:
2172         case MONO_TYPE_MVAR:
2173                 /* gsharedvt */
2174                 return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2175         default:
2176                 g_error ("unknown type 0x%02x in ret_type_to_call_opcode", type->type);
2177         }
2178         return -1;
2179 }
2180
2181 /*
2182  * target_type_is_incompatible:
2183  * @cfg: MonoCompile context
2184  *
2185  * Check that the item @arg on the evaluation stack can be stored
2186  * in the target type (can be a local, or field, etc).
2187  * The cfg arg can be used to check if we need verification or just
2188  * validity checks.
2189  *
2190  * Returns: non-0 value if arg can't be stored on a target.
2191  */
2192 static int
2193 target_type_is_incompatible (MonoCompile *cfg, MonoType *target, MonoInst *arg)
2194 {
2195         MonoType *simple_type;
2196         MonoClass *klass;
2197
2198         if (target->byref) {
2199                 /* FIXME: check that the pointed to types match */
2200                 if (arg->type == STACK_MP) {
2201                         MonoClass *base_class = mono_class_from_mono_type (target);
2202                         /* This is needed to handle gshared types + ldaddr */
2203                         simple_type = mini_get_underlying_type (&base_class->byval_arg);
2204                         return target->type != MONO_TYPE_I && arg->klass != base_class && arg->klass != mono_class_from_mono_type (simple_type);
2205                 }
2206                 if (arg->type == STACK_PTR)
2207                         return 0;
2208                 return 1;
2209         }
2210
2211         simple_type = mini_get_underlying_type (target);
2212         switch (simple_type->type) {
2213         case MONO_TYPE_VOID:
2214                 return 1;
2215         case MONO_TYPE_I1:
2216         case MONO_TYPE_U1:
2217         case MONO_TYPE_I2:
2218         case MONO_TYPE_U2:
2219         case MONO_TYPE_I4:
2220         case MONO_TYPE_U4:
2221                 if (arg->type != STACK_I4 && arg->type != STACK_PTR)
2222                         return 1;
2223                 return 0;
2224         case MONO_TYPE_PTR:
2225                 /* STACK_MP is needed when setting pinned locals */
2226                 if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
2227                         return 1;
2228                 return 0;
2229         case MONO_TYPE_I:
2230         case MONO_TYPE_U:
2231         case MONO_TYPE_FNPTR:
2232                 /* 
2233                  * Some opcodes like ldloca returns 'transient pointers' which can be stored in
2234                  * in native int. (#688008).
2235                  */
2236                 if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
2237                         return 1;
2238                 return 0;
2239         case MONO_TYPE_CLASS:
2240         case MONO_TYPE_STRING:
2241         case MONO_TYPE_OBJECT:
2242         case MONO_TYPE_SZARRAY:
2243         case MONO_TYPE_ARRAY:    
2244                 if (arg->type != STACK_OBJ)
2245                         return 1;
2246                 /* FIXME: check type compatibility */
2247                 return 0;
2248         case MONO_TYPE_I8:
2249         case MONO_TYPE_U8:
2250                 if (arg->type != STACK_I8)
2251                         return 1;
2252                 return 0;
2253         case MONO_TYPE_R4:
2254                 if (arg->type != cfg->r4_stack_type)
2255                         return 1;
2256                 return 0;
2257         case MONO_TYPE_R8:
2258                 if (arg->type != STACK_R8)
2259                         return 1;
2260                 return 0;
2261         case MONO_TYPE_VALUETYPE:
2262                 if (arg->type != STACK_VTYPE)
2263                         return 1;
2264                 klass = mono_class_from_mono_type (simple_type);
2265                 if (klass != arg->klass)
2266                         return 1;
2267                 return 0;
2268         case MONO_TYPE_TYPEDBYREF:
2269                 if (arg->type != STACK_VTYPE)
2270                         return 1;
2271                 klass = mono_class_from_mono_type (simple_type);
2272                 if (klass != arg->klass)
2273                         return 1;
2274                 return 0;
2275         case MONO_TYPE_GENERICINST:
2276                 if (mono_type_generic_inst_is_valuetype (simple_type)) {
2277                         MonoClass *target_class;
2278                         if (arg->type != STACK_VTYPE)
2279                                 return 1;
2280                         klass = mono_class_from_mono_type (simple_type);
2281                         target_class = mono_class_from_mono_type (target);
2282                         /* The second cases is needed when doing partial sharing */
2283                         if (klass != arg->klass && target_class != arg->klass && target_class != mono_class_from_mono_type (mini_get_underlying_type (&arg->klass->byval_arg)))
2284                                 return 1;
2285                         return 0;
2286                 } else {
2287                         if (arg->type != STACK_OBJ)
2288                                 return 1;
2289                         /* FIXME: check type compatibility */
2290                         return 0;
2291                 }
2292         case MONO_TYPE_VAR:
2293         case MONO_TYPE_MVAR:
2294                 g_assert (cfg->gshared);
2295                 if (mini_type_var_is_vt (simple_type)) {
2296                         if (arg->type != STACK_VTYPE)
2297                                 return 1;
2298                 } else {
2299                         if (arg->type != STACK_OBJ)
2300                                 return 1;
2301                 }
2302                 return 0;
2303         default:
2304                 g_error ("unknown type 0x%02x in target_type_is_incompatible", simple_type->type);
2305         }
2306         return 1;
2307 }
2308
2309 /*
2310  * Prepare arguments for passing to a function call.
2311  * Return a non-zero value if the arguments can't be passed to the given
2312  * signature.
2313  * The type checks are not yet complete and some conversions may need
2314  * casts on 32 or 64 bit architectures.
2315  *
2316  * FIXME: implement this using target_type_is_incompatible ()
2317  */
2318 static int
2319 check_call_signature (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args)
2320 {
2321         MonoType *simple_type;
2322         int i;
2323
2324         if (sig->hasthis) {
2325                 if (args [0]->type != STACK_OBJ && args [0]->type != STACK_MP && args [0]->type != STACK_PTR)
2326                         return 1;
2327                 args++;
2328         }
2329         for (i = 0; i < sig->param_count; ++i) {
2330                 if (sig->params [i]->byref) {
2331                         if (args [i]->type != STACK_MP && args [i]->type != STACK_PTR)
2332                                 return 1;
2333                         continue;
2334                 }
2335                 simple_type = mini_get_underlying_type (sig->params [i]);
2336 handle_enum:
2337                 switch (simple_type->type) {
2338                 case MONO_TYPE_VOID:
2339                         return 1;
2340                         continue;
2341                 case MONO_TYPE_I1:
2342                 case MONO_TYPE_U1:
2343                 case MONO_TYPE_I2:
2344                 case MONO_TYPE_U2:
2345                 case MONO_TYPE_I4:
2346                 case MONO_TYPE_U4:
2347                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR)
2348                                 return 1;
2349                         continue;
2350                 case MONO_TYPE_I:
2351                 case MONO_TYPE_U:
2352                 case MONO_TYPE_PTR:
2353                 case MONO_TYPE_FNPTR:
2354                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR && args [i]->type != STACK_MP && args [i]->type != STACK_OBJ)
2355                                 return 1;
2356                         continue;
2357                 case MONO_TYPE_CLASS:
2358                 case MONO_TYPE_STRING:
2359                 case MONO_TYPE_OBJECT:
2360                 case MONO_TYPE_SZARRAY:
2361                 case MONO_TYPE_ARRAY:    
2362                         if (args [i]->type != STACK_OBJ)
2363                                 return 1;
2364                         continue;
2365                 case MONO_TYPE_I8:
2366                 case MONO_TYPE_U8:
2367                         if (args [i]->type != STACK_I8)
2368                                 return 1;
2369                         continue;
2370                 case MONO_TYPE_R4:
2371                         if (args [i]->type != cfg->r4_stack_type)
2372                                 return 1;
2373                         continue;
2374                 case MONO_TYPE_R8:
2375                         if (args [i]->type != STACK_R8)
2376                                 return 1;
2377                         continue;
2378                 case MONO_TYPE_VALUETYPE:
2379                         if (simple_type->data.klass->enumtype) {
2380                                 simple_type = mono_class_enum_basetype (simple_type->data.klass);
2381                                 goto handle_enum;
2382                         }
2383                         if (args [i]->type != STACK_VTYPE)
2384                                 return 1;
2385                         continue;
2386                 case MONO_TYPE_TYPEDBYREF:
2387                         if (args [i]->type != STACK_VTYPE)
2388                                 return 1;
2389                         continue;
2390                 case MONO_TYPE_GENERICINST:
2391                         simple_type = &simple_type->data.generic_class->container_class->byval_arg;
2392                         goto handle_enum;
2393                 case MONO_TYPE_VAR:
2394                 case MONO_TYPE_MVAR:
2395                         /* gsharedvt */
2396                         if (args [i]->type != STACK_VTYPE)
2397                                 return 1;
2398                         continue;
2399                 default:
2400                         g_error ("unknown type 0x%02x in check_call_signature",
2401                                  simple_type->type);
2402                 }
2403         }
2404         return 0;
2405 }
2406
2407 static int
2408 callvirt_to_call (int opcode)
2409 {
2410         switch (opcode) {
2411         case OP_CALL_MEMBASE:
2412                 return OP_CALL;
2413         case OP_VOIDCALL_MEMBASE:
2414                 return OP_VOIDCALL;
2415         case OP_FCALL_MEMBASE:
2416                 return OP_FCALL;
2417         case OP_RCALL_MEMBASE:
2418                 return OP_RCALL;
2419         case OP_VCALL_MEMBASE:
2420                 return OP_VCALL;
2421         case OP_LCALL_MEMBASE:
2422                 return OP_LCALL;
2423         default:
2424                 g_assert_not_reached ();
2425         }
2426
2427         return -1;
2428 }
2429
2430 static int
2431 callvirt_to_call_reg (int opcode)
2432 {
2433         switch (opcode) {
2434         case OP_CALL_MEMBASE:
2435                 return OP_CALL_REG;
2436         case OP_VOIDCALL_MEMBASE:
2437                 return OP_VOIDCALL_REG;
2438         case OP_FCALL_MEMBASE:
2439                 return OP_FCALL_REG;
2440         case OP_RCALL_MEMBASE:
2441                 return OP_RCALL_REG;
2442         case OP_VCALL_MEMBASE:
2443                 return OP_VCALL_REG;
2444         case OP_LCALL_MEMBASE:
2445                 return OP_LCALL_REG;
2446         default:
2447                 g_assert_not_reached ();
2448         }
2449
2450         return -1;
2451 }
2452
2453 /* Either METHOD or IMT_ARG needs to be set */
2454 static void
2455 emit_imt_argument (MonoCompile *cfg, MonoCallInst *call, MonoMethod *method, MonoInst *imt_arg)
2456 {
2457         int method_reg;
2458
2459         if (COMPILE_LLVM (cfg)) {
2460                 if (imt_arg) {
2461                         method_reg = alloc_preg (cfg);
2462                         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
2463                 } else {
2464                         MonoInst *ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_METHODCONST, method);
2465                         method_reg = ins->dreg;
2466                 }
2467
2468 #ifdef ENABLE_LLVM
2469                 call->imt_arg_reg = method_reg;
2470 #endif
2471                 mono_call_inst_add_outarg_reg (cfg, call, method_reg, MONO_ARCH_IMT_REG, FALSE);
2472                 return;
2473         }
2474
2475         if (imt_arg) {
2476                 method_reg = alloc_preg (cfg);
2477                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
2478         } else {
2479                 MonoInst *ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_METHODCONST, method);
2480                 method_reg = ins->dreg;
2481         }
2482
2483         mono_call_inst_add_outarg_reg (cfg, call, method_reg, MONO_ARCH_IMT_REG, FALSE);
2484 }
2485
2486 static MonoJumpInfo *
2487 mono_patch_info_new (MonoMemPool *mp, int ip, MonoJumpInfoType type, gconstpointer target)
2488 {
2489         MonoJumpInfo *ji = (MonoJumpInfo *)mono_mempool_alloc (mp, sizeof (MonoJumpInfo));
2490
2491         ji->ip.i = ip;
2492         ji->type = type;
2493         ji->data.target = target;
2494
2495         return ji;
2496 }
2497
2498 static int
2499 mini_class_check_context_used (MonoCompile *cfg, MonoClass *klass)
2500 {
2501         if (cfg->gshared)
2502                 return mono_class_check_context_used (klass);
2503         else
2504                 return 0;
2505 }
2506
2507 static int
2508 mini_method_check_context_used (MonoCompile *cfg, MonoMethod *method)
2509 {
2510         if (cfg->gshared)
2511                 return mono_method_check_context_used (method);
2512         else
2513                 return 0;
2514 }
2515
2516 /*
2517  * check_method_sharing:
2518  *
2519  *   Check whenever the vtable or an mrgctx needs to be passed when calling CMETHOD.
2520  */
2521 static void
2522 check_method_sharing (MonoCompile *cfg, MonoMethod *cmethod, gboolean *out_pass_vtable, gboolean *out_pass_mrgctx)
2523 {
2524         gboolean pass_vtable = FALSE;
2525         gboolean pass_mrgctx = FALSE;
2526
2527         if (((cmethod->flags & METHOD_ATTRIBUTE_STATIC) || cmethod->klass->valuetype) &&
2528                 (cmethod->klass->generic_class || cmethod->klass->generic_container)) {
2529                 gboolean sharable = FALSE;
2530
2531                 if (mono_method_is_generic_sharable_full (cmethod, TRUE, TRUE, TRUE))
2532                         sharable = TRUE;
2533
2534                 /*
2535                  * Pass vtable iff target method might
2536                  * be shared, which means that sharing
2537                  * is enabled for its class and its
2538                  * context is sharable (and it's not a
2539                  * generic method).
2540                  */
2541                 if (sharable && !(mini_method_get_context (cmethod) && mini_method_get_context (cmethod)->method_inst))
2542                         pass_vtable = TRUE;
2543         }
2544
2545         if (mini_method_get_context (cmethod) &&
2546                 mini_method_get_context (cmethod)->method_inst) {
2547                 g_assert (!pass_vtable);
2548
2549                 if (mono_method_is_generic_sharable_full (cmethod, TRUE, TRUE, TRUE)) {
2550                         pass_mrgctx = TRUE;
2551                 } else {
2552                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (mono_method_signature (cmethod)))
2553                                 pass_mrgctx = TRUE;
2554                 }
2555         }
2556
2557         if (out_pass_vtable)
2558                 *out_pass_vtable = pass_vtable;
2559         if (out_pass_mrgctx)
2560                 *out_pass_mrgctx = pass_mrgctx;
2561 }
2562
2563 inline static MonoCallInst *
2564 mono_emit_call_args (MonoCompile *cfg, MonoMethodSignature *sig, 
2565                                          MonoInst **args, int calli, int virtual_, int tail, int rgctx, int unbox_trampoline)
2566 {
2567         MonoType *sig_ret;
2568         MonoCallInst *call;
2569 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
2570         int i;
2571 #endif
2572
2573         if (cfg->llvm_only)
2574                 tail = FALSE;
2575
2576         if (tail) {
2577                 emit_instrumentation_call (cfg, mono_profiler_method_leave);
2578
2579                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
2580         } else
2581                 MONO_INST_NEW_CALL (cfg, call, ret_type_to_call_opcode (cfg, sig->ret, calli, virtual_));
2582
2583         call->args = args;
2584         call->signature = sig;
2585         call->rgctx_reg = rgctx;
2586         sig_ret = mini_get_underlying_type (sig->ret);
2587
2588         type_to_eval_stack_type ((cfg), sig_ret, &call->inst);
2589
2590         if (tail) {
2591                 if (mini_type_is_vtype (sig_ret)) {
2592                         call->vret_var = cfg->vret_addr;
2593                         //g_assert_not_reached ();
2594                 }
2595         } else if (mini_type_is_vtype (sig_ret)) {
2596                 MonoInst *temp = mono_compile_create_var (cfg, sig_ret, OP_LOCAL);
2597                 MonoInst *loada;
2598
2599                 temp->backend.is_pinvoke = sig->pinvoke;
2600
2601                 /*
2602                  * We use a new opcode OP_OUTARG_VTRETADDR instead of LDADDR for emitting the
2603                  * address of return value to increase optimization opportunities.
2604                  * Before vtype decomposition, the dreg of the call ins itself represents the
2605                  * fact the call modifies the return value. After decomposition, the call will
2606                  * be transformed into one of the OP_VOIDCALL opcodes, and the VTRETADDR opcode
2607                  * will be transformed into an LDADDR.
2608                  */
2609                 MONO_INST_NEW (cfg, loada, OP_OUTARG_VTRETADDR);
2610                 loada->dreg = alloc_preg (cfg);
2611                 loada->inst_p0 = temp;
2612                 /* We reference the call too since call->dreg could change during optimization */
2613                 loada->inst_p1 = call;
2614                 MONO_ADD_INS (cfg->cbb, loada);
2615
2616                 call->inst.dreg = temp->dreg;
2617
2618                 call->vret_var = loada;
2619         } else if (!MONO_TYPE_IS_VOID (sig_ret))
2620                 call->inst.dreg = alloc_dreg (cfg, (MonoStackType)call->inst.type);
2621
2622 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
2623         if (COMPILE_SOFT_FLOAT (cfg)) {
2624                 /* 
2625                  * If the call has a float argument, we would need to do an r8->r4 conversion using 
2626                  * an icall, but that cannot be done during the call sequence since it would clobber
2627                  * the call registers + the stack. So we do it before emitting the call.
2628                  */
2629                 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
2630                         MonoType *t;
2631                         MonoInst *in = call->args [i];
2632
2633                         if (i >= sig->hasthis)
2634                                 t = sig->params [i - sig->hasthis];
2635                         else
2636                                 t = &mono_defaults.int_class->byval_arg;
2637                         t = mono_type_get_underlying_type (t);
2638
2639                         if (!t->byref && t->type == MONO_TYPE_R4) {
2640                                 MonoInst *iargs [1];
2641                                 MonoInst *conv;
2642
2643                                 iargs [0] = in;
2644                                 conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
2645
2646                                 /* The result will be in an int vreg */
2647                                 call->args [i] = conv;
2648                         }
2649                 }
2650         }
2651 #endif
2652
2653         call->need_unbox_trampoline = unbox_trampoline;
2654
2655 #ifdef ENABLE_LLVM
2656         if (COMPILE_LLVM (cfg))
2657                 mono_llvm_emit_call (cfg, call);
2658         else
2659                 mono_arch_emit_call (cfg, call);
2660 #else
2661         mono_arch_emit_call (cfg, call);
2662 #endif
2663
2664         cfg->param_area = MAX (cfg->param_area, call->stack_usage);
2665         cfg->flags |= MONO_CFG_HAS_CALLS;
2666         
2667         return call;
2668 }
2669
2670 static void
2671 set_rgctx_arg (MonoCompile *cfg, MonoCallInst *call, int rgctx_reg, MonoInst *rgctx_arg)
2672 {
2673         mono_call_inst_add_outarg_reg (cfg, call, rgctx_reg, MONO_ARCH_RGCTX_REG, FALSE);
2674         cfg->uses_rgctx_reg = TRUE;
2675         call->rgctx_reg = TRUE;
2676 #ifdef ENABLE_LLVM
2677         call->rgctx_arg_reg = rgctx_reg;
2678 #endif
2679 }       
2680
2681 inline static MonoInst*
2682 mono_emit_calli (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args, MonoInst *addr, MonoInst *imt_arg, MonoInst *rgctx_arg)
2683 {
2684         MonoCallInst *call;
2685         MonoInst *ins;
2686         int rgctx_reg = -1;
2687         gboolean check_sp = FALSE;
2688
2689         if (cfg->check_pinvoke_callconv && cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
2690                 WrapperInfo *info = mono_marshal_get_wrapper_info (cfg->method);
2691
2692                 if (info && info->subtype == WRAPPER_SUBTYPE_PINVOKE)
2693                         check_sp = TRUE;
2694         }
2695
2696         if (rgctx_arg) {
2697                 rgctx_reg = mono_alloc_preg (cfg);
2698                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, rgctx_arg->dreg);
2699         }
2700
2701         if (check_sp) {
2702                 if (!cfg->stack_inbalance_var)
2703                         cfg->stack_inbalance_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2704
2705                 MONO_INST_NEW (cfg, ins, OP_GET_SP);
2706                 ins->dreg = cfg->stack_inbalance_var->dreg;
2707                 MONO_ADD_INS (cfg->cbb, ins);
2708         }
2709
2710         call = mono_emit_call_args (cfg, sig, args, TRUE, FALSE, FALSE, rgctx_arg ? TRUE : FALSE, FALSE);
2711
2712         call->inst.sreg1 = addr->dreg;
2713
2714         if (imt_arg)
2715                 emit_imt_argument (cfg, call, NULL, imt_arg);
2716
2717         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2718
2719         if (check_sp) {
2720                 int sp_reg;
2721
2722                 sp_reg = mono_alloc_preg (cfg);
2723
2724                 MONO_INST_NEW (cfg, ins, OP_GET_SP);
2725                 ins->dreg = sp_reg;
2726                 MONO_ADD_INS (cfg->cbb, ins);
2727
2728                 /* Restore the stack so we don't crash when throwing the exception */
2729                 MONO_INST_NEW (cfg, ins, OP_SET_SP);
2730                 ins->sreg1 = cfg->stack_inbalance_var->dreg;
2731                 MONO_ADD_INS (cfg->cbb, ins);
2732
2733                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, cfg->stack_inbalance_var->dreg, sp_reg);
2734                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "ExecutionEngineException");
2735         }
2736
2737         if (rgctx_arg)
2738                 set_rgctx_arg (cfg, call, rgctx_reg, rgctx_arg);
2739
2740         return (MonoInst*)call;
2741 }
2742
2743 static MonoInst*
2744 emit_get_gsharedvt_info_klass (MonoCompile *cfg, MonoClass *klass, MonoRgctxInfoType rgctx_type);
2745
2746 static MonoInst*
2747 emit_get_rgctx_method (MonoCompile *cfg, int context_used, MonoMethod *cmethod, MonoRgctxInfoType rgctx_type);
2748 static MonoInst*
2749 emit_get_rgctx_klass (MonoCompile *cfg, int context_used, MonoClass *klass, MonoRgctxInfoType rgctx_type);
2750
2751 static MonoInst*
2752 mono_emit_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSignature *sig, gboolean tail,
2753                                                         MonoInst **args, MonoInst *this_ins, MonoInst *imt_arg, MonoInst *rgctx_arg)
2754 {
2755 #ifndef DISABLE_REMOTING
2756         gboolean might_be_remote = FALSE;
2757 #endif
2758         gboolean virtual_ = this_ins != NULL;
2759         gboolean enable_for_aot = TRUE;
2760         int context_used;
2761         MonoCallInst *call;
2762         MonoInst *call_target = NULL;
2763         int rgctx_reg = 0;
2764         gboolean need_unbox_trampoline;
2765
2766         if (!sig)
2767                 sig = mono_method_signature (method);
2768
2769         if (cfg->llvm_only && (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE))
2770                 g_assert_not_reached ();
2771
2772         if (rgctx_arg) {
2773                 rgctx_reg = mono_alloc_preg (cfg);
2774                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, rgctx_arg->dreg);
2775         }
2776
2777         if (method->string_ctor) {
2778                 /* Create the real signature */
2779                 /* FIXME: Cache these */
2780                 MonoMethodSignature *ctor_sig = mono_metadata_signature_dup_mempool (cfg->mempool, sig);
2781                 ctor_sig->ret = &mono_defaults.string_class->byval_arg;
2782
2783                 sig = ctor_sig;
2784         }
2785
2786         context_used = mini_method_check_context_used (cfg, method);
2787
2788 #ifndef DISABLE_REMOTING
2789         might_be_remote = this_ins && sig->hasthis &&
2790                 (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class) &&
2791                 !(method->flags & METHOD_ATTRIBUTE_VIRTUAL) && (!MONO_CHECK_THIS (this_ins) || context_used);
2792
2793         if (might_be_remote && context_used) {
2794                 MonoInst *addr;
2795
2796                 g_assert (cfg->gshared);
2797
2798                 addr = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK);
2799
2800                 return mono_emit_calli (cfg, sig, args, addr, NULL, NULL);
2801         }
2802 #endif
2803
2804         if (cfg->llvm_only && !call_target && virtual_ && (method->flags & METHOD_ATTRIBUTE_VIRTUAL))
2805                 return emit_llvmonly_virtual_call (cfg, method, sig, 0, args);
2806
2807         need_unbox_trampoline = method->klass == mono_defaults.object_class || (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE);
2808
2809         call = mono_emit_call_args (cfg, sig, args, FALSE, virtual_, tail, rgctx_arg ? TRUE : FALSE, need_unbox_trampoline);
2810
2811 #ifndef DISABLE_REMOTING
2812         if (might_be_remote)
2813                 call->method = mono_marshal_get_remoting_invoke_with_check (method);
2814         else
2815 #endif
2816                 call->method = method;
2817         call->inst.flags |= MONO_INST_HAS_METHOD;
2818         call->inst.inst_left = this_ins;
2819         call->tail_call = tail;
2820
2821         if (virtual_) {
2822                 int vtable_reg, slot_reg, this_reg;
2823                 int offset;
2824
2825                 this_reg = this_ins->dreg;
2826
2827                 if (!cfg->llvm_only && (method->klass->parent == mono_defaults.multicastdelegate_class) && !strcmp (method->name, "Invoke")) {
2828                         MonoInst *dummy_use;
2829
2830                         MONO_EMIT_NULL_CHECK (cfg, this_reg);
2831
2832                         /* Make a call to delegate->invoke_impl */
2833                         call->inst.inst_basereg = this_reg;
2834                         call->inst.inst_offset = MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl);
2835                         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2836
2837                         /* We must emit a dummy use here because the delegate trampoline will
2838                         replace the 'this' argument with the delegate target making this activation
2839                         no longer a root for the delegate.
2840                         This is an issue for delegates that target collectible code such as dynamic
2841                         methods of GC'able assemblies.
2842
2843                         For a test case look into #667921.
2844
2845                         FIXME: a dummy use is not the best way to do it as the local register allocator
2846                         will put it on a caller save register and spil it around the call. 
2847                         Ideally, we would either put it on a callee save register or only do the store part.  
2848                          */
2849                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, args [0]);
2850
2851                         return (MonoInst*)call;
2852                 }
2853
2854                 if ((!cfg->compile_aot || enable_for_aot) && 
2855                         (!(method->flags & METHOD_ATTRIBUTE_VIRTUAL) || 
2856                          (MONO_METHOD_IS_FINAL (method) &&
2857                           method->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK)) &&
2858                         !(mono_class_is_marshalbyref (method->klass) && context_used)) {
2859                         /* 
2860                          * the method is not virtual, we just need to ensure this is not null
2861                          * and then we can call the method directly.
2862                          */
2863 #ifndef DISABLE_REMOTING
2864                         if (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class) {
2865                                 /* 
2866                                  * The check above ensures method is not gshared, this is needed since
2867                                  * gshared methods can't have wrappers.
2868                                  */
2869                                 method = call->method = mono_marshal_get_remoting_invoke_with_check (method);
2870                         }
2871 #endif
2872
2873                         if (!method->string_ctor)
2874                                 MONO_EMIT_NEW_CHECK_THIS (cfg, this_reg);
2875
2876                         call->inst.opcode = callvirt_to_call (call->inst.opcode);
2877                 } else if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) && MONO_METHOD_IS_FINAL (method)) {
2878                         /*
2879                          * the method is virtual, but we can statically dispatch since either
2880                          * it's class or the method itself are sealed.
2881                          * But first we need to ensure it's not a null reference.
2882                          */
2883                         MONO_EMIT_NEW_CHECK_THIS (cfg, this_reg);
2884
2885                         call->inst.opcode = callvirt_to_call (call->inst.opcode);
2886                 } else if (call_target) {
2887                         vtable_reg = alloc_preg (cfg);
2888                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
2889
2890                         call->inst.opcode = callvirt_to_call_reg (call->inst.opcode);
2891                         call->inst.sreg1 = call_target->dreg;
2892                         call->inst.flags &= !MONO_INST_HAS_METHOD;
2893                 } else {
2894                         vtable_reg = alloc_preg (cfg);
2895                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
2896                         if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2897                                 guint32 imt_slot = mono_method_get_imt_slot (method);
2898                                 emit_imt_argument (cfg, call, call->method, imt_arg);
2899                                 slot_reg = vtable_reg;
2900                                 offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
2901                         } else {
2902                                 slot_reg = vtable_reg;
2903                                 offset = MONO_STRUCT_OFFSET (MonoVTable, vtable) +
2904                                         ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
2905                                 if (imt_arg) {
2906                                         g_assert (mono_method_signature (method)->generic_param_count);
2907                                         emit_imt_argument (cfg, call, call->method, imt_arg);
2908                                 }
2909                         }
2910
2911                         call->inst.sreg1 = slot_reg;
2912                         call->inst.inst_offset = offset;
2913                         call->is_virtual = TRUE;
2914                 }
2915         }
2916
2917         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2918
2919         if (rgctx_arg)
2920                 set_rgctx_arg (cfg, call, rgctx_reg, rgctx_arg);
2921
2922         return (MonoInst*)call;
2923 }
2924
2925 MonoInst*
2926 mono_emit_method_call (MonoCompile *cfg, MonoMethod *method, MonoInst **args, MonoInst *this_ins)
2927 {
2928         return mono_emit_method_call_full (cfg, method, mono_method_signature (method), FALSE, args, this_ins, NULL, NULL);
2929 }
2930
2931 MonoInst*
2932 mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig,
2933                                            MonoInst **args)
2934 {
2935         MonoCallInst *call;
2936
2937         g_assert (sig);
2938
2939         call = mono_emit_call_args (cfg, sig, args, FALSE, FALSE, FALSE, FALSE, FALSE);
2940         call->fptr = func;
2941
2942         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2943
2944         return (MonoInst*)call;
2945 }
2946
2947 MonoInst*
2948 mono_emit_jit_icall (MonoCompile *cfg, gconstpointer func, MonoInst **args)
2949 {
2950         MonoJitICallInfo *info = mono_find_jit_icall_by_addr (func);
2951
2952         g_assert (info);
2953
2954         return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
2955 }
2956
2957 /*
2958  * mono_emit_abs_call:
2959  *
2960  *   Emit a call to the runtime function described by PATCH_TYPE and DATA.
2961  */
2962 inline static MonoInst*
2963 mono_emit_abs_call (MonoCompile *cfg, MonoJumpInfoType patch_type, gconstpointer data, 
2964                                         MonoMethodSignature *sig, MonoInst **args)
2965 {
2966         MonoJumpInfo *ji = mono_patch_info_new (cfg->mempool, 0, patch_type, data);
2967         MonoInst *ins;
2968
2969         /* 
2970          * We pass ji as the call address, the PATCH_INFO_ABS resolving code will
2971          * handle it.
2972          */
2973         if (cfg->abs_patches == NULL)
2974                 cfg->abs_patches = g_hash_table_new (NULL, NULL);
2975         g_hash_table_insert (cfg->abs_patches, ji, ji);
2976         ins = mono_emit_native_call (cfg, ji, sig, args);
2977         ((MonoCallInst*)ins)->fptr_is_patch = TRUE;
2978         return ins;
2979 }
2980
2981 static MonoMethodSignature*
2982 sig_to_rgctx_sig (MonoMethodSignature *sig)
2983 {
2984         // FIXME: memory allocation
2985         MonoMethodSignature *res;
2986         int i;
2987
2988         res = (MonoMethodSignature *)g_malloc (MONO_SIZEOF_METHOD_SIGNATURE + (sig->param_count + 1) * sizeof (MonoType*));
2989         memcpy (res, sig, MONO_SIZEOF_METHOD_SIGNATURE);
2990         res->param_count = sig->param_count + 1;
2991         for (i = 0; i < sig->param_count; ++i)
2992                 res->params [i] = sig->params [i];
2993         res->params [sig->param_count] = &mono_defaults.int_class->this_arg;
2994         return res;
2995 }
2996
2997 /* Make an indirect call to FSIG passing an additional argument */
2998 static MonoInst*
2999 emit_extra_arg_calli (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **orig_args, int arg_reg, MonoInst *call_target)
3000 {
3001         MonoMethodSignature *csig;
3002         MonoInst *args_buf [16];
3003         MonoInst **args;
3004         int i, pindex, tmp_reg;
3005
3006         /* Make a call with an rgctx/extra arg */
3007         if (fsig->param_count + 2 < 16)
3008                 args = args_buf;
3009         else
3010                 args = (MonoInst **)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (fsig->param_count + 2));
3011         pindex = 0;
3012         if (fsig->hasthis)
3013                 args [pindex ++] = orig_args [0];
3014         for (i = 0; i < fsig->param_count; ++i)
3015                 args [pindex ++] = orig_args [fsig->hasthis + i];
3016         tmp_reg = alloc_preg (cfg);
3017         EMIT_NEW_UNALU (cfg, args [pindex], OP_MOVE, tmp_reg, arg_reg);
3018         csig = sig_to_rgctx_sig (fsig);
3019         return mono_emit_calli (cfg, csig, args, call_target, NULL, NULL);
3020 }
3021
3022 /* Emit an indirect call to the function descriptor ADDR */
3023 static MonoInst*
3024 emit_llvmonly_calli (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, MonoInst *addr)
3025 {
3026         int addr_reg, arg_reg;
3027         MonoInst *call_target;
3028
3029         g_assert (cfg->llvm_only);
3030
3031         /*
3032          * addr points to a <addr, arg> pair, load both of them, and
3033          * make a call to addr, passing arg as an extra arg.
3034          */
3035         addr_reg = alloc_preg (cfg);
3036         EMIT_NEW_LOAD_MEMBASE (cfg, call_target, OP_LOAD_MEMBASE, addr_reg, addr->dreg, 0);
3037         arg_reg = alloc_preg (cfg);
3038         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, arg_reg, addr->dreg, sizeof (gpointer));
3039
3040         return emit_extra_arg_calli (cfg, fsig, args, arg_reg, call_target);
3041 }
3042
3043 static gboolean
3044 direct_icalls_enabled (MonoCompile *cfg)
3045 {
3046         /* LLVM on amd64 can't handle calls to non-32 bit addresses */
3047 #ifdef TARGET_AMD64
3048         if (cfg->compile_llvm)
3049                 return FALSE;
3050 #endif
3051         if (cfg->gen_sdb_seq_points || cfg->disable_direct_icalls)
3052                 return FALSE;
3053         return TRUE;
3054 }
3055
3056 MonoInst*
3057 mono_emit_jit_icall_by_info (MonoCompile *cfg, MonoJitICallInfo *info, MonoInst **args)
3058 {
3059         /*
3060          * Call the jit icall without a wrapper if possible.
3061          * The wrapper is needed for the following reasons:
3062          * - to handle exceptions thrown using mono_raise_exceptions () from the
3063          *   icall function. The EH code needs the lmf frame pushed by the
3064          *   wrapper to be able to unwind back to managed code.
3065          * - to be able to do stack walks for asynchronously suspended
3066          *   threads when debugging.
3067          */
3068         if (info->no_raise && direct_icalls_enabled (cfg)) {
3069                 char *name;
3070                 int costs;
3071
3072                 if (!info->wrapper_method) {
3073                         name = g_strdup_printf ("__icall_wrapper_%s", info->name);
3074                         info->wrapper_method = mono_marshal_get_icall_wrapper (info->sig, name, info->func, TRUE);
3075                         g_free (name);
3076                         mono_memory_barrier ();
3077                 }
3078
3079                 /*
3080                  * Inline the wrapper method, which is basically a call to the C icall, and
3081                  * an exception check.
3082                  */
3083                 costs = inline_method (cfg, info->wrapper_method, NULL,
3084                                                            args, NULL, cfg->real_offset, TRUE);
3085                 g_assert (costs > 0);
3086                 g_assert (!MONO_TYPE_IS_VOID (info->sig->ret));
3087
3088                 return args [0];
3089         } else {
3090                 return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
3091         }
3092 }
3093  
3094 static MonoInst*
3095 mono_emit_widen_call_res (MonoCompile *cfg, MonoInst *ins, MonoMethodSignature *fsig)
3096 {
3097         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
3098                 if ((fsig->pinvoke || LLVM_ENABLED) && !fsig->ret->byref) {
3099                         int widen_op = -1;
3100
3101                         /* 
3102                          * Native code might return non register sized integers 
3103                          * without initializing the upper bits.
3104                          */
3105                         switch (mono_type_to_load_membase (cfg, fsig->ret)) {
3106                         case OP_LOADI1_MEMBASE:
3107                                 widen_op = OP_ICONV_TO_I1;
3108                                 break;
3109                         case OP_LOADU1_MEMBASE:
3110                                 widen_op = OP_ICONV_TO_U1;
3111                                 break;
3112                         case OP_LOADI2_MEMBASE:
3113                                 widen_op = OP_ICONV_TO_I2;
3114                                 break;
3115                         case OP_LOADU2_MEMBASE:
3116                                 widen_op = OP_ICONV_TO_U2;
3117                                 break;
3118                         default:
3119                                 break;
3120                         }
3121
3122                         if (widen_op != -1) {
3123                                 int dreg = alloc_preg (cfg);
3124                                 MonoInst *widen;
3125
3126                                 EMIT_NEW_UNALU (cfg, widen, widen_op, dreg, ins->dreg);
3127                                 widen->type = ins->type;
3128                                 ins = widen;
3129                         }
3130                 }
3131         }
3132
3133         return ins;
3134 }
3135
3136 static MonoMethod*
3137 get_memcpy_method (void)
3138 {
3139         static MonoMethod *memcpy_method = NULL;
3140         if (!memcpy_method) {
3141                 memcpy_method = mono_class_get_method_from_name (mono_defaults.string_class, "memcpy", 3);
3142                 if (!memcpy_method)
3143                         g_error ("Old corlib found. Install a new one");
3144         }
3145         return memcpy_method;
3146 }
3147
3148 static void
3149 create_write_barrier_bitmap (MonoCompile *cfg, MonoClass *klass, unsigned *wb_bitmap, int offset)
3150 {
3151         MonoClassField *field;
3152         gpointer iter = NULL;
3153
3154         while ((field = mono_class_get_fields (klass, &iter))) {
3155                 int foffset;
3156
3157                 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
3158                         continue;
3159                 foffset = klass->valuetype ? field->offset - sizeof (MonoObject): field->offset;
3160                 if (mini_type_is_reference (mono_field_get_type (field))) {
3161                         g_assert ((foffset % SIZEOF_VOID_P) == 0);
3162                         *wb_bitmap |= 1 << ((offset + foffset) / SIZEOF_VOID_P);
3163                 } else {
3164                         MonoClass *field_class = mono_class_from_mono_type (field->type);
3165                         if (field_class->has_references)
3166                                 create_write_barrier_bitmap (cfg, field_class, wb_bitmap, offset + foffset);
3167                 }
3168         }
3169 }
3170
3171 static void
3172 emit_write_barrier (MonoCompile *cfg, MonoInst *ptr, MonoInst *value)
3173 {
3174         int card_table_shift_bits;
3175         gpointer card_table_mask;
3176         guint8 *card_table;
3177         MonoInst *dummy_use;
3178         int nursery_shift_bits;
3179         size_t nursery_size;
3180
3181         if (!cfg->gen_write_barriers)
3182                 return;
3183
3184         card_table = mono_gc_get_card_table (&card_table_shift_bits, &card_table_mask);
3185
3186         mono_gc_get_nursery (&nursery_shift_bits, &nursery_size);
3187
3188         if (cfg->backend->have_card_table_wb && !cfg->compile_aot && card_table && nursery_shift_bits > 0 && !COMPILE_LLVM (cfg)) {
3189                 MonoInst *wbarrier;
3190
3191                 MONO_INST_NEW (cfg, wbarrier, OP_CARD_TABLE_WBARRIER);
3192                 wbarrier->sreg1 = ptr->dreg;
3193                 wbarrier->sreg2 = value->dreg;
3194                 MONO_ADD_INS (cfg->cbb, wbarrier);
3195         } else if (card_table && !cfg->compile_aot && !mono_gc_card_table_nursery_check ()) {
3196                 int offset_reg = alloc_preg (cfg);
3197                 int card_reg;
3198                 MonoInst *ins;
3199
3200                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_UN_IMM, offset_reg, ptr->dreg, card_table_shift_bits);
3201                 if (card_table_mask)
3202                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, offset_reg, offset_reg, card_table_mask);
3203
3204                 /*We can't use PADD_IMM since the cardtable might end up in high addresses and amd64 doesn't support
3205                  * IMM's larger than 32bits.
3206                  */
3207                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_CARD_TABLE_ADDR, NULL);
3208                 card_reg = ins->dreg;
3209
3210                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, offset_reg, offset_reg, card_reg);
3211                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, offset_reg, 0, 1);
3212         } else {
3213                 MonoMethod *write_barrier = mono_gc_get_write_barrier ();
3214                 mono_emit_method_call (cfg, write_barrier, &ptr, NULL);
3215         }
3216
3217         EMIT_NEW_DUMMY_USE (cfg, dummy_use, value);
3218 }
3219
3220 static gboolean
3221 mono_emit_wb_aware_memcpy (MonoCompile *cfg, MonoClass *klass, MonoInst *iargs[4], int size, int align)
3222 {
3223         int dest_ptr_reg, tmp_reg, destreg, srcreg, offset;
3224         unsigned need_wb = 0;
3225
3226         if (align == 0)
3227                 align = 4;
3228
3229         /*types with references can't have alignment smaller than sizeof(void*) */
3230         if (align < SIZEOF_VOID_P)
3231                 return FALSE;
3232
3233         /*This value cannot be bigger than 32 due to the way we calculate the required wb bitmap.*/
3234         if (size > 32 * SIZEOF_VOID_P)
3235                 return FALSE;
3236
3237         create_write_barrier_bitmap (cfg, klass, &need_wb, 0);
3238
3239         /* We don't unroll more than 5 stores to avoid code bloat. */
3240         if (size > 5 * SIZEOF_VOID_P) {
3241                 /*This is harmless and simplify mono_gc_wbarrier_value_copy_bitmap */
3242                 size += (SIZEOF_VOID_P - 1);
3243                 size &= ~(SIZEOF_VOID_P - 1);
3244
3245                 EMIT_NEW_ICONST (cfg, iargs [2], size);
3246                 EMIT_NEW_ICONST (cfg, iargs [3], need_wb);
3247                 mono_emit_jit_icall (cfg, mono_gc_wbarrier_value_copy_bitmap, iargs);
3248                 return TRUE;
3249         }
3250
3251         destreg = iargs [0]->dreg;
3252         srcreg = iargs [1]->dreg;
3253         offset = 0;
3254
3255         dest_ptr_reg = alloc_preg (cfg);
3256         tmp_reg = alloc_preg (cfg);
3257
3258         /*tmp = dreg*/
3259         EMIT_NEW_UNALU (cfg, iargs [0], OP_MOVE, dest_ptr_reg, destreg);
3260
3261         while (size >= SIZEOF_VOID_P) {
3262                 MonoInst *load_inst;
3263                 MONO_INST_NEW (cfg, load_inst, OP_LOAD_MEMBASE);
3264                 load_inst->dreg = tmp_reg;
3265                 load_inst->inst_basereg = srcreg;
3266                 load_inst->inst_offset = offset;
3267                 MONO_ADD_INS (cfg->cbb, load_inst);
3268
3269                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, dest_ptr_reg, 0, tmp_reg);
3270
3271                 if (need_wb & 0x1)
3272                         emit_write_barrier (cfg, iargs [0], load_inst);
3273
3274                 offset += SIZEOF_VOID_P;
3275                 size -= SIZEOF_VOID_P;
3276                 need_wb >>= 1;
3277
3278                 /*tmp += sizeof (void*)*/
3279                 if (size >= SIZEOF_VOID_P) {
3280                         NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, dest_ptr_reg, dest_ptr_reg, SIZEOF_VOID_P);
3281                         MONO_ADD_INS (cfg->cbb, iargs [0]);
3282                 }
3283         }
3284
3285         /* Those cannot be references since size < sizeof (void*) */
3286         while (size >= 4) {
3287                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, tmp_reg, srcreg, offset);
3288                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, tmp_reg);
3289                 offset += 4;
3290                 size -= 4;
3291         }
3292
3293         while (size >= 2) {
3294                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, tmp_reg, srcreg, offset);
3295                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, offset, tmp_reg);
3296                 offset += 2;
3297                 size -= 2;
3298         }
3299
3300         while (size >= 1) {
3301                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, tmp_reg, srcreg, offset);
3302                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, tmp_reg);
3303                 offset += 1;
3304                 size -= 1;
3305         }
3306
3307         return TRUE;
3308 }
3309
3310 /*
3311  * Emit code to copy a valuetype of type @klass whose address is stored in
3312  * @src->dreg to memory whose address is stored at @dest->dreg.
3313  */
3314 void
3315 mini_emit_stobj (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *klass, gboolean native)
3316 {
3317         MonoInst *iargs [4];
3318         int n;
3319         guint32 align = 0;
3320         MonoMethod *memcpy_method;
3321         MonoInst *size_ins = NULL;
3322         MonoInst *memcpy_ins = NULL;
3323
3324         g_assert (klass);
3325         if (cfg->gshared)
3326                 klass = mono_class_from_mono_type (mini_get_underlying_type (&klass->byval_arg));
3327
3328         /*
3329          * This check breaks with spilled vars... need to handle it during verification anyway.
3330          * g_assert (klass && klass == src->klass && klass == dest->klass);
3331          */
3332
3333         if (mini_is_gsharedvt_klass (klass)) {
3334                 g_assert (!native);
3335                 size_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_VALUE_SIZE);
3336                 memcpy_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_MEMCPY);
3337         }
3338
3339         if (native)
3340                 n = mono_class_native_size (klass, &align);
3341         else
3342                 n = mono_class_value_size (klass, &align);
3343
3344         /* if native is true there should be no references in the struct */
3345         if (cfg->gen_write_barriers && (klass->has_references || size_ins) && !native) {
3346                 /* Avoid barriers when storing to the stack */
3347                 if (!((dest->opcode == OP_ADD_IMM && dest->sreg1 == cfg->frame_reg) ||
3348                           (dest->opcode == OP_LDADDR))) {
3349                         int context_used;
3350
3351                         iargs [0] = dest;
3352                         iargs [1] = src;
3353
3354                         context_used = mini_class_check_context_used (cfg, klass);
3355
3356                         /* It's ok to intrinsify under gsharing since shared code types are layout stable. */
3357                         if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && mono_emit_wb_aware_memcpy (cfg, klass, iargs, n, align)) {
3358                                 return;
3359                         } else if (context_used) {
3360                                 iargs [2] = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
3361                         }  else {
3362                                 iargs [2] = emit_runtime_constant (cfg, MONO_PATCH_INFO_CLASS, klass);
3363                                 if (!cfg->compile_aot)
3364                                         mono_class_compute_gc_descriptor (klass);
3365                         }
3366
3367                         if (size_ins)
3368                                 mono_emit_jit_icall (cfg, mono_gsharedvt_value_copy, iargs);
3369                         else
3370                                 mono_emit_jit_icall (cfg, mono_value_copy, iargs);
3371                         return;
3372                 }
3373         }
3374
3375         if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 8) {
3376                 /* FIXME: Optimize the case when src/dest is OP_LDADDR */
3377                 mini_emit_memcpy (cfg, dest->dreg, 0, src->dreg, 0, n, align);
3378         } else {
3379                 iargs [0] = dest;
3380                 iargs [1] = src;
3381                 if (size_ins)
3382                         iargs [2] = size_ins;
3383                 else
3384                         EMIT_NEW_ICONST (cfg, iargs [2], n);
3385                 
3386                 memcpy_method = get_memcpy_method ();
3387                 if (memcpy_ins)
3388                         mono_emit_calli (cfg, mono_method_signature (memcpy_method), iargs, memcpy_ins, NULL, NULL);
3389                 else
3390                         mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
3391         }
3392 }
3393
3394 static MonoMethod*
3395 get_memset_method (void)
3396 {
3397         static MonoMethod *memset_method = NULL;
3398         if (!memset_method) {
3399                 memset_method = mono_class_get_method_from_name (mono_defaults.string_class, "memset", 3);
3400                 if (!memset_method)
3401                         g_error ("Old corlib found. Install a new one");
3402         }
3403         return memset_method;
3404 }
3405
3406 void
3407 mini_emit_initobj (MonoCompile *cfg, MonoInst *dest, const guchar *ip, MonoClass *klass)
3408 {
3409         MonoInst *iargs [3];
3410         int n;
3411         guint32 align;
3412         MonoMethod *memset_method;
3413         MonoInst *size_ins = NULL;
3414         MonoInst *bzero_ins = NULL;
3415         static MonoMethod *bzero_method;
3416
3417         /* FIXME: Optimize this for the case when dest is an LDADDR */
3418         mono_class_init (klass);
3419         if (mini_is_gsharedvt_klass (klass)) {
3420                 size_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_VALUE_SIZE);
3421                 bzero_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_BZERO);
3422                 if (!bzero_method)
3423                         bzero_method = mono_class_get_method_from_name (mono_defaults.string_class, "bzero_aligned_1", 2);
3424                 g_assert (bzero_method);
3425                 iargs [0] = dest;
3426                 iargs [1] = size_ins;
3427                 mono_emit_calli (cfg, mono_method_signature (bzero_method), iargs, bzero_ins, NULL, NULL);
3428                 return;
3429         }
3430
3431         klass = mono_class_from_mono_type (mini_get_underlying_type (&klass->byval_arg));
3432
3433         n = mono_class_value_size (klass, &align);
3434
3435         if (n <= sizeof (gpointer) * 8) {
3436                 mini_emit_memset (cfg, dest->dreg, 0, n, 0, align);
3437         }
3438         else {
3439                 memset_method = get_memset_method ();
3440                 iargs [0] = dest;
3441                 EMIT_NEW_ICONST (cfg, iargs [1], 0);
3442                 EMIT_NEW_ICONST (cfg, iargs [2], n);
3443                 mono_emit_method_call (cfg, memset_method, iargs, NULL);
3444         }
3445 }
3446
3447 /*
3448  * emit_get_rgctx:
3449  *
3450  *   Emit IR to return either the this pointer for instance method,
3451  * or the mrgctx for static methods.
3452  */
3453 static MonoInst*
3454 emit_get_rgctx (MonoCompile *cfg, MonoMethod *method, int context_used)
3455 {
3456         MonoInst *this_ins = NULL;
3457
3458         g_assert (cfg->gshared);
3459
3460         if (!(method->flags & METHOD_ATTRIBUTE_STATIC) &&
3461                         !(context_used & MONO_GENERIC_CONTEXT_USED_METHOD) &&
3462                         !method->klass->valuetype)
3463                 EMIT_NEW_ARGLOAD (cfg, this_ins, 0);
3464
3465         if (context_used & MONO_GENERIC_CONTEXT_USED_METHOD) {
3466                 MonoInst *mrgctx_loc, *mrgctx_var;
3467
3468                 g_assert (!this_ins);
3469                 g_assert (method->is_inflated && mono_method_get_context (method)->method_inst);
3470
3471                 mrgctx_loc = mono_get_vtable_var (cfg);
3472                 EMIT_NEW_TEMPLOAD (cfg, mrgctx_var, mrgctx_loc->inst_c0);
3473
3474                 return mrgctx_var;
3475         } else if (method->flags & METHOD_ATTRIBUTE_STATIC || method->klass->valuetype) {
3476                 MonoInst *vtable_loc, *vtable_var;
3477
3478                 g_assert (!this_ins);
3479
3480                 vtable_loc = mono_get_vtable_var (cfg);
3481                 EMIT_NEW_TEMPLOAD (cfg, vtable_var, vtable_loc->inst_c0);
3482
3483                 if (method->is_inflated && mono_method_get_context (method)->method_inst) {
3484                         MonoInst *mrgctx_var = vtable_var;
3485                         int vtable_reg;
3486
3487                         vtable_reg = alloc_preg (cfg);
3488                         EMIT_NEW_LOAD_MEMBASE (cfg, vtable_var, OP_LOAD_MEMBASE, vtable_reg, mrgctx_var->dreg, MONO_STRUCT_OFFSET (MonoMethodRuntimeGenericContext, class_vtable));
3489                         vtable_var->type = STACK_PTR;
3490                 }
3491
3492                 return vtable_var;
3493         } else {
3494                 MonoInst *ins;
3495                 int vtable_reg;
3496         
3497                 vtable_reg = alloc_preg (cfg);
3498                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, vtable_reg, this_ins->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3499                 return ins;
3500         }
3501 }
3502
3503 static MonoJumpInfoRgctxEntry *
3504 mono_patch_info_rgctx_entry_new (MonoMemPool *mp, MonoMethod *method, gboolean in_mrgctx, MonoJumpInfoType patch_type, gconstpointer patch_data, MonoRgctxInfoType info_type)
3505 {
3506         MonoJumpInfoRgctxEntry *res = (MonoJumpInfoRgctxEntry *)mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoRgctxEntry));
3507         res->method = method;
3508         res->in_mrgctx = in_mrgctx;
3509         res->data = (MonoJumpInfo *)mono_mempool_alloc0 (mp, sizeof (MonoJumpInfo));
3510         res->data->type = patch_type;
3511         res->data->data.target = patch_data;
3512         res->info_type = info_type;
3513
3514         return res;
3515 }
3516
3517 static inline MonoInst*
3518 emit_rgctx_fetch_inline (MonoCompile *cfg, MonoInst *rgctx, MonoJumpInfoRgctxEntry *entry)
3519 {
3520         MonoInst *args [16];
3521         MonoInst *call;
3522
3523         // FIXME: No fastpath since the slot is not a compile time constant
3524         args [0] = rgctx;
3525         EMIT_NEW_AOTCONST (cfg, args [1], MONO_PATCH_INFO_RGCTX_SLOT_INDEX, entry);
3526         if (entry->in_mrgctx)
3527                 call = mono_emit_jit_icall (cfg, mono_fill_method_rgctx, args);
3528         else
3529                 call = mono_emit_jit_icall (cfg, mono_fill_class_rgctx, args);
3530         return call;
3531 #if 0
3532         /*
3533          * FIXME: This can be called during decompose, which is a problem since it creates
3534          * new bblocks.
3535          * Also, the fastpath doesn't work since the slot number is dynamically allocated.
3536          */
3537         int i, slot, depth, index, rgctx_reg, val_reg, res_reg;
3538         gboolean mrgctx;
3539         MonoBasicBlock *is_null_bb, *end_bb;
3540         MonoInst *res, *ins, *call;
3541         MonoInst *args[16];
3542
3543         slot = mini_get_rgctx_entry_slot (entry);
3544
3545         mrgctx = MONO_RGCTX_SLOT_IS_MRGCTX (slot);
3546         index = MONO_RGCTX_SLOT_INDEX (slot);
3547         if (mrgctx)
3548                 index += MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
3549         for (depth = 0; ; ++depth) {
3550                 int size = mono_class_rgctx_get_array_size (depth, mrgctx);
3551
3552                 if (index < size - 1)
3553                         break;
3554                 index -= size - 1;
3555         }
3556
3557         NEW_BBLOCK (cfg, end_bb);
3558         NEW_BBLOCK (cfg, is_null_bb);
3559
3560         if (mrgctx) {
3561                 rgctx_reg = rgctx->dreg;
3562         } else {
3563                 rgctx_reg = alloc_preg (cfg);
3564
3565                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, rgctx_reg, rgctx->dreg, MONO_STRUCT_OFFSET (MonoVTable, runtime_generic_context));
3566                 // FIXME: Avoid this check by allocating the table when the vtable is created etc.
3567                 NEW_BBLOCK (cfg, is_null_bb);
3568
3569                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rgctx_reg, 0);
3570                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3571         }
3572
3573         for (i = 0; i < depth; ++i) {
3574                 int array_reg = alloc_preg (cfg);
3575
3576                 /* load ptr to next array */
3577                 if (mrgctx && i == 0)
3578                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, rgctx_reg, MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT);
3579                 else
3580                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, rgctx_reg, 0);
3581                 rgctx_reg = array_reg;
3582                 /* is the ptr null? */
3583                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rgctx_reg, 0);
3584                 /* if yes, jump to actual trampoline */
3585                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3586         }
3587
3588         /* fetch slot */
3589         val_reg = alloc_preg (cfg);
3590         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, val_reg, rgctx_reg, (index + 1) * sizeof (gpointer));
3591         /* is the slot null? */
3592         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, val_reg, 0);
3593         /* if yes, jump to actual trampoline */
3594         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3595
3596         /* Fastpath */
3597         res_reg = alloc_preg (cfg);
3598         MONO_INST_NEW (cfg, ins, OP_MOVE);
3599         ins->dreg = res_reg;
3600         ins->sreg1 = val_reg;
3601         MONO_ADD_INS (cfg->cbb, ins);
3602         res = ins;
3603         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3604
3605         /* Slowpath */
3606         MONO_START_BB (cfg, is_null_bb);
3607         args [0] = rgctx;
3608         EMIT_NEW_ICONST (cfg, args [1], index);
3609         if (mrgctx)
3610                 call = mono_emit_jit_icall (cfg, mono_fill_method_rgctx, args);
3611         else
3612                 call = mono_emit_jit_icall (cfg, mono_fill_class_rgctx, args);
3613         MONO_INST_NEW (cfg, ins, OP_MOVE);
3614         ins->dreg = res_reg;
3615         ins->sreg1 = call->dreg;
3616         MONO_ADD_INS (cfg->cbb, ins);
3617         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3618
3619         MONO_START_BB (cfg, end_bb);
3620
3621         return res;
3622 #endif
3623 }
3624
3625 /*
3626  * emit_rgctx_fetch:
3627  *
3628  *   Emit IR to load the value of the rgctx entry ENTRY from the rgctx
3629  * given by RGCTX.
3630  */
3631 static inline MonoInst*
3632 emit_rgctx_fetch (MonoCompile *cfg, MonoInst *rgctx, MonoJumpInfoRgctxEntry *entry)
3633 {
3634         if (cfg->llvm_only)
3635                 return emit_rgctx_fetch_inline (cfg, rgctx, entry);
3636         else
3637                 return mono_emit_abs_call (cfg, MONO_PATCH_INFO_RGCTX_FETCH, entry, helper_sig_rgctx_lazy_fetch_trampoline, &rgctx);
3638 }
3639
3640 static MonoInst*
3641 emit_get_rgctx_klass (MonoCompile *cfg, int context_used,
3642                                           MonoClass *klass, MonoRgctxInfoType rgctx_type)
3643 {
3644         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);
3645         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3646
3647         return emit_rgctx_fetch (cfg, rgctx, entry);
3648 }
3649
3650 static MonoInst*
3651 emit_get_rgctx_sig (MonoCompile *cfg, int context_used,
3652                                         MonoMethodSignature *sig, MonoRgctxInfoType rgctx_type)
3653 {
3654         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);
3655         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3656
3657         return emit_rgctx_fetch (cfg, rgctx, entry);
3658 }
3659
3660 static MonoInst*
3661 emit_get_rgctx_gsharedvt_call (MonoCompile *cfg, int context_used,
3662                                                            MonoMethodSignature *sig, MonoMethod *cmethod, MonoRgctxInfoType rgctx_type)
3663 {
3664         MonoJumpInfoGSharedVtCall *call_info;
3665         MonoJumpInfoRgctxEntry *entry;
3666         MonoInst *rgctx;
3667
3668         call_info = (MonoJumpInfoGSharedVtCall *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoGSharedVtCall));
3669         call_info->sig = sig;
3670         call_info->method = cmethod;
3671
3672         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);
3673         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3674
3675         return emit_rgctx_fetch (cfg, rgctx, entry);
3676 }
3677
3678 /*
3679  * emit_get_rgctx_virt_method:
3680  *
3681  *   Return data for method VIRT_METHOD for a receiver of type KLASS.
3682  */
3683 static MonoInst*
3684 emit_get_rgctx_virt_method (MonoCompile *cfg, int context_used,
3685                                                         MonoClass *klass, MonoMethod *virt_method, MonoRgctxInfoType rgctx_type)
3686 {
3687         MonoJumpInfoVirtMethod *info;
3688         MonoJumpInfoRgctxEntry *entry;
3689         MonoInst *rgctx;
3690
3691         info = (MonoJumpInfoVirtMethod *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoVirtMethod));
3692         info->klass = klass;
3693         info->method = virt_method;
3694
3695         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);
3696         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3697
3698         return emit_rgctx_fetch (cfg, rgctx, entry);
3699 }
3700
3701 static MonoInst*
3702 emit_get_rgctx_gsharedvt_method (MonoCompile *cfg, int context_used,
3703                                                                  MonoMethod *cmethod, MonoGSharedVtMethodInfo *info)
3704 {
3705         MonoJumpInfoRgctxEntry *entry;
3706         MonoInst *rgctx;
3707
3708         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);
3709         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3710
3711         return emit_rgctx_fetch (cfg, rgctx, entry);
3712 }
3713
3714 /*
3715  * emit_get_rgctx_method:
3716  *
3717  *   Emit IR to load the property RGCTX_TYPE of CMETHOD. If context_used is 0, emit
3718  * normal constants, else emit a load from the rgctx.
3719  */
3720 static MonoInst*
3721 emit_get_rgctx_method (MonoCompile *cfg, int context_used,
3722                                            MonoMethod *cmethod, MonoRgctxInfoType rgctx_type)
3723 {
3724         if (!context_used) {
3725                 MonoInst *ins;
3726
3727                 switch (rgctx_type) {
3728                 case MONO_RGCTX_INFO_METHOD:
3729                         EMIT_NEW_METHODCONST (cfg, ins, cmethod);
3730                         return ins;
3731                 case MONO_RGCTX_INFO_METHOD_RGCTX:
3732                         EMIT_NEW_METHOD_RGCTX_CONST (cfg, ins, cmethod);
3733                         return ins;
3734                 default:
3735                         g_assert_not_reached ();
3736                 }
3737         } else {
3738                 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);
3739                 MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3740
3741                 return emit_rgctx_fetch (cfg, rgctx, entry);
3742         }
3743 }
3744
3745 static MonoInst*
3746 emit_get_rgctx_field (MonoCompile *cfg, int context_used,
3747                                           MonoClassField *field, MonoRgctxInfoType rgctx_type)
3748 {
3749         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);
3750         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3751
3752         return emit_rgctx_fetch (cfg, rgctx, entry);
3753 }
3754
3755 static int
3756 get_gsharedvt_info_slot (MonoCompile *cfg, gpointer data, MonoRgctxInfoType rgctx_type)
3757 {
3758         MonoGSharedVtMethodInfo *info = cfg->gsharedvt_info;
3759         MonoRuntimeGenericContextInfoTemplate *template_;
3760         int i, idx;
3761
3762         g_assert (info);
3763
3764         for (i = 0; i < info->num_entries; ++i) {
3765                 MonoRuntimeGenericContextInfoTemplate *otemplate = &info->entries [i];
3766
3767                 if (otemplate->info_type == rgctx_type && otemplate->data == data && rgctx_type != MONO_RGCTX_INFO_LOCAL_OFFSET)
3768                         return i;
3769         }
3770
3771         if (info->num_entries == info->count_entries) {
3772                 MonoRuntimeGenericContextInfoTemplate *new_entries;
3773                 int new_count_entries = info->count_entries ? info->count_entries * 2 : 16;
3774
3775                 new_entries = (MonoRuntimeGenericContextInfoTemplate *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoRuntimeGenericContextInfoTemplate) * new_count_entries);
3776
3777                 memcpy (new_entries, info->entries, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
3778                 info->entries = new_entries;
3779                 info->count_entries = new_count_entries;
3780         }
3781
3782         idx = info->num_entries;
3783         template_ = &info->entries [idx];
3784         template_->info_type = rgctx_type;
3785         template_->data = data;
3786
3787         info->num_entries ++;
3788
3789         return idx;
3790 }
3791
3792 /*
3793  * emit_get_gsharedvt_info:
3794  *
3795  *   This is similar to emit_get_rgctx_.., but loads the data from the gsharedvt info var instead of calling an rgctx fetch trampoline.
3796  */
3797 static MonoInst*
3798 emit_get_gsharedvt_info (MonoCompile *cfg, gpointer data, MonoRgctxInfoType rgctx_type)
3799 {
3800         MonoInst *ins;
3801         int idx, dreg;
3802
3803         idx = get_gsharedvt_info_slot (cfg, data, rgctx_type);
3804         /* Load info->entries [idx] */
3805         dreg = alloc_preg (cfg);
3806         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, cfg->gsharedvt_info_var->dreg, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, entries) + (idx * sizeof (gpointer)));
3807
3808         return ins;
3809 }
3810
3811 static MonoInst*
3812 emit_get_gsharedvt_info_klass (MonoCompile *cfg, MonoClass *klass, MonoRgctxInfoType rgctx_type)
3813 {
3814         return emit_get_gsharedvt_info (cfg, &klass->byval_arg, rgctx_type);
3815 }
3816
3817 /*
3818  * On return the caller must check @klass for load errors.
3819  */
3820 static void
3821 emit_class_init (MonoCompile *cfg, MonoClass *klass)
3822 {
3823         MonoInst *vtable_arg;
3824         int context_used;
3825
3826         context_used = mini_class_check_context_used (cfg, klass);
3827
3828         if (context_used) {
3829                 vtable_arg = emit_get_rgctx_klass (cfg, context_used,
3830                                                                                    klass, MONO_RGCTX_INFO_VTABLE);
3831         } else {
3832                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
3833
3834                 if (!vtable)
3835                         return;
3836                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
3837         }
3838
3839         if (!COMPILE_LLVM (cfg) && cfg->backend->have_op_generic_class_init) {
3840                 MonoInst *ins;
3841
3842                 /*
3843                  * Using an opcode instead of emitting IR here allows the hiding of the call inside the opcode,
3844                  * so this doesn't have to clobber any regs and it doesn't break basic blocks.
3845                  */
3846                 MONO_INST_NEW (cfg, ins, OP_GENERIC_CLASS_INIT);
3847                 ins->sreg1 = vtable_arg->dreg;
3848                 MONO_ADD_INS (cfg->cbb, ins);
3849         } else {
3850                 static int byte_offset = -1;
3851                 static guint8 bitmask;
3852                 int bits_reg, inited_reg;
3853                 MonoBasicBlock *inited_bb;
3854                 MonoInst *args [16];
3855
3856                 if (byte_offset < 0)
3857                         mono_marshal_find_bitfield_offset (MonoVTable, initialized, &byte_offset, &bitmask);
3858
3859                 bits_reg = alloc_ireg (cfg);
3860                 inited_reg = alloc_ireg (cfg);
3861
3862                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, bits_reg, vtable_arg->dreg, byte_offset);
3863                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, inited_reg, bits_reg, bitmask);
3864
3865                 NEW_BBLOCK (cfg, inited_bb);
3866
3867                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, inited_reg, 0);
3868                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, inited_bb);
3869
3870                 args [0] = vtable_arg;
3871                 mono_emit_jit_icall (cfg, mono_generic_class_init, args);
3872
3873                 MONO_START_BB (cfg, inited_bb);
3874         }
3875 }
3876
3877 static void
3878 emit_seq_point (MonoCompile *cfg, MonoMethod *method, guint8* ip, gboolean intr_loc, gboolean nonempty_stack)
3879 {
3880         MonoInst *ins;
3881
3882         if (cfg->gen_seq_points && cfg->method == method) {
3883                 NEW_SEQ_POINT (cfg, ins, ip - cfg->header->code, intr_loc);
3884                 if (nonempty_stack)
3885                         ins->flags |= MONO_INST_NONEMPTY_STACK;
3886                 MONO_ADD_INS (cfg->cbb, ins);
3887         }
3888 }
3889
3890 static void
3891 save_cast_details (MonoCompile *cfg, MonoClass *klass, int obj_reg, gboolean null_check)
3892 {
3893         if (mini_get_debug_options ()->better_cast_details) {
3894                 int vtable_reg = alloc_preg (cfg);
3895                 int klass_reg = alloc_preg (cfg);
3896                 MonoBasicBlock *is_null_bb = NULL;
3897                 MonoInst *tls_get;
3898                 int to_klass_reg, context_used;
3899
3900                 if (null_check) {
3901                         NEW_BBLOCK (cfg, is_null_bb);
3902
3903                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
3904                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3905                 }
3906
3907                 tls_get = mono_get_jit_tls_intrinsic (cfg);
3908                 if (!tls_get) {
3909                         fprintf (stderr, "error: --debug=casts not supported on this platform.\n.");
3910                         exit (1);
3911                 }
3912
3913                 MONO_ADD_INS (cfg->cbb, tls_get);
3914                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3915                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
3916
3917                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), klass_reg);
3918
3919                 context_used = mini_class_check_context_used (cfg, klass);
3920                 if (context_used) {
3921                         MonoInst *class_ins;
3922
3923                         class_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
3924                         to_klass_reg = class_ins->dreg;
3925                 } else {
3926                         to_klass_reg = alloc_preg (cfg);
3927                         MONO_EMIT_NEW_CLASSCONST (cfg, to_klass_reg, klass);
3928                 }
3929                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_to), to_klass_reg);
3930
3931                 if (null_check)
3932                         MONO_START_BB (cfg, is_null_bb);
3933         }
3934 }
3935
3936 static void
3937 reset_cast_details (MonoCompile *cfg)
3938 {
3939         /* Reset the variables holding the cast details */
3940         if (mini_get_debug_options ()->better_cast_details) {
3941                 MonoInst *tls_get = mono_get_jit_tls_intrinsic (cfg);
3942
3943                 MONO_ADD_INS (cfg->cbb, tls_get);
3944                 /* It is enough to reset the from field */
3945                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), 0);
3946         }
3947 }
3948
3949 /*
3950  * On return the caller must check @array_class for load errors
3951  */
3952 static void
3953 mini_emit_check_array_type (MonoCompile *cfg, MonoInst *obj, MonoClass *array_class)
3954 {
3955         int vtable_reg = alloc_preg (cfg);
3956         int context_used;
3957
3958         context_used = mini_class_check_context_used (cfg, array_class);
3959
3960         save_cast_details (cfg, array_class, obj->dreg, FALSE);
3961
3962         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3963
3964         if (cfg->opt & MONO_OPT_SHARED) {
3965                 int class_reg = alloc_preg (cfg);
3966                 MonoInst *ins;
3967
3968                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, class_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
3969                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_CLASS, array_class);
3970                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, class_reg, ins->dreg);
3971         } else if (context_used) {
3972                 MonoInst *vtable_ins;
3973
3974                 vtable_ins = emit_get_rgctx_klass (cfg, context_used, array_class, MONO_RGCTX_INFO_VTABLE);
3975                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, vtable_reg, vtable_ins->dreg);
3976         } else {
3977                 if (cfg->compile_aot) {
3978                         int vt_reg;
3979                         MonoVTable *vtable;
3980
3981                         if (!(vtable = mono_class_vtable (cfg->domain, array_class)))
3982                                 return;
3983                         vt_reg = alloc_preg (cfg);
3984                         MONO_EMIT_NEW_VTABLECONST (cfg, vt_reg, vtable);
3985                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, vtable_reg, vt_reg);
3986                 } else {
3987                         MonoVTable *vtable;
3988                         if (!(vtable = mono_class_vtable (cfg->domain, array_class)))
3989                                 return;
3990                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vtable);
3991                 }
3992         }
3993         
3994         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "ArrayTypeMismatchException");
3995
3996         reset_cast_details (cfg);
3997 }
3998
3999 /**
4000  * Handles unbox of a Nullable<T>. If context_used is non zero, then shared 
4001  * generic code is generated.
4002  */
4003 static MonoInst*
4004 handle_unbox_nullable (MonoCompile* cfg, MonoInst* val, MonoClass* klass, int context_used)
4005 {
4006         MonoMethod* method = mono_class_get_method_from_name (klass, "Unbox", 1);
4007
4008         if (context_used) {
4009                 MonoInst *rgctx, *addr;
4010
4011                 /* FIXME: What if the class is shared?  We might not
4012                    have to get the address of the method from the
4013                    RGCTX. */
4014                 addr = emit_get_rgctx_method (cfg, context_used, method,
4015                                                                           MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
4016                 if (cfg->llvm_only && cfg->gsharedvt) {
4017                         return emit_llvmonly_calli (cfg, mono_method_signature (method), &val, addr);
4018                 } else {
4019                         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
4020
4021                         return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
4022                 }
4023         } else {
4024                 gboolean pass_vtable, pass_mrgctx;
4025                 MonoInst *rgctx_arg = NULL;
4026
4027                 check_method_sharing (cfg, method, &pass_vtable, &pass_mrgctx);
4028                 g_assert (!pass_mrgctx);
4029
4030                 if (pass_vtable) {
4031                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
4032
4033                         g_assert (vtable);
4034                         EMIT_NEW_VTABLECONST (cfg, rgctx_arg, vtable);
4035                 }
4036
4037                 return mono_emit_method_call_full (cfg, method, NULL, FALSE, &val, NULL, NULL, rgctx_arg);
4038         }
4039 }
4040
4041 static MonoInst*
4042 handle_unbox (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, int context_used)
4043 {
4044         MonoInst *add;
4045         int obj_reg;
4046         int vtable_reg = alloc_dreg (cfg ,STACK_PTR);
4047         int klass_reg = alloc_dreg (cfg ,STACK_PTR);
4048         int eclass_reg = alloc_dreg (cfg ,STACK_PTR);
4049         int rank_reg = alloc_dreg (cfg ,STACK_I4);
4050
4051         obj_reg = sp [0]->dreg;
4052         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4053         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
4054
4055         /* FIXME: generics */
4056         g_assert (klass->rank == 0);
4057                         
4058         // Check rank == 0
4059         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, 0);
4060         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
4061
4062         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4063         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, element_class));
4064
4065         if (context_used) {
4066                 MonoInst *element_class;
4067
4068                 /* This assertion is from the unboxcast insn */
4069                 g_assert (klass->rank == 0);
4070
4071                 element_class = emit_get_rgctx_klass (cfg, context_used,
4072                                 klass, MONO_RGCTX_INFO_ELEMENT_KLASS);
4073
4074                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, eclass_reg, element_class->dreg);
4075                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
4076         } else {
4077                 save_cast_details (cfg, klass->element_class, obj_reg, FALSE);
4078                 mini_emit_class_check (cfg, eclass_reg, klass->element_class);
4079                 reset_cast_details (cfg);
4080         }
4081
4082         NEW_BIALU_IMM (cfg, add, OP_ADD_IMM, alloc_dreg (cfg, STACK_MP), obj_reg, sizeof (MonoObject));
4083         MONO_ADD_INS (cfg->cbb, add);
4084         add->type = STACK_MP;
4085         add->klass = klass;
4086
4087         return add;
4088 }
4089
4090 static MonoInst*
4091 handle_unbox_gsharedvt (MonoCompile *cfg, MonoClass *klass, MonoInst *obj)
4092 {
4093         MonoInst *addr, *klass_inst, *is_ref, *args[16];
4094         MonoBasicBlock *is_ref_bb, *is_nullable_bb, *end_bb;
4095         MonoInst *ins;
4096         int dreg, addr_reg;
4097
4098         klass_inst = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_KLASS);
4099
4100         /* obj */
4101         args [0] = obj;
4102
4103         /* klass */
4104         args [1] = klass_inst;
4105
4106         /* CASTCLASS */
4107         obj = mono_emit_jit_icall (cfg, mono_object_castclass_unbox, args);
4108
4109         NEW_BBLOCK (cfg, is_ref_bb);
4110         NEW_BBLOCK (cfg, is_nullable_bb);
4111         NEW_BBLOCK (cfg, end_bb);
4112         is_ref = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_CLASS_BOX_TYPE);
4113         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, MONO_GSHAREDVT_BOX_TYPE_REF);
4114         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
4115
4116         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
4117         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_nullable_bb);
4118
4119         /* This will contain either the address of the unboxed vtype, or an address of the temporary where the ref is stored */
4120         addr_reg = alloc_dreg (cfg, STACK_MP);
4121
4122         /* Non-ref case */
4123         /* UNBOX */
4124         NEW_BIALU_IMM (cfg, addr, OP_ADD_IMM, addr_reg, obj->dreg, sizeof (MonoObject));
4125         MONO_ADD_INS (cfg->cbb, addr);
4126
4127         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4128
4129         /* Ref case */
4130         MONO_START_BB (cfg, is_ref_bb);
4131
4132         /* Save the ref to a temporary */
4133         dreg = alloc_ireg (cfg);
4134         EMIT_NEW_VARLOADA_VREG (cfg, addr, dreg, &klass->byval_arg);
4135         addr->dreg = addr_reg;
4136         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, obj->dreg);
4137         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4138
4139         /* Nullable case */
4140         MONO_START_BB (cfg, is_nullable_bb);
4141
4142         {
4143                 MonoInst *addr = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX);
4144                 MonoInst *unbox_call;
4145                 MonoMethodSignature *unbox_sig;
4146
4147                 unbox_sig = (MonoMethodSignature *)mono_mempool_alloc0 (cfg->mempool, MONO_SIZEOF_METHOD_SIGNATURE + (1 * sizeof (MonoType *)));
4148                 unbox_sig->ret = &klass->byval_arg;
4149                 unbox_sig->param_count = 1;
4150                 unbox_sig->params [0] = &mono_defaults.object_class->byval_arg;
4151
4152                 if (cfg->llvm_only)
4153                         unbox_call = emit_llvmonly_calli (cfg, unbox_sig, &obj, addr);
4154                 else
4155                         unbox_call = mono_emit_calli (cfg, unbox_sig, &obj, addr, NULL, NULL);
4156
4157                 EMIT_NEW_VARLOADA_VREG (cfg, addr, unbox_call->dreg, &klass->byval_arg);
4158                 addr->dreg = addr_reg;
4159         }
4160
4161         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4162
4163         /* End */
4164         MONO_START_BB (cfg, end_bb);
4165
4166         /* LDOBJ */
4167         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr_reg, 0);
4168
4169         return ins;
4170 }
4171
4172 /*
4173  * Returns NULL and set the cfg exception on error.
4174  */
4175 static MonoInst*
4176 handle_alloc (MonoCompile *cfg, MonoClass *klass, gboolean for_box, int context_used)
4177 {
4178         MonoInst *iargs [2];
4179         void *alloc_ftn;
4180
4181         if (context_used) {
4182                 MonoInst *data;
4183                 MonoRgctxInfoType rgctx_info;
4184                 MonoInst *iargs [2];
4185                 gboolean known_instance_size = !mini_is_gsharedvt_klass (klass);
4186
4187                 MonoMethod *managed_alloc = mono_gc_get_managed_allocator (klass, for_box, known_instance_size);
4188
4189                 if (cfg->opt & MONO_OPT_SHARED)
4190                         rgctx_info = MONO_RGCTX_INFO_KLASS;
4191                 else
4192                         rgctx_info = MONO_RGCTX_INFO_VTABLE;
4193                 data = emit_get_rgctx_klass (cfg, context_used, klass, rgctx_info);
4194
4195                 if (cfg->opt & MONO_OPT_SHARED) {
4196                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
4197                         iargs [1] = data;
4198                         alloc_ftn = ves_icall_object_new;
4199                 } else {
4200                         iargs [0] = data;
4201                         alloc_ftn = ves_icall_object_new_specific;
4202                 }
4203
4204                 if (managed_alloc && !(cfg->opt & MONO_OPT_SHARED)) {
4205                         if (known_instance_size) {
4206                                 int size = mono_class_instance_size (klass);
4207                                 if (size < sizeof (MonoObject))
4208                                         g_error ("Invalid size %d for class %s", size, mono_type_get_full_name (klass));
4209
4210                                 EMIT_NEW_ICONST (cfg, iargs [1], mono_gc_get_aligned_size_for_allocator (size));
4211                         }
4212                         return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
4213                 }
4214
4215                 return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
4216         }
4217
4218         if (cfg->opt & MONO_OPT_SHARED) {
4219                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
4220                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
4221
4222                 alloc_ftn = ves_icall_object_new;
4223         } else if (cfg->compile_aot && cfg->cbb->out_of_line && klass->type_token && klass->image == mono_defaults.corlib && !klass->generic_class) {
4224                 /* This happens often in argument checking code, eg. throw new FooException... */
4225                 /* Avoid relocations and save some space by calling a helper function specialized to mscorlib */
4226                 EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (klass->type_token));
4227                 return mono_emit_jit_icall (cfg, mono_helper_newobj_mscorlib, iargs);
4228         } else {
4229                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
4230                 MonoMethod *managed_alloc = NULL;
4231                 gboolean pass_lw;
4232
4233                 if (!vtable) {
4234                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4235                         cfg->exception_ptr = klass;
4236                         return NULL;
4237                 }
4238
4239                 managed_alloc = mono_gc_get_managed_allocator (klass, for_box, TRUE);
4240
4241                 if (managed_alloc) {
4242                         int size = mono_class_instance_size (klass);
4243                         if (size < sizeof (MonoObject))
4244                                 g_error ("Invalid size %d for class %s", size, mono_type_get_full_name (klass));
4245
4246                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
4247                         EMIT_NEW_ICONST (cfg, iargs [1], mono_gc_get_aligned_size_for_allocator (size));
4248                         return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
4249                 }
4250                 alloc_ftn = mono_class_get_allocation_ftn (vtable, for_box, &pass_lw);
4251                 if (pass_lw) {
4252                         guint32 lw = vtable->klass->instance_size;
4253                         lw = ((lw + (sizeof (gpointer) - 1)) & ~(sizeof (gpointer) - 1)) / sizeof (gpointer);
4254                         EMIT_NEW_ICONST (cfg, iargs [0], lw);
4255                         EMIT_NEW_VTABLECONST (cfg, iargs [1], vtable);
4256                 }
4257                 else {
4258                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
4259                 }
4260         }
4261
4262         return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
4263 }
4264         
4265 /*
4266  * Returns NULL and set the cfg exception on error.
4267  */     
4268 static MonoInst*
4269 handle_box (MonoCompile *cfg, MonoInst *val, MonoClass *klass, int context_used)
4270 {
4271         MonoInst *alloc, *ins;
4272
4273         if (mono_class_is_nullable (klass)) {
4274                 MonoMethod* method = mono_class_get_method_from_name (klass, "Box", 1);
4275
4276                 if (context_used) {
4277                         if (cfg->llvm_only && cfg->gsharedvt) {
4278                                 MonoInst *addr = emit_get_rgctx_method (cfg, context_used, method,
4279                                                                                                                 MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
4280                                 return emit_llvmonly_calli (cfg, mono_method_signature (method), &val, addr);
4281                         } else {
4282                                 /* FIXME: What if the class is shared?  We might not
4283                                    have to get the method address from the RGCTX. */
4284                                 MonoInst *addr = emit_get_rgctx_method (cfg, context_used, method,
4285                                                                                                                 MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
4286                                 MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
4287
4288                                 return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
4289                         }
4290                 } else {
4291                         gboolean pass_vtable, pass_mrgctx;
4292                         MonoInst *rgctx_arg = NULL;
4293
4294                         check_method_sharing (cfg, method, &pass_vtable, &pass_mrgctx);
4295                         g_assert (!pass_mrgctx);
4296
4297                         if (pass_vtable) {
4298                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
4299
4300                                 g_assert (vtable);
4301                                 EMIT_NEW_VTABLECONST (cfg, rgctx_arg, vtable);
4302                         }
4303
4304                         return mono_emit_method_call_full (cfg, method, NULL, FALSE, &val, NULL, NULL, rgctx_arg);
4305                 }
4306         }
4307
4308         if (mini_is_gsharedvt_klass (klass)) {
4309                 MonoBasicBlock *is_ref_bb, *is_nullable_bb, *end_bb;
4310                 MonoInst *res, *is_ref, *src_var, *addr;
4311                 int dreg;
4312
4313                 dreg = alloc_ireg (cfg);
4314
4315                 NEW_BBLOCK (cfg, is_ref_bb);
4316                 NEW_BBLOCK (cfg, is_nullable_bb);
4317                 NEW_BBLOCK (cfg, end_bb);
4318                 is_ref = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_CLASS_BOX_TYPE);
4319                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, MONO_GSHAREDVT_BOX_TYPE_REF);
4320                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
4321
4322                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
4323                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_nullable_bb);
4324
4325                 /* Non-ref case */
4326                 alloc = handle_alloc (cfg, klass, TRUE, context_used);
4327                 if (!alloc)
4328                         return NULL;
4329                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
4330                 ins->opcode = OP_STOREV_MEMBASE;
4331
4332                 EMIT_NEW_UNALU (cfg, res, OP_MOVE, dreg, alloc->dreg);
4333                 res->type = STACK_OBJ;
4334                 res->klass = klass;
4335                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4336                 
4337                 /* Ref case */
4338                 MONO_START_BB (cfg, is_ref_bb);
4339
4340                 /* val is a vtype, so has to load the value manually */
4341                 src_var = get_vreg_to_inst (cfg, val->dreg);
4342                 if (!src_var)
4343                         src_var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, val->dreg);
4344                 EMIT_NEW_VARLOADA (cfg, addr, src_var, src_var->inst_vtype);
4345                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, addr->dreg, 0);
4346                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4347
4348                 /* Nullable case */
4349                 MONO_START_BB (cfg, is_nullable_bb);
4350
4351                 {
4352                         MonoInst *addr = emit_get_gsharedvt_info_klass (cfg, klass,
4353                                                                                                         MONO_RGCTX_INFO_NULLABLE_CLASS_BOX);
4354                         MonoInst *box_call;
4355                         MonoMethodSignature *box_sig;
4356
4357                         /*
4358                          * klass is Nullable<T>, need to call Nullable<T>.Box () using a gsharedvt signature, but we cannot
4359                          * construct that method at JIT time, so have to do things by hand.
4360                          */
4361                         box_sig = (MonoMethodSignature *)mono_mempool_alloc0 (cfg->mempool, MONO_SIZEOF_METHOD_SIGNATURE + (1 * sizeof (MonoType *)));
4362                         box_sig->ret = &mono_defaults.object_class->byval_arg;
4363                         box_sig->param_count = 1;
4364                         box_sig->params [0] = &klass->byval_arg;
4365
4366                         if (cfg->llvm_only)
4367                                 box_call = emit_llvmonly_calli (cfg, box_sig, &val, addr);
4368                         else
4369                                 box_call = mono_emit_calli (cfg, box_sig, &val, addr, NULL, NULL);
4370                         EMIT_NEW_UNALU (cfg, res, OP_MOVE, dreg, box_call->dreg);
4371                         res->type = STACK_OBJ;
4372                         res->klass = klass;
4373                 }
4374
4375                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4376
4377                 MONO_START_BB (cfg, end_bb);
4378
4379                 return res;
4380         } else {
4381                 alloc = handle_alloc (cfg, klass, TRUE, context_used);
4382                 if (!alloc)
4383                         return NULL;
4384
4385                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
4386                 return alloc;
4387         }
4388 }
4389
4390 static gboolean
4391 mini_class_has_reference_variant_generic_argument (MonoCompile *cfg, MonoClass *klass, int context_used)
4392 {
4393         int i;
4394         MonoGenericContainer *container;
4395         MonoGenericInst *ginst;
4396
4397         if (klass->generic_class) {
4398                 container = klass->generic_class->container_class->generic_container;
4399                 ginst = klass->generic_class->context.class_inst;
4400         } else if (klass->generic_container && context_used) {
4401                 container = klass->generic_container;
4402                 ginst = container->context.class_inst;
4403         } else {
4404                 return FALSE;
4405         }
4406
4407         for (i = 0; i < container->type_argc; ++i) {
4408                 MonoType *type;
4409                 if (!(mono_generic_container_get_param_info (container, i)->flags & (MONO_GEN_PARAM_VARIANT|MONO_GEN_PARAM_COVARIANT)))
4410                         continue;
4411                 type = ginst->type_argv [i];
4412                 if (mini_type_is_reference (type))
4413                         return TRUE;
4414         }
4415         return FALSE;
4416 }
4417
4418 static GHashTable* direct_icall_type_hash;
4419
4420 static gboolean
4421 icall_is_direct_callable (MonoCompile *cfg, MonoMethod *cmethod)
4422 {
4423         /* LLVM on amd64 can't handle calls to non-32 bit addresses */
4424         if (!direct_icalls_enabled (cfg))
4425                 return FALSE;
4426
4427         /*
4428          * An icall is directly callable if it doesn't directly or indirectly call mono_raise_exception ().
4429          * Whitelist a few icalls for now.
4430          */
4431         if (!direct_icall_type_hash) {
4432                 GHashTable *h = g_hash_table_new (g_str_hash, g_str_equal);
4433
4434                 g_hash_table_insert (h, (char*)"Decimal", GUINT_TO_POINTER (1));
4435                 g_hash_table_insert (h, (char*)"Number", GUINT_TO_POINTER (1));
4436                 g_hash_table_insert (h, (char*)"Buffer", GUINT_TO_POINTER (1));
4437                 g_hash_table_insert (h, (char*)"Monitor", GUINT_TO_POINTER (1));
4438                 mono_memory_barrier ();
4439                 direct_icall_type_hash = h;
4440         }
4441
4442         if (cmethod->klass == mono_defaults.math_class)
4443                 return TRUE;
4444         /* No locking needed */
4445         if (cmethod->klass->image == mono_defaults.corlib && g_hash_table_lookup (direct_icall_type_hash, cmethod->klass->name))
4446                 return TRUE;
4447         return FALSE;
4448 }
4449
4450 /* Return whenever METHOD calls Assembly.GetCallingAssembly () */
4451 // FIXME: It would be better to generalize this using some kind of method attribute
4452 // or automatic detection
4453 static gboolean
4454 method_needs_calling_assembly (MonoMethod *method)
4455 {
4456         MonoClass *klass = method->klass;
4457
4458         if (klass->image != mono_defaults.corlib)
4459                 return FALSE;
4460         if (!strcmp (klass->name_space, "System") && !strcmp (klass->name, "Activator") &&
4461                 !strcmp (method->name, "CreateInstance"))
4462                 return TRUE;
4463         return FALSE;
4464 }
4465
4466 #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)
4467
4468 static MonoInst*
4469 emit_castclass_with_cache (MonoCompile *cfg, MonoClass *klass, MonoInst **args)
4470 {
4471         MonoMethod *mono_castclass;
4472         MonoInst *res;
4473
4474         mono_castclass = mono_marshal_get_castclass_with_cache ();
4475
4476         save_cast_details (cfg, klass, args [0]->dreg, TRUE);
4477         res = mono_emit_method_call (cfg, mono_castclass, args, NULL);
4478         reset_cast_details (cfg);
4479
4480         return res;
4481 }
4482
4483 static int
4484 get_castclass_cache_idx (MonoCompile *cfg)
4485 {
4486         /* Each CASTCLASS_CACHE patch needs a unique index which identifies the call site */
4487         cfg->castclass_cache_index ++;
4488         return (cfg->method_index << 16) | cfg->castclass_cache_index;
4489 }
4490
4491 static MonoInst*
4492 emit_castclass_with_cache_nonshared (MonoCompile *cfg, MonoInst *obj, MonoClass *klass)
4493 {
4494         MonoInst *args [3];
4495         int idx;
4496
4497         /* obj */
4498         args [0] = obj;
4499
4500         /* klass */
4501         EMIT_NEW_CLASSCONST (cfg, args [1], klass);
4502
4503         /* inline cache*/
4504         idx = get_castclass_cache_idx (cfg);
4505         args [2] = emit_runtime_constant (cfg, MONO_PATCH_INFO_CASTCLASS_CACHE, GINT_TO_POINTER (idx));
4506
4507         /*The wrapper doesn't inline well so the bloat of inlining doesn't pay off.*/
4508         return emit_castclass_with_cache (cfg, klass, args);
4509 }
4510
4511 /*
4512  * Returns NULL and set the cfg exception on error.
4513  */
4514 static MonoInst*
4515 handle_castclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src, guint8 *ip, int *inline_costs)
4516 {
4517         MonoBasicBlock *is_null_bb;
4518         int obj_reg = src->dreg;
4519         int vtable_reg = alloc_preg (cfg);
4520         int context_used;
4521         MonoInst *klass_inst = NULL, *res;
4522
4523         context_used = mini_class_check_context_used (cfg, klass);
4524
4525         if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
4526                 res = emit_castclass_with_cache_nonshared (cfg, src, klass);
4527                 (*inline_costs) += 2;
4528                 return res;
4529         } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
4530                 MonoMethod *mono_castclass;
4531                 MonoInst *iargs [1];
4532                 int costs;
4533
4534                 mono_castclass = mono_marshal_get_castclass (klass); 
4535                 iargs [0] = src;
4536                                 
4537                 save_cast_details (cfg, klass, src->dreg, TRUE);
4538                 costs = inline_method (cfg, mono_castclass, mono_method_signature (mono_castclass), 
4539                                                            iargs, ip, cfg->real_offset, TRUE);
4540                 reset_cast_details (cfg);
4541                 CHECK_CFG_EXCEPTION;
4542                 g_assert (costs > 0);
4543                                 
4544                 cfg->real_offset += 5;
4545
4546                 (*inline_costs) += costs;
4547
4548                 return src;
4549         }
4550
4551         if (context_used) {
4552                 MonoInst *args [3];
4553
4554                 if(mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || is_complex_isinst (klass)) {
4555                         MonoInst *cache_ins;
4556
4557                         cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
4558
4559                         /* obj */
4560                         args [0] = src;
4561
4562                         /* klass - it's the second element of the cache entry*/
4563                         EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer));
4564
4565                         /* cache */
4566                         args [2] = cache_ins;
4567
4568                         return emit_castclass_with_cache (cfg, klass, args);
4569                 }
4570
4571                 klass_inst = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
4572         }
4573
4574         NEW_BBLOCK (cfg, is_null_bb);
4575
4576         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4577         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
4578
4579         save_cast_details (cfg, klass, obj_reg, FALSE);
4580
4581         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4582                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4583                 mini_emit_iface_cast (cfg, vtable_reg, klass, NULL, NULL);
4584         } else {
4585                 int klass_reg = alloc_preg (cfg);
4586
4587                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4588
4589                 if (!klass->rank && !cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && (klass->flags & TYPE_ATTRIBUTE_SEALED)) {
4590                         /* the remoting code is broken, access the class for now */
4591                         if (0) { /*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
4592                                 MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
4593                                 if (!vt) {
4594                                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4595                                         cfg->exception_ptr = klass;
4596                                         return NULL;
4597                                 }
4598                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vt);
4599                         } else {
4600                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4601                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
4602                         }
4603                         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
4604                 } else {
4605                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4606                         mini_emit_castclass_inst (cfg, obj_reg, klass_reg, klass, klass_inst, is_null_bb);
4607                 }
4608         }
4609
4610         MONO_START_BB (cfg, is_null_bb);
4611
4612         reset_cast_details (cfg);
4613
4614         return src;
4615
4616 exception_exit:
4617         return NULL;
4618 }
4619
4620 /*
4621  * Returns NULL and set the cfg exception on error.
4622  */
4623 static MonoInst*
4624 handle_isinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context_used)
4625 {
4626         MonoInst *ins;
4627         MonoBasicBlock *is_null_bb, *false_bb, *end_bb;
4628         int obj_reg = src->dreg;
4629         int vtable_reg = alloc_preg (cfg);
4630         int res_reg = alloc_ireg_ref (cfg);
4631         MonoInst *klass_inst = NULL;
4632
4633         if (context_used) {
4634                 MonoInst *args [3];
4635
4636                 if(mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || is_complex_isinst (klass)) {
4637                         MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
4638                         MonoInst *cache_ins;
4639
4640                         cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
4641
4642                         /* obj */
4643                         args [0] = src;
4644
4645                         /* klass - it's the second element of the cache entry*/
4646                         EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer));
4647
4648                         /* cache */
4649                         args [2] = cache_ins;
4650
4651                         return mono_emit_method_call (cfg, mono_isinst, args, NULL);
4652                 }
4653
4654                 klass_inst = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
4655         }
4656
4657         NEW_BBLOCK (cfg, is_null_bb);
4658         NEW_BBLOCK (cfg, false_bb);
4659         NEW_BBLOCK (cfg, end_bb);
4660
4661         /* Do the assignment at the beginning, so the other assignment can be if converted */
4662         EMIT_NEW_UNALU (cfg, ins, OP_MOVE, res_reg, obj_reg);
4663         ins->type = STACK_OBJ;
4664         ins->klass = klass;
4665
4666         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4667         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_null_bb);
4668
4669         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4670
4671         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4672                 g_assert (!context_used);
4673                 /* the is_null_bb target simply copies the input register to the output */
4674                 mini_emit_iface_cast (cfg, vtable_reg, klass, false_bb, is_null_bb);
4675         } else {
4676                 int klass_reg = alloc_preg (cfg);
4677
4678                 if (klass->rank) {
4679                         int rank_reg = alloc_preg (cfg);
4680                         int eclass_reg = alloc_preg (cfg);
4681
4682                         g_assert (!context_used);
4683                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
4684                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank);
4685                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4686                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4687                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, cast_class));
4688                         if (klass->cast_class == mono_defaults.object_class) {
4689                                 int parent_reg = alloc_preg (cfg);
4690                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, parent_reg, eclass_reg, MONO_STRUCT_OFFSET (MonoClass, parent));
4691                                 mini_emit_class_check_branch (cfg, parent_reg, mono_defaults.enum_class->parent, OP_PBNE_UN, is_null_bb);
4692                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);
4693                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4694                         } else if (klass->cast_class == mono_defaults.enum_class->parent) {
4695                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class->parent, OP_PBEQ, is_null_bb);
4696                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);                          
4697                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4698                         } else if (klass->cast_class == mono_defaults.enum_class) {
4699                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);
4700                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4701                         } else if (klass->cast_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
4702                                 mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb);
4703                         } else {
4704                                 if ((klass->rank == 1) && (klass->byval_arg.type == MONO_TYPE_SZARRAY)) {
4705                                         /* Check that the object is a vector too */
4706                                         int bounds_reg = alloc_preg (cfg);
4707                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, obj_reg, MONO_STRUCT_OFFSET (MonoArray, bounds));
4708                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
4709                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4710                                 }
4711
4712                                 /* the is_null_bb target simply copies the input register to the output */
4713                                 mini_emit_isninst_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb);
4714                         }
4715                 } else if (mono_class_is_nullable (klass)) {
4716                         g_assert (!context_used);
4717                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4718                         /* the is_null_bb target simply copies the input register to the output */
4719                         mini_emit_isninst_cast (cfg, klass_reg, klass->cast_class, false_bb, is_null_bb);
4720                 } else {
4721                         if (!cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && (klass->flags & TYPE_ATTRIBUTE_SEALED)) {
4722                                 g_assert (!context_used);
4723                                 /* the remoting code is broken, access the class for now */
4724                                 if (0) {/*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
4725                                         MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
4726                                         if (!vt) {
4727                                                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4728                                                 cfg->exception_ptr = klass;
4729                                                 return NULL;
4730                                         }
4731                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vt);
4732                                 } else {
4733                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4734                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
4735                                 }
4736                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4737                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, is_null_bb);
4738                         } else {
4739                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4740                                 /* the is_null_bb target simply copies the input register to the output */
4741                                 mini_emit_isninst_cast_inst (cfg, klass_reg, klass, klass_inst, false_bb, is_null_bb);
4742                         }
4743                 }
4744         }
4745
4746         MONO_START_BB (cfg, false_bb);
4747
4748         MONO_EMIT_NEW_PCONST (cfg, res_reg, 0);
4749         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4750
4751         MONO_START_BB (cfg, is_null_bb);
4752
4753         MONO_START_BB (cfg, end_bb);
4754
4755         return ins;
4756 }
4757
4758 static MonoInst*
4759 handle_cisinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
4760 {
4761         /* This opcode takes as input an object reference and a class, and returns:
4762         0) if the object is an instance of the class,
4763         1) if the object is not instance of the class,
4764         2) if the object is a proxy whose type cannot be determined */
4765
4766         MonoInst *ins;
4767 #ifndef DISABLE_REMOTING
4768         MonoBasicBlock *true_bb, *false_bb, *false2_bb, *end_bb, *no_proxy_bb, *interface_fail_bb;
4769 #else
4770         MonoBasicBlock *true_bb, *false_bb, *end_bb;
4771 #endif
4772         int obj_reg = src->dreg;
4773         int dreg = alloc_ireg (cfg);
4774         int tmp_reg;
4775 #ifndef DISABLE_REMOTING
4776         int klass_reg = alloc_preg (cfg);
4777 #endif
4778
4779         NEW_BBLOCK (cfg, true_bb);
4780         NEW_BBLOCK (cfg, false_bb);
4781         NEW_BBLOCK (cfg, end_bb);
4782 #ifndef DISABLE_REMOTING
4783         NEW_BBLOCK (cfg, false2_bb);
4784         NEW_BBLOCK (cfg, no_proxy_bb);
4785 #endif
4786
4787         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4788         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, false_bb);
4789
4790         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4791 #ifndef DISABLE_REMOTING
4792                 NEW_BBLOCK (cfg, interface_fail_bb);
4793 #endif
4794
4795                 tmp_reg = alloc_preg (cfg);
4796                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4797 #ifndef DISABLE_REMOTING
4798                 mini_emit_iface_cast (cfg, tmp_reg, klass, interface_fail_bb, true_bb);
4799                 MONO_START_BB (cfg, interface_fail_bb);
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, false_bb);
4803
4804                 tmp_reg = alloc_preg (cfg);
4805                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4806                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4807                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false2_bb);                
4808 #else
4809                 mini_emit_iface_cast (cfg, tmp_reg, klass, false_bb, true_bb);
4810 #endif
4811         } else {
4812 #ifndef DISABLE_REMOTING
4813                 tmp_reg = alloc_preg (cfg);
4814                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4815                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4816
4817                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, no_proxy_bb);          
4818                 tmp_reg = alloc_preg (cfg);
4819                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, remote_class));
4820                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoRemoteClass, proxy_class));
4821
4822                 tmp_reg = alloc_preg (cfg);             
4823                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4824                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4825                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, no_proxy_bb);
4826                 
4827                 mini_emit_isninst_cast (cfg, klass_reg, klass, false2_bb, true_bb);
4828                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false2_bb);
4829
4830                 MONO_START_BB (cfg, no_proxy_bb);
4831
4832                 mini_emit_isninst_cast (cfg, klass_reg, klass, false_bb, true_bb);
4833 #else
4834                 g_error ("transparent proxy support is disabled while trying to JIT code that uses it");
4835 #endif
4836         }
4837
4838         MONO_START_BB (cfg, false_bb);
4839
4840         MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4841         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4842
4843 #ifndef DISABLE_REMOTING
4844         MONO_START_BB (cfg, false2_bb);
4845
4846         MONO_EMIT_NEW_ICONST (cfg, dreg, 2);
4847         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4848 #endif
4849
4850         MONO_START_BB (cfg, true_bb);
4851
4852         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
4853
4854         MONO_START_BB (cfg, end_bb);
4855
4856         /* FIXME: */
4857         MONO_INST_NEW (cfg, ins, OP_ICONST);
4858         ins->dreg = dreg;
4859         ins->type = STACK_I4;
4860
4861         return ins;
4862 }
4863
4864 static MonoInst*
4865 handle_ccastclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
4866 {
4867         /* This opcode takes as input an object reference and a class, and returns:
4868         0) if the object is an instance of the class,
4869         1) if the object is a proxy whose type cannot be determined
4870         an InvalidCastException exception is thrown otherwhise*/
4871         
4872         MonoInst *ins;
4873 #ifndef DISABLE_REMOTING
4874         MonoBasicBlock *end_bb, *ok_result_bb, *no_proxy_bb, *interface_fail_bb, *fail_1_bb;
4875 #else
4876         MonoBasicBlock *ok_result_bb;
4877 #endif
4878         int obj_reg = src->dreg;
4879         int dreg = alloc_ireg (cfg);
4880         int tmp_reg = alloc_preg (cfg);
4881
4882 #ifndef DISABLE_REMOTING
4883         int klass_reg = alloc_preg (cfg);
4884         NEW_BBLOCK (cfg, end_bb);
4885 #endif
4886
4887         NEW_BBLOCK (cfg, ok_result_bb);
4888
4889         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4890         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, ok_result_bb);
4891
4892         save_cast_details (cfg, klass, obj_reg, FALSE);
4893
4894         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4895 #ifndef DISABLE_REMOTING
4896                 NEW_BBLOCK (cfg, interface_fail_bb);
4897         
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, interface_fail_bb, ok_result_bb);
4900                 MONO_START_BB (cfg, interface_fail_bb);
4901                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4902
4903                 mini_emit_class_check (cfg, klass_reg, mono_defaults.transparent_proxy_class);
4904
4905                 tmp_reg = alloc_preg (cfg);             
4906                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4907                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4908                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
4909                 
4910                 MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4911                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4912 #else
4913                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4914                 mini_emit_iface_cast (cfg, tmp_reg, klass, NULL, NULL);
4915                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, ok_result_bb);
4916 #endif
4917         } else {
4918 #ifndef DISABLE_REMOTING
4919                 NEW_BBLOCK (cfg, no_proxy_bb);
4920
4921                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4922                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4923                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, no_proxy_bb);          
4924
4925                 tmp_reg = alloc_preg (cfg);
4926                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, remote_class));
4927                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoRemoteClass, proxy_class));
4928
4929                 tmp_reg = alloc_preg (cfg);
4930                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4931                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4932                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, no_proxy_bb);
4933
4934                 NEW_BBLOCK (cfg, fail_1_bb);
4935                 
4936                 mini_emit_isninst_cast (cfg, klass_reg, klass, fail_1_bb, ok_result_bb);
4937
4938                 MONO_START_BB (cfg, fail_1_bb);
4939
4940                 MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4941                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4942
4943                 MONO_START_BB (cfg, no_proxy_bb);
4944
4945                 mini_emit_castclass (cfg, obj_reg, klass_reg, klass, ok_result_bb);
4946 #else
4947                 g_error ("Transparent proxy support is disabled while trying to JIT code that uses it");
4948 #endif
4949         }
4950
4951         MONO_START_BB (cfg, ok_result_bb);
4952
4953         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
4954
4955 #ifndef DISABLE_REMOTING
4956         MONO_START_BB (cfg, end_bb);
4957 #endif
4958
4959         /* FIXME: */
4960         MONO_INST_NEW (cfg, ins, OP_ICONST);
4961         ins->dreg = dreg;
4962         ins->type = STACK_I4;
4963
4964         return ins;
4965 }
4966
4967 static G_GNUC_UNUSED MonoInst*
4968 handle_enum_has_flag (MonoCompile *cfg, MonoClass *klass, MonoInst *enum_this, MonoInst *enum_flag)
4969 {
4970         MonoType *enum_type = mono_type_get_underlying_type (&klass->byval_arg);
4971         guint32 load_opc = mono_type_to_load_membase (cfg, enum_type);
4972         gboolean is_i4;
4973
4974         switch (enum_type->type) {
4975         case MONO_TYPE_I8:
4976         case MONO_TYPE_U8:
4977 #if SIZEOF_REGISTER == 8
4978         case MONO_TYPE_I:
4979         case MONO_TYPE_U:
4980 #endif
4981                 is_i4 = FALSE;
4982                 break;
4983         default:
4984                 is_i4 = TRUE;
4985                 break;
4986         }
4987
4988         {
4989                 MonoInst *load, *and_, *cmp, *ceq;
4990                 int enum_reg = is_i4 ? alloc_ireg (cfg) : alloc_lreg (cfg);
4991                 int and_reg = is_i4 ? alloc_ireg (cfg) : alloc_lreg (cfg);
4992                 int dest_reg = alloc_ireg (cfg);
4993
4994                 EMIT_NEW_LOAD_MEMBASE (cfg, load, load_opc, enum_reg, enum_this->dreg, 0);
4995                 EMIT_NEW_BIALU (cfg, and_, is_i4 ? OP_IAND : OP_LAND, and_reg, enum_reg, enum_flag->dreg);
4996                 EMIT_NEW_BIALU (cfg, cmp, is_i4 ? OP_ICOMPARE : OP_LCOMPARE, -1, and_reg, enum_flag->dreg);
4997                 EMIT_NEW_UNALU (cfg, ceq, is_i4 ? OP_ICEQ : OP_LCEQ, dest_reg, -1);
4998
4999                 ceq->type = STACK_I4;
5000
5001                 if (!is_i4) {
5002                         load = mono_decompose_opcode (cfg, load);
5003                         and_ = mono_decompose_opcode (cfg, and_);
5004                         cmp = mono_decompose_opcode (cfg, cmp);
5005                         ceq = mono_decompose_opcode (cfg, ceq);
5006                 }
5007
5008                 return ceq;
5009         }
5010 }
5011
5012 /*
5013  * Returns NULL and set the cfg exception on error.
5014  */
5015 static G_GNUC_UNUSED MonoInst*
5016 handle_delegate_ctor (MonoCompile *cfg, MonoClass *klass, MonoInst *target, MonoMethod *method, int context_used, gboolean virtual_)
5017 {
5018         MonoInst *ptr;
5019         int dreg;
5020         gpointer trampoline;
5021         MonoInst *obj, *method_ins, *tramp_ins;
5022         MonoDomain *domain;
5023         guint8 **code_slot;
5024
5025         if (virtual_ && !cfg->llvm_only) {
5026                 MonoMethod *invoke = mono_get_delegate_invoke (klass);
5027                 g_assert (invoke);
5028
5029                 if (!mono_get_delegate_virtual_invoke_impl (mono_method_signature (invoke), context_used ? NULL : method))
5030                         return NULL;
5031         }
5032
5033         obj = handle_alloc (cfg, klass, FALSE, mono_class_check_context_used (klass));
5034         if (!obj)
5035                 return NULL;
5036
5037         /* Inline the contents of mono_delegate_ctor */
5038
5039         /* Set target field */
5040         /* Optimize away setting of NULL target */
5041         if (!(target->opcode == OP_PCONST && target->inst_p0 == 0)) {
5042                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, target), target->dreg);
5043                 if (cfg->gen_write_barriers) {
5044                         dreg = alloc_preg (cfg);
5045                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, target));
5046                         emit_write_barrier (cfg, ptr, target);
5047                 }
5048         }
5049
5050         /* Set method field */
5051         method_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD);
5052         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method), method_ins->dreg);
5053
5054         /* 
5055          * To avoid looking up the compiled code belonging to the target method
5056          * in mono_delegate_trampoline (), we allocate a per-domain memory slot to
5057          * store it, and we fill it after the method has been compiled.
5058          */
5059         if (!method->dynamic && !(cfg->opt & MONO_OPT_SHARED)) {
5060                 MonoInst *code_slot_ins;
5061
5062                 if (context_used) {
5063                         code_slot_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD_DELEGATE_CODE);
5064                 } else {
5065                         domain = mono_domain_get ();
5066                         mono_domain_lock (domain);
5067                         if (!domain_jit_info (domain)->method_code_hash)
5068                                 domain_jit_info (domain)->method_code_hash = g_hash_table_new (NULL, NULL);
5069                         code_slot = (guint8 **)g_hash_table_lookup (domain_jit_info (domain)->method_code_hash, method);
5070                         if (!code_slot) {
5071                                 code_slot = (guint8 **)mono_domain_alloc0 (domain, sizeof (gpointer));
5072                                 g_hash_table_insert (domain_jit_info (domain)->method_code_hash, method, code_slot);
5073                         }
5074                         mono_domain_unlock (domain);
5075
5076                         code_slot_ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_METHOD_CODE_SLOT, method);
5077                 }
5078                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_code), code_slot_ins->dreg);                
5079         }
5080
5081         if (cfg->llvm_only) {
5082                 MonoInst *args [16];
5083
5084                 if (virtual_) {
5085                         args [0] = obj;
5086                         args [1] = target;
5087                         args [2] = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD);
5088                         mono_emit_jit_icall (cfg, mono_llvmonly_init_delegate_virtual, args);
5089                 } else {
5090                         args [0] = obj;
5091                         mono_emit_jit_icall (cfg, mono_llvmonly_init_delegate, args);
5092                 }
5093
5094                 return obj;
5095         }
5096
5097         if (cfg->compile_aot) {
5098                 MonoDelegateClassMethodPair *del_tramp;
5099
5100                 del_tramp = (MonoDelegateClassMethodPair *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoDelegateClassMethodPair));
5101                 del_tramp->klass = klass;
5102                 del_tramp->method = context_used ? NULL : method;
5103                 del_tramp->is_virtual = virtual_;
5104                 EMIT_NEW_AOTCONST (cfg, tramp_ins, MONO_PATCH_INFO_DELEGATE_TRAMPOLINE, del_tramp);
5105         } else {
5106                 if (virtual_)
5107                         trampoline = mono_create_delegate_virtual_trampoline (cfg->domain, klass, context_used ? NULL : method);
5108                 else
5109                         trampoline = mono_create_delegate_trampoline_info (cfg->domain, klass, context_used ? NULL : method);
5110                 EMIT_NEW_PCONST (cfg, tramp_ins, trampoline);
5111         }
5112
5113         /* Set invoke_impl field */
5114         if (virtual_) {
5115                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl), tramp_ins->dreg);
5116         } else {
5117                 dreg = alloc_preg (cfg);
5118                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, tramp_ins->dreg, MONO_STRUCT_OFFSET (MonoDelegateTrampInfo, invoke_impl));
5119                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl), dreg);
5120
5121                 dreg = alloc_preg (cfg);
5122                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, tramp_ins->dreg, MONO_STRUCT_OFFSET (MonoDelegateTrampInfo, method_ptr));
5123                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr), dreg);
5124         }
5125
5126         dreg = alloc_preg (cfg);
5127         MONO_EMIT_NEW_ICONST (cfg, dreg, virtual_ ? 1 : 0);
5128         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_is_virtual), dreg);
5129
5130         /* All the checks which are in mono_delegate_ctor () are done by the delegate trampoline */
5131
5132         return obj;
5133 }
5134
5135 static MonoInst*
5136 handle_array_new (MonoCompile *cfg, int rank, MonoInst **sp, unsigned char *ip)
5137 {
5138         MonoJitICallInfo *info;
5139
5140         /* Need to register the icall so it gets an icall wrapper */
5141         info = mono_get_array_new_va_icall (rank);
5142
5143         cfg->flags |= MONO_CFG_HAS_VARARGS;
5144
5145         /* mono_array_new_va () needs a vararg calling convention */
5146         cfg->exception_message = g_strdup ("array-new");
5147         cfg->disable_llvm = TRUE;
5148
5149         /* FIXME: This uses info->sig, but it should use the signature of the wrapper */
5150         return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, sp);
5151 }
5152
5153 /*
5154  * handle_constrained_gsharedvt_call:
5155  *
5156  *   Handle constrained calls where the receiver is a gsharedvt type.
5157  * Return the instruction representing the call. Set the cfg exception on failure.
5158  */
5159 static MonoInst*
5160 handle_constrained_gsharedvt_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp, MonoClass *constrained_class,
5161                                                                    gboolean *ref_emit_widen)
5162 {
5163         MonoInst *ins = NULL;
5164         gboolean emit_widen = *ref_emit_widen;
5165
5166         /*
5167          * Constrained calls need to behave differently at runtime dependending on whenever the receiver is instantiated as ref type or as a vtype.
5168          * 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
5169          * pack the arguments into an array, and do the rest of the work in in an icall.
5170          */
5171         if (((cmethod->klass == mono_defaults.object_class) || (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) || (!cmethod->klass->valuetype && cmethod->klass->image != mono_defaults.corlib)) &&
5172                 (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)) &&
5173                 (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]))))) {
5174                 MonoInst *args [16];
5175
5176                 /*
5177                  * This case handles calls to
5178                  * - object:ToString()/Equals()/GetHashCode(),
5179                  * - System.IComparable<T>:CompareTo()
5180                  * - System.IEquatable<T>:Equals ()
5181                  * plus some simple interface calls enough to support AsyncTaskMethodBuilder.
5182                  */
5183
5184                 args [0] = sp [0];
5185                 if (mono_method_check_context_used (cmethod))
5186                         args [1] = emit_get_rgctx_method (cfg, mono_method_check_context_used (cmethod), cmethod, MONO_RGCTX_INFO_METHOD);
5187                 else
5188                         EMIT_NEW_METHODCONST (cfg, args [1], cmethod);
5189                 args [2] = emit_get_rgctx_klass (cfg, mono_class_check_context_used (constrained_class), constrained_class, MONO_RGCTX_INFO_KLASS);
5190
5191                 /* !fsig->hasthis is for the wrapper for the Object.GetType () icall */
5192                 if (fsig->hasthis && fsig->param_count) {
5193                         /* Pass the arguments using a localloc-ed array using the format expected by runtime_invoke () */
5194                         MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
5195                         ins->dreg = alloc_preg (cfg);
5196                         ins->inst_imm = fsig->param_count * sizeof (mgreg_t);
5197                         MONO_ADD_INS (cfg->cbb, ins);
5198                         args [4] = ins;
5199
5200                         if (mini_is_gsharedvt_type (fsig->params [0])) {
5201                                 int addr_reg, deref_arg_reg;
5202
5203                                 ins = emit_get_gsharedvt_info_klass (cfg, mono_class_from_mono_type (fsig->params [0]), MONO_RGCTX_INFO_CLASS_BOX_TYPE);
5204                                 deref_arg_reg = alloc_preg (cfg);
5205                                 /* deref_arg = BOX_TYPE != MONO_GSHAREDVT_BOX_TYPE_VTYPE */
5206                                 EMIT_NEW_BIALU_IMM (cfg, args [3], OP_ISUB_IMM, deref_arg_reg, ins->dreg, 1);
5207
5208                                 EMIT_NEW_VARLOADA_VREG (cfg, ins, sp [1]->dreg, fsig->params [0]);
5209                                 addr_reg = ins->dreg;
5210                                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [4]->dreg, 0, addr_reg);
5211                         } else {
5212                                 EMIT_NEW_ICONST (cfg, args [3], 0);
5213                                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [4]->dreg, 0, sp [1]->dreg);
5214                         }
5215                 } else {
5216                         EMIT_NEW_ICONST (cfg, args [3], 0);
5217                         EMIT_NEW_ICONST (cfg, args [4], 0);
5218                 }
5219                 ins = mono_emit_jit_icall (cfg, mono_gsharedvt_constrained_call, args);
5220                 emit_widen = FALSE;
5221
5222                 if (mini_is_gsharedvt_type (fsig->ret)) {
5223                         ins = handle_unbox_gsharedvt (cfg, mono_class_from_mono_type (fsig->ret), ins);
5224                 } else if (MONO_TYPE_IS_PRIMITIVE (fsig->ret) || MONO_TYPE_ISSTRUCT (fsig->ret)) {
5225                         MonoInst *add;
5226
5227                         /* Unbox */
5228                         NEW_BIALU_IMM (cfg, add, OP_ADD_IMM, alloc_dreg (cfg, STACK_MP), ins->dreg, sizeof (MonoObject));
5229                         MONO_ADD_INS (cfg->cbb, add);
5230                         /* Load value */
5231                         NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, add->dreg, 0);
5232                         MONO_ADD_INS (cfg->cbb, ins);
5233                         /* ins represents the call result */
5234                 }
5235         } else {
5236                 GSHAREDVT_FAILURE (CEE_CALLVIRT);
5237         }
5238
5239         *ref_emit_widen = emit_widen;
5240
5241         return ins;
5242
5243  exception_exit:
5244         return NULL;
5245 }
5246
5247 static void
5248 mono_emit_load_got_addr (MonoCompile *cfg)
5249 {
5250         MonoInst *getaddr, *dummy_use;
5251
5252         if (!cfg->got_var || cfg->got_var_allocated)
5253                 return;
5254
5255         MONO_INST_NEW (cfg, getaddr, OP_LOAD_GOTADDR);
5256         getaddr->cil_code = cfg->header->code;
5257         getaddr->dreg = cfg->got_var->dreg;
5258
5259         /* Add it to the start of the first bblock */
5260         if (cfg->bb_entry->code) {
5261                 getaddr->next = cfg->bb_entry->code;
5262                 cfg->bb_entry->code = getaddr;
5263         }
5264         else
5265                 MONO_ADD_INS (cfg->bb_entry, getaddr);
5266
5267         cfg->got_var_allocated = TRUE;
5268
5269         /* 
5270          * Add a dummy use to keep the got_var alive, since real uses might
5271          * only be generated by the back ends.
5272          * Add it to end_bblock, so the variable's lifetime covers the whole
5273          * method.
5274          * It would be better to make the usage of the got var explicit in all
5275          * cases when the backend needs it (i.e. calls, throw etc.), so this
5276          * wouldn't be needed.
5277          */
5278         NEW_DUMMY_USE (cfg, dummy_use, cfg->got_var);
5279         MONO_ADD_INS (cfg->bb_exit, dummy_use);
5280 }
5281
5282 static int inline_limit;
5283 static gboolean inline_limit_inited;
5284
5285 static gboolean
5286 mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method)
5287 {
5288         MonoMethodHeaderSummary header;
5289         MonoVTable *vtable;
5290 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
5291         MonoMethodSignature *sig = mono_method_signature (method);
5292         int i;
5293 #endif
5294
5295         if (cfg->disable_inline)
5296                 return FALSE;
5297         if (cfg->gshared)
5298                 return FALSE;
5299
5300         if (cfg->inline_depth > 10)
5301                 return FALSE;
5302
5303         if (!mono_method_get_header_summary (method, &header))
5304                 return FALSE;
5305
5306         /*runtime, icall and pinvoke are checked by summary call*/
5307         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_NOINLINING) ||
5308             (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) ||
5309             (mono_class_is_marshalbyref (method->klass)) ||
5310             header.has_clauses)
5311                 return FALSE;
5312
5313         /* also consider num_locals? */
5314         /* Do the size check early to avoid creating vtables */
5315         if (!inline_limit_inited) {
5316                 if (g_getenv ("MONO_INLINELIMIT"))
5317                         inline_limit = atoi (g_getenv ("MONO_INLINELIMIT"));
5318                 else
5319                         inline_limit = INLINE_LENGTH_LIMIT;
5320                 inline_limit_inited = TRUE;
5321         }
5322         if (header.code_size >= inline_limit && !(method->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING))
5323                 return FALSE;
5324
5325         /*
5326          * if we can initialize the class of the method right away, we do,
5327          * otherwise we don't allow inlining if the class needs initialization,
5328          * since it would mean inserting a call to mono_runtime_class_init()
5329          * inside the inlined code
5330          */
5331         if (!(cfg->opt & MONO_OPT_SHARED)) {
5332                 /* The AggressiveInlining hint is a good excuse to force that cctor to run. */
5333                 if (method->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING) {
5334                         vtable = mono_class_vtable (cfg->domain, method->klass);
5335                         if (!vtable)
5336                                 return FALSE;
5337                         if (!cfg->compile_aot)
5338                                 mono_runtime_class_init (vtable);
5339                 } else if (method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) {
5340                         if (cfg->run_cctors && method->klass->has_cctor) {
5341                                 /*FIXME it would easier and lazier to just use mono_class_try_get_vtable */
5342                                 if (!method->klass->runtime_info)
5343                                         /* No vtable created yet */
5344                                         return FALSE;
5345                                 vtable = mono_class_vtable (cfg->domain, method->klass);
5346                                 if (!vtable)
5347                                         return FALSE;
5348                                 /* This makes so that inline cannot trigger */
5349                                 /* .cctors: too many apps depend on them */
5350                                 /* running with a specific order... */
5351                                 if (! vtable->initialized)
5352                                         return FALSE;
5353                                 mono_runtime_class_init (vtable);
5354                         }
5355                 } else if (mono_class_needs_cctor_run (method->klass, NULL)) {
5356                         if (!method->klass->runtime_info)
5357                                 /* No vtable created yet */
5358                                 return FALSE;
5359                         vtable = mono_class_vtable (cfg->domain, method->klass);
5360                         if (!vtable)
5361                                 return FALSE;
5362                         if (!vtable->initialized)
5363                                 return FALSE;
5364                 }
5365         } else {
5366                 /* 
5367                  * If we're compiling for shared code
5368                  * the cctor will need to be run at aot method load time, for example,
5369                  * or at the end of the compilation of the inlining method.
5370                  */
5371                 if (mono_class_needs_cctor_run (method->klass, NULL) && !((method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT)))
5372                         return FALSE;
5373         }
5374
5375 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
5376         if (mono_arch_is_soft_float ()) {
5377                 /* FIXME: */
5378                 if (sig->ret && sig->ret->type == MONO_TYPE_R4)
5379                         return FALSE;
5380                 for (i = 0; i < sig->param_count; ++i)
5381                         if (!sig->params [i]->byref && sig->params [i]->type == MONO_TYPE_R4)
5382                                 return FALSE;
5383         }
5384 #endif
5385
5386         if (g_list_find (cfg->dont_inline, method))
5387                 return FALSE;
5388
5389         return TRUE;
5390 }
5391
5392 static gboolean
5393 mini_field_access_needs_cctor_run (MonoCompile *cfg, MonoMethod *method, MonoClass *klass, MonoVTable *vtable)
5394 {
5395         if (!cfg->compile_aot) {
5396                 g_assert (vtable);
5397                 if (vtable->initialized)
5398                         return FALSE;
5399         }
5400
5401         if (klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) {
5402                 if (cfg->method == method)
5403                         return FALSE;
5404         }
5405
5406         if (!mono_class_needs_cctor_run (klass, method))
5407                 return FALSE;
5408
5409         if (! (method->flags & METHOD_ATTRIBUTE_STATIC) && (klass == method->klass))
5410                 /* The initialization is already done before the method is called */
5411                 return FALSE;
5412
5413         return TRUE;
5414 }
5415
5416 static MonoInst*
5417 mini_emit_ldelema_1_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index, gboolean bcheck)
5418 {
5419         MonoInst *ins;
5420         guint32 size;
5421         int mult_reg, add_reg, array_reg, index_reg, index2_reg;
5422         int context_used;
5423
5424         if (mini_is_gsharedvt_variable_klass (klass)) {
5425                 size = -1;
5426         } else {
5427                 mono_class_init (klass);
5428                 size = mono_class_array_element_size (klass);
5429         }
5430
5431         mult_reg = alloc_preg (cfg);
5432         array_reg = arr->dreg;
5433         index_reg = index->dreg;
5434
5435 #if SIZEOF_REGISTER == 8
5436         /* The array reg is 64 bits but the index reg is only 32 */
5437         if (COMPILE_LLVM (cfg)) {
5438                 /* Not needed */
5439                 index2_reg = index_reg;
5440         } else {
5441                 index2_reg = alloc_preg (cfg);
5442                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index2_reg, index_reg);
5443         }
5444 #else
5445         if (index->type == STACK_I8) {
5446                 index2_reg = alloc_preg (cfg);
5447                 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I4, index2_reg, index_reg);
5448         } else {
5449                 index2_reg = index_reg;
5450         }
5451 #endif
5452
5453         if (bcheck)
5454                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index2_reg);
5455
5456 #if defined(TARGET_X86) || defined(TARGET_AMD64)
5457         if (size == 1 || size == 2 || size == 4 || size == 8) {
5458                 static const int fast_log2 [] = { 1, 0, 1, -1, 2, -1, -1, -1, 3 };
5459
5460                 EMIT_NEW_X86_LEA (cfg, ins, array_reg, index2_reg, fast_log2 [size], MONO_STRUCT_OFFSET (MonoArray, vector));
5461                 ins->klass = mono_class_get_element_class (klass);
5462                 ins->type = STACK_MP;
5463
5464                 return ins;
5465         }
5466 #endif          
5467
5468         add_reg = alloc_ireg_mp (cfg);
5469
5470         if (size == -1) {
5471                 MonoInst *rgctx_ins;
5472
5473                 /* gsharedvt */
5474                 g_assert (cfg->gshared);
5475                 context_used = mini_class_check_context_used (cfg, klass);
5476                 g_assert (context_used);
5477                 rgctx_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE);
5478                 MONO_EMIT_NEW_BIALU (cfg, OP_IMUL, mult_reg, index2_reg, rgctx_ins->dreg);
5479         } else {
5480                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MUL_IMM, mult_reg, index2_reg, size);
5481         }
5482         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, array_reg, mult_reg);
5483         NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, MONO_STRUCT_OFFSET (MonoArray, vector));
5484         ins->klass = mono_class_get_element_class (klass);
5485         ins->type = STACK_MP;
5486         MONO_ADD_INS (cfg->cbb, ins);
5487
5488         return ins;
5489 }
5490
5491 static MonoInst*
5492 mini_emit_ldelema_2_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index_ins1, MonoInst *index_ins2)
5493 {
5494         int bounds_reg = alloc_preg (cfg);
5495         int add_reg = alloc_ireg_mp (cfg);
5496         int mult_reg = alloc_preg (cfg);
5497         int mult2_reg = alloc_preg (cfg);
5498         int low1_reg = alloc_preg (cfg);
5499         int low2_reg = alloc_preg (cfg);
5500         int high1_reg = alloc_preg (cfg);
5501         int high2_reg = alloc_preg (cfg);
5502         int realidx1_reg = alloc_preg (cfg);
5503         int realidx2_reg = alloc_preg (cfg);
5504         int sum_reg = alloc_preg (cfg);
5505         int index1, index2, tmpreg;
5506         MonoInst *ins;
5507         guint32 size;
5508
5509         mono_class_init (klass);
5510         size = mono_class_array_element_size (klass);
5511
5512         index1 = index_ins1->dreg;
5513         index2 = index_ins2->dreg;
5514
5515 #if SIZEOF_REGISTER == 8
5516         /* The array reg is 64 bits but the index reg is only 32 */
5517         if (COMPILE_LLVM (cfg)) {
5518                 /* Not needed */
5519         } else {
5520                 tmpreg = alloc_preg (cfg);
5521                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, tmpreg, index1);
5522                 index1 = tmpreg;
5523                 tmpreg = alloc_preg (cfg);
5524                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, tmpreg, index2);
5525                 index2 = tmpreg;
5526         }
5527 #else
5528         // FIXME: Do we need to do something here for i8 indexes, like in ldelema_1_ins ?
5529         tmpreg = -1;
5530 #endif
5531
5532         /* range checking */
5533         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, 
5534                                        arr->dreg, MONO_STRUCT_OFFSET (MonoArray, bounds));
5535
5536         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low1_reg, 
5537                                        bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
5538         MONO_EMIT_NEW_BIALU (cfg, OP_PSUB, realidx1_reg, index1, low1_reg);
5539         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high1_reg, 
5540                                        bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, length));
5541         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, high1_reg, realidx1_reg);
5542         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException");
5543
5544         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low2_reg, 
5545                                        bounds_reg, sizeof (MonoArrayBounds) + MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
5546         MONO_EMIT_NEW_BIALU (cfg, OP_PSUB, realidx2_reg, index2, low2_reg);
5547         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high2_reg, 
5548                                        bounds_reg, sizeof (MonoArrayBounds) + MONO_STRUCT_OFFSET (MonoArrayBounds, length));
5549         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, high2_reg, realidx2_reg);
5550         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException");
5551
5552         MONO_EMIT_NEW_BIALU (cfg, OP_PMUL, mult_reg, high2_reg, realidx1_reg);
5553         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, mult_reg, realidx2_reg);
5554         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PMUL_IMM, mult2_reg, sum_reg, size);
5555         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult2_reg, arr->dreg);
5556         NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, MONO_STRUCT_OFFSET (MonoArray, vector));
5557
5558         ins->type = STACK_MP;
5559         ins->klass = klass;
5560         MONO_ADD_INS (cfg->cbb, ins);
5561
5562         return ins;
5563 }
5564
5565 static MonoInst*
5566 mini_emit_ldelema_ins (MonoCompile *cfg, MonoMethod *cmethod, MonoInst **sp, unsigned char *ip, gboolean is_set)
5567 {
5568         int rank;
5569         MonoInst *addr;
5570         MonoMethod *addr_method;
5571         int element_size;
5572         MonoClass *eclass = cmethod->klass->element_class;
5573
5574         rank = mono_method_signature (cmethod)->param_count - (is_set? 1: 0);
5575
5576         if (rank == 1)
5577                 return mini_emit_ldelema_1_ins (cfg, eclass, sp [0], sp [1], TRUE);
5578
5579         /* emit_ldelema_2 depends on OP_LMUL */
5580         if (!cfg->backend->emulate_mul_div && rank == 2 && (cfg->opt & MONO_OPT_INTRINS) && !mini_is_gsharedvt_variable_klass (eclass)) {
5581                 return mini_emit_ldelema_2_ins (cfg, eclass, sp [0], sp [1], sp [2]);
5582         }
5583
5584         if (mini_is_gsharedvt_variable_klass (eclass))
5585                 element_size = 0;
5586         else
5587                 element_size = mono_class_array_element_size (eclass);
5588         addr_method = mono_marshal_get_array_address (rank, element_size);
5589         addr = mono_emit_method_call (cfg, addr_method, sp, NULL);
5590
5591         return addr;
5592 }
5593
5594 static MonoBreakPolicy
5595 always_insert_breakpoint (MonoMethod *method)
5596 {
5597         return MONO_BREAK_POLICY_ALWAYS;
5598 }
5599
5600 static MonoBreakPolicyFunc break_policy_func = always_insert_breakpoint;
5601
5602 /**
5603  * mono_set_break_policy:
5604  * policy_callback: the new callback function
5605  *
5606  * Allow embedders to decide wherther to actually obey breakpoint instructions
5607  * (both break IL instructions and Debugger.Break () method calls), for example
5608  * to not allow an app to be aborted by a perfectly valid IL opcode when executing
5609  * untrusted or semi-trusted code.
5610  *
5611  * @policy_callback will be called every time a break point instruction needs to
5612  * be inserted with the method argument being the method that calls Debugger.Break()
5613  * or has the IL break instruction. The callback should return #MONO_BREAK_POLICY_NEVER
5614  * if it wants the breakpoint to not be effective in the given method.
5615  * #MONO_BREAK_POLICY_ALWAYS is the default.
5616  */
5617 void
5618 mono_set_break_policy (MonoBreakPolicyFunc policy_callback)
5619 {
5620         if (policy_callback)
5621                 break_policy_func = policy_callback;
5622         else
5623                 break_policy_func = always_insert_breakpoint;
5624 }
5625
5626 static gboolean
5627 should_insert_brekpoint (MonoMethod *method) {
5628         switch (break_policy_func (method)) {
5629         case MONO_BREAK_POLICY_ALWAYS:
5630                 return TRUE;
5631         case MONO_BREAK_POLICY_NEVER:
5632                 return FALSE;
5633         case MONO_BREAK_POLICY_ON_DBG:
5634                 g_warning ("mdb no longer supported");
5635                 return FALSE;
5636         default:
5637                 g_warning ("Incorrect value returned from break policy callback");
5638                 return FALSE;
5639         }
5640 }
5641
5642 /* optimize the simple GetGenericValueImpl/SetGenericValueImpl generic icalls */
5643 static MonoInst*
5644 emit_array_generic_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set)
5645 {
5646         MonoInst *addr, *store, *load;
5647         MonoClass *eklass = mono_class_from_mono_type (fsig->params [2]);
5648
5649         /* the bounds check is already done by the callers */
5650         addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1], FALSE);
5651         if (is_set) {
5652                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, args [2]->dreg, 0);
5653                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, addr->dreg, 0, load->dreg);
5654                 if (mini_type_is_reference (fsig->params [2]))
5655                         emit_write_barrier (cfg, addr, load);
5656         } else {
5657                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, addr->dreg, 0);
5658                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, args [2]->dreg, 0, load->dreg);
5659         }
5660         return store;
5661 }
5662
5663
5664 static gboolean
5665 generic_class_is_reference_type (MonoCompile *cfg, MonoClass *klass)
5666 {
5667         return mini_type_is_reference (&klass->byval_arg);
5668 }
5669
5670 static MonoInst*
5671 emit_array_store (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, gboolean safety_checks)
5672 {
5673         if (safety_checks && generic_class_is_reference_type (cfg, klass) &&
5674                 !(sp [2]->opcode == OP_PCONST && sp [2]->inst_p0 == NULL)) {
5675                 MonoClass *obj_array = mono_array_class_get_cached (mono_defaults.object_class, 1);
5676                 MonoMethod *helper = mono_marshal_get_virtual_stelemref (obj_array);
5677                 MonoInst *iargs [3];
5678
5679                 if (!helper->slot)
5680                         mono_class_setup_vtable (obj_array);
5681                 g_assert (helper->slot);
5682
5683                 if (sp [0]->type != STACK_OBJ)
5684                         return NULL;
5685                 if (sp [2]->type != STACK_OBJ)
5686                         return NULL;
5687
5688                 iargs [2] = sp [2];
5689                 iargs [1] = sp [1];
5690                 iargs [0] = sp [0];
5691
5692                 return mono_emit_method_call (cfg, helper, iargs, sp [0]);
5693         } else {
5694                 MonoInst *ins;
5695
5696                 if (mini_is_gsharedvt_variable_klass (klass)) {
5697                         MonoInst *addr;
5698
5699                         // FIXME-VT: OP_ICONST optimization
5700                         addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
5701                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
5702                         ins->opcode = OP_STOREV_MEMBASE;
5703                 } else if (sp [1]->opcode == OP_ICONST) {
5704                         int array_reg = sp [0]->dreg;
5705                         int index_reg = sp [1]->dreg;
5706                         int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + MONO_STRUCT_OFFSET (MonoArray, vector);
5707
5708                         if (SIZEOF_REGISTER == 8 && COMPILE_LLVM (cfg))
5709                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, index_reg, index_reg);
5710
5711                         if (safety_checks)
5712                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
5713                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset, sp [2]->dreg);
5714                 } else {
5715                         MonoInst *addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], safety_checks);
5716                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
5717                         if (generic_class_is_reference_type (cfg, klass))
5718                                 emit_write_barrier (cfg, addr, sp [2]);
5719                 }
5720                 return ins;
5721         }
5722 }
5723
5724 static MonoInst*
5725 emit_array_unsafe_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set)
5726 {
5727         MonoClass *eklass;
5728         
5729         if (is_set)
5730                 eklass = mono_class_from_mono_type (fsig->params [2]);
5731         else
5732                 eklass = mono_class_from_mono_type (fsig->ret);
5733
5734         if (is_set) {
5735                 return emit_array_store (cfg, eklass, args, FALSE);
5736         } else {
5737                 MonoInst *ins, *addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1], FALSE);
5738                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &eklass->byval_arg, addr->dreg, 0);
5739                 return ins;
5740         }
5741 }
5742
5743 static gboolean
5744 is_unsafe_mov_compatible (MonoCompile *cfg, MonoClass *param_klass, MonoClass *return_klass)
5745 {
5746         uint32_t align;
5747         int param_size, return_size;
5748
5749         param_klass = mono_class_from_mono_type (mini_get_underlying_type (&param_klass->byval_arg));
5750         return_klass = mono_class_from_mono_type (mini_get_underlying_type (&return_klass->byval_arg));
5751
5752         if (cfg->verbose_level > 3)
5753                 printf ("[UNSAFE-MOV-INTRISIC] %s <- %s\n", return_klass->name, param_klass->name);
5754
5755         //Don't allow mixing reference types with value types
5756         if (param_klass->valuetype != return_klass->valuetype) {
5757                 if (cfg->verbose_level > 3)
5758                         printf ("[UNSAFE-MOV-INTRISIC]\tone of the args is a valuetype and the other is not\n");
5759                 return FALSE;
5760         }
5761
5762         if (!param_klass->valuetype) {
5763                 if (cfg->verbose_level > 3)
5764                         printf ("[UNSAFE-MOV-INTRISIC]\targs are reference types\n");
5765                 return TRUE;
5766         }
5767
5768         //That are blitable
5769         if (param_klass->has_references || return_klass->has_references)
5770                 return FALSE;
5771
5772         /* Avoid mixing structs and primitive types/enums, they need to be handled differently in the JIT */
5773         if ((MONO_TYPE_ISSTRUCT (&param_klass->byval_arg) && !MONO_TYPE_ISSTRUCT (&return_klass->byval_arg)) ||
5774                 (!MONO_TYPE_ISSTRUCT (&param_klass->byval_arg) && MONO_TYPE_ISSTRUCT (&return_klass->byval_arg))) {
5775                         if (cfg->verbose_level > 3)
5776                                 printf ("[UNSAFE-MOV-INTRISIC]\tmixing structs and scalars\n");
5777                 return FALSE;
5778         }
5779
5780         if (param_klass->byval_arg.type == MONO_TYPE_R4 || param_klass->byval_arg.type == MONO_TYPE_R8 ||
5781                 return_klass->byval_arg.type == MONO_TYPE_R4 || return_klass->byval_arg.type == MONO_TYPE_R8) {
5782                 if (cfg->verbose_level > 3)
5783                         printf ("[UNSAFE-MOV-INTRISIC]\tfloat or double are not supported\n");
5784                 return FALSE;
5785         }
5786
5787         param_size = mono_class_value_size (param_klass, &align);
5788         return_size = mono_class_value_size (return_klass, &align);
5789
5790         //We can do it if sizes match
5791         if (param_size == return_size) {
5792                 if (cfg->verbose_level > 3)
5793                         printf ("[UNSAFE-MOV-INTRISIC]\tsame size\n");
5794                 return TRUE;
5795         }
5796
5797         //No simple way to handle struct if sizes don't match
5798         if (MONO_TYPE_ISSTRUCT (&param_klass->byval_arg)) {
5799                 if (cfg->verbose_level > 3)
5800                         printf ("[UNSAFE-MOV-INTRISIC]\tsize mismatch and type is a struct\n");
5801                 return FALSE;
5802         }
5803
5804         /*
5805          * Same reg size category.
5806          * A quick note on why we don't require widening here.
5807          * The intrinsic is "R Array.UnsafeMov<S,R> (S s)".
5808          *
5809          * Since the source value comes from a function argument, the JIT will already have
5810          * the value in a VREG and performed any widening needed before (say, when loading from a field).
5811          */
5812         if (param_size <= 4 && return_size <= 4) {
5813                 if (cfg->verbose_level > 3)
5814                         printf ("[UNSAFE-MOV-INTRISIC]\tsize mismatch but both are of the same reg class\n");
5815                 return TRUE;
5816         }
5817
5818         return FALSE;
5819 }
5820
5821 static MonoInst*
5822 emit_array_unsafe_mov (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args)
5823 {
5824         MonoClass *param_klass = mono_class_from_mono_type (fsig->params [0]);
5825         MonoClass *return_klass = mono_class_from_mono_type (fsig->ret);
5826
5827         if (mini_is_gsharedvt_variable_type (fsig->ret))
5828                 return NULL;
5829
5830         //Valuetypes that are semantically equivalent or numbers than can be widened to
5831         if (is_unsafe_mov_compatible (cfg, param_klass, return_klass))
5832                 return args [0];
5833
5834         //Arrays of valuetypes that are semantically equivalent
5835         if (param_klass->rank == 1 && return_klass->rank == 1 && is_unsafe_mov_compatible (cfg, param_klass->element_class, return_klass->element_class))
5836                 return args [0];
5837
5838         return NULL;
5839 }
5840
5841 static MonoInst*
5842 mini_emit_inst_for_ctor (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5843 {
5844 #ifdef MONO_ARCH_SIMD_INTRINSICS
5845         MonoInst *ins = NULL;
5846
5847         if (cfg->opt & MONO_OPT_SIMD) {
5848                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
5849                 if (ins)
5850                         return ins;
5851         }
5852 #endif
5853
5854         return mono_emit_native_types_intrinsics (cfg, cmethod, fsig, args);
5855 }
5856
5857 static MonoInst*
5858 emit_memory_barrier (MonoCompile *cfg, int kind)
5859 {
5860         MonoInst *ins = NULL;
5861         MONO_INST_NEW (cfg, ins, OP_MEMORY_BARRIER);
5862         MONO_ADD_INS (cfg->cbb, ins);
5863         ins->backend.memory_barrier_kind = kind;
5864
5865         return ins;
5866 }
5867
5868 static MonoInst*
5869 llvm_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5870 {
5871         MonoInst *ins = NULL;
5872         int opcode = 0;
5873
5874         /* The LLVM backend supports these intrinsics */
5875         if (cmethod->klass == mono_defaults.math_class) {
5876                 if (strcmp (cmethod->name, "Sin") == 0) {
5877                         opcode = OP_SIN;
5878                 } else if (strcmp (cmethod->name, "Cos") == 0) {
5879                         opcode = OP_COS;
5880                 } else if (strcmp (cmethod->name, "Sqrt") == 0) {
5881                         opcode = OP_SQRT;
5882                 } else if (strcmp (cmethod->name, "Abs") == 0 && fsig->params [0]->type == MONO_TYPE_R8) {
5883                         opcode = OP_ABS;
5884                 }
5885
5886                 if (opcode && fsig->param_count == 1) {
5887                         MONO_INST_NEW (cfg, ins, opcode);
5888                         ins->type = STACK_R8;
5889                         ins->dreg = mono_alloc_freg (cfg);
5890                         ins->sreg1 = args [0]->dreg;
5891                         MONO_ADD_INS (cfg->cbb, ins);
5892                 }
5893
5894                 opcode = 0;
5895                 if (cfg->opt & MONO_OPT_CMOV) {
5896                         if (strcmp (cmethod->name, "Min") == 0) {
5897                                 if (fsig->params [0]->type == MONO_TYPE_I4)
5898                                         opcode = OP_IMIN;
5899                                 if (fsig->params [0]->type == MONO_TYPE_U4)
5900                                         opcode = OP_IMIN_UN;
5901                                 else if (fsig->params [0]->type == MONO_TYPE_I8)
5902                                         opcode = OP_LMIN;
5903                                 else if (fsig->params [0]->type == MONO_TYPE_U8)
5904                                         opcode = OP_LMIN_UN;
5905                         } else if (strcmp (cmethod->name, "Max") == 0) {
5906                                 if (fsig->params [0]->type == MONO_TYPE_I4)
5907                                         opcode = OP_IMAX;
5908                                 if (fsig->params [0]->type == MONO_TYPE_U4)
5909                                         opcode = OP_IMAX_UN;
5910                                 else if (fsig->params [0]->type == MONO_TYPE_I8)
5911                                         opcode = OP_LMAX;
5912                                 else if (fsig->params [0]->type == MONO_TYPE_U8)
5913                                         opcode = OP_LMAX_UN;
5914                         }
5915                 }
5916
5917                 if (opcode && fsig->param_count == 2) {
5918                         MONO_INST_NEW (cfg, ins, opcode);
5919                         ins->type = fsig->params [0]->type == MONO_TYPE_I4 ? STACK_I4 : STACK_I8;
5920                         ins->dreg = mono_alloc_ireg (cfg);
5921                         ins->sreg1 = args [0]->dreg;
5922                         ins->sreg2 = args [1]->dreg;
5923                         MONO_ADD_INS (cfg->cbb, ins);
5924                 }
5925         }
5926
5927         return ins;
5928 }
5929
5930 static MonoInst*
5931 mini_emit_inst_for_sharable_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5932 {
5933         if (cmethod->klass == mono_defaults.array_class) {
5934                 if (strcmp (cmethod->name, "UnsafeStore") == 0)
5935                         return emit_array_unsafe_access (cfg, fsig, args, TRUE);
5936                 else if (strcmp (cmethod->name, "UnsafeLoad") == 0)
5937                         return emit_array_unsafe_access (cfg, fsig, args, FALSE);
5938                 else if (strcmp (cmethod->name, "UnsafeMov") == 0)
5939                         return emit_array_unsafe_mov (cfg, fsig, args);
5940         }
5941
5942         return NULL;
5943 }
5944
5945 static MonoInst*
5946 mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5947 {
5948         MonoInst *ins = NULL;
5949
5950         static MonoClass *runtime_helpers_class = NULL;
5951         if (! runtime_helpers_class)
5952                 runtime_helpers_class = mono_class_from_name (mono_defaults.corlib,
5953                         "System.Runtime.CompilerServices", "RuntimeHelpers");
5954
5955         if (cmethod->klass == mono_defaults.string_class) {
5956                 if (strcmp (cmethod->name, "get_Chars") == 0 && fsig->param_count + fsig->hasthis == 2) {
5957                         int dreg = alloc_ireg (cfg);
5958                         int index_reg = alloc_preg (cfg);
5959                         int add_reg = alloc_preg (cfg);
5960
5961 #if SIZEOF_REGISTER == 8
5962                         if (COMPILE_LLVM (cfg)) {
5963                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, index_reg, args [1]->dreg);
5964                         } else {
5965                                 /* The array reg is 64 bits but the index reg is only 32 */
5966                                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index_reg, args [1]->dreg);
5967                         }
5968 #else
5969                         index_reg = args [1]->dreg;
5970 #endif  
5971                         MONO_EMIT_BOUNDS_CHECK (cfg, args [0]->dreg, MonoString, length, index_reg);
5972
5973 #if defined(TARGET_X86) || defined(TARGET_AMD64)
5974                         EMIT_NEW_X86_LEA (cfg, ins, args [0]->dreg, index_reg, 1, MONO_STRUCT_OFFSET (MonoString, chars));
5975                         add_reg = ins->dreg;
5976                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
5977                                                                    add_reg, 0);
5978 #else
5979                         int mult_reg = alloc_preg (cfg);
5980                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, mult_reg, index_reg, 1);
5981                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult_reg, args [0]->dreg);
5982                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
5983                                                                    add_reg, MONO_STRUCT_OFFSET (MonoString, chars));
5984 #endif
5985                         type_from_op (cfg, ins, NULL, NULL);
5986                         return ins;
5987                 } else if (strcmp (cmethod->name, "get_Length") == 0 && fsig->param_count + fsig->hasthis == 1) {
5988                         int dreg = alloc_ireg (cfg);
5989                         /* Decompose later to allow more optimizations */
5990                         EMIT_NEW_UNALU (cfg, ins, OP_STRLEN, dreg, args [0]->dreg);
5991                         ins->type = STACK_I4;
5992                         ins->flags |= MONO_INST_FAULT;
5993                         cfg->cbb->has_array_access = TRUE;
5994                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
5995
5996                         return ins;
5997                 } else 
5998                         return NULL;
5999         } else if (cmethod->klass == mono_defaults.object_class) {
6000
6001                 if (strcmp (cmethod->name, "GetType") == 0 && fsig->param_count + fsig->hasthis == 1) {
6002                         int dreg = alloc_ireg_ref (cfg);
6003                         int vt_reg = alloc_preg (cfg);
6004                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vt_reg, args [0]->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
6005                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, vt_reg, MONO_STRUCT_OFFSET (MonoVTable, type));
6006                         type_from_op (cfg, ins, NULL, NULL);
6007
6008                         return ins;
6009                 } else if (!cfg->backend->emulate_mul_div && strcmp (cmethod->name, "InternalGetHashCode") == 0 && fsig->param_count == 1 && !mono_gc_is_moving ()) {
6010                         int dreg = alloc_ireg (cfg);
6011                         int t1 = alloc_ireg (cfg);
6012         
6013                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, t1, args [0]->dreg, 3);
6014                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_MUL_IMM, dreg, t1, 2654435761u);
6015                         ins->type = STACK_I4;
6016
6017                         return ins;
6018                 } else if (strcmp (cmethod->name, ".ctor") == 0 && fsig->param_count == 0) {
6019                         MONO_INST_NEW (cfg, ins, OP_NOP);
6020                         MONO_ADD_INS (cfg->cbb, ins);
6021                         return ins;
6022                 } else
6023                         return NULL;
6024         } else if (cmethod->klass == mono_defaults.array_class) {
6025                 if (strcmp (cmethod->name, "GetGenericValueImpl") == 0 && fsig->param_count + fsig->hasthis == 3 && !cfg->gsharedvt)
6026                         return emit_array_generic_access (cfg, fsig, args, FALSE);
6027                 else if (strcmp (cmethod->name, "SetGenericValueImpl") == 0 && fsig->param_count + fsig->hasthis == 3 && !cfg->gsharedvt)
6028                         return emit_array_generic_access (cfg, fsig, args, TRUE);
6029
6030 #ifndef MONO_BIG_ARRAYS
6031                 /*
6032                  * This is an inline version of GetLength/GetLowerBound(0) used frequently in
6033                  * Array methods.
6034                  */
6035                 else if (((strcmp (cmethod->name, "GetLength") == 0 && fsig->param_count + fsig->hasthis == 2) ||
6036                          (strcmp (cmethod->name, "GetLowerBound") == 0 && fsig->param_count + fsig->hasthis == 2)) &&
6037                          args [1]->opcode == OP_ICONST && args [1]->inst_c0 == 0) {
6038                         int dreg = alloc_ireg (cfg);
6039                         int bounds_reg = alloc_ireg_mp (cfg);
6040                         MonoBasicBlock *end_bb, *szarray_bb;
6041                         gboolean get_length = strcmp (cmethod->name, "GetLength") == 0;
6042
6043                         NEW_BBLOCK (cfg, end_bb);
6044                         NEW_BBLOCK (cfg, szarray_bb);
6045
6046                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOAD_MEMBASE, bounds_reg,
6047                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, bounds));
6048                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
6049                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, szarray_bb);
6050                         /* Non-szarray case */
6051                         if (get_length)
6052                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
6053                                                                            bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, length));
6054                         else
6055                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
6056                                                                            bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
6057                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
6058                         MONO_START_BB (cfg, szarray_bb);
6059                         /* Szarray case */
6060                         if (get_length)
6061                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
6062                                                                            args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, max_length));
6063                         else
6064                                 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
6065                         MONO_START_BB (cfg, end_bb);
6066
6067                         EMIT_NEW_UNALU (cfg, ins, OP_MOVE, dreg, dreg);
6068                         ins->type = STACK_I4;
6069                         
6070                         return ins;
6071                 }
6072 #endif
6073
6074                 if (cmethod->name [0] != 'g')
6075                         return NULL;
6076
6077                 if (strcmp (cmethod->name, "get_Rank") == 0 && fsig->param_count + fsig->hasthis == 1) {
6078                         int dreg = alloc_ireg (cfg);
6079                         int vtable_reg = alloc_preg (cfg);
6080                         MONO_EMIT_NEW_LOAD_MEMBASE_OP_FAULT (cfg, OP_LOAD_MEMBASE, vtable_reg, 
6081                                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
6082                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU1_MEMBASE, dreg,
6083                                                                    vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
6084                         type_from_op (cfg, ins, NULL, NULL);
6085
6086                         return ins;
6087                 } else if (strcmp (cmethod->name, "get_Length") == 0 && fsig->param_count + fsig->hasthis == 1) {
6088                         int dreg = alloc_ireg (cfg);
6089
6090                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOADI4_MEMBASE, dreg, 
6091                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, max_length));
6092                         type_from_op (cfg, ins, NULL, NULL);
6093
6094                         return ins;
6095                 } else
6096                         return NULL;
6097         } else if (cmethod->klass == runtime_helpers_class) {
6098
6099                 if (strcmp (cmethod->name, "get_OffsetToStringData") == 0 && fsig->param_count == 0) {
6100                         EMIT_NEW_ICONST (cfg, ins, MONO_STRUCT_OFFSET (MonoString, chars));
6101                         return ins;
6102                 } else
6103                         return NULL;
6104         } else if (cmethod->klass == mono_defaults.thread_class) {
6105                 if (strcmp (cmethod->name, "SpinWait_nop") == 0 && fsig->param_count == 0) {
6106                         MONO_INST_NEW (cfg, ins, OP_RELAXED_NOP);
6107                         MONO_ADD_INS (cfg->cbb, ins);
6108                         return ins;
6109                 } else if (strcmp (cmethod->name, "MemoryBarrier") == 0 && fsig->param_count == 0) {
6110                         return emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6111                 } else if (!strcmp (cmethod->name, "VolatileRead") && fsig->param_count == 1) {
6112                         guint32 opcode = 0;
6113                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
6114
6115                         if (fsig->params [0]->type == MONO_TYPE_I1)
6116                                 opcode = OP_LOADI1_MEMBASE;
6117                         else if (fsig->params [0]->type == MONO_TYPE_U1)
6118                                 opcode = OP_LOADU1_MEMBASE;
6119                         else if (fsig->params [0]->type == MONO_TYPE_I2)
6120                                 opcode = OP_LOADI2_MEMBASE;
6121                         else if (fsig->params [0]->type == MONO_TYPE_U2)
6122                                 opcode = OP_LOADU2_MEMBASE;
6123                         else if (fsig->params [0]->type == MONO_TYPE_I4)
6124                                 opcode = OP_LOADI4_MEMBASE;
6125                         else if (fsig->params [0]->type == MONO_TYPE_U4)
6126                                 opcode = OP_LOADU4_MEMBASE;
6127                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_U8)
6128                                 opcode = OP_LOADI8_MEMBASE;
6129                         else if (fsig->params [0]->type == MONO_TYPE_R4)
6130                                 opcode = OP_LOADR4_MEMBASE;
6131                         else if (fsig->params [0]->type == MONO_TYPE_R8)
6132                                 opcode = OP_LOADR8_MEMBASE;
6133                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I || fsig->params [0]->type == MONO_TYPE_U)
6134                                 opcode = OP_LOAD_MEMBASE;
6135
6136                         if (opcode) {
6137                                 MONO_INST_NEW (cfg, ins, opcode);
6138                                 ins->inst_basereg = args [0]->dreg;
6139                                 ins->inst_offset = 0;
6140                                 MONO_ADD_INS (cfg->cbb, ins);
6141
6142                                 switch (fsig->params [0]->type) {
6143                                 case MONO_TYPE_I1:
6144                                 case MONO_TYPE_U1:
6145                                 case MONO_TYPE_I2:
6146                                 case MONO_TYPE_U2:
6147                                 case MONO_TYPE_I4:
6148                                 case MONO_TYPE_U4:
6149                                         ins->dreg = mono_alloc_ireg (cfg);
6150                                         ins->type = STACK_I4;
6151                                         break;
6152                                 case MONO_TYPE_I8:
6153                                 case MONO_TYPE_U8:
6154                                         ins->dreg = mono_alloc_lreg (cfg);
6155                                         ins->type = STACK_I8;
6156                                         break;
6157                                 case MONO_TYPE_I:
6158                                 case MONO_TYPE_U:
6159                                         ins->dreg = mono_alloc_ireg (cfg);
6160 #if SIZEOF_REGISTER == 8
6161                                         ins->type = STACK_I8;
6162 #else
6163                                         ins->type = STACK_I4;
6164 #endif
6165                                         break;
6166                                 case MONO_TYPE_R4:
6167                                 case MONO_TYPE_R8:
6168                                         ins->dreg = mono_alloc_freg (cfg);
6169                                         ins->type = STACK_R8;
6170                                         break;
6171                                 default:
6172                                         g_assert (mini_type_is_reference (fsig->params [0]));
6173                                         ins->dreg = mono_alloc_ireg_ref (cfg);
6174                                         ins->type = STACK_OBJ;
6175                                         break;
6176                                 }
6177
6178                                 if (opcode == OP_LOADI8_MEMBASE)
6179                                         ins = mono_decompose_opcode (cfg, ins);
6180
6181                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6182
6183                                 return ins;
6184                         }
6185                 } else if (!strcmp (cmethod->name, "VolatileWrite") && fsig->param_count == 2) {
6186                         guint32 opcode = 0;
6187                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
6188
6189                         if (fsig->params [0]->type == MONO_TYPE_I1 || fsig->params [0]->type == MONO_TYPE_U1)
6190                                 opcode = OP_STOREI1_MEMBASE_REG;
6191                         else if (fsig->params [0]->type == MONO_TYPE_I2 || fsig->params [0]->type == MONO_TYPE_U2)
6192                                 opcode = OP_STOREI2_MEMBASE_REG;
6193                         else if (fsig->params [0]->type == MONO_TYPE_I4 || fsig->params [0]->type == MONO_TYPE_U4)
6194                                 opcode = OP_STOREI4_MEMBASE_REG;
6195                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_U8)
6196                                 opcode = OP_STOREI8_MEMBASE_REG;
6197                         else if (fsig->params [0]->type == MONO_TYPE_R4)
6198                                 opcode = OP_STORER4_MEMBASE_REG;
6199                         else if (fsig->params [0]->type == MONO_TYPE_R8)
6200                                 opcode = OP_STORER8_MEMBASE_REG;
6201                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I || fsig->params [0]->type == MONO_TYPE_U)
6202                                 opcode = OP_STORE_MEMBASE_REG;
6203
6204                         if (opcode) {
6205                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6206
6207                                 MONO_INST_NEW (cfg, ins, opcode);
6208                                 ins->sreg1 = args [1]->dreg;
6209                                 ins->inst_destbasereg = args [0]->dreg;
6210                                 ins->inst_offset = 0;
6211                                 MONO_ADD_INS (cfg->cbb, ins);
6212
6213                                 if (opcode == OP_STOREI8_MEMBASE_REG)
6214                                         ins = mono_decompose_opcode (cfg, ins);
6215
6216                                 return ins;
6217                         }
6218                 }
6219         } else if (cmethod->klass->image == mono_defaults.corlib &&
6220                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
6221                            (strcmp (cmethod->klass->name, "Interlocked") == 0)) {
6222                 ins = NULL;
6223
6224 #if SIZEOF_REGISTER == 8
6225                 if (!cfg->llvm_only && strcmp (cmethod->name, "Read") == 0 && fsig->param_count == 1 && (fsig->params [0]->type == MONO_TYPE_I8)) {
6226                         if (!cfg->llvm_only && mono_arch_opcode_supported (OP_ATOMIC_LOAD_I8)) {
6227                                 MONO_INST_NEW (cfg, ins, OP_ATOMIC_LOAD_I8);
6228                                 ins->dreg = mono_alloc_preg (cfg);
6229                                 ins->sreg1 = args [0]->dreg;
6230                                 ins->type = STACK_I8;
6231                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_SEQ;
6232                                 MONO_ADD_INS (cfg->cbb, ins);
6233                         } else {
6234                                 MonoInst *load_ins;
6235
6236                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6237
6238                                 /* 64 bit reads are already atomic */
6239                                 MONO_INST_NEW (cfg, load_ins, OP_LOADI8_MEMBASE);
6240                                 load_ins->dreg = mono_alloc_preg (cfg);
6241                                 load_ins->inst_basereg = args [0]->dreg;
6242                                 load_ins->inst_offset = 0;
6243                                 load_ins->type = STACK_I8;
6244                                 MONO_ADD_INS (cfg->cbb, load_ins);
6245
6246                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6247
6248                                 ins = load_ins;
6249                         }
6250                 }
6251 #endif
6252
6253                 if (strcmp (cmethod->name, "Increment") == 0 && fsig->param_count == 1) {
6254                         MonoInst *ins_iconst;
6255                         guint32 opcode = 0;
6256
6257                         if (fsig->params [0]->type == MONO_TYPE_I4) {
6258                                 opcode = OP_ATOMIC_ADD_I4;
6259                                 cfg->has_atomic_add_i4 = TRUE;
6260                         }
6261 #if SIZEOF_REGISTER == 8
6262                         else if (fsig->params [0]->type == MONO_TYPE_I8)
6263                                 opcode = OP_ATOMIC_ADD_I8;
6264 #endif
6265                         if (opcode) {
6266                                 if (!mono_arch_opcode_supported (opcode))
6267                                         return NULL;
6268                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
6269                                 ins_iconst->inst_c0 = 1;
6270                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
6271                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
6272
6273                                 MONO_INST_NEW (cfg, ins, opcode);
6274                                 ins->dreg = mono_alloc_ireg (cfg);
6275                                 ins->inst_basereg = args [0]->dreg;
6276                                 ins->inst_offset = 0;
6277                                 ins->sreg2 = ins_iconst->dreg;
6278                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
6279                                 MONO_ADD_INS (cfg->cbb, ins);
6280                         }
6281                 } else if (strcmp (cmethod->name, "Decrement") == 0 && fsig->param_count == 1) {
6282                         MonoInst *ins_iconst;
6283                         guint32 opcode = 0;
6284
6285                         if (fsig->params [0]->type == MONO_TYPE_I4) {
6286                                 opcode = OP_ATOMIC_ADD_I4;
6287                                 cfg->has_atomic_add_i4 = TRUE;
6288                         }
6289 #if SIZEOF_REGISTER == 8
6290                         else if (fsig->params [0]->type == MONO_TYPE_I8)
6291                                 opcode = OP_ATOMIC_ADD_I8;
6292 #endif
6293                         if (opcode) {
6294                                 if (!mono_arch_opcode_supported (opcode))
6295                                         return NULL;
6296                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
6297                                 ins_iconst->inst_c0 = -1;
6298                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
6299                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
6300
6301                                 MONO_INST_NEW (cfg, ins, opcode);
6302                                 ins->dreg = mono_alloc_ireg (cfg);
6303                                 ins->inst_basereg = args [0]->dreg;
6304                                 ins->inst_offset = 0;
6305                                 ins->sreg2 = ins_iconst->dreg;
6306                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
6307                                 MONO_ADD_INS (cfg->cbb, ins);
6308                         }
6309                 } else if (strcmp (cmethod->name, "Add") == 0 && fsig->param_count == 2) {
6310                         guint32 opcode = 0;
6311
6312                         if (fsig->params [0]->type == MONO_TYPE_I4) {
6313                                 opcode = OP_ATOMIC_ADD_I4;
6314                                 cfg->has_atomic_add_i4 = TRUE;
6315                         }
6316 #if SIZEOF_REGISTER == 8
6317                         else if (fsig->params [0]->type == MONO_TYPE_I8)
6318                                 opcode = OP_ATOMIC_ADD_I8;
6319 #endif
6320                         if (opcode) {
6321                                 if (!mono_arch_opcode_supported (opcode))
6322                                         return NULL;
6323                                 MONO_INST_NEW (cfg, ins, opcode);
6324                                 ins->dreg = mono_alloc_ireg (cfg);
6325                                 ins->inst_basereg = args [0]->dreg;
6326                                 ins->inst_offset = 0;
6327                                 ins->sreg2 = args [1]->dreg;
6328                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
6329                                 MONO_ADD_INS (cfg->cbb, ins);
6330                         }
6331                 }
6332                 else if (strcmp (cmethod->name, "Exchange") == 0 && fsig->param_count == 2) {
6333                         MonoInst *f2i = NULL, *i2f;
6334                         guint32 opcode, f2i_opcode, i2f_opcode;
6335                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
6336                         gboolean is_float = fsig->params [0]->type == MONO_TYPE_R4 || fsig->params [0]->type == MONO_TYPE_R8;
6337
6338                         if (fsig->params [0]->type == MONO_TYPE_I4 ||
6339                             fsig->params [0]->type == MONO_TYPE_R4) {
6340                                 opcode = OP_ATOMIC_EXCHANGE_I4;
6341                                 f2i_opcode = OP_MOVE_F_TO_I4;
6342                                 i2f_opcode = OP_MOVE_I4_TO_F;
6343                                 cfg->has_atomic_exchange_i4 = TRUE;
6344                         }
6345 #if SIZEOF_REGISTER == 8
6346                         else if (is_ref ||
6347                                  fsig->params [0]->type == MONO_TYPE_I8 ||
6348                                  fsig->params [0]->type == MONO_TYPE_R8 ||
6349                                  fsig->params [0]->type == MONO_TYPE_I) {
6350                                 opcode = OP_ATOMIC_EXCHANGE_I8;
6351                                 f2i_opcode = OP_MOVE_F_TO_I8;
6352                                 i2f_opcode = OP_MOVE_I8_TO_F;
6353                         }
6354 #else
6355                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I) {
6356                                 opcode = OP_ATOMIC_EXCHANGE_I4;
6357                                 cfg->has_atomic_exchange_i4 = TRUE;
6358                         }
6359 #endif
6360                         else
6361                                 return NULL;
6362
6363                         if (!mono_arch_opcode_supported (opcode))
6364                                 return NULL;
6365
6366                         if (is_float) {
6367                                 /* TODO: Decompose these opcodes instead of bailing here. */
6368                                 if (COMPILE_SOFT_FLOAT (cfg))
6369                                         return NULL;
6370
6371                                 MONO_INST_NEW (cfg, f2i, f2i_opcode);
6372                                 f2i->dreg = mono_alloc_ireg (cfg);
6373                                 f2i->sreg1 = args [1]->dreg;
6374                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
6375                                         f2i->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6376                                 MONO_ADD_INS (cfg->cbb, f2i);
6377                         }
6378
6379                         MONO_INST_NEW (cfg, ins, opcode);
6380                         ins->dreg = is_ref ? mono_alloc_ireg_ref (cfg) : mono_alloc_ireg (cfg);
6381                         ins->inst_basereg = args [0]->dreg;
6382                         ins->inst_offset = 0;
6383                         ins->sreg2 = is_float ? f2i->dreg : args [1]->dreg;
6384                         MONO_ADD_INS (cfg->cbb, ins);
6385
6386                         switch (fsig->params [0]->type) {
6387                         case MONO_TYPE_I4:
6388                                 ins->type = STACK_I4;
6389                                 break;
6390                         case MONO_TYPE_I8:
6391                                 ins->type = STACK_I8;
6392                                 break;
6393                         case MONO_TYPE_I:
6394 #if SIZEOF_REGISTER == 8
6395                                 ins->type = STACK_I8;
6396 #else
6397                                 ins->type = STACK_I4;
6398 #endif
6399                                 break;
6400                         case MONO_TYPE_R4:
6401                         case MONO_TYPE_R8:
6402                                 ins->type = STACK_R8;
6403                                 break;
6404                         default:
6405                                 g_assert (mini_type_is_reference (fsig->params [0]));
6406                                 ins->type = STACK_OBJ;
6407                                 break;
6408                         }
6409
6410                         if (is_float) {
6411                                 MONO_INST_NEW (cfg, i2f, i2f_opcode);
6412                                 i2f->dreg = mono_alloc_freg (cfg);
6413                                 i2f->sreg1 = ins->dreg;
6414                                 i2f->type = STACK_R8;
6415                                 if (i2f_opcode == OP_MOVE_I4_TO_F)
6416                                         i2f->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6417                                 MONO_ADD_INS (cfg->cbb, i2f);
6418
6419                                 ins = i2f;
6420                         }
6421
6422                         if (cfg->gen_write_barriers && is_ref)
6423                                 emit_write_barrier (cfg, args [0], args [1]);
6424                 }
6425                 else if ((strcmp (cmethod->name, "CompareExchange") == 0) && fsig->param_count == 3) {
6426                         MonoInst *f2i_new = NULL, *f2i_cmp = NULL, *i2f;
6427                         guint32 opcode, f2i_opcode, i2f_opcode;
6428                         gboolean is_ref = mini_type_is_reference (fsig->params [1]);
6429                         gboolean is_float = fsig->params [1]->type == MONO_TYPE_R4 || fsig->params [1]->type == MONO_TYPE_R8;
6430
6431                         if (fsig->params [1]->type == MONO_TYPE_I4 ||
6432                             fsig->params [1]->type == MONO_TYPE_R4) {
6433                                 opcode = OP_ATOMIC_CAS_I4;
6434                                 f2i_opcode = OP_MOVE_F_TO_I4;
6435                                 i2f_opcode = OP_MOVE_I4_TO_F;
6436                                 cfg->has_atomic_cas_i4 = TRUE;
6437                         }
6438 #if SIZEOF_REGISTER == 8
6439                         else if (is_ref ||
6440                                  fsig->params [1]->type == MONO_TYPE_I8 ||
6441                                  fsig->params [1]->type == MONO_TYPE_R8 ||
6442                                  fsig->params [1]->type == MONO_TYPE_I) {
6443                                 opcode = OP_ATOMIC_CAS_I8;
6444                                 f2i_opcode = OP_MOVE_F_TO_I8;
6445                                 i2f_opcode = OP_MOVE_I8_TO_F;
6446                         }
6447 #else
6448                         else if (is_ref || fsig->params [1]->type == MONO_TYPE_I) {
6449                                 opcode = OP_ATOMIC_CAS_I4;
6450                                 cfg->has_atomic_cas_i4 = TRUE;
6451                         }
6452 #endif
6453                         else
6454                                 return NULL;
6455
6456                         if (!mono_arch_opcode_supported (opcode))
6457                                 return NULL;
6458
6459                         if (is_float) {
6460                                 /* TODO: Decompose these opcodes instead of bailing here. */
6461                                 if (COMPILE_SOFT_FLOAT (cfg))
6462                                         return NULL;
6463
6464                                 MONO_INST_NEW (cfg, f2i_new, f2i_opcode);
6465                                 f2i_new->dreg = mono_alloc_ireg (cfg);
6466                                 f2i_new->sreg1 = args [1]->dreg;
6467                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
6468                                         f2i_new->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6469                                 MONO_ADD_INS (cfg->cbb, f2i_new);
6470
6471                                 MONO_INST_NEW (cfg, f2i_cmp, f2i_opcode);
6472                                 f2i_cmp->dreg = mono_alloc_ireg (cfg);
6473                                 f2i_cmp->sreg1 = args [2]->dreg;
6474                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
6475                                         f2i_cmp->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6476                                 MONO_ADD_INS (cfg->cbb, f2i_cmp);
6477                         }
6478
6479                         MONO_INST_NEW (cfg, ins, opcode);
6480                         ins->dreg = is_ref ? alloc_ireg_ref (cfg) : alloc_ireg (cfg);
6481                         ins->sreg1 = args [0]->dreg;
6482                         ins->sreg2 = is_float ? f2i_new->dreg : args [1]->dreg;
6483                         ins->sreg3 = is_float ? f2i_cmp->dreg : args [2]->dreg;
6484                         MONO_ADD_INS (cfg->cbb, ins);
6485
6486                         switch (fsig->params [1]->type) {
6487                         case MONO_TYPE_I4:
6488                                 ins->type = STACK_I4;
6489                                 break;
6490                         case MONO_TYPE_I8:
6491                                 ins->type = STACK_I8;
6492                                 break;
6493                         case MONO_TYPE_I:
6494 #if SIZEOF_REGISTER == 8
6495                                 ins->type = STACK_I8;
6496 #else
6497                                 ins->type = STACK_I4;
6498 #endif
6499                                 break;
6500                         case MONO_TYPE_R4:
6501                                 ins->type = cfg->r4_stack_type;
6502                                 break;
6503                         case MONO_TYPE_R8:
6504                                 ins->type = STACK_R8;
6505                                 break;
6506                         default:
6507                                 g_assert (mini_type_is_reference (fsig->params [1]));
6508                                 ins->type = STACK_OBJ;
6509                                 break;
6510                         }
6511
6512                         if (is_float) {
6513                                 MONO_INST_NEW (cfg, i2f, i2f_opcode);
6514                                 i2f->dreg = mono_alloc_freg (cfg);
6515                                 i2f->sreg1 = ins->dreg;
6516                                 i2f->type = STACK_R8;
6517                                 if (i2f_opcode == OP_MOVE_I4_TO_F)
6518                                         i2f->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6519                                 MONO_ADD_INS (cfg->cbb, i2f);
6520
6521                                 ins = i2f;
6522                         }
6523
6524                         if (cfg->gen_write_barriers && is_ref)
6525                                 emit_write_barrier (cfg, args [0], args [1]);
6526                 }
6527                 else if ((strcmp (cmethod->name, "CompareExchange") == 0) && fsig->param_count == 4 &&
6528                          fsig->params [1]->type == MONO_TYPE_I4) {
6529                         MonoInst *cmp, *ceq;
6530
6531                         if (!mono_arch_opcode_supported (OP_ATOMIC_CAS_I4))
6532                                 return NULL;
6533
6534                         /* int32 r = CAS (location, value, comparand); */
6535                         MONO_INST_NEW (cfg, ins, OP_ATOMIC_CAS_I4);
6536                         ins->dreg = alloc_ireg (cfg);
6537                         ins->sreg1 = args [0]->dreg;
6538                         ins->sreg2 = args [1]->dreg;
6539                         ins->sreg3 = args [2]->dreg;
6540                         ins->type = STACK_I4;
6541                         MONO_ADD_INS (cfg->cbb, ins);
6542
6543                         /* bool result = r == comparand; */
6544                         MONO_INST_NEW (cfg, cmp, OP_ICOMPARE);
6545                         cmp->sreg1 = ins->dreg;
6546                         cmp->sreg2 = args [2]->dreg;
6547                         cmp->type = STACK_I4;
6548                         MONO_ADD_INS (cfg->cbb, cmp);
6549
6550                         MONO_INST_NEW (cfg, ceq, OP_ICEQ);
6551                         ceq->dreg = alloc_ireg (cfg);
6552                         ceq->type = STACK_I4;
6553                         MONO_ADD_INS (cfg->cbb, ceq);
6554
6555                         /* *success = result; */
6556                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, args [3]->dreg, 0, ceq->dreg);
6557
6558                         cfg->has_atomic_cas_i4 = TRUE;
6559                 }
6560                 else if (strcmp (cmethod->name, "MemoryBarrier") == 0 && fsig->param_count == 0)
6561                         ins = emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6562
6563                 if (ins)
6564                         return ins;
6565         } else if (cmethod->klass->image == mono_defaults.corlib &&
6566                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
6567                            (strcmp (cmethod->klass->name, "Volatile") == 0)) {
6568                 ins = NULL;
6569
6570                 if (!cfg->llvm_only && !strcmp (cmethod->name, "Read") && fsig->param_count == 1) {
6571                         guint32 opcode = 0;
6572                         MonoType *t = fsig->params [0];
6573                         gboolean is_ref;
6574                         gboolean is_float = t->type == MONO_TYPE_R4 || t->type == MONO_TYPE_R8;
6575
6576                         g_assert (t->byref);
6577                         /* t is a byref type, so the reference check is more complicated */
6578                         is_ref = mini_type_is_reference (&mono_class_from_mono_type (t)->byval_arg);
6579                         if (t->type == MONO_TYPE_I1)
6580                                 opcode = OP_ATOMIC_LOAD_I1;
6581                         else if (t->type == MONO_TYPE_U1 || t->type == MONO_TYPE_BOOLEAN)
6582                                 opcode = OP_ATOMIC_LOAD_U1;
6583                         else if (t->type == MONO_TYPE_I2)
6584                                 opcode = OP_ATOMIC_LOAD_I2;
6585                         else if (t->type == MONO_TYPE_U2)
6586                                 opcode = OP_ATOMIC_LOAD_U2;
6587                         else if (t->type == MONO_TYPE_I4)
6588                                 opcode = OP_ATOMIC_LOAD_I4;
6589                         else if (t->type == MONO_TYPE_U4)
6590                                 opcode = OP_ATOMIC_LOAD_U4;
6591                         else if (t->type == MONO_TYPE_R4)
6592                                 opcode = OP_ATOMIC_LOAD_R4;
6593                         else if (t->type == MONO_TYPE_R8)
6594                                 opcode = OP_ATOMIC_LOAD_R8;
6595 #if SIZEOF_REGISTER == 8
6596                         else if (t->type == MONO_TYPE_I8 || t->type == MONO_TYPE_I)
6597                                 opcode = OP_ATOMIC_LOAD_I8;
6598                         else if (is_ref || t->type == MONO_TYPE_U8 || t->type == MONO_TYPE_U)
6599                                 opcode = OP_ATOMIC_LOAD_U8;
6600 #else
6601                         else if (t->type == MONO_TYPE_I)
6602                                 opcode = OP_ATOMIC_LOAD_I4;
6603                         else if (is_ref || t->type == MONO_TYPE_U)
6604                                 opcode = OP_ATOMIC_LOAD_U4;
6605 #endif
6606
6607                         if (opcode) {
6608                                 if (!mono_arch_opcode_supported (opcode))
6609                                         return NULL;
6610
6611                                 MONO_INST_NEW (cfg, ins, opcode);
6612                                 ins->dreg = is_ref ? mono_alloc_ireg_ref (cfg) : (is_float ? mono_alloc_freg (cfg) : mono_alloc_ireg (cfg));
6613                                 ins->sreg1 = args [0]->dreg;
6614                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_ACQ;
6615                                 MONO_ADD_INS (cfg->cbb, ins);
6616
6617                                 switch (t->type) {
6618                                 case MONO_TYPE_BOOLEAN:
6619                                 case MONO_TYPE_I1:
6620                                 case MONO_TYPE_U1:
6621                                 case MONO_TYPE_I2:
6622                                 case MONO_TYPE_U2:
6623                                 case MONO_TYPE_I4:
6624                                 case MONO_TYPE_U4:
6625                                         ins->type = STACK_I4;
6626                                         break;
6627                                 case MONO_TYPE_I8:
6628                                 case MONO_TYPE_U8:
6629                                         ins->type = STACK_I8;
6630                                         break;
6631                                 case MONO_TYPE_I:
6632                                 case MONO_TYPE_U:
6633 #if SIZEOF_REGISTER == 8
6634                                         ins->type = STACK_I8;
6635 #else
6636                                         ins->type = STACK_I4;
6637 #endif
6638                                         break;
6639                                 case MONO_TYPE_R4:
6640                                         ins->type = cfg->r4_stack_type;
6641                                         break;
6642                                 case MONO_TYPE_R8:
6643                                         ins->type = STACK_R8;
6644                                         break;
6645                                 default:
6646                                         g_assert (is_ref);
6647                                         ins->type = STACK_OBJ;
6648                                         break;
6649                                 }
6650                         }
6651                 }
6652
6653                 if (!cfg->llvm_only && !strcmp (cmethod->name, "Write") && fsig->param_count == 2) {
6654                         guint32 opcode = 0;
6655                         MonoType *t = fsig->params [0];
6656                         gboolean is_ref;
6657
6658                         g_assert (t->byref);
6659                         is_ref = mini_type_is_reference (&mono_class_from_mono_type (t)->byval_arg);
6660                         if (t->type == MONO_TYPE_I1)
6661                                 opcode = OP_ATOMIC_STORE_I1;
6662                         else if (t->type == MONO_TYPE_U1 || t->type == MONO_TYPE_BOOLEAN)
6663                                 opcode = OP_ATOMIC_STORE_U1;
6664                         else if (t->type == MONO_TYPE_I2)
6665                                 opcode = OP_ATOMIC_STORE_I2;
6666                         else if (t->type == MONO_TYPE_U2)
6667                                 opcode = OP_ATOMIC_STORE_U2;
6668                         else if (t->type == MONO_TYPE_I4)
6669                                 opcode = OP_ATOMIC_STORE_I4;
6670                         else if (t->type == MONO_TYPE_U4)
6671                                 opcode = OP_ATOMIC_STORE_U4;
6672                         else if (t->type == MONO_TYPE_R4)
6673                                 opcode = OP_ATOMIC_STORE_R4;
6674                         else if (t->type == MONO_TYPE_R8)
6675                                 opcode = OP_ATOMIC_STORE_R8;
6676 #if SIZEOF_REGISTER == 8
6677                         else if (t->type == MONO_TYPE_I8 || t->type == MONO_TYPE_I)
6678                                 opcode = OP_ATOMIC_STORE_I8;
6679                         else if (is_ref || t->type == MONO_TYPE_U8 || t->type == MONO_TYPE_U)
6680                                 opcode = OP_ATOMIC_STORE_U8;
6681 #else
6682                         else if (t->type == MONO_TYPE_I)
6683                                 opcode = OP_ATOMIC_STORE_I4;
6684                         else if (is_ref || t->type == MONO_TYPE_U)
6685                                 opcode = OP_ATOMIC_STORE_U4;
6686 #endif
6687
6688                         if (opcode) {
6689                                 if (!mono_arch_opcode_supported (opcode))
6690                                         return NULL;
6691
6692                                 MONO_INST_NEW (cfg, ins, opcode);
6693                                 ins->dreg = args [0]->dreg;
6694                                 ins->sreg1 = args [1]->dreg;
6695                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_REL;
6696                                 MONO_ADD_INS (cfg->cbb, ins);
6697
6698                                 if (cfg->gen_write_barriers && is_ref)
6699                                         emit_write_barrier (cfg, args [0], args [1]);
6700                         }
6701                 }
6702
6703                 if (ins)
6704                         return ins;
6705         } else if (cmethod->klass->image == mono_defaults.corlib &&
6706                            (strcmp (cmethod->klass->name_space, "System.Diagnostics") == 0) &&
6707                            (strcmp (cmethod->klass->name, "Debugger") == 0)) {
6708                 if (!strcmp (cmethod->name, "Break") && fsig->param_count == 0) {
6709                         if (should_insert_brekpoint (cfg->method)) {
6710                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
6711                         } else {
6712                                 MONO_INST_NEW (cfg, ins, OP_NOP);
6713                                 MONO_ADD_INS (cfg->cbb, ins);
6714                         }
6715                         return ins;
6716                 }
6717         } else if (cmethod->klass->image == mono_defaults.corlib &&
6718                    (strcmp (cmethod->klass->name_space, "System") == 0) &&
6719                    (strcmp (cmethod->klass->name, "Environment") == 0)) {
6720                 if (!strcmp (cmethod->name, "get_IsRunningOnWindows") && fsig->param_count == 0) {
6721 #ifdef TARGET_WIN32
6722                         EMIT_NEW_ICONST (cfg, ins, 1);
6723 #else
6724                         EMIT_NEW_ICONST (cfg, ins, 0);
6725 #endif
6726                 }
6727         } else if (cmethod->klass->image == mono_defaults.corlib &&
6728                            (strcmp (cmethod->klass->name_space, "System.Reflection") == 0) &&
6729                            (strcmp (cmethod->klass->name, "Assembly") == 0)) {
6730                 if (cfg->llvm_only && !strcmp (cmethod->name, "GetExecutingAssembly")) {
6731                         /* No stack walks are currently available, so implement this as an intrinsic */
6732                         MonoInst *assembly_ins;
6733
6734                         EMIT_NEW_AOTCONST (cfg, assembly_ins, MONO_PATCH_INFO_IMAGE, cfg->method->klass->image);
6735                         ins = mono_emit_jit_icall (cfg, mono_get_assembly_object, &assembly_ins);
6736                         return ins;
6737                 }
6738                 if (cfg->llvm_only && !strcmp (cmethod->name, "GetCallingAssembly")) {
6739                         /* No stack walks are currently available, so implement this as an intrinsic */
6740                         ins = mono_emit_jit_icall (cfg, mono_llvmonly_get_calling_assembly, NULL);
6741                         return ins;
6742                 }
6743         } else if (cmethod->klass->image == mono_defaults.corlib &&
6744                            (strcmp (cmethod->klass->name_space, "System.Reflection") == 0) &&
6745                            (strcmp (cmethod->klass->name, "MethodBase") == 0)) {
6746                 if (cfg->llvm_only && !strcmp (cmethod->name, "GetCurrentMethod")) {
6747                         /* No stack walks are currently available, so implement this as an intrinsic */
6748                         MonoInst *method_ins;
6749                         MonoMethod *declaring = cfg->method;
6750
6751                         /* This returns the declaring generic method */
6752                         if (declaring->is_inflated)
6753                                 declaring = ((MonoMethodInflated*)cfg->method)->declaring;
6754                         EMIT_NEW_AOTCONST (cfg, method_ins, MONO_PATCH_INFO_METHODCONST, declaring);
6755                         ins = mono_emit_jit_icall (cfg, mono_get_method_object, &method_ins);
6756                         cfg->no_inline = TRUE;
6757                         if (cfg->method != cfg->current_method)
6758                                 inline_failure (cfg, "MethodBase:GetCurrentMethod ()");
6759                         return ins;
6760                 }
6761         } else if (cmethod->klass == mono_defaults.math_class) {
6762                 /* 
6763                  * There is general branchless code for Min/Max, but it does not work for 
6764                  * all inputs:
6765                  * http://everything2.com/?node_id=1051618
6766                  */
6767         } else if (((!strcmp (cmethod->klass->image->assembly->aname.name, "MonoMac") ||
6768                     !strcmp (cmethod->klass->image->assembly->aname.name, "monotouch")) &&
6769                                 !strcmp (cmethod->klass->name_space, "XamCore.ObjCRuntime") &&
6770                                 !strcmp (cmethod->klass->name, "Selector")) ||
6771                            (!strcmp (cmethod->klass->image->assembly->aname.name, "Xamarin.iOS") &&
6772                                 !strcmp (cmethod->klass->name_space, "ObjCRuntime") &&
6773                                 !strcmp (cmethod->klass->name, "Selector"))
6774                            ) {
6775                 if (cfg->backend->have_objc_get_selector &&
6776                         !strcmp (cmethod->name, "GetHandle") && fsig->param_count == 1 &&
6777                     (args [0]->opcode == OP_GOT_ENTRY || args [0]->opcode == OP_AOTCONST) &&
6778                     cfg->compile_aot && !cfg->llvm_only) {
6779                         MonoInst *pi;
6780                         MonoJumpInfoToken *ji;
6781                         MonoString *s;
6782
6783                         // FIXME: llvmonly
6784
6785                         cfg->exception_message = g_strdup ("GetHandle");
6786                         cfg->disable_llvm = TRUE;
6787
6788                         if (args [0]->opcode == OP_GOT_ENTRY) {
6789                                 pi = (MonoInst *)args [0]->inst_p1;
6790                                 g_assert (pi->opcode == OP_PATCH_INFO);
6791                                 g_assert (GPOINTER_TO_INT (pi->inst_p1) == MONO_PATCH_INFO_LDSTR);
6792                                 ji = (MonoJumpInfoToken *)pi->inst_p0;
6793                         } else {
6794                                 g_assert (GPOINTER_TO_INT (args [0]->inst_p1) == MONO_PATCH_INFO_LDSTR);
6795                                 ji = (MonoJumpInfoToken *)args [0]->inst_p0;
6796                         }
6797
6798                         NULLIFY_INS (args [0]);
6799
6800                         // FIXME: Ugly
6801                         s = mono_ldstr (cfg->domain, ji->image, mono_metadata_token_index (ji->token));
6802                         MONO_INST_NEW (cfg, ins, OP_OBJC_GET_SELECTOR);
6803                         ins->dreg = mono_alloc_ireg (cfg);
6804                         // FIXME: Leaks
6805                         ins->inst_p0 = mono_string_to_utf8 (s);
6806                         MONO_ADD_INS (cfg->cbb, ins);
6807                         return ins;
6808                 }
6809         }
6810
6811 #ifdef MONO_ARCH_SIMD_INTRINSICS
6812         if (cfg->opt & MONO_OPT_SIMD) {
6813                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
6814                 if (ins)
6815                         return ins;
6816         }
6817 #endif
6818
6819         ins = mono_emit_native_types_intrinsics (cfg, cmethod, fsig, args);
6820         if (ins)
6821                 return ins;
6822
6823         if (COMPILE_LLVM (cfg)) {
6824                 ins = llvm_emit_inst_for_method (cfg, cmethod, fsig, args);
6825                 if (ins)
6826                         return ins;
6827         }
6828
6829         return mono_arch_emit_inst_for_method (cfg, cmethod, fsig, args);
6830 }
6831
6832 /*
6833  * This entry point could be used later for arbitrary method
6834  * redirection.
6835  */
6836 inline static MonoInst*
6837 mini_redirect_call (MonoCompile *cfg, MonoMethod *method,  
6838                                         MonoMethodSignature *signature, MonoInst **args, MonoInst *this_ins)
6839 {
6840         if (method->klass == mono_defaults.string_class) {
6841                 /* managed string allocation support */
6842                 if (strcmp (method->name, "InternalAllocateStr") == 0 && !(mono_profiler_events & MONO_PROFILE_ALLOCATIONS) && !(cfg->opt & MONO_OPT_SHARED)) {
6843                         MonoInst *iargs [2];
6844                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
6845                         MonoMethod *managed_alloc = NULL;
6846
6847                         g_assert (vtable); /*Should not fail since it System.String*/
6848 #ifndef MONO_CROSS_COMPILE
6849                         managed_alloc = mono_gc_get_managed_allocator (method->klass, FALSE, FALSE);
6850 #endif
6851                         if (!managed_alloc)
6852                                 return NULL;
6853                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
6854                         iargs [1] = args [0];
6855                         return mono_emit_method_call (cfg, managed_alloc, iargs, this_ins);
6856                 }
6857         }
6858         return NULL;
6859 }
6860
6861 static void
6862 mono_save_args (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **sp)
6863 {
6864         MonoInst *store, *temp;
6865         int i;
6866
6867         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
6868                 MonoType *argtype = (sig->hasthis && (i == 0)) ? type_from_stack_type (*sp) : sig->params [i - sig->hasthis];
6869
6870                 /*
6871                  * FIXME: We should use *args++ = sp [0], but that would mean the arg
6872                  * would be different than the MonoInst's used to represent arguments, and
6873                  * the ldelema implementation can't deal with that.
6874                  * Solution: When ldelema is used on an inline argument, create a var for 
6875                  * it, emit ldelema on that var, and emit the saving code below in
6876                  * inline_method () if needed.
6877                  */
6878                 temp = mono_compile_create_var (cfg, argtype, OP_LOCAL);
6879                 cfg->args [i] = temp;
6880                 /* This uses cfg->args [i] which is set by the preceeding line */
6881                 EMIT_NEW_ARGSTORE (cfg, store, i, *sp);
6882                 store->cil_code = sp [0]->cil_code;
6883                 sp++;
6884         }
6885 }
6886
6887 #define MONO_INLINE_CALLED_LIMITED_METHODS 1
6888 #define MONO_INLINE_CALLER_LIMITED_METHODS 1
6889
6890 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
6891 static gboolean
6892 check_inline_called_method_name_limit (MonoMethod *called_method)
6893 {
6894         int strncmp_result;
6895         static const char *limit = NULL;
6896         
6897         if (limit == NULL) {
6898                 const char *limit_string = g_getenv ("MONO_INLINE_CALLED_METHOD_NAME_LIMIT");
6899
6900                 if (limit_string != NULL)
6901                         limit = limit_string;
6902                 else
6903                         limit = "";
6904         }
6905
6906         if (limit [0] != '\0') {
6907                 char *called_method_name = mono_method_full_name (called_method, TRUE);
6908
6909                 strncmp_result = strncmp (called_method_name, limit, strlen (limit));
6910                 g_free (called_method_name);
6911         
6912                 //return (strncmp_result <= 0);
6913                 return (strncmp_result == 0);
6914         } else {
6915                 return TRUE;
6916         }
6917 }
6918 #endif
6919
6920 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
6921 static gboolean
6922 check_inline_caller_method_name_limit (MonoMethod *caller_method)
6923 {
6924         int strncmp_result;
6925         static const char *limit = NULL;
6926         
6927         if (limit == NULL) {
6928                 const char *limit_string = g_getenv ("MONO_INLINE_CALLER_METHOD_NAME_LIMIT");
6929                 if (limit_string != NULL) {
6930                         limit = limit_string;
6931                 } else {
6932                         limit = "";
6933                 }
6934         }
6935
6936         if (limit [0] != '\0') {
6937                 char *caller_method_name = mono_method_full_name (caller_method, TRUE);
6938
6939                 strncmp_result = strncmp (caller_method_name, limit, strlen (limit));
6940                 g_free (caller_method_name);
6941         
6942                 //return (strncmp_result <= 0);
6943                 return (strncmp_result == 0);
6944         } else {
6945                 return TRUE;
6946         }
6947 }
6948 #endif
6949
6950 static void
6951 emit_init_rvar (MonoCompile *cfg, int dreg, MonoType *rtype)
6952 {
6953         static double r8_0 = 0.0;
6954         static float r4_0 = 0.0;
6955         MonoInst *ins;
6956         int t;
6957
6958         rtype = mini_get_underlying_type (rtype);
6959         t = rtype->type;
6960
6961         if (rtype->byref) {
6962                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
6963         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
6964                 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
6965         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
6966                 MONO_EMIT_NEW_I8CONST (cfg, dreg, 0);
6967         } else if (cfg->r4fp && t == MONO_TYPE_R4) {
6968                 MONO_INST_NEW (cfg, ins, OP_R4CONST);
6969                 ins->type = STACK_R4;
6970                 ins->inst_p0 = (void*)&r4_0;
6971                 ins->dreg = dreg;
6972                 MONO_ADD_INS (cfg->cbb, ins);
6973         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
6974                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
6975                 ins->type = STACK_R8;
6976                 ins->inst_p0 = (void*)&r8_0;
6977                 ins->dreg = dreg;
6978                 MONO_ADD_INS (cfg->cbb, ins);
6979         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
6980                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (rtype))) {
6981                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (rtype));
6982         } else if (((t == MONO_TYPE_VAR) || (t == MONO_TYPE_MVAR)) && mini_type_var_is_vt (rtype)) {
6983                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (rtype));
6984         } else {
6985                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
6986         }
6987 }
6988
6989 static void
6990 emit_dummy_init_rvar (MonoCompile *cfg, int dreg, MonoType *rtype)
6991 {
6992         int t;
6993
6994         rtype = mini_get_underlying_type (rtype);
6995         t = rtype->type;
6996
6997         if (rtype->byref) {
6998                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_PCONST);
6999         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
7000                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_ICONST);
7001         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
7002                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_I8CONST);
7003         } else if (cfg->r4fp && t == MONO_TYPE_R4) {
7004                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_R4CONST);
7005         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
7006                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_R8CONST);
7007         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
7008                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (rtype))) {
7009                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_VZERO);
7010         } else if (((t == MONO_TYPE_VAR) || (t == MONO_TYPE_MVAR)) && mini_type_var_is_vt (rtype)) {
7011                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_VZERO);
7012         } else {
7013                 emit_init_rvar (cfg, dreg, rtype);
7014         }
7015 }
7016
7017 /* If INIT is FALSE, emit dummy initialization statements to keep the IR valid */
7018 static void
7019 emit_init_local (MonoCompile *cfg, int local, MonoType *type, gboolean init)
7020 {
7021         MonoInst *var = cfg->locals [local];
7022         if (COMPILE_SOFT_FLOAT (cfg)) {
7023                 MonoInst *store;
7024                 int reg = alloc_dreg (cfg, (MonoStackType)var->type);
7025                 emit_init_rvar (cfg, reg, type);
7026                 EMIT_NEW_LOCSTORE (cfg, store, local, cfg->cbb->last_ins);
7027         } else {
7028                 if (init)
7029                         emit_init_rvar (cfg, var->dreg, type);
7030                 else
7031                         emit_dummy_init_rvar (cfg, var->dreg, type);
7032         }
7033 }
7034
7035 /*
7036  * inline_method:
7037  *
7038  *   Return the cost of inlining CMETHOD.
7039  */
7040 static int
7041 inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp,
7042                            guchar *ip, guint real_offset, gboolean inline_always)
7043 {
7044         MonoInst *ins, *rvar = NULL;
7045         MonoMethodHeader *cheader;
7046         MonoBasicBlock *ebblock, *sbblock;
7047         int i, costs;
7048         MonoMethod *prev_inlined_method;
7049         MonoInst **prev_locals, **prev_args;
7050         MonoType **prev_arg_types;
7051         guint prev_real_offset;
7052         GHashTable *prev_cbb_hash;
7053         MonoBasicBlock **prev_cil_offset_to_bb;
7054         MonoBasicBlock *prev_cbb;
7055         unsigned char* prev_cil_start;
7056         guint32 prev_cil_offset_to_bb_len;
7057         MonoMethod *prev_current_method;
7058         MonoGenericContext *prev_generic_context;
7059         gboolean ret_var_set, prev_ret_var_set, prev_disable_inline, virtual_ = FALSE;
7060
7061         g_assert (cfg->exception_type == MONO_EXCEPTION_NONE);
7062
7063 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
7064         if ((! inline_always) && ! check_inline_called_method_name_limit (cmethod))
7065                 return 0;
7066 #endif
7067 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
7068         if ((! inline_always) && ! check_inline_caller_method_name_limit (cfg->method))
7069                 return 0;
7070 #endif
7071
7072         if (!fsig)
7073                 fsig = mono_method_signature (cmethod);
7074
7075         if (cfg->verbose_level > 2)
7076                 printf ("INLINE START %p %s -> %s\n", cmethod,  mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
7077
7078         if (!cmethod->inline_info) {
7079                 cfg->stat_inlineable_methods++;
7080                 cmethod->inline_info = 1;
7081         }
7082
7083         /* allocate local variables */
7084         cheader = mono_method_get_header (cmethod);
7085
7086         if (cheader == NULL || mono_loader_get_last_error ()) {
7087                 if (cheader)
7088                         mono_metadata_free_mh (cheader);
7089                 if (inline_always && mono_loader_get_last_error ()) {
7090                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
7091                         mono_error_set_from_loader_error (&cfg->error);
7092                 }
7093
7094                 mono_loader_clear_error ();
7095                 return 0;
7096         }
7097
7098         /*Must verify before creating locals as it can cause the JIT to assert.*/
7099         if (mono_compile_is_broken (cfg, cmethod, FALSE)) {
7100                 mono_metadata_free_mh (cheader);
7101                 return 0;
7102         }
7103
7104         /* allocate space to store the return value */
7105         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
7106                 rvar = mono_compile_create_var (cfg, fsig->ret, OP_LOCAL);
7107         }
7108
7109         prev_locals = cfg->locals;
7110         cfg->locals = (MonoInst **)mono_mempool_alloc0 (cfg->mempool, cheader->num_locals * sizeof (MonoInst*));
7111         for (i = 0; i < cheader->num_locals; ++i)
7112                 cfg->locals [i] = mono_compile_create_var (cfg, cheader->locals [i], OP_LOCAL);
7113
7114         /* allocate start and end blocks */
7115         /* This is needed so if the inline is aborted, we can clean up */
7116         NEW_BBLOCK (cfg, sbblock);
7117         sbblock->real_offset = real_offset;
7118
7119         NEW_BBLOCK (cfg, ebblock);
7120         ebblock->block_num = cfg->num_bblocks++;
7121         ebblock->real_offset = real_offset;
7122
7123         prev_args = cfg->args;
7124         prev_arg_types = cfg->arg_types;
7125         prev_inlined_method = cfg->inlined_method;
7126         cfg->inlined_method = cmethod;
7127         cfg->ret_var_set = FALSE;
7128         cfg->inline_depth ++;
7129         prev_real_offset = cfg->real_offset;
7130         prev_cbb_hash = cfg->cbb_hash;
7131         prev_cil_offset_to_bb = cfg->cil_offset_to_bb;
7132         prev_cil_offset_to_bb_len = cfg->cil_offset_to_bb_len;
7133         prev_cil_start = cfg->cil_start;
7134         prev_cbb = cfg->cbb;
7135         prev_current_method = cfg->current_method;
7136         prev_generic_context = cfg->generic_context;
7137         prev_ret_var_set = cfg->ret_var_set;
7138         prev_disable_inline = cfg->disable_inline;
7139
7140         if (ip && *ip == CEE_CALLVIRT && !(cmethod->flags & METHOD_ATTRIBUTE_STATIC))
7141                 virtual_ = TRUE;
7142
7143         costs = mono_method_to_ir (cfg, cmethod, sbblock, ebblock, rvar, sp, real_offset, virtual_);
7144
7145         ret_var_set = cfg->ret_var_set;
7146
7147         cfg->inlined_method = prev_inlined_method;
7148         cfg->real_offset = prev_real_offset;
7149         cfg->cbb_hash = prev_cbb_hash;
7150         cfg->cil_offset_to_bb = prev_cil_offset_to_bb;
7151         cfg->cil_offset_to_bb_len = prev_cil_offset_to_bb_len;
7152         cfg->cil_start = prev_cil_start;
7153         cfg->locals = prev_locals;
7154         cfg->args = prev_args;
7155         cfg->arg_types = prev_arg_types;
7156         cfg->current_method = prev_current_method;
7157         cfg->generic_context = prev_generic_context;
7158         cfg->ret_var_set = prev_ret_var_set;
7159         cfg->disable_inline = prev_disable_inline;
7160         cfg->inline_depth --;
7161
7162         if ((costs >= 0 && costs < 60) || inline_always || (costs >= 0 && (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING))) {
7163                 if (cfg->verbose_level > 2)
7164                         printf ("INLINE END %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
7165                 
7166                 cfg->stat_inlined_methods++;
7167
7168                 /* always add some code to avoid block split failures */
7169                 MONO_INST_NEW (cfg, ins, OP_NOP);
7170                 MONO_ADD_INS (prev_cbb, ins);
7171
7172                 prev_cbb->next_bb = sbblock;
7173                 link_bblock (cfg, prev_cbb, sbblock);
7174
7175                 /* 
7176                  * Get rid of the begin and end bblocks if possible to aid local
7177                  * optimizations.
7178                  */
7179                 mono_merge_basic_blocks (cfg, prev_cbb, sbblock);
7180
7181                 if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] != ebblock))
7182                         mono_merge_basic_blocks (cfg, prev_cbb, prev_cbb->out_bb [0]);
7183
7184                 if ((ebblock->in_count == 1) && ebblock->in_bb [0]->out_count == 1) {
7185                         MonoBasicBlock *prev = ebblock->in_bb [0];
7186
7187                         if (prev->next_bb == ebblock) {
7188                                 mono_merge_basic_blocks (cfg, prev, ebblock);
7189                                 cfg->cbb = prev;
7190                                 if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] == prev)) {
7191                                         mono_merge_basic_blocks (cfg, prev_cbb, prev);
7192                                         cfg->cbb = prev_cbb;
7193                                 }
7194                         } else {
7195                                 /* There could be a bblock after 'prev', and making 'prev' the current bb could cause problems */
7196                                 cfg->cbb = ebblock;
7197                         }
7198                 } else {
7199                         /* 
7200                          * Its possible that the rvar is set in some prev bblock, but not in others.
7201                          * (#1835).
7202                          */
7203                         if (rvar) {
7204                                 MonoBasicBlock *bb;
7205
7206                                 for (i = 0; i < ebblock->in_count; ++i) {
7207                                         bb = ebblock->in_bb [i];
7208
7209                                         if (bb->last_ins && bb->last_ins->opcode == OP_NOT_REACHED) {
7210                                                 cfg->cbb = bb;
7211
7212                                                 emit_init_rvar (cfg, rvar->dreg, fsig->ret);
7213                                         }
7214                                 }
7215                         }
7216
7217                         cfg->cbb = ebblock;
7218                 }
7219
7220                 if (rvar) {
7221                         /*
7222                          * If the inlined method contains only a throw, then the ret var is not 
7223                          * set, so set it to a dummy value.
7224                          */
7225                         if (!ret_var_set)
7226                                 emit_init_rvar (cfg, rvar->dreg, fsig->ret);
7227
7228                         EMIT_NEW_TEMPLOAD (cfg, ins, rvar->inst_c0);
7229                         *sp++ = ins;
7230                 }
7231                 cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
7232                 return costs + 1;
7233         } else {
7234                 if (cfg->verbose_level > 2)
7235                         printf ("INLINE ABORTED %s (cost %d)\n", mono_method_full_name (cmethod, TRUE), costs);
7236                 cfg->exception_type = MONO_EXCEPTION_NONE;
7237                 mono_loader_clear_error ();
7238
7239                 /* This gets rid of the newly added bblocks */
7240                 cfg->cbb = prev_cbb;
7241         }
7242         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
7243         return 0;
7244 }
7245
7246 /*
7247  * Some of these comments may well be out-of-date.
7248  * Design decisions: we do a single pass over the IL code (and we do bblock 
7249  * splitting/merging in the few cases when it's required: a back jump to an IL
7250  * address that was not already seen as bblock starting point).
7251  * Code is validated as we go (full verification is still better left to metadata/verify.c).
7252  * Complex operations are decomposed in simpler ones right away. We need to let the 
7253  * arch-specific code peek and poke inside this process somehow (except when the 
7254  * optimizations can take advantage of the full semantic info of coarse opcodes).
7255  * All the opcodes of the form opcode.s are 'normalized' to opcode.
7256  * MonoInst->opcode initially is the IL opcode or some simplification of that 
7257  * (OP_LOAD, OP_STORE). The arch-specific code may rearrange it to an arch-specific 
7258  * opcode with value bigger than OP_LAST.
7259  * At this point the IR can be handed over to an interpreter, a dumb code generator
7260  * or to the optimizing code generator that will translate it to SSA form.
7261  *
7262  * Profiling directed optimizations.
7263  * We may compile by default with few or no optimizations and instrument the code
7264  * or the user may indicate what methods to optimize the most either in a config file
7265  * or through repeated runs where the compiler applies offline the optimizations to 
7266  * each method and then decides if it was worth it.
7267  */
7268
7269 #define CHECK_TYPE(ins) if (!(ins)->type) UNVERIFIED
7270 #define CHECK_STACK(num) if ((sp - stack_start) < (num)) UNVERIFIED
7271 #define CHECK_STACK_OVF(num) if (((sp - stack_start) + (num)) > header->max_stack) UNVERIFIED
7272 #define CHECK_ARG(num) if ((unsigned)(num) >= (unsigned)num_args) UNVERIFIED
7273 #define CHECK_LOCAL(num) if ((unsigned)(num) >= (unsigned)header->num_locals) UNVERIFIED
7274 #define CHECK_OPSIZE(size) if (ip + size > end) UNVERIFIED
7275 #define CHECK_UNVERIFIABLE(cfg) if (cfg->unverifiable) UNVERIFIED
7276 #define CHECK_TYPELOAD(klass) if (!(klass) || (klass)->exception_type) TYPE_LOAD_ERROR ((klass))
7277
7278 /* offset from br.s -> br like opcodes */
7279 #define BIG_BRANCH_OFFSET 13
7280
7281 static gboolean
7282 ip_in_bb (MonoCompile *cfg, MonoBasicBlock *bb, const guint8* ip)
7283 {
7284         MonoBasicBlock *b = cfg->cil_offset_to_bb [ip - cfg->cil_start];
7285
7286         return b == NULL || b == bb;
7287 }
7288
7289 static int
7290 get_basic_blocks (MonoCompile *cfg, MonoMethodHeader* header, guint real_offset, unsigned char *start, unsigned char *end, unsigned char **pos)
7291 {
7292         unsigned char *ip = start;
7293         unsigned char *target;
7294         int i;
7295         guint cli_addr;
7296         MonoBasicBlock *bblock;
7297         const MonoOpcode *opcode;
7298
7299         while (ip < end) {
7300                 cli_addr = ip - start;
7301                 i = mono_opcode_value ((const guint8 **)&ip, end);
7302                 if (i < 0)
7303                         UNVERIFIED;
7304                 opcode = &mono_opcodes [i];
7305                 switch (opcode->argument) {
7306                 case MonoInlineNone:
7307                         ip++; 
7308                         break;
7309                 case MonoInlineString:
7310                 case MonoInlineType:
7311                 case MonoInlineField:
7312                 case MonoInlineMethod:
7313                 case MonoInlineTok:
7314                 case MonoInlineSig:
7315                 case MonoShortInlineR:
7316                 case MonoInlineI:
7317                         ip += 5;
7318                         break;
7319                 case MonoInlineVar:
7320                         ip += 3;
7321                         break;
7322                 case MonoShortInlineVar:
7323                 case MonoShortInlineI:
7324                         ip += 2;
7325                         break;
7326                 case MonoShortInlineBrTarget:
7327                         target = start + cli_addr + 2 + (signed char)ip [1];
7328                         GET_BBLOCK (cfg, bblock, target);
7329                         ip += 2;
7330                         if (ip < end)
7331                                 GET_BBLOCK (cfg, bblock, ip);
7332                         break;
7333                 case MonoInlineBrTarget:
7334                         target = start + cli_addr + 5 + (gint32)read32 (ip + 1);
7335                         GET_BBLOCK (cfg, bblock, target);
7336                         ip += 5;
7337                         if (ip < end)
7338                                 GET_BBLOCK (cfg, bblock, ip);
7339                         break;
7340                 case MonoInlineSwitch: {
7341                         guint32 n = read32 (ip + 1);
7342                         guint32 j;
7343                         ip += 5;
7344                         cli_addr += 5 + 4 * n;
7345                         target = start + cli_addr;
7346                         GET_BBLOCK (cfg, bblock, target);
7347                         
7348                         for (j = 0; j < n; ++j) {
7349                                 target = start + cli_addr + (gint32)read32 (ip);
7350                                 GET_BBLOCK (cfg, bblock, target);
7351                                 ip += 4;
7352                         }
7353                         break;
7354                 }
7355                 case MonoInlineR:
7356                 case MonoInlineI8:
7357                         ip += 9;
7358                         break;
7359                 default:
7360                         g_assert_not_reached ();
7361                 }
7362
7363                 if (i == CEE_THROW) {
7364                         unsigned char *bb_start = ip - 1;
7365                         
7366                         /* Find the start of the bblock containing the throw */
7367                         bblock = NULL;
7368                         while ((bb_start >= start) && !bblock) {
7369                                 bblock = cfg->cil_offset_to_bb [(bb_start) - start];
7370                                 bb_start --;
7371                         }
7372                         if (bblock)
7373                                 bblock->out_of_line = 1;
7374                 }
7375         }
7376         return 0;
7377 unverified:
7378 exception_exit:
7379         *pos = ip;
7380         return 1;
7381 }
7382
7383 static inline MonoMethod *
7384 mini_get_method_allow_open (MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context, MonoError *error)
7385 {
7386         MonoMethod *method;
7387
7388         mono_error_init (error);
7389
7390         if (m->wrapper_type != MONO_WRAPPER_NONE) {
7391                 method = (MonoMethod *)mono_method_get_wrapper_data (m, token);
7392                 if (context) {
7393                         method = mono_class_inflate_generic_method_checked (method, context, error);
7394                 }
7395         } else {
7396                 method = mono_get_method_checked (m->klass->image, token, klass, context, error);
7397         }
7398
7399         return method;
7400 }
7401
7402 static inline MonoMethod *
7403 mini_get_method (MonoCompile *cfg, MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
7404 {
7405         MonoError error;
7406         MonoMethod *method = mini_get_method_allow_open (m, token, klass, context, cfg ? &cfg->error : &error);
7407
7408         if (method && cfg && !cfg->gshared && mono_class_is_open_constructed_type (&method->klass->byval_arg)) {
7409                 mono_error_set_bad_image (&cfg->error, cfg->method->klass->image, "Method with open type while not compiling gshared");
7410                 method = NULL;
7411         }
7412
7413         if (!method && !cfg)
7414                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
7415
7416         return method;
7417 }
7418
7419 static inline MonoClass*
7420 mini_get_class (MonoMethod *method, guint32 token, MonoGenericContext *context)
7421 {
7422         MonoError error;
7423         MonoClass *klass;
7424
7425         if (method->wrapper_type != MONO_WRAPPER_NONE) {
7426                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
7427                 if (context)
7428                         klass = mono_class_inflate_generic_class (klass, context);
7429         } else {
7430                 klass = mono_class_get_and_inflate_typespec_checked (method->klass->image, token, context, &error);
7431                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
7432         }
7433         if (klass)
7434                 mono_class_init (klass);
7435         return klass;
7436 }
7437
7438 static inline MonoMethodSignature*
7439 mini_get_signature (MonoMethod *method, guint32 token, MonoGenericContext *context)
7440 {
7441         MonoMethodSignature *fsig;
7442
7443         if (method->wrapper_type != MONO_WRAPPER_NONE) {
7444                 fsig = (MonoMethodSignature *)mono_method_get_wrapper_data (method, token);
7445         } else {
7446                 fsig = mono_metadata_parse_signature (method->klass->image, token);
7447         }
7448         if (context) {
7449                 MonoError error;
7450                 fsig = mono_inflate_generic_signature(fsig, context, &error);
7451                 // FIXME:
7452                 g_assert(mono_error_ok(&error));
7453         }
7454         return fsig;
7455 }
7456
7457 static MonoMethod*
7458 throw_exception (void)
7459 {
7460         static MonoMethod *method = NULL;
7461
7462         if (!method) {
7463                 MonoSecurityManager *secman = mono_security_manager_get_methods ();
7464                 method = mono_class_get_method_from_name (secman->securitymanager, "ThrowException", 1);
7465         }
7466         g_assert (method);
7467         return method;
7468 }
7469
7470 static void
7471 emit_throw_exception (MonoCompile *cfg, MonoException *ex)
7472 {
7473         MonoMethod *thrower = throw_exception ();
7474         MonoInst *args [1];
7475
7476         EMIT_NEW_PCONST (cfg, args [0], ex);
7477         mono_emit_method_call (cfg, thrower, args, NULL);
7478 }
7479
7480 /*
7481  * Return the original method is a wrapper is specified. We can only access 
7482  * the custom attributes from the original method.
7483  */
7484 static MonoMethod*
7485 get_original_method (MonoMethod *method)
7486 {
7487         if (method->wrapper_type == MONO_WRAPPER_NONE)
7488                 return method;
7489
7490         /* native code (which is like Critical) can call any managed method XXX FIXME XXX to validate all usages */
7491         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED)
7492                 return NULL;
7493
7494         /* in other cases we need to find the original method */
7495         return mono_marshal_method_from_wrapper (method);
7496 }
7497
7498 static void
7499 ensure_method_is_allowed_to_access_field (MonoCompile *cfg, MonoMethod *caller, MonoClassField *field)
7500 {
7501         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
7502         MonoException *ex = mono_security_core_clr_is_field_access_allowed (get_original_method (caller), field);
7503         if (ex)
7504                 emit_throw_exception (cfg, ex);
7505 }
7506
7507 static void
7508 ensure_method_is_allowed_to_call_method (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee)
7509 {
7510         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
7511         MonoException *ex = mono_security_core_clr_is_call_allowed (get_original_method (caller), callee);
7512         if (ex)
7513                 emit_throw_exception (cfg, ex);
7514 }
7515
7516 /*
7517  * Check that the IL instructions at ip are the array initialization
7518  * sequence and return the pointer to the data and the size.
7519  */
7520 static const char*
7521 initialize_array_data (MonoMethod *method, gboolean aot, unsigned char *ip, MonoClass *klass, guint32 len, int *out_size, guint32 *out_field_token)
7522 {
7523         /*
7524          * newarr[System.Int32]
7525          * dup
7526          * ldtoken field valuetype ...
7527          * call void class [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype [mscorlib]System.RuntimeFieldHandle)
7528          */
7529         if (ip [0] == CEE_DUP && ip [1] == CEE_LDTOKEN && ip [5] == 0x4 && ip [6] == CEE_CALL) {
7530                 MonoError error;
7531                 guint32 token = read32 (ip + 7);
7532                 guint32 field_token = read32 (ip + 2);
7533                 guint32 field_index = field_token & 0xffffff;
7534                 guint32 rva;
7535                 const char *data_ptr;
7536                 int size = 0;
7537                 MonoMethod *cmethod;
7538                 MonoClass *dummy_class;
7539                 MonoClassField *field = mono_field_from_token_checked (method->klass->image, field_token, &dummy_class, NULL, &error);
7540                 int dummy_align;
7541
7542                 if (!field) {
7543                         mono_error_cleanup (&error); /* FIXME don't swallow the error */
7544                         return NULL;
7545                 }
7546
7547                 *out_field_token = field_token;
7548
7549                 cmethod = mini_get_method (NULL, method, token, NULL, NULL);
7550                 if (!cmethod)
7551                         return NULL;
7552                 if (strcmp (cmethod->name, "InitializeArray") || strcmp (cmethod->klass->name, "RuntimeHelpers") || cmethod->klass->image != mono_defaults.corlib)
7553                         return NULL;
7554                 switch (mono_type_get_underlying_type (&klass->byval_arg)->type) {
7555                 case MONO_TYPE_BOOLEAN:
7556                 case MONO_TYPE_I1:
7557                 case MONO_TYPE_U1:
7558                         size = 1; break;
7559                 /* we need to swap on big endian, so punt. Should we handle R4 and R8 as well? */
7560 #if TARGET_BYTE_ORDER == G_LITTLE_ENDIAN
7561                 case MONO_TYPE_CHAR:
7562                 case MONO_TYPE_I2:
7563                 case MONO_TYPE_U2:
7564                         size = 2; break;
7565                 case MONO_TYPE_I4:
7566                 case MONO_TYPE_U4:
7567                 case MONO_TYPE_R4:
7568                         size = 4; break;
7569                 case MONO_TYPE_R8:
7570                 case MONO_TYPE_I8:
7571                 case MONO_TYPE_U8:
7572                         size = 8; break;
7573 #endif
7574                 default:
7575                         return NULL;
7576                 }
7577                 size *= len;
7578                 if (size > mono_type_size (field->type, &dummy_align))
7579                     return NULL;
7580                 *out_size = size;
7581                 /*g_print ("optimized in %s: size: %d, numelems: %d\n", method->name, size, newarr->inst_newa_len->inst_c0);*/
7582                 if (!image_is_dynamic (method->klass->image)) {
7583                         field_index = read32 (ip + 2) & 0xffffff;
7584                         mono_metadata_field_info (method->klass->image, field_index - 1, NULL, &rva, NULL);
7585                         data_ptr = mono_image_rva_map (method->klass->image, rva);
7586                         /*g_print ("field: 0x%08x, rva: %d, rva_ptr: %p\n", read32 (ip + 2), rva, data_ptr);*/
7587                         /* for aot code we do the lookup on load */
7588                         if (aot && data_ptr)
7589                                 return (const char *)GUINT_TO_POINTER (rva);
7590                 } else {
7591                         /*FIXME is it possible to AOT a SRE assembly not meant to be saved? */ 
7592                         g_assert (!aot);
7593                         data_ptr = mono_field_get_data (field);
7594                 }
7595                 return data_ptr;
7596         }
7597         return NULL;
7598 }
7599
7600 static void
7601 set_exception_type_from_invalid_il (MonoCompile *cfg, MonoMethod *method, unsigned char *ip)
7602 {
7603         char *method_fname = mono_method_full_name (method, TRUE);
7604         char *method_code;
7605         MonoMethodHeader *header = mono_method_get_header (method);
7606
7607         if (header->code_size == 0)
7608                 method_code = g_strdup ("method body is empty.");
7609         else
7610                 method_code = mono_disasm_code_one (NULL, method, ip, NULL);
7611         mono_cfg_set_exception_invalid_program (cfg, g_strdup_printf ("Invalid IL code in %s: %s\n", method_fname, method_code));
7612         g_free (method_fname);
7613         g_free (method_code);
7614         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
7615 }
7616
7617 static void
7618 emit_stloc_ir (MonoCompile *cfg, MonoInst **sp, MonoMethodHeader *header, int n)
7619 {
7620         MonoInst *ins;
7621         guint32 opcode = mono_type_to_regmove (cfg, header->locals [n]);
7622         if ((opcode == OP_MOVE) && cfg->cbb->last_ins == sp [0]  &&
7623                         ((sp [0]->opcode == OP_ICONST) || (sp [0]->opcode == OP_I8CONST))) {
7624                 /* Optimize reg-reg moves away */
7625                 /* 
7626                  * Can't optimize other opcodes, since sp[0] might point to
7627                  * the last ins of a decomposed opcode.
7628                  */
7629                 sp [0]->dreg = (cfg)->locals [n]->dreg;
7630         } else {
7631                 EMIT_NEW_LOCSTORE (cfg, ins, n, *sp);
7632         }
7633 }
7634
7635 /*
7636  * ldloca inhibits many optimizations so try to get rid of it in common
7637  * cases.
7638  */
7639 static inline unsigned char *
7640 emit_optimized_ldloca_ir (MonoCompile *cfg, unsigned char *ip, unsigned char *end, int size)
7641 {
7642         int local, token;
7643         MonoClass *klass;
7644         MonoType *type;
7645
7646         if (size == 1) {
7647                 local = ip [1];
7648                 ip += 2;
7649         } else {
7650                 local = read16 (ip + 2);
7651                 ip += 4;
7652         }
7653         
7654         if (ip + 6 < end && (ip [0] == CEE_PREFIX1) && (ip [1] == CEE_INITOBJ) && ip_in_bb (cfg, cfg->cbb, ip + 1)) {
7655                 /* From the INITOBJ case */
7656                 token = read32 (ip + 2);
7657                 klass = mini_get_class (cfg->current_method, token, cfg->generic_context);
7658                 CHECK_TYPELOAD (klass);
7659                 type = mini_get_underlying_type (&klass->byval_arg);
7660                 emit_init_local (cfg, local, type, TRUE);
7661                 return ip + 6;
7662         }
7663  exception_exit:
7664         return NULL;
7665 }
7666
7667 static MonoInst*
7668 emit_llvmonly_virtual_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, int context_used, MonoInst **sp)
7669 {
7670         MonoInst *icall_args [16];
7671         MonoInst *call_target, *ins, *vtable_ins;
7672         int arg_reg, this_reg, vtable_reg;
7673         gboolean is_iface = cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE;
7674         gboolean is_gsharedvt = cfg->gsharedvt && mini_is_gsharedvt_variable_signature (fsig);
7675         gboolean variant_iface = FALSE;
7676         guint32 slot;
7677         int offset;
7678
7679         /*
7680          * In llvm-only mode, vtables contain function descriptors instead of
7681          * method addresses/trampolines.
7682          */
7683         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
7684
7685         if (is_iface)
7686                 slot = mono_method_get_imt_slot (cmethod);
7687         else
7688                 slot = mono_method_get_vtable_index (cmethod);
7689
7690         this_reg = sp [0]->dreg;
7691
7692         if (is_iface && mono_class_has_variant_generic_params (cmethod->klass))
7693                 variant_iface = TRUE;
7694
7695         if (!fsig->generic_param_count && !is_iface && !is_gsharedvt) {
7696                 /*
7697                  * The simplest case, a normal virtual call.
7698                  */
7699                 int slot_reg = alloc_preg (cfg);
7700                 int addr_reg = alloc_preg (cfg);
7701                 int arg_reg = alloc_preg (cfg);
7702                 MonoBasicBlock *non_null_bb;
7703
7704                 vtable_reg = alloc_preg (cfg);
7705                 EMIT_NEW_LOAD_MEMBASE (cfg, vtable_ins, OP_LOAD_MEMBASE, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
7706                 offset = MONO_STRUCT_OFFSET (MonoVTable, vtable) + (slot * SIZEOF_VOID_P);
7707
7708                 /* Load the vtable slot, which contains a function descriptor. */
7709                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, slot_reg, vtable_reg, offset);
7710
7711                 NEW_BBLOCK (cfg, non_null_bb);
7712
7713                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, slot_reg, 0);
7714                 cfg->cbb->last_ins->flags |= MONO_INST_LIKELY;
7715                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, non_null_bb);
7716
7717                 /* Slow path */
7718                 // FIXME: Make the wrapper use the preserveall cconv
7719                 // FIXME: Use one icall per slot for small slot numbers ?
7720                 icall_args [0] = vtable_ins;
7721                 EMIT_NEW_ICONST (cfg, icall_args [1], slot);
7722                 /* Make the icall return the vtable slot value to save some code space */
7723                 ins = mono_emit_jit_icall (cfg, mono_init_vtable_slot, icall_args);
7724                 ins->dreg = slot_reg;
7725                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, non_null_bb);
7726
7727                 /* Fastpath */
7728                 MONO_START_BB (cfg, non_null_bb);
7729                 /* Load the address + arg from the vtable slot */
7730                 EMIT_NEW_LOAD_MEMBASE (cfg, call_target, OP_LOAD_MEMBASE, addr_reg, slot_reg, 0);
7731                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, arg_reg, slot_reg, SIZEOF_VOID_P);
7732
7733                 return emit_extra_arg_calli (cfg, fsig, sp, arg_reg, call_target);
7734         }
7735
7736         if (!fsig->generic_param_count && is_iface && !variant_iface && !is_gsharedvt) {
7737                 /*
7738                  * A simple interface call
7739                  *
7740                  * We make a call through an imt slot to obtain the function descriptor we need to call.
7741                  * The imt slot contains a function descriptor for a runtime function + arg.
7742                  */
7743                 int slot_reg = alloc_preg (cfg);
7744                 int addr_reg = alloc_preg (cfg);
7745                 int arg_reg = alloc_preg (cfg);
7746                 MonoInst *thunk_addr_ins, *thunk_arg_ins, *ftndesc_ins;
7747
7748                 vtable_reg = alloc_preg (cfg);
7749                 EMIT_NEW_LOAD_MEMBASE (cfg, vtable_ins, OP_LOAD_MEMBASE, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
7750                 offset = ((gint32)slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
7751
7752                 /*
7753                  * The slot is already initialized when the vtable is created so there is no need
7754                  * to check it here.
7755                  */
7756
7757                 /* Load the imt slot, which contains a function descriptor. */
7758                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, slot_reg, vtable_reg, offset);
7759
7760                 /* Load the address + arg of the imt thunk from the imt slot */
7761                 EMIT_NEW_LOAD_MEMBASE (cfg, thunk_addr_ins, OP_LOAD_MEMBASE, addr_reg, slot_reg, 0);
7762                 EMIT_NEW_LOAD_MEMBASE (cfg, thunk_arg_ins, OP_LOAD_MEMBASE, arg_reg, slot_reg, SIZEOF_VOID_P);
7763                 /*
7764                  * IMT thunks in llvm-only mode are C functions which take an info argument
7765                  * plus the imt method and return the ftndesc to call.
7766                  */
7767                 icall_args [0] = thunk_arg_ins;
7768                 icall_args [1] = emit_get_rgctx_method (cfg, context_used,
7769                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD);
7770                 ftndesc_ins = mono_emit_calli (cfg, helper_sig_llvmonly_imt_thunk, icall_args, thunk_addr_ins, NULL, NULL);
7771
7772                 return emit_llvmonly_calli (cfg, fsig, sp, ftndesc_ins);
7773         }
7774
7775         if ((fsig->generic_param_count || variant_iface) && !is_gsharedvt) {
7776                 /*
7777                  * This is similar to the interface case, the vtable slot points to an imt thunk which is
7778                  * dynamically extended as more instantiations are discovered.
7779                  * This handles generic virtual methods both on classes and interfaces.
7780                  */
7781                 int slot_reg = alloc_preg (cfg);
7782                 int addr_reg = alloc_preg (cfg);
7783                 int arg_reg = alloc_preg (cfg);
7784                 int ftndesc_reg = alloc_preg (cfg);
7785                 MonoInst *thunk_addr_ins, *thunk_arg_ins, *ftndesc_ins;
7786                 MonoBasicBlock *slowpath_bb, *end_bb;
7787
7788                 NEW_BBLOCK (cfg, slowpath_bb);
7789                 NEW_BBLOCK (cfg, end_bb);
7790
7791                 vtable_reg = alloc_preg (cfg);
7792                 EMIT_NEW_LOAD_MEMBASE (cfg, vtable_ins, OP_LOAD_MEMBASE, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
7793                 if (is_iface)
7794                         offset = ((gint32)slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
7795                 else
7796                         offset = MONO_STRUCT_OFFSET (MonoVTable, vtable) + (slot * SIZEOF_VOID_P);
7797
7798                 /* Load the slot, which contains a function descriptor. */
7799                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, slot_reg, vtable_reg, offset);
7800
7801                 /* These slots are not initialized, so fall back to the slow path until they are initialized */
7802                 /* That happens when mono_method_add_generic_virtual_invocation () creates an IMT thunk */
7803                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, slot_reg, 0);
7804                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, slowpath_bb);
7805
7806                 /* Fastpath */
7807                 /* Same as with iface calls */
7808                 EMIT_NEW_LOAD_MEMBASE (cfg, thunk_addr_ins, OP_LOAD_MEMBASE, addr_reg, slot_reg, 0);
7809                 EMIT_NEW_LOAD_MEMBASE (cfg, thunk_arg_ins, OP_LOAD_MEMBASE, arg_reg, slot_reg, SIZEOF_VOID_P);
7810                 icall_args [0] = thunk_arg_ins;
7811                 icall_args [1] = emit_get_rgctx_method (cfg, context_used,
7812                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD);
7813                 ftndesc_ins = mono_emit_calli (cfg, helper_sig_llvmonly_imt_thunk, icall_args, thunk_addr_ins, NULL, NULL);
7814                 ftndesc_ins->dreg = ftndesc_reg;
7815                 /*
7816                  * Unlike normal iface calls, these imt thunks can return NULL, i.e. when they are passed an instantiation
7817                  * they don't know about yet. Fall back to the slowpath in that case.
7818                  */
7819                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, ftndesc_reg, 0);
7820                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, slowpath_bb);
7821
7822                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
7823
7824                 /* Slowpath */
7825                 MONO_START_BB (cfg, slowpath_bb);
7826                 icall_args [0] = vtable_ins;
7827                 EMIT_NEW_ICONST (cfg, icall_args [1], slot);
7828                 icall_args [2] = emit_get_rgctx_method (cfg, context_used,
7829                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD);
7830                 if (is_iface)
7831                         ftndesc_ins = mono_emit_jit_icall (cfg, mono_resolve_generic_virtual_iface_call, icall_args);
7832                 else
7833                         ftndesc_ins = mono_emit_jit_icall (cfg, mono_resolve_generic_virtual_call, icall_args);
7834                 ftndesc_ins->dreg = ftndesc_reg;
7835                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
7836
7837                 /* Common case */
7838                 MONO_START_BB (cfg, end_bb);
7839                 return emit_llvmonly_calli (cfg, fsig, sp, ftndesc_ins);
7840         }
7841
7842         /*
7843          * Non-optimized cases
7844          */
7845         icall_args [0] = sp [0];
7846         EMIT_NEW_ICONST (cfg, icall_args [1], slot);
7847
7848         icall_args [2] = emit_get_rgctx_method (cfg, context_used,
7849                                                                                         cmethod, MONO_RGCTX_INFO_METHOD);
7850
7851         arg_reg = alloc_preg (cfg);
7852         MONO_EMIT_NEW_PCONST (cfg, arg_reg, NULL);
7853         EMIT_NEW_VARLOADA_VREG (cfg, icall_args [3], arg_reg, &mono_defaults.int_class->byval_arg);
7854
7855         g_assert (is_gsharedvt);
7856         if (is_iface)
7857                 call_target = mono_emit_jit_icall (cfg, mono_resolve_iface_call_gsharedvt, icall_args);
7858         else
7859                 call_target = mono_emit_jit_icall (cfg, mono_resolve_vcall_gsharedvt, icall_args);
7860
7861         /*
7862          * Pass the extra argument even if the callee doesn't receive it, most
7863          * calling conventions allow this.
7864          */
7865         return emit_extra_arg_calli (cfg, fsig, sp, arg_reg, call_target);
7866 }
7867
7868 static gboolean
7869 is_exception_class (MonoClass *klass)
7870 {
7871         while (klass) {
7872                 if (klass == mono_defaults.exception_class)
7873                         return TRUE;
7874                 klass = klass->parent;
7875         }
7876         return FALSE;
7877 }
7878
7879 /*
7880  * is_jit_optimizer_disabled:
7881  *
7882  *   Determine whenever M's assembly has a DebuggableAttribute with the
7883  * IsJITOptimizerDisabled flag set.
7884  */
7885 static gboolean
7886 is_jit_optimizer_disabled (MonoMethod *m)
7887 {
7888         MonoAssembly *ass = m->klass->image->assembly;
7889         MonoCustomAttrInfo* attrs;
7890         static MonoClass *klass;
7891         int i;
7892         gboolean val = FALSE;
7893
7894         g_assert (ass);
7895         if (ass->jit_optimizer_disabled_inited)
7896                 return ass->jit_optimizer_disabled;
7897
7898         if (!klass)
7899                 klass = mono_class_from_name (mono_defaults.corlib, "System.Diagnostics", "DebuggableAttribute");
7900         if (!klass) {
7901                 /* Linked away */
7902                 ass->jit_optimizer_disabled = FALSE;
7903                 mono_memory_barrier ();
7904                 ass->jit_optimizer_disabled_inited = TRUE;
7905                 return FALSE;
7906         }
7907
7908         attrs = mono_custom_attrs_from_assembly (ass);
7909         if (attrs) {
7910                 for (i = 0; i < attrs->num_attrs; ++i) {
7911                         MonoCustomAttrEntry *attr = &attrs->attrs [i];
7912                         const gchar *p;
7913                         MonoMethodSignature *sig;
7914
7915                         if (!attr->ctor || attr->ctor->klass != klass)
7916                                 continue;
7917                         /* Decode the attribute. See reflection.c */
7918                         p = (const char*)attr->data;
7919                         g_assert (read16 (p) == 0x0001);
7920                         p += 2;
7921
7922                         // FIXME: Support named parameters
7923                         sig = mono_method_signature (attr->ctor);
7924                         if (sig->param_count != 2 || sig->params [0]->type != MONO_TYPE_BOOLEAN || sig->params [1]->type != MONO_TYPE_BOOLEAN)
7925                                 continue;
7926                         /* Two boolean arguments */
7927                         p ++;
7928                         val = *p;
7929                 }
7930                 mono_custom_attrs_free (attrs);
7931         }
7932
7933         ass->jit_optimizer_disabled = val;
7934         mono_memory_barrier ();
7935         ass->jit_optimizer_disabled_inited = TRUE;
7936
7937         return val;
7938 }
7939
7940 static gboolean
7941 is_supported_tail_call (MonoCompile *cfg, MonoMethod *method, MonoMethod *cmethod, MonoMethodSignature *fsig, int call_opcode)
7942 {
7943         gboolean supported_tail_call;
7944         int i;
7945
7946         supported_tail_call = mono_arch_tail_call_supported (cfg, mono_method_signature (method), mono_method_signature (cmethod));
7947
7948         for (i = 0; i < fsig->param_count; ++i) {
7949                 if (fsig->params [i]->byref || fsig->params [i]->type == MONO_TYPE_PTR || fsig->params [i]->type == MONO_TYPE_FNPTR)
7950                         /* These can point to the current method's stack */
7951                         supported_tail_call = FALSE;
7952         }
7953         if (fsig->hasthis && cmethod->klass->valuetype)
7954                 /* this might point to the current method's stack */
7955                 supported_tail_call = FALSE;
7956         if (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
7957                 supported_tail_call = FALSE;
7958         if (cfg->method->save_lmf)
7959                 supported_tail_call = FALSE;
7960         if (cmethod->wrapper_type && cmethod->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD)
7961                 supported_tail_call = FALSE;
7962         if (call_opcode != CEE_CALL)
7963                 supported_tail_call = FALSE;
7964
7965         /* Debugging support */
7966 #if 0
7967         if (supported_tail_call) {
7968                 if (!mono_debug_count ())
7969                         supported_tail_call = FALSE;
7970         }
7971 #endif
7972
7973         return supported_tail_call;
7974 }
7975
7976 /*
7977  * handle_ctor_call:
7978  *
7979  *   Handle calls made to ctors from NEWOBJ opcodes.
7980  */
7981 static void
7982 handle_ctor_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, int context_used,
7983                                   MonoInst **sp, guint8 *ip, int *inline_costs)
7984 {
7985         MonoInst *vtable_arg = NULL, *callvirt_this_arg = NULL, *ins;
7986
7987         if (cmethod->klass->valuetype && mono_class_generic_sharing_enabled (cmethod->klass) &&
7988                                         mono_method_is_generic_sharable (cmethod, TRUE)) {
7989                 if (cmethod->is_inflated && mono_method_get_context (cmethod)->method_inst) {
7990                         mono_class_vtable (cfg->domain, cmethod->klass);
7991                         CHECK_TYPELOAD (cmethod->klass);
7992
7993                         vtable_arg = emit_get_rgctx_method (cfg, context_used,
7994                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
7995                 } else {
7996                         if (context_used) {
7997                                 vtable_arg = emit_get_rgctx_klass (cfg, context_used,
7998                                                                                                    cmethod->klass, MONO_RGCTX_INFO_VTABLE);
7999                         } else {
8000                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
8001
8002                                 CHECK_TYPELOAD (cmethod->klass);
8003                                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
8004                         }
8005                 }
8006         }
8007
8008         /* Avoid virtual calls to ctors if possible */
8009         if (mono_class_is_marshalbyref (cmethod->klass))
8010                 callvirt_this_arg = sp [0];
8011
8012         if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_ctor (cfg, cmethod, fsig, sp))) {
8013                 g_assert (MONO_TYPE_IS_VOID (fsig->ret));
8014                 CHECK_CFG_EXCEPTION;
8015         } else if ((cfg->opt & MONO_OPT_INLINE) && cmethod && !context_used && !vtable_arg &&
8016                            mono_method_check_inlining (cfg, cmethod) &&
8017                            !mono_class_is_subclass_of (cmethod->klass, mono_defaults.exception_class, FALSE)) {
8018                 int costs;
8019
8020                 if ((costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, FALSE))) {
8021                         cfg->real_offset += 5;
8022
8023                         *inline_costs += costs - 5;
8024                 } else {
8025                         INLINE_FAILURE ("inline failure");
8026                         // FIXME-VT: Clean this up
8027                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig))
8028                                 GSHAREDVT_FAILURE(*ip);
8029                         mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, callvirt_this_arg, NULL, NULL);
8030                 }
8031         } else if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) {
8032                 MonoInst *addr;
8033
8034                 addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE);
8035
8036                 if (cfg->llvm_only) {
8037                         // FIXME: Avoid initializing vtable_arg
8038                         emit_llvmonly_calli (cfg, fsig, sp, addr);
8039                 } else {
8040                         mono_emit_calli (cfg, fsig, sp, addr, NULL, vtable_arg);
8041                 }
8042         } else if (context_used &&
8043                            ((!mono_method_is_generic_sharable_full (cmethod, TRUE, FALSE, FALSE) ||
8044                                  !mono_class_generic_sharing_enabled (cmethod->klass)) || cfg->gsharedvt)) {
8045                 MonoInst *cmethod_addr;
8046
8047                 /* Generic calls made out of gsharedvt methods cannot be patched, so use an indirect call */
8048
8049                 if (cfg->llvm_only) {
8050                         MonoInst *addr = emit_get_rgctx_method (cfg, context_used, cmethod,
8051                                                                                                         MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
8052                         emit_llvmonly_calli (cfg, fsig, sp, addr);
8053                 } else {
8054                         cmethod_addr = emit_get_rgctx_method (cfg, context_used,
8055                                                                                                   cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
8056
8057                         mono_emit_calli (cfg, fsig, sp, cmethod_addr, NULL, vtable_arg);
8058                 }
8059         } else {
8060                 INLINE_FAILURE ("ctor call");
8061                 ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp,
8062                                                                                   callvirt_this_arg, NULL, vtable_arg);
8063         }
8064  exception_exit:
8065         return;
8066 }
8067
8068 static void
8069 emit_setret (MonoCompile *cfg, MonoInst *val)
8070 {
8071         MonoType *ret_type = mini_get_underlying_type (mono_method_signature (cfg->method)->ret);
8072         MonoInst *ins;
8073
8074         if (mini_type_to_stind (cfg, ret_type) == CEE_STOBJ) {
8075                 MonoInst *ret_addr;
8076
8077                 if (!cfg->vret_addr) {
8078                         EMIT_NEW_VARSTORE (cfg, ins, cfg->ret, ret_type, val);
8079                 } else {
8080                         EMIT_NEW_RETLOADA (cfg, ret_addr);
8081
8082                         EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STOREV_MEMBASE, ret_addr->dreg, 0, val->dreg);
8083                         ins->klass = mono_class_from_mono_type (ret_type);
8084                 }
8085         } else {
8086 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
8087                 if (COMPILE_SOFT_FLOAT (cfg) && !ret_type->byref && ret_type->type == MONO_TYPE_R4) {
8088                         MonoInst *iargs [1];
8089                         MonoInst *conv;
8090
8091                         iargs [0] = val;
8092                         conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
8093                         mono_arch_emit_setret (cfg, cfg->method, conv);
8094                 } else {
8095                         mono_arch_emit_setret (cfg, cfg->method, val);
8096                 }
8097 #else
8098                 mono_arch_emit_setret (cfg, cfg->method, val);
8099 #endif
8100         }
8101 }
8102
8103 /*
8104  * mono_method_to_ir:
8105  *
8106  *   Translate the .net IL into linear IR.
8107  */
8108 int
8109 mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock, 
8110                    MonoInst *return_var, MonoInst **inline_args, 
8111                    guint inline_offset, gboolean is_virtual_call)
8112 {
8113         MonoError error;
8114         MonoInst *ins, **sp, **stack_start;
8115         MonoBasicBlock *tblock = NULL, *init_localsbb = NULL;
8116         MonoSimpleBasicBlock *bb = NULL, *original_bb = NULL;
8117         MonoMethod *cmethod, *method_definition;
8118         MonoInst **arg_array;
8119         MonoMethodHeader *header;
8120         MonoImage *image;
8121         guint32 token, ins_flag;
8122         MonoClass *klass;
8123         MonoClass *constrained_class = NULL;
8124         unsigned char *ip, *end, *target, *err_pos;
8125         MonoMethodSignature *sig;
8126         MonoGenericContext *generic_context = NULL;
8127         MonoGenericContainer *generic_container = NULL;
8128         MonoType **param_types;
8129         int i, n, start_new_bblock, dreg;
8130         int num_calls = 0, inline_costs = 0;
8131         int breakpoint_id = 0;
8132         guint num_args;
8133         GSList *class_inits = NULL;
8134         gboolean dont_verify, dont_verify_stloc, readonly = FALSE;
8135         int context_used;
8136         gboolean init_locals, seq_points, skip_dead_blocks;
8137         gboolean sym_seq_points = FALSE;
8138         MonoDebugMethodInfo *minfo;
8139         MonoBitSet *seq_point_locs = NULL;
8140         MonoBitSet *seq_point_set_locs = NULL;
8141
8142         cfg->disable_inline = is_jit_optimizer_disabled (method);
8143
8144         /* serialization and xdomain stuff may need access to private fields and methods */
8145         dont_verify = method->klass->image->assembly->corlib_internal? TRUE: FALSE;
8146         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE;
8147         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH;
8148         dont_verify |= method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE; /* bug #77896 */
8149         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP;
8150         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP_INVOKE;
8151
8152         /* still some type unsafety issues in marshal wrappers... (unknown is PtrToStructure) */
8153         dont_verify_stloc = method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE;
8154         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_UNKNOWN;
8155         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED;
8156         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_STELEMREF;
8157
8158         image = method->klass->image;
8159         header = mono_method_get_header (method);
8160         if (!header) {
8161                 if (mono_loader_get_last_error ()) {
8162                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
8163                         mono_error_set_from_loader_error (&cfg->error);
8164                 } else {
8165                         mono_cfg_set_exception_invalid_program (cfg, g_strdup_printf ("Missing or incorrect header for method %s", cfg->method->name));
8166                 }
8167                 goto exception_exit;
8168         }
8169         generic_container = mono_method_get_generic_container (method);
8170         sig = mono_method_signature (method);
8171         num_args = sig->hasthis + sig->param_count;
8172         ip = (unsigned char*)header->code;
8173         cfg->cil_start = ip;
8174         end = ip + header->code_size;
8175         cfg->stat_cil_code_size += header->code_size;
8176
8177         seq_points = cfg->gen_seq_points && cfg->method == method;
8178
8179         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
8180                 /* We could hit a seq point before attaching to the JIT (#8338) */
8181                 seq_points = FALSE;
8182         }
8183
8184         if (cfg->gen_sdb_seq_points && cfg->method == method) {
8185                 minfo = mono_debug_lookup_method (method);
8186                 if (minfo) {
8187                         MonoSymSeqPoint *sps;
8188                         int i, n_il_offsets;
8189
8190                         mono_debug_get_seq_points (minfo, NULL, NULL, NULL, &sps, &n_il_offsets);
8191                         seq_point_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
8192                         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);
8193                         sym_seq_points = TRUE;
8194                         for (i = 0; i < n_il_offsets; ++i) {
8195                                 if (sps [i].il_offset < header->code_size)
8196                                         mono_bitset_set_fast (seq_point_locs, sps [i].il_offset);
8197                         }
8198                         g_free (sps);
8199                 } else if (!method->wrapper_type && !method->dynamic && mono_debug_image_has_debug_info (method->klass->image)) {
8200                         /* Methods without line number info like auto-generated property accessors */
8201                         seq_point_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
8202                         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);
8203                         sym_seq_points = TRUE;
8204                 }
8205         }
8206
8207         /* 
8208          * Methods without init_locals set could cause asserts in various passes
8209          * (#497220). To work around this, we emit dummy initialization opcodes
8210          * (OP_DUMMY_ICONST etc.) which generate no code. These are only supported
8211          * on some platforms.
8212          */
8213         if ((cfg->opt & MONO_OPT_UNSAFE) && cfg->backend->have_dummy_init)
8214                 init_locals = header->init_locals;
8215         else
8216                 init_locals = TRUE;
8217
8218         method_definition = method;
8219         while (method_definition->is_inflated) {
8220                 MonoMethodInflated *imethod = (MonoMethodInflated *) method_definition;
8221                 method_definition = imethod->declaring;
8222         }
8223
8224         /* SkipVerification is not allowed if core-clr is enabled */
8225         if (!dont_verify && mini_assembly_can_skip_verification (cfg->domain, method)) {
8226                 dont_verify = TRUE;
8227                 dont_verify_stloc = TRUE;
8228         }
8229
8230         if (sig->is_inflated)
8231                 generic_context = mono_method_get_context (method);
8232         else if (generic_container)
8233                 generic_context = &generic_container->context;
8234         cfg->generic_context = generic_context;
8235
8236         if (!cfg->gshared)
8237                 g_assert (!sig->has_type_parameters);
8238
8239         if (sig->generic_param_count && method->wrapper_type == MONO_WRAPPER_NONE) {
8240                 g_assert (method->is_inflated);
8241                 g_assert (mono_method_get_context (method)->method_inst);
8242         }
8243         if (method->is_inflated && mono_method_get_context (method)->method_inst)
8244                 g_assert (sig->generic_param_count);
8245
8246         if (cfg->method == method) {
8247                 cfg->real_offset = 0;
8248         } else {
8249                 cfg->real_offset = inline_offset;
8250         }
8251
8252         cfg->cil_offset_to_bb = (MonoBasicBlock **)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoBasicBlock*) * header->code_size);
8253         cfg->cil_offset_to_bb_len = header->code_size;
8254
8255         cfg->current_method = method;
8256
8257         if (cfg->verbose_level > 2)
8258                 printf ("method to IR %s\n", mono_method_full_name (method, TRUE));
8259
8260         param_types = (MonoType **)mono_mempool_alloc (cfg->mempool, sizeof (MonoType*) * num_args);
8261         if (sig->hasthis)
8262                 param_types [0] = method->klass->valuetype?&method->klass->this_arg:&method->klass->byval_arg;
8263         for (n = 0; n < sig->param_count; ++n)
8264                 param_types [n + sig->hasthis] = sig->params [n];
8265         cfg->arg_types = param_types;
8266
8267         cfg->dont_inline = g_list_prepend (cfg->dont_inline, method);
8268         if (cfg->method == method) {
8269
8270                 if (cfg->prof_options & MONO_PROFILE_INS_COVERAGE)
8271                         cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, header->code_size);
8272
8273                 /* ENTRY BLOCK */
8274                 NEW_BBLOCK (cfg, start_bblock);
8275                 cfg->bb_entry = start_bblock;
8276                 start_bblock->cil_code = NULL;
8277                 start_bblock->cil_length = 0;
8278
8279                 /* EXIT BLOCK */
8280                 NEW_BBLOCK (cfg, end_bblock);
8281                 cfg->bb_exit = end_bblock;
8282                 end_bblock->cil_code = NULL;
8283                 end_bblock->cil_length = 0;
8284                 end_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
8285                 g_assert (cfg->num_bblocks == 2);
8286
8287                 arg_array = cfg->args;
8288
8289                 if (header->num_clauses) {
8290                         cfg->spvars = g_hash_table_new (NULL, NULL);
8291                         cfg->exvars = g_hash_table_new (NULL, NULL);
8292                 }
8293                 /* handle exception clauses */
8294                 for (i = 0; i < header->num_clauses; ++i) {
8295                         MonoBasicBlock *try_bb;
8296                         MonoExceptionClause *clause = &header->clauses [i];
8297                         GET_BBLOCK (cfg, try_bb, ip + clause->try_offset);
8298
8299                         try_bb->real_offset = clause->try_offset;
8300                         try_bb->try_start = TRUE;
8301                         try_bb->region = ((i + 1) << 8) | clause->flags;
8302                         GET_BBLOCK (cfg, tblock, ip + clause->handler_offset);
8303                         tblock->real_offset = clause->handler_offset;
8304                         tblock->flags |= BB_EXCEPTION_HANDLER;
8305
8306                         /*
8307                          * Linking the try block with the EH block hinders inlining as we won't be able to 
8308                          * merge the bblocks from inlining and produce an artificial hole for no good reason.
8309                          */
8310                         if (COMPILE_LLVM (cfg))
8311                                 link_bblock (cfg, try_bb, tblock);
8312
8313                         if (*(ip + clause->handler_offset) == CEE_POP)
8314                                 tblock->flags |= BB_EXCEPTION_DEAD_OBJ;
8315
8316                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY ||
8317                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER ||
8318                             clause->flags == MONO_EXCEPTION_CLAUSE_FAULT) {
8319                                 MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
8320                                 MONO_ADD_INS (tblock, ins);
8321
8322                                 if (seq_points && clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY && clause->flags != MONO_EXCEPTION_CLAUSE_FILTER) {
8323                                         /* finally clauses already have a seq point */
8324                                         /* seq points for filter clauses are emitted below */
8325                                         NEW_SEQ_POINT (cfg, ins, clause->handler_offset, TRUE);
8326                                         MONO_ADD_INS (tblock, ins);
8327                                 }
8328
8329                                 /* todo: is a fault block unsafe to optimize? */
8330                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
8331                                         tblock->flags |= BB_EXCEPTION_UNSAFE;
8332                         }
8333
8334                         /*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);
8335                           while (p < end) {
8336                           printf ("%s", mono_disasm_code_one (NULL, method, p, &p));
8337                           }*/
8338                         /* catch and filter blocks get the exception object on the stack */
8339                         if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE ||
8340                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
8341
8342                                 /* mostly like handle_stack_args (), but just sets the input args */
8343                                 /* printf ("handling clause at IL_%04x\n", clause->handler_offset); */
8344                                 tblock->in_scount = 1;
8345                                 tblock->in_stack = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
8346                                 tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
8347
8348                                 cfg->cbb = tblock;
8349
8350 #ifdef MONO_CONTEXT_SET_LLVM_EXC_REG
8351                                 /* The EH code passes in the exception in a register to both JITted and LLVM compiled code */
8352                                 if (!cfg->compile_llvm) {
8353                                         MONO_INST_NEW (cfg, ins, OP_GET_EX_OBJ);
8354                                         ins->dreg = tblock->in_stack [0]->dreg;
8355                                         MONO_ADD_INS (tblock, ins);
8356                                 }
8357 #else
8358                                 MonoInst *dummy_use;
8359
8360                                 /* 
8361                                  * Add a dummy use for the exvar so its liveness info will be
8362                                  * correct.
8363                                  */
8364                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, tblock->in_stack [0]);
8365 #endif
8366
8367                                 if (seq_points && clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
8368                                         NEW_SEQ_POINT (cfg, ins, clause->handler_offset, TRUE);
8369                                         MONO_ADD_INS (tblock, ins);
8370                                 }
8371                                 
8372                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
8373                                         GET_BBLOCK (cfg, tblock, ip + clause->data.filter_offset);
8374                                         tblock->flags |= BB_EXCEPTION_HANDLER;
8375                                         tblock->real_offset = clause->data.filter_offset;
8376                                         tblock->in_scount = 1;
8377                                         tblock->in_stack = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
8378                                         /* The filter block shares the exvar with the handler block */
8379                                         tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
8380                                         MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
8381                                         MONO_ADD_INS (tblock, ins);
8382                                 }
8383                         }
8384
8385                         if (clause->flags != MONO_EXCEPTION_CLAUSE_FILTER &&
8386                                         clause->data.catch_class &&
8387                                         cfg->gshared &&
8388                                         mono_class_check_context_used (clause->data.catch_class)) {
8389                                 /*
8390                                  * In shared generic code with catch
8391                                  * clauses containing type variables
8392                                  * the exception handling code has to
8393                                  * be able to get to the rgctx.
8394                                  * Therefore we have to make sure that
8395                                  * the vtable/mrgctx argument (for
8396                                  * static or generic methods) or the
8397                                  * "this" argument (for non-static
8398                                  * methods) are live.
8399                                  */
8400                                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
8401                                                 mini_method_get_context (method)->method_inst ||
8402                                                 method->klass->valuetype) {
8403                                         mono_get_vtable_var (cfg);
8404                                 } else {
8405                                         MonoInst *dummy_use;
8406
8407                                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, arg_array [0]);
8408                                 }
8409                         }
8410                 }
8411         } else {
8412                 arg_array = (MonoInst **) alloca (sizeof (MonoInst *) * num_args);
8413                 cfg->cbb = start_bblock;
8414                 cfg->args = arg_array;
8415                 mono_save_args (cfg, sig, inline_args);
8416         }
8417
8418         /* FIRST CODE BLOCK */
8419         NEW_BBLOCK (cfg, tblock);
8420         tblock->cil_code = ip;
8421         cfg->cbb = tblock;
8422         cfg->ip = ip;
8423
8424         ADD_BBLOCK (cfg, tblock);
8425
8426         if (cfg->method == method) {
8427                 breakpoint_id = mono_debugger_method_has_breakpoint (method);
8428                 if (breakpoint_id) {
8429                         MONO_INST_NEW (cfg, ins, OP_BREAK);
8430                         MONO_ADD_INS (cfg->cbb, ins);
8431                 }
8432         }
8433
8434         /* we use a separate basic block for the initialization code */
8435         NEW_BBLOCK (cfg, init_localsbb);
8436         cfg->bb_init = init_localsbb;
8437         init_localsbb->real_offset = cfg->real_offset;
8438         start_bblock->next_bb = init_localsbb;
8439         init_localsbb->next_bb = cfg->cbb;
8440         link_bblock (cfg, start_bblock, init_localsbb);
8441         link_bblock (cfg, init_localsbb, cfg->cbb);
8442                 
8443         cfg->cbb = init_localsbb;
8444
8445         if (cfg->gsharedvt && cfg->method == method) {
8446                 MonoGSharedVtMethodInfo *info;
8447                 MonoInst *var, *locals_var;
8448                 int dreg;
8449
8450                 info = (MonoGSharedVtMethodInfo *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoGSharedVtMethodInfo));
8451                 info->method = cfg->method;
8452                 info->count_entries = 16;
8453                 info->entries = (MonoRuntimeGenericContextInfoTemplate *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
8454                 cfg->gsharedvt_info = info;
8455
8456                 var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
8457                 /* prevent it from being register allocated */
8458                 //var->flags |= MONO_INST_VOLATILE;
8459                 cfg->gsharedvt_info_var = var;
8460
8461                 ins = emit_get_rgctx_gsharedvt_method (cfg, mini_method_check_context_used (cfg, method), method, info);
8462                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, var->dreg, ins->dreg);
8463
8464                 /* Allocate locals */
8465                 locals_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
8466                 /* prevent it from being register allocated */
8467                 //locals_var->flags |= MONO_INST_VOLATILE;
8468                 cfg->gsharedvt_locals_var = locals_var;
8469
8470                 dreg = alloc_ireg (cfg);
8471                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, dreg, var->dreg, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, locals_size));
8472
8473                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
8474                 ins->dreg = locals_var->dreg;
8475                 ins->sreg1 = dreg;
8476                 MONO_ADD_INS (cfg->cbb, ins);
8477                 cfg->gsharedvt_locals_var_ins = ins;
8478                 
8479                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
8480                 /*
8481                 if (init_locals)
8482                         ins->flags |= MONO_INST_INIT;
8483                 */
8484         }
8485
8486         if (mono_security_core_clr_enabled ()) {
8487                 /* check if this is native code, e.g. an icall or a p/invoke */
8488                 if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
8489                         MonoMethod *wrapped = mono_marshal_method_from_wrapper (method);
8490                         if (wrapped) {
8491                                 gboolean pinvk = (wrapped->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL);
8492                                 gboolean icall = (wrapped->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL);
8493
8494                                 /* if this ia a native call then it can only be JITted from platform code */
8495                                 if ((icall || pinvk) && method->klass && method->klass->image) {
8496                                         if (!mono_security_core_clr_is_platform_image (method->klass->image)) {
8497                                                 MonoException *ex = icall ? mono_get_exception_security () : 
8498                                                         mono_get_exception_method_access ();
8499                                                 emit_throw_exception (cfg, ex);
8500                                         }
8501                                 }
8502                         }
8503                 }
8504         }
8505
8506         CHECK_CFG_EXCEPTION;
8507
8508         if (header->code_size == 0)
8509                 UNVERIFIED;
8510
8511         if (get_basic_blocks (cfg, header, cfg->real_offset, ip, end, &err_pos)) {
8512                 ip = err_pos;
8513                 UNVERIFIED;
8514         }
8515
8516         if (cfg->method == method)
8517                 mono_debug_init_method (cfg, cfg->cbb, breakpoint_id);
8518
8519         for (n = 0; n < header->num_locals; ++n) {
8520                 if (header->locals [n]->type == MONO_TYPE_VOID && !header->locals [n]->byref)
8521                         UNVERIFIED;
8522         }
8523         class_inits = NULL;
8524
8525         /* We force the vtable variable here for all shared methods
8526            for the possibility that they might show up in a stack
8527            trace where their exact instantiation is needed. */
8528         if (cfg->gshared && method == cfg->method) {
8529                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
8530                                 mini_method_get_context (method)->method_inst ||
8531                                 method->klass->valuetype) {
8532                         mono_get_vtable_var (cfg);
8533                 } else {
8534                         /* FIXME: Is there a better way to do this?
8535                            We need the variable live for the duration
8536                            of the whole method. */
8537                         cfg->args [0]->flags |= MONO_INST_VOLATILE;
8538                 }
8539         }
8540
8541         /* add a check for this != NULL to inlined methods */
8542         if (is_virtual_call) {
8543                 MonoInst *arg_ins;
8544
8545                 NEW_ARGLOAD (cfg, arg_ins, 0);
8546                 MONO_ADD_INS (cfg->cbb, arg_ins);
8547                 MONO_EMIT_NEW_CHECK_THIS (cfg, arg_ins->dreg);
8548         }
8549
8550         skip_dead_blocks = !dont_verify;
8551         if (skip_dead_blocks) {
8552                 original_bb = bb = mono_basic_block_split (method, &cfg->error);
8553                 CHECK_CFG_ERROR;
8554                 g_assert (bb);
8555         }
8556
8557         /* we use a spare stack slot in SWITCH and NEWOBJ and others */
8558         stack_start = sp = (MonoInst **)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (header->max_stack + 1));
8559
8560         ins_flag = 0;
8561         start_new_bblock = 0;
8562         while (ip < end) {
8563                 if (cfg->method == method)
8564                         cfg->real_offset = ip - header->code;
8565                 else
8566                         cfg->real_offset = inline_offset;
8567                 cfg->ip = ip;
8568
8569                 context_used = 0;
8570
8571                 if (start_new_bblock) {
8572                         cfg->cbb->cil_length = ip - cfg->cbb->cil_code;
8573                         if (start_new_bblock == 2) {
8574                                 g_assert (ip == tblock->cil_code);
8575                         } else {
8576                                 GET_BBLOCK (cfg, tblock, ip);
8577                         }
8578                         cfg->cbb->next_bb = tblock;
8579                         cfg->cbb = tblock;
8580                         start_new_bblock = 0;
8581                         for (i = 0; i < cfg->cbb->in_scount; ++i) {
8582                                 if (cfg->verbose_level > 3)
8583                                         printf ("loading %d from temp %d\n", i, (int)cfg->cbb->in_stack [i]->inst_c0);
8584                                 EMIT_NEW_TEMPLOAD (cfg, ins, cfg->cbb->in_stack [i]->inst_c0);
8585                                 *sp++ = ins;
8586                         }
8587                         if (class_inits)
8588                                 g_slist_free (class_inits);
8589                         class_inits = NULL;
8590                 } else {
8591                         if ((tblock = cfg->cil_offset_to_bb [ip - cfg->cil_start]) && (tblock != cfg->cbb)) {
8592                                 link_bblock (cfg, cfg->cbb, tblock);
8593                                 if (sp != stack_start) {
8594                                         handle_stack_args (cfg, stack_start, sp - stack_start);
8595                                         sp = stack_start;
8596                                         CHECK_UNVERIFIABLE (cfg);
8597                                 }
8598                                 cfg->cbb->next_bb = tblock;
8599                                 cfg->cbb = tblock;
8600                                 for (i = 0; i < cfg->cbb->in_scount; ++i) {
8601                                         if (cfg->verbose_level > 3)
8602                                                 printf ("loading %d from temp %d\n", i, (int)cfg->cbb->in_stack [i]->inst_c0);
8603                                         EMIT_NEW_TEMPLOAD (cfg, ins, cfg->cbb->in_stack [i]->inst_c0);
8604                                         *sp++ = ins;
8605                                 }
8606                                 g_slist_free (class_inits);
8607                                 class_inits = NULL;
8608                         }
8609                 }
8610
8611                 if (skip_dead_blocks) {
8612                         int ip_offset = ip - header->code;
8613
8614                         if (ip_offset == bb->end)
8615                                 bb = bb->next;
8616
8617                         if (bb->dead) {
8618                                 int op_size = mono_opcode_size (ip, end);
8619                                 g_assert (op_size > 0); /*The BB formation pass must catch all bad ops*/
8620
8621                                 if (cfg->verbose_level > 3) printf ("SKIPPING DEAD OP at %x\n", ip_offset);
8622
8623                                 if (ip_offset + op_size == bb->end) {
8624                                         MONO_INST_NEW (cfg, ins, OP_NOP);
8625                                         MONO_ADD_INS (cfg->cbb, ins);
8626                                         start_new_bblock = 1;
8627                                 }
8628
8629                                 ip += op_size;
8630                                 continue;
8631                         }
8632                 }
8633                 /*
8634                  * Sequence points are points where the debugger can place a breakpoint.
8635                  * Currently, we generate these automatically at points where the IL
8636                  * stack is empty.
8637                  */
8638                 if (seq_points && ((!sym_seq_points && (sp == stack_start)) || (sym_seq_points && mono_bitset_test_fast (seq_point_locs, ip - header->code)))) {
8639                         /*
8640                          * Make methods interruptable at the beginning, and at the targets of
8641                          * backward branches.
8642                          * Also, do this at the start of every bblock in methods with clauses too,
8643                          * to be able to handle instructions with inprecise control flow like
8644                          * throw/endfinally.
8645                          * Backward branches are handled at the end of method-to-ir ().
8646                          */
8647                         gboolean intr_loc = ip == header->code || (!cfg->cbb->last_ins && cfg->header->num_clauses);
8648                         gboolean sym_seq_point = sym_seq_points && mono_bitset_test_fast (seq_point_locs, ip - header->code);
8649
8650                         /* Avoid sequence points on empty IL like .volatile */
8651                         // FIXME: Enable this
8652                         //if (!(cfg->cbb->last_ins && cfg->cbb->last_ins->opcode == OP_SEQ_POINT)) {
8653                         NEW_SEQ_POINT (cfg, ins, ip - header->code, intr_loc);
8654                         if ((sp != stack_start) && !sym_seq_point)
8655                                 ins->flags |= MONO_INST_NONEMPTY_STACK;
8656                         MONO_ADD_INS (cfg->cbb, ins);
8657
8658                         if (sym_seq_points)
8659                                 mono_bitset_set_fast (seq_point_set_locs, ip - header->code);
8660                 }
8661
8662                 cfg->cbb->real_offset = cfg->real_offset;
8663
8664                 if ((cfg->method == method) && cfg->coverage_info) {
8665                         guint32 cil_offset = ip - header->code;
8666                         cfg->coverage_info->data [cil_offset].cil_code = ip;
8667
8668                         /* TODO: Use an increment here */
8669 #if defined(TARGET_X86)
8670                         MONO_INST_NEW (cfg, ins, OP_STORE_MEM_IMM);
8671                         ins->inst_p0 = &(cfg->coverage_info->data [cil_offset].count);
8672                         ins->inst_imm = 1;
8673                         MONO_ADD_INS (cfg->cbb, ins);
8674 #else
8675                         EMIT_NEW_PCONST (cfg, ins, &(cfg->coverage_info->data [cil_offset].count));
8676                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, ins->dreg, 0, 1);
8677 #endif
8678                 }
8679
8680                 if (cfg->verbose_level > 3)
8681                         printf ("converting (in B%d: stack: %d) %s", cfg->cbb->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
8682
8683                 switch (*ip) {
8684                 case CEE_NOP:
8685                         if (seq_points && !sym_seq_points && sp != stack_start) {
8686                                 /*
8687                                  * The C# compiler uses these nops to notify the JIT that it should
8688                                  * insert seq points.
8689                                  */
8690                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, FALSE);
8691                                 MONO_ADD_INS (cfg->cbb, ins);
8692                         }
8693                         if (cfg->keep_cil_nops)
8694                                 MONO_INST_NEW (cfg, ins, OP_HARD_NOP);
8695                         else
8696                                 MONO_INST_NEW (cfg, ins, OP_NOP);
8697                         ip++;
8698                         MONO_ADD_INS (cfg->cbb, ins);
8699                         break;
8700                 case CEE_BREAK:
8701                         if (should_insert_brekpoint (cfg->method)) {
8702                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
8703                         } else {
8704                                 MONO_INST_NEW (cfg, ins, OP_NOP);
8705                         }
8706                         ip++;
8707                         MONO_ADD_INS (cfg->cbb, ins);
8708                         break;
8709                 case CEE_LDARG_0:
8710                 case CEE_LDARG_1:
8711                 case CEE_LDARG_2:
8712                 case CEE_LDARG_3:
8713                         CHECK_STACK_OVF (1);
8714                         n = (*ip)-CEE_LDARG_0;
8715                         CHECK_ARG (n);
8716                         EMIT_NEW_ARGLOAD (cfg, ins, n);
8717                         ip++;
8718                         *sp++ = ins;
8719                         break;
8720                 case CEE_LDLOC_0:
8721                 case CEE_LDLOC_1:
8722                 case CEE_LDLOC_2:
8723                 case CEE_LDLOC_3:
8724                         CHECK_STACK_OVF (1);
8725                         n = (*ip)-CEE_LDLOC_0;
8726                         CHECK_LOCAL (n);
8727                         EMIT_NEW_LOCLOAD (cfg, ins, n);
8728                         ip++;
8729                         *sp++ = ins;
8730                         break;
8731                 case CEE_STLOC_0:
8732                 case CEE_STLOC_1:
8733                 case CEE_STLOC_2:
8734                 case CEE_STLOC_3: {
8735                         CHECK_STACK (1);
8736                         n = (*ip)-CEE_STLOC_0;
8737                         CHECK_LOCAL (n);
8738                         --sp;
8739                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
8740                                 UNVERIFIED;
8741                         emit_stloc_ir (cfg, sp, header, n);
8742                         ++ip;
8743                         inline_costs += 1;
8744                         break;
8745                         }
8746                 case CEE_LDARG_S:
8747                         CHECK_OPSIZE (2);
8748                         CHECK_STACK_OVF (1);
8749                         n = ip [1];
8750                         CHECK_ARG (n);
8751                         EMIT_NEW_ARGLOAD (cfg, ins, n);
8752                         *sp++ = ins;
8753                         ip += 2;
8754                         break;
8755                 case CEE_LDARGA_S:
8756                         CHECK_OPSIZE (2);
8757                         CHECK_STACK_OVF (1);
8758                         n = ip [1];
8759                         CHECK_ARG (n);
8760                         NEW_ARGLOADA (cfg, ins, n);
8761                         MONO_ADD_INS (cfg->cbb, ins);
8762                         *sp++ = ins;
8763                         ip += 2;
8764                         break;
8765                 case CEE_STARG_S:
8766                         CHECK_OPSIZE (2);
8767                         CHECK_STACK (1);
8768                         --sp;
8769                         n = ip [1];
8770                         CHECK_ARG (n);
8771                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [ip [1]], *sp))
8772                                 UNVERIFIED;
8773                         EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
8774                         ip += 2;
8775                         break;
8776                 case CEE_LDLOC_S:
8777                         CHECK_OPSIZE (2);
8778                         CHECK_STACK_OVF (1);
8779                         n = ip [1];
8780                         CHECK_LOCAL (n);
8781                         EMIT_NEW_LOCLOAD (cfg, ins, n);
8782                         *sp++ = ins;
8783                         ip += 2;
8784                         break;
8785                 case CEE_LDLOCA_S: {
8786                         unsigned char *tmp_ip;
8787                         CHECK_OPSIZE (2);
8788                         CHECK_STACK_OVF (1);
8789                         CHECK_LOCAL (ip [1]);
8790
8791                         if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 1))) {
8792                                 ip = tmp_ip;
8793                                 inline_costs += 1;
8794                                 break;
8795                         }
8796
8797                         EMIT_NEW_LOCLOADA (cfg, ins, ip [1]);
8798                         *sp++ = ins;
8799                         ip += 2;
8800                         break;
8801                 }
8802                 case CEE_STLOC_S:
8803                         CHECK_OPSIZE (2);
8804                         CHECK_STACK (1);
8805                         --sp;
8806                         CHECK_LOCAL (ip [1]);
8807                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [ip [1]], *sp))
8808                                 UNVERIFIED;
8809                         emit_stloc_ir (cfg, sp, header, ip [1]);
8810                         ip += 2;
8811                         inline_costs += 1;
8812                         break;
8813                 case CEE_LDNULL:
8814                         CHECK_STACK_OVF (1);
8815                         EMIT_NEW_PCONST (cfg, ins, NULL);
8816                         ins->type = STACK_OBJ;
8817                         ++ip;
8818                         *sp++ = ins;
8819                         break;
8820                 case CEE_LDC_I4_M1:
8821                         CHECK_STACK_OVF (1);
8822                         EMIT_NEW_ICONST (cfg, ins, -1);
8823                         ++ip;
8824                         *sp++ = ins;
8825                         break;
8826                 case CEE_LDC_I4_0:
8827                 case CEE_LDC_I4_1:
8828                 case CEE_LDC_I4_2:
8829                 case CEE_LDC_I4_3:
8830                 case CEE_LDC_I4_4:
8831                 case CEE_LDC_I4_5:
8832                 case CEE_LDC_I4_6:
8833                 case CEE_LDC_I4_7:
8834                 case CEE_LDC_I4_8:
8835                         CHECK_STACK_OVF (1);
8836                         EMIT_NEW_ICONST (cfg, ins, (*ip) - CEE_LDC_I4_0);
8837                         ++ip;
8838                         *sp++ = ins;
8839                         break;
8840                 case CEE_LDC_I4_S:
8841                         CHECK_OPSIZE (2);
8842                         CHECK_STACK_OVF (1);
8843                         ++ip;
8844                         EMIT_NEW_ICONST (cfg, ins, *((signed char*)ip));
8845                         ++ip;
8846                         *sp++ = ins;
8847                         break;
8848                 case CEE_LDC_I4:
8849                         CHECK_OPSIZE (5);
8850                         CHECK_STACK_OVF (1);
8851                         EMIT_NEW_ICONST (cfg, ins, (gint32)read32 (ip + 1));
8852                         ip += 5;
8853                         *sp++ = ins;
8854                         break;
8855                 case CEE_LDC_I8:
8856                         CHECK_OPSIZE (9);
8857                         CHECK_STACK_OVF (1);
8858                         MONO_INST_NEW (cfg, ins, OP_I8CONST);
8859                         ins->type = STACK_I8;
8860                         ins->dreg = alloc_dreg (cfg, STACK_I8);
8861                         ++ip;
8862                         ins->inst_l = (gint64)read64 (ip);
8863                         MONO_ADD_INS (cfg->cbb, ins);
8864                         ip += 8;
8865                         *sp++ = ins;
8866                         break;
8867                 case CEE_LDC_R4: {
8868                         float *f;
8869                         gboolean use_aotconst = FALSE;
8870
8871 #ifdef TARGET_POWERPC
8872                         /* FIXME: Clean this up */
8873                         if (cfg->compile_aot)
8874                                 use_aotconst = TRUE;
8875 #endif
8876
8877                         /* FIXME: we should really allocate this only late in the compilation process */
8878                         f = (float *)mono_domain_alloc (cfg->domain, sizeof (float));
8879                         CHECK_OPSIZE (5);
8880                         CHECK_STACK_OVF (1);
8881
8882                         if (use_aotconst) {
8883                                 MonoInst *cons;
8884                                 int dreg;
8885
8886                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R4, f);
8887
8888                                 dreg = alloc_freg (cfg);
8889                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR4_MEMBASE, dreg, cons->dreg, 0);
8890                                 ins->type = cfg->r4_stack_type;
8891                         } else {
8892                                 MONO_INST_NEW (cfg, ins, OP_R4CONST);
8893                                 ins->type = cfg->r4_stack_type;
8894                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
8895                                 ins->inst_p0 = f;
8896                                 MONO_ADD_INS (cfg->cbb, ins);
8897                         }
8898                         ++ip;
8899                         readr4 (ip, f);
8900                         ip += 4;
8901                         *sp++ = ins;                    
8902                         break;
8903                 }
8904                 case CEE_LDC_R8: {
8905                         double *d;
8906                         gboolean use_aotconst = FALSE;
8907
8908 #ifdef TARGET_POWERPC
8909                         /* FIXME: Clean this up */
8910                         if (cfg->compile_aot)
8911                                 use_aotconst = TRUE;
8912 #endif
8913
8914                         /* FIXME: we should really allocate this only late in the compilation process */
8915                         d = (double *)mono_domain_alloc (cfg->domain, sizeof (double));
8916                         CHECK_OPSIZE (9);
8917                         CHECK_STACK_OVF (1);
8918
8919                         if (use_aotconst) {
8920                                 MonoInst *cons;
8921                                 int dreg;
8922
8923                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R8, d);
8924
8925                                 dreg = alloc_freg (cfg);
8926                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR8_MEMBASE, dreg, cons->dreg, 0);
8927                                 ins->type = STACK_R8;
8928                         } else {
8929                                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
8930                                 ins->type = STACK_R8;
8931                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
8932                                 ins->inst_p0 = d;
8933                                 MONO_ADD_INS (cfg->cbb, ins);
8934                         }
8935                         ++ip;
8936                         readr8 (ip, d);
8937                         ip += 8;
8938                         *sp++ = ins;
8939                         break;
8940                 }
8941                 case CEE_DUP: {
8942                         MonoInst *temp, *store;
8943                         CHECK_STACK (1);
8944                         CHECK_STACK_OVF (1);
8945                         sp--;
8946                         ins = *sp;
8947
8948                         temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
8949                         EMIT_NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
8950
8951                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
8952                         *sp++ = ins;
8953
8954                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
8955                         *sp++ = ins;
8956
8957                         ++ip;
8958                         inline_costs += 2;
8959                         break;
8960                 }
8961                 case CEE_POP:
8962                         CHECK_STACK (1);
8963                         ip++;
8964                         --sp;
8965
8966 #ifdef TARGET_X86
8967                         if (sp [0]->type == STACK_R8)
8968                                 /* we need to pop the value from the x86 FP stack */
8969                                 MONO_EMIT_NEW_UNALU (cfg, OP_X86_FPOP, -1, sp [0]->dreg);
8970 #endif
8971                         break;
8972                 case CEE_JMP: {
8973                         MonoCallInst *call;
8974                         MonoMethodSignature *fsig;
8975                         int i, n;
8976
8977                         INLINE_FAILURE ("jmp");
8978                         GSHAREDVT_FAILURE (*ip);
8979
8980                         CHECK_OPSIZE (5);
8981                         if (stack_start != sp)
8982                                 UNVERIFIED;
8983                         token = read32 (ip + 1);
8984                         /* FIXME: check the signature matches */
8985                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
8986                         CHECK_CFG_ERROR;
8987  
8988                         if (cfg->gshared && mono_method_check_context_used (cmethod))
8989                                 GENERIC_SHARING_FAILURE (CEE_JMP);
8990
8991                         emit_instrumentation_call (cfg, mono_profiler_method_leave);
8992
8993                         fsig = mono_method_signature (cmethod);
8994                         n = fsig->param_count + fsig->hasthis;
8995                         if (cfg->llvm_only) {
8996                                 MonoInst **args;
8997
8998                                 args = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * n);
8999                                 for (i = 0; i < n; ++i)
9000                                         EMIT_NEW_ARGLOAD (cfg, args [i], i);
9001                                 ins = mono_emit_method_call_full (cfg, cmethod, fsig, TRUE, args, NULL, NULL, NULL);
9002                                 /*
9003                                  * The code in mono-basic-block.c treats the rest of the code as dead, but we
9004                                  * have to emit a normal return since llvm expects it.
9005                                  */
9006                                 if (cfg->ret)
9007                                         emit_setret (cfg, ins);
9008                                 MONO_INST_NEW (cfg, ins, OP_BR);
9009                                 ins->inst_target_bb = end_bblock;
9010                                 MONO_ADD_INS (cfg->cbb, ins);
9011                                 link_bblock (cfg, cfg->cbb, end_bblock);
9012                                 ip += 5;
9013                                 break;
9014                         } else if (cfg->backend->have_op_tail_call) {
9015                                 /* Handle tail calls similarly to calls */
9016                                 DISABLE_AOT (cfg);
9017
9018                                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
9019                                 call->method = cmethod;
9020                                 call->tail_call = TRUE;
9021                                 call->signature = mono_method_signature (cmethod);
9022                                 call->args = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * n);
9023                                 call->inst.inst_p0 = cmethod;
9024                                 for (i = 0; i < n; ++i)
9025                                         EMIT_NEW_ARGLOAD (cfg, call->args [i], i);
9026
9027                                 mono_arch_emit_call (cfg, call);
9028                                 cfg->param_area = MAX(cfg->param_area, call->stack_usage);
9029                                 MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
9030                         } else {
9031                                 for (i = 0; i < num_args; ++i)
9032                                         /* Prevent arguments from being optimized away */
9033                                         arg_array [i]->flags |= MONO_INST_VOLATILE;
9034
9035                                 MONO_INST_NEW_CALL (cfg, call, OP_JMP);
9036                                 ins = (MonoInst*)call;
9037                                 ins->inst_p0 = cmethod;
9038                                 MONO_ADD_INS (cfg->cbb, ins);
9039                         }
9040
9041                         ip += 5;
9042                         start_new_bblock = 1;
9043                         break;
9044                 }
9045                 case CEE_CALLI: {
9046                         MonoInst *addr;
9047                         MonoMethodSignature *fsig;
9048
9049                         CHECK_OPSIZE (5);
9050                         token = read32 (ip + 1);
9051
9052                         ins = NULL;
9053
9054                         //GSHAREDVT_FAILURE (*ip);
9055                         cmethod = NULL;
9056                         CHECK_STACK (1);
9057                         --sp;
9058                         addr = *sp;
9059                         fsig = mini_get_signature (method, token, generic_context);
9060
9061                         if (method->dynamic && fsig->pinvoke) {
9062                                 MonoInst *args [3];
9063
9064                                 /*
9065                                  * This is a call through a function pointer using a pinvoke
9066                                  * signature. Have to create a wrapper and call that instead.
9067                                  * FIXME: This is very slow, need to create a wrapper at JIT time
9068                                  * instead based on the signature.
9069                                  */
9070                                 EMIT_NEW_IMAGECONST (cfg, args [0], method->klass->image);
9071                                 EMIT_NEW_PCONST (cfg, args [1], fsig);
9072                                 args [2] = addr;
9073                                 addr = mono_emit_jit_icall (cfg, mono_get_native_calli_wrapper, args);
9074                         }
9075
9076                         n = fsig->param_count + fsig->hasthis;
9077
9078                         CHECK_STACK (n);
9079
9080                         //g_assert (!virtual_ || fsig->hasthis);
9081
9082                         sp -= n;
9083
9084                         inline_costs += 10 * num_calls++;
9085
9086                         /*
9087                          * Making generic calls out of gsharedvt methods.
9088                          * This needs to be used for all generic calls, not just ones with a gsharedvt signature, to avoid
9089                          * patching gshared method addresses into a gsharedvt method.
9090                          */
9091                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) {
9092                                 /*
9093                                  * We pass the address to the gsharedvt trampoline in the rgctx reg
9094                                  */
9095                                 MonoInst *callee = addr;
9096
9097                                 if (method->wrapper_type != MONO_WRAPPER_DELEGATE_INVOKE)
9098                                         /* Not tested */
9099                                         GSHAREDVT_FAILURE (*ip);
9100
9101                                 if (cfg->llvm_only)
9102                                         // FIXME:
9103                                         GSHAREDVT_FAILURE (*ip);
9104
9105                                 addr = emit_get_rgctx_sig (cfg, context_used,
9106                                                                                           fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
9107                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, callee);
9108                                 goto calli_end;
9109                         }
9110
9111                         /* Prevent inlining of methods with indirect calls */
9112                         INLINE_FAILURE ("indirect call");
9113
9114                         if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST || addr->opcode == OP_GOT_ENTRY) {
9115                                 MonoJumpInfoType info_type;
9116                                 gpointer info_data;
9117
9118                                 /*
9119                                  * Instead of emitting an indirect call, emit a direct call
9120                                  * with the contents of the aotconst as the patch info.
9121                                  */
9122                                 if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST) {
9123                                         info_type = (MonoJumpInfoType)addr->inst_c1;
9124                                         info_data = addr->inst_p0;
9125                                 } else {
9126                                         info_type = (MonoJumpInfoType)addr->inst_right->inst_c1;
9127                                         info_data = addr->inst_right->inst_left;
9128                                 }
9129
9130                                 if (info_type == MONO_PATCH_INFO_ICALL_ADDR || info_type == MONO_PATCH_INFO_JIT_ICALL_ADDR) {
9131                                         ins = (MonoInst*)mono_emit_abs_call (cfg, info_type, info_data, fsig, sp);
9132                                         NULLIFY_INS (addr);
9133                                         goto calli_end;
9134                                 }
9135                         }
9136                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9137
9138                         calli_end:
9139
9140                         /* End of call, INS should contain the result of the call, if any */
9141
9142                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9143                                 g_assert (ins);
9144                                 *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
9145                         }
9146
9147                         CHECK_CFG_EXCEPTION;
9148
9149                         ip += 5;
9150                         ins_flag = 0;
9151                         constrained_class = NULL;
9152                         break;
9153                 }
9154                 case CEE_CALL:
9155                 case CEE_CALLVIRT: {
9156                         MonoInst *addr = NULL;
9157                         MonoMethodSignature *fsig = NULL;
9158                         int array_rank = 0;
9159                         int virtual_ = *ip == CEE_CALLVIRT;
9160                         gboolean pass_imt_from_rgctx = FALSE;
9161                         MonoInst *imt_arg = NULL;
9162                         MonoInst *keep_this_alive = NULL;
9163                         gboolean pass_vtable = FALSE;
9164                         gboolean pass_mrgctx = FALSE;
9165                         MonoInst *vtable_arg = NULL;
9166                         gboolean check_this = FALSE;
9167                         gboolean supported_tail_call = FALSE;
9168                         gboolean tail_call = FALSE;
9169                         gboolean need_seq_point = FALSE;
9170                         guint32 call_opcode = *ip;
9171                         gboolean emit_widen = TRUE;
9172                         gboolean push_res = TRUE;
9173                         gboolean skip_ret = FALSE;
9174                         gboolean delegate_invoke = FALSE;
9175                         gboolean direct_icall = FALSE;
9176                         gboolean constrained_partial_call = FALSE;
9177                         gboolean needs_calling_assembly = FALSE;
9178                         MonoMethod *cil_method;
9179
9180                         CHECK_OPSIZE (5);
9181                         token = read32 (ip + 1);
9182
9183                         ins = NULL;
9184
9185                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
9186                         CHECK_CFG_ERROR;
9187
9188                         cil_method = cmethod;
9189                                 
9190                         if (constrained_class) {
9191                                 if ((constrained_class->byval_arg.type == MONO_TYPE_VAR || constrained_class->byval_arg.type == MONO_TYPE_MVAR) && cfg->gshared) {
9192                                         if (!mini_is_gsharedvt_klass (constrained_class)) {
9193                                                 g_assert (!cmethod->klass->valuetype);
9194                                                 if (!mini_type_is_reference (&constrained_class->byval_arg))
9195                                                         constrained_partial_call = TRUE;
9196                                         }
9197                                 }
9198
9199                                 if (method->wrapper_type != MONO_WRAPPER_NONE) {
9200                                         if (cfg->verbose_level > 2)
9201                                                 printf ("DM Constrained call to %s\n", mono_type_get_full_name (constrained_class));
9202                                         if (!((constrained_class->byval_arg.type == MONO_TYPE_VAR ||
9203                                                    constrained_class->byval_arg.type == MONO_TYPE_MVAR) &&
9204                                                   cfg->gshared)) {
9205                                                 cmethod = mono_get_method_constrained_with_method (image, cil_method, constrained_class, generic_context, &cfg->error);
9206                                                 CHECK_CFG_ERROR;
9207                                         }
9208                                 } else {
9209                                         if (cfg->verbose_level > 2)
9210                                                 printf ("Constrained call to %s\n", mono_type_get_full_name (constrained_class));
9211
9212                                         if ((constrained_class->byval_arg.type == MONO_TYPE_VAR || constrained_class->byval_arg.type == MONO_TYPE_MVAR) && cfg->gshared) {
9213                                                 /* 
9214                                                  * This is needed since get_method_constrained can't find 
9215                                                  * the method in klass representing a type var.
9216                                                  * The type var is guaranteed to be a reference type in this
9217                                                  * case.
9218                                                  */
9219                                                 if (!mini_is_gsharedvt_klass (constrained_class))
9220                                                         g_assert (!cmethod->klass->valuetype);
9221                                         } else {
9222                                                 cmethod = mono_get_method_constrained_checked (image, token, constrained_class, generic_context, &cil_method, &cfg->error);
9223                                                 CHECK_CFG_ERROR;
9224                                         }
9225                                 }
9226                         }
9227                                         
9228                         if (!cmethod || mono_loader_get_last_error ()) {
9229                                 if (mono_loader_get_last_error ()) {
9230                                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
9231                                         mono_error_set_from_loader_error (&cfg->error);
9232                                         CHECK_CFG_ERROR;
9233                                 } else {
9234                                         LOAD_ERROR;
9235                                 }
9236                         }
9237                         if (!dont_verify && !cfg->skip_visibility) {
9238                                 MonoMethod *target_method = cil_method;
9239                                 if (method->is_inflated) {
9240                                         target_method = mini_get_method_allow_open (method, token, NULL, &(mono_method_get_generic_container (method_definition)->context), &cfg->error);
9241                                         CHECK_CFG_ERROR;
9242                                 }
9243                                 if (!mono_method_can_access_method (method_definition, target_method) &&
9244                                         !mono_method_can_access_method (method, cil_method))
9245                                         METHOD_ACCESS_FAILURE (method, cil_method);
9246                         }
9247
9248                         if (mono_security_core_clr_enabled ())
9249                                 ensure_method_is_allowed_to_call_method (cfg, method, cil_method);
9250
9251                         if (!virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_ABSTRACT))
9252                                 /* MS.NET seems to silently convert this to a callvirt */
9253                                 virtual_ = 1;
9254
9255                         {
9256                                 /*
9257                                  * MS.NET accepts non virtual calls to virtual final methods of transparent proxy classes and
9258                                  * converts to a callvirt.
9259                                  *
9260                                  * tests/bug-515884.il is an example of this behavior
9261                                  */
9262                                 const int test_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_STATIC;
9263                                 const int expected_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL;
9264                                 if (!virtual_ && mono_class_is_marshalbyref (cmethod->klass) && (cmethod->flags & test_flags) == expected_flags && cfg->method->wrapper_type == MONO_WRAPPER_NONE)
9265                                         virtual_ = 1;
9266                         }
9267
9268                         if (!cmethod->klass->inited)
9269                                 if (!mono_class_init (cmethod->klass))
9270                                         TYPE_LOAD_ERROR (cmethod->klass);
9271
9272                         fsig = mono_method_signature (cmethod);
9273                         if (!fsig)
9274                                 LOAD_ERROR;
9275                         if (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL &&
9276                                 mini_class_is_system_array (cmethod->klass)) {
9277                                 array_rank = cmethod->klass->rank;
9278                         } else if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && icall_is_direct_callable (cfg, cmethod)) {
9279                                 direct_icall = TRUE;
9280                         } else if (fsig->pinvoke) {
9281                                 MonoMethod *wrapper = mono_marshal_get_native_wrapper (cmethod, TRUE, cfg->compile_aot);
9282                                 fsig = mono_method_signature (wrapper);
9283                         } else if (constrained_class) {
9284                         } else {
9285                                 fsig = mono_method_get_signature_checked (cmethod, image, token, generic_context, &cfg->error);
9286                                 CHECK_CFG_ERROR;
9287                         }
9288
9289                         if (cfg->llvm_only && !cfg->method->wrapper_type)
9290                                 cfg->signatures = g_slist_prepend_mempool (cfg->mempool, cfg->signatures, fsig);
9291
9292                         /* See code below */
9293                         if (cmethod->klass == mono_defaults.monitor_class && !strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1) {
9294                                 MonoBasicBlock *tbb;
9295
9296                                 GET_BBLOCK (cfg, tbb, ip + 5);
9297                                 if (tbb->try_start && MONO_REGION_FLAGS(tbb->region) == MONO_EXCEPTION_CLAUSE_FINALLY) {
9298                                         /*
9299                                          * We want to extend the try block to cover the call, but we can't do it if the
9300                                          * call is made directly since its followed by an exception check.
9301                                          */
9302                                         direct_icall = FALSE;
9303                                 }
9304                         }
9305
9306                         /*
9307                          * Stack walks are not supported in llvmonly mode, so
9308                          * when calling methods which call GetCallingAssembly (), save the
9309                          * current assembly in the caller. The call to GetCallingAssembly ()
9310                          * will be turned into an icall which will retrieve the value.
9311                          */
9312                         if (cfg->llvm_only && cmethod && method_needs_calling_assembly (cmethod)) {
9313                                 needs_calling_assembly = TRUE;
9314
9315                                 MonoInst *assembly_ins;
9316
9317                                 EMIT_NEW_AOTCONST (cfg, assembly_ins, MONO_PATCH_INFO_IMAGE, cfg->method->klass->image);
9318                                 ins = mono_emit_jit_icall (cfg, mono_llvmonly_set_calling_assembly, &assembly_ins);
9319                         }
9320
9321                         mono_save_token_info (cfg, image, token, cil_method);
9322
9323                         if (!(seq_point_locs && mono_bitset_test_fast (seq_point_locs, ip + 5 - header->code)))
9324                                 need_seq_point = TRUE;
9325
9326                         /* Don't support calls made using type arguments for now */
9327                         /*
9328                           if (cfg->gsharedvt) {
9329                           if (mini_is_gsharedvt_signature (fsig))
9330                           GSHAREDVT_FAILURE (*ip);
9331                           }
9332                         */
9333
9334                         if (cmethod->string_ctor && method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE)
9335                                 g_assert_not_reached ();
9336
9337                         n = fsig->param_count + fsig->hasthis;
9338
9339                         if (!cfg->gshared && cmethod->klass->generic_container)
9340                                 UNVERIFIED;
9341
9342                         if (!cfg->gshared)
9343                                 g_assert (!mono_method_check_context_used (cmethod));
9344
9345                         CHECK_STACK (n);
9346
9347                         //g_assert (!virtual_ || fsig->hasthis);
9348
9349                         sp -= n;
9350
9351                         /*
9352                          * We have the `constrained.' prefix opcode.
9353                          */
9354                         if (constrained_class) {
9355                                 if (mini_is_gsharedvt_klass (constrained_class)) {
9356                                         if ((cmethod->klass != mono_defaults.object_class) && constrained_class->valuetype && cmethod->klass->valuetype) {
9357                                                 /* The 'Own method' case below */
9358                                         } else if (cmethod->klass->image != mono_defaults.corlib && !(cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) && !cmethod->klass->valuetype) {
9359                                                 /* 'The type parameter is instantiated as a reference type' case below. */
9360                                         } else {
9361                                                 ins = handle_constrained_gsharedvt_call (cfg, cmethod, fsig, sp, constrained_class, &emit_widen);
9362                                                 CHECK_CFG_EXCEPTION;
9363                                                 g_assert (ins);
9364                                                 goto call_end;
9365                                         }
9366                                 }
9367
9368                                 if (constrained_partial_call) {
9369                                         gboolean need_box = TRUE;
9370
9371                                         /*
9372                                          * The receiver is a valuetype, but the exact type is not known at compile time. This means the
9373                                          * called method is not known at compile time either. The called method could end up being
9374                                          * one of the methods on the parent classes (object/valuetype/enum), in which case we need
9375                                          * to box the receiver.
9376                                          * A simple solution would be to box always and make a normal virtual call, but that would
9377                                          * be bad performance wise.
9378                                          */
9379                                         if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE && cmethod->klass->generic_class) {
9380                                                 /*
9381                                                  * The parent classes implement no generic interfaces, so the called method will be a vtype method, so no boxing neccessary.
9382                                                  */
9383                                                 need_box = FALSE;
9384                                         }
9385
9386                                         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)) {
9387                                                 /* The called method is not virtual, i.e. Object:GetType (), the receiver is a vtype, has to box */
9388                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
9389                                                 ins->klass = constrained_class;
9390                                                 sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
9391                                                 CHECK_CFG_EXCEPTION;
9392                                         } else if (need_box) {
9393                                                 MonoInst *box_type;
9394                                                 MonoBasicBlock *is_ref_bb, *end_bb;
9395                                                 MonoInst *nonbox_call;
9396
9397                                                 /*
9398                                                  * Determine at runtime whenever the called method is defined on object/valuetype/enum, and emit a boxing call
9399                                                  * if needed.
9400                                                  * FIXME: It is possible to inline the called method in a lot of cases, i.e. for T_INT,
9401                                                  * the no-box case goes to a method in Int32, while the box case goes to a method in Enum.
9402                                                  */
9403                                                 addr = emit_get_rgctx_virt_method (cfg, mono_class_check_context_used (constrained_class), constrained_class, cmethod, MONO_RGCTX_INFO_VIRT_METHOD_CODE);
9404
9405                                                 NEW_BBLOCK (cfg, is_ref_bb);
9406                                                 NEW_BBLOCK (cfg, end_bb);
9407
9408                                                 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);
9409                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, box_type->dreg, MONO_GSHAREDVT_BOX_TYPE_REF);
9410                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
9411
9412                                                 /* Non-ref case */
9413                                                 nonbox_call = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9414
9415                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
9416
9417                                                 /* Ref case */
9418                                                 MONO_START_BB (cfg, is_ref_bb);
9419                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
9420                                                 ins->klass = constrained_class;
9421                                                 sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
9422                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9423
9424                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
9425
9426                                                 MONO_START_BB (cfg, end_bb);
9427                                                 cfg->cbb = end_bb;
9428
9429                                                 nonbox_call->dreg = ins->dreg;
9430                                                 goto call_end;
9431                                         } else {
9432                                                 g_assert (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE);
9433                                                 addr = emit_get_rgctx_virt_method (cfg, mono_class_check_context_used (constrained_class), constrained_class, cmethod, MONO_RGCTX_INFO_VIRT_METHOD_CODE);
9434                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9435                                                 goto call_end;
9436                                         }
9437                                 } else if (constrained_class->valuetype && (cmethod->klass == mono_defaults.object_class || cmethod->klass == mono_defaults.enum_class->parent || cmethod->klass == mono_defaults.enum_class)) {
9438                                         /*
9439                                          * The type parameter is instantiated as a valuetype,
9440                                          * but that type doesn't override the method we're
9441                                          * calling, so we need to box `this'.
9442                                          */
9443                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
9444                                         ins->klass = constrained_class;
9445                                         sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
9446                                         CHECK_CFG_EXCEPTION;
9447                                 } else if (!constrained_class->valuetype) {
9448                                         int dreg = alloc_ireg_ref (cfg);
9449
9450                                         /*
9451                                          * The type parameter is instantiated as a reference
9452                                          * type.  We have a managed pointer on the stack, so
9453                                          * we need to dereference it here.
9454                                          */
9455                                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, sp [0]->dreg, 0);
9456                                         ins->type = STACK_OBJ;
9457                                         sp [0] = ins;
9458                                 } else {
9459                                         if (cmethod->klass->valuetype) {
9460                                                 /* Own method */
9461                                         } else {
9462                                                 /* Interface method */
9463                                                 int ioffset, slot;
9464
9465                                                 mono_class_setup_vtable (constrained_class);
9466                                                 CHECK_TYPELOAD (constrained_class);
9467                                                 ioffset = mono_class_interface_offset (constrained_class, cmethod->klass);
9468                                                 if (ioffset == -1)
9469                                                         TYPE_LOAD_ERROR (constrained_class);
9470                                                 slot = mono_method_get_vtable_slot (cmethod);
9471                                                 if (slot == -1)
9472                                                         TYPE_LOAD_ERROR (cmethod->klass);
9473                                                 cmethod = constrained_class->vtable [ioffset + slot];
9474
9475                                                 if (cmethod->klass == mono_defaults.enum_class) {
9476                                                         /* Enum implements some interfaces, so treat this as the first case */
9477                                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
9478                                                         ins->klass = constrained_class;
9479                                                         sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
9480                                                         CHECK_CFG_EXCEPTION;
9481                                                 }
9482                                         }
9483                                         virtual_ = 0;
9484                                 }
9485                                 constrained_class = NULL;
9486                         }
9487
9488                         if (check_call_signature (cfg, fsig, sp))
9489                                 UNVERIFIED;
9490
9491                         if ((cmethod->klass->parent == mono_defaults.multicastdelegate_class) && !strcmp (cmethod->name, "Invoke"))
9492                                 delegate_invoke = TRUE;
9493
9494                         if ((cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_sharable_method (cfg, cmethod, fsig, sp))) {
9495                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9496                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
9497                                         emit_widen = FALSE;
9498                                 }
9499
9500                                 goto call_end;
9501                         }
9502
9503                         /* 
9504                          * If the callee is a shared method, then its static cctor
9505                          * might not get called after the call was patched.
9506                          */
9507                         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)) {
9508                                 emit_class_init (cfg, cmethod->klass);
9509                                 CHECK_TYPELOAD (cmethod->klass);
9510                         }
9511
9512                         check_method_sharing (cfg, cmethod, &pass_vtable, &pass_mrgctx);
9513
9514                         if (cfg->gshared) {
9515                                 MonoGenericContext *cmethod_context = mono_method_get_context (cmethod);
9516
9517                                 context_used = mini_method_check_context_used (cfg, cmethod);
9518
9519                                 if (context_used && (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
9520                                         /* Generic method interface
9521                                            calls are resolved via a
9522                                            helper function and don't
9523                                            need an imt. */
9524                                         if (!cmethod_context || !cmethod_context->method_inst)
9525                                                 pass_imt_from_rgctx = TRUE;
9526                                 }
9527
9528                                 /*
9529                                  * If a shared method calls another
9530                                  * shared method then the caller must
9531                                  * have a generic sharing context
9532                                  * because the magic trampoline
9533                                  * requires it.  FIXME: We shouldn't
9534                                  * have to force the vtable/mrgctx
9535                                  * variable here.  Instead there
9536                                  * should be a flag in the cfg to
9537                                  * request a generic sharing context.
9538                                  */
9539                                 if (context_used &&
9540                                                 ((method->flags & METHOD_ATTRIBUTE_STATIC) || method->klass->valuetype))
9541                                         mono_get_vtable_var (cfg);
9542                         }
9543
9544                         if (pass_vtable) {
9545                                 if (context_used) {
9546                                         vtable_arg = emit_get_rgctx_klass (cfg, context_used, cmethod->klass, MONO_RGCTX_INFO_VTABLE);
9547                                 } else {
9548                                         MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
9549
9550                                         CHECK_TYPELOAD (cmethod->klass);
9551                                         EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
9552                                 }
9553                         }
9554
9555                         if (pass_mrgctx) {
9556                                 g_assert (!vtable_arg);
9557
9558                                 if (!cfg->compile_aot) {
9559                                         /* 
9560                                          * emit_get_rgctx_method () calls mono_class_vtable () so check 
9561                                          * for type load errors before.
9562                                          */
9563                                         mono_class_setup_vtable (cmethod->klass);
9564                                         CHECK_TYPELOAD (cmethod->klass);
9565                                 }
9566
9567                                 vtable_arg = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
9568
9569                                 /* !marshalbyref is needed to properly handle generic methods + remoting */
9570                                 if ((!(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
9571                                          MONO_METHOD_IS_FINAL (cmethod)) &&
9572                                         !mono_class_is_marshalbyref (cmethod->klass)) {
9573                                         if (virtual_)
9574                                                 check_this = TRUE;
9575                                         virtual_ = 0;
9576                                 }
9577                         }
9578
9579                         if (pass_imt_from_rgctx) {
9580                                 g_assert (!pass_vtable);
9581
9582                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9583                                         cmethod, MONO_RGCTX_INFO_METHOD);
9584                         }
9585
9586                         if (check_this)
9587                                 MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
9588
9589                         /* Calling virtual generic methods */
9590                         if (virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) &&
9591                             !(MONO_METHOD_IS_FINAL (cmethod) && 
9592                               cmethod->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK) &&
9593                             fsig->generic_param_count && 
9594                                 !(cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) &&
9595                                 !cfg->llvm_only) {
9596                                 MonoInst *this_temp, *this_arg_temp, *store;
9597                                 MonoInst *iargs [4];
9598
9599                                 g_assert (fsig->is_inflated);
9600
9601                                 /* Prevent inlining of methods that contain indirect calls */
9602                                 INLINE_FAILURE ("virtual generic call");
9603
9604                                 if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig))
9605                                         GSHAREDVT_FAILURE (*ip);
9606
9607                                 if (cfg->backend->have_generalized_imt_thunk && cfg->backend->gshared_supported && cmethod->wrapper_type == MONO_WRAPPER_NONE) {
9608                                         g_assert (!imt_arg);
9609                                         if (!context_used)
9610                                                 g_assert (cmethod->is_inflated);
9611                                         imt_arg = emit_get_rgctx_method (cfg, context_used,
9612                                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
9613                                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, sp [0], imt_arg, NULL);
9614                                 } else {
9615                                         this_temp = mono_compile_create_var (cfg, type_from_stack_type (sp [0]), OP_LOCAL);
9616                                         NEW_TEMPSTORE (cfg, store, this_temp->inst_c0, sp [0]);
9617                                         MONO_ADD_INS (cfg->cbb, store);
9618
9619                                         /* FIXME: This should be a managed pointer */
9620                                         this_arg_temp = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
9621
9622                                         EMIT_NEW_TEMPLOAD (cfg, iargs [0], this_temp->inst_c0);
9623                                         iargs [1] = emit_get_rgctx_method (cfg, context_used,
9624                                                                                                            cmethod, MONO_RGCTX_INFO_METHOD);
9625                                         EMIT_NEW_TEMPLOADA (cfg, iargs [2], this_arg_temp->inst_c0);
9626                                         addr = mono_emit_jit_icall (cfg,
9627                                                                                                 mono_helper_compile_generic_method, iargs);
9628
9629                                         EMIT_NEW_TEMPLOAD (cfg, sp [0], this_arg_temp->inst_c0);
9630
9631                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9632                                 }
9633
9634                                 goto call_end;
9635                         }
9636
9637                         /*
9638                          * Implement a workaround for the inherent races involved in locking:
9639                          * Monitor.Enter ()
9640                          * try {
9641                          * } finally {
9642                          *    Monitor.Exit ()
9643                          * }
9644                          * If a thread abort happens between the call to Monitor.Enter () and the start of the
9645                          * try block, the Exit () won't be executed, see:
9646                          * http://www.bluebytesoftware.com/blog/2007/01/30/MonitorEnterThreadAbortsAndOrphanedLocks.aspx
9647                          * To work around this, we extend such try blocks to include the last x bytes
9648                          * of the Monitor.Enter () call.
9649                          */
9650                         if (cmethod->klass == mono_defaults.monitor_class && !strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1) {
9651                                 MonoBasicBlock *tbb;
9652
9653                                 GET_BBLOCK (cfg, tbb, ip + 5);
9654                                 /* 
9655                                  * Only extend try blocks with a finally, to avoid catching exceptions thrown
9656                                  * from Monitor.Enter like ArgumentNullException.
9657                                  */
9658                                 if (tbb->try_start && MONO_REGION_FLAGS(tbb->region) == MONO_EXCEPTION_CLAUSE_FINALLY) {
9659                                         /* Mark this bblock as needing to be extended */
9660                                         tbb->extend_try_block = TRUE;
9661                                 }
9662                         }
9663
9664                         /* Conversion to a JIT intrinsic */
9665                         if ((cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_method (cfg, cmethod, fsig, sp))) {
9666                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9667                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
9668                                         emit_widen = FALSE;
9669                                 }
9670                                 goto call_end;
9671                         }
9672
9673                         /* Inlining */
9674                         if ((cfg->opt & MONO_OPT_INLINE) &&
9675                                 (!virtual_ || !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) || MONO_METHOD_IS_FINAL (cmethod)) &&
9676                             mono_method_check_inlining (cfg, cmethod)) {
9677                                 int costs;
9678                                 gboolean always = FALSE;
9679
9680                                 if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
9681                                         (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
9682                                         /* Prevent inlining of methods that call wrappers */
9683                                         INLINE_FAILURE ("wrapper call");
9684                                         cmethod = mono_marshal_get_native_wrapper (cmethod, TRUE, FALSE);
9685                                         always = TRUE;
9686                                 }
9687
9688                                 costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, always);
9689                                 if (costs) {
9690                                         cfg->real_offset += 5;
9691
9692                                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9693                                                 /* *sp is already set by inline_method */
9694                                                 sp++;
9695                                                 push_res = FALSE;
9696                                         }
9697
9698                                         inline_costs += costs;
9699
9700                                         goto call_end;
9701                                 }
9702                         }
9703
9704                         /* Tail recursion elimination */
9705                         if ((cfg->opt & MONO_OPT_TAILC) && call_opcode == CEE_CALL && cmethod == method && ip [5] == CEE_RET && !vtable_arg) {
9706                                 gboolean has_vtargs = FALSE;
9707                                 int i;
9708
9709                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
9710                                 INLINE_FAILURE ("tail call");
9711
9712                                 /* keep it simple */
9713                                 for (i =  fsig->param_count - 1; i >= 0; i--) {
9714                                         if (MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->params [i])) 
9715                                                 has_vtargs = TRUE;
9716                                 }
9717
9718                                 if (!has_vtargs) {
9719                                         for (i = 0; i < n; ++i)
9720                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
9721                                         MONO_INST_NEW (cfg, ins, OP_BR);
9722                                         MONO_ADD_INS (cfg->cbb, ins);
9723                                         tblock = start_bblock->out_bb [0];
9724                                         link_bblock (cfg, cfg->cbb, tblock);
9725                                         ins->inst_target_bb = tblock;
9726                                         start_new_bblock = 1;
9727
9728                                         /* skip the CEE_RET, too */
9729                                         if (ip_in_bb (cfg, cfg->cbb, ip + 5))
9730                                                 skip_ret = TRUE;
9731                                         push_res = FALSE;
9732                                         goto call_end;
9733                                 }
9734                         }
9735
9736                         inline_costs += 10 * num_calls++;
9737
9738                         /*
9739                          * Making generic calls out of gsharedvt methods.
9740                          * This needs to be used for all generic calls, not just ones with a gsharedvt signature, to avoid
9741                          * patching gshared method addresses into a gsharedvt method.
9742                          */
9743                         if (cfg->gsharedvt && (mini_is_gsharedvt_signature (fsig) || cmethod->is_inflated || cmethod->klass->generic_class) &&
9744                                 !(cmethod->klass->rank && cmethod->klass->byval_arg.type != MONO_TYPE_SZARRAY) &&
9745                                 (!(cfg->llvm_only && virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL)))) {
9746                                 MonoRgctxInfoType info_type;
9747
9748                                 if (virtual_) {
9749                                         //if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)
9750                                                 //GSHAREDVT_FAILURE (*ip);
9751                                         // disable for possible remoting calls
9752                                         if (fsig->hasthis && (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class))
9753                                                 GSHAREDVT_FAILURE (*ip);
9754                                         if (fsig->generic_param_count) {
9755                                                 /* virtual generic call */
9756                                                 g_assert (!imt_arg);
9757                                                 /* Same as the virtual generic case above */
9758                                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9759                                                                                                                  cmethod, MONO_RGCTX_INFO_METHOD);
9760                                                 /* This is not needed, as the trampoline code will pass one, and it might be passed in the same reg as the imt arg */
9761                                                 vtable_arg = NULL;
9762                                         } else if ((cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) && !imt_arg) {
9763                                                 /* This can happen when we call a fully instantiated iface method */
9764                                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9765                                                                                                                  cmethod, MONO_RGCTX_INFO_METHOD);
9766                                                 vtable_arg = NULL;
9767                                         }
9768                                 }
9769
9770                                 if ((cmethod->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (cmethod->name, "Invoke")))
9771                                         keep_this_alive = sp [0];
9772
9773                                 if (virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))
9774                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
9775                                 else
9776                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE;
9777                                 addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, info_type);
9778
9779                                 if (cfg->llvm_only) {
9780                                         // FIXME: Avoid initializing vtable_arg
9781                                         ins = emit_llvmonly_calli (cfg, fsig, sp, addr);
9782                                 } else {
9783                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
9784                                 }
9785                                 goto call_end;
9786                         }
9787
9788                         /* Generic sharing */
9789
9790                         /*
9791                          * Use this if the callee is gsharedvt sharable too, since
9792                          * at runtime we might find an instantiation so the call cannot
9793                          * be patched (the 'no_patch' code path in mini-trampolines.c).
9794                          */
9795                         if (context_used && !imt_arg && !array_rank && !delegate_invoke &&
9796                                 (!mono_method_is_generic_sharable_full (cmethod, TRUE, FALSE, FALSE) ||
9797                                  !mono_class_generic_sharing_enabled (cmethod->klass)) &&
9798                                 (!virtual_ || MONO_METHOD_IS_FINAL (cmethod) ||
9799                                  !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))) {
9800                                 INLINE_FAILURE ("gshared");
9801
9802                                 g_assert (cfg->gshared && cmethod);
9803                                 g_assert (!addr);
9804
9805                                 /*
9806                                  * We are compiling a call to a
9807                                  * generic method from shared code,
9808                                  * which means that we have to look up
9809                                  * the method in the rgctx and do an
9810                                  * indirect call.
9811                                  */
9812                                 if (fsig->hasthis)
9813                                         MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
9814
9815                                 if (cfg->llvm_only) {
9816                                         if (cfg->gsharedvt && mini_is_gsharedvt_variable_signature (fsig))
9817                                                 addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER);
9818                                         else
9819                                                 addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
9820                                         // FIXME: Avoid initializing imt_arg/vtable_arg
9821                                         ins = emit_llvmonly_calli (cfg, fsig, sp, addr);
9822                                 } else {
9823                                         addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
9824                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
9825                                 }
9826                                 goto call_end;
9827                         }
9828
9829                         /* Direct calls to icalls */
9830                         if (direct_icall) {
9831                                 MonoMethod *wrapper;
9832                                 int costs;
9833
9834                                 /* Inline the wrapper */
9835                                 wrapper = mono_marshal_get_native_wrapper (cmethod, TRUE, cfg->compile_aot);
9836
9837                                 costs = inline_method (cfg, wrapper, fsig, sp, ip, cfg->real_offset, TRUE);
9838                                 g_assert (costs > 0);
9839                                 cfg->real_offset += 5;
9840
9841                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9842                                         /* *sp is already set by inline_method */
9843                                         sp++;
9844                                         push_res = FALSE;
9845                                 }
9846
9847                                 inline_costs += costs;
9848
9849                                 goto call_end;
9850                         }
9851                                         
9852                         /* Array methods */
9853                         if (array_rank) {
9854                                 MonoInst *addr;
9855
9856                                 if (strcmp (cmethod->name, "Set") == 0) { /* array Set */ 
9857                                         MonoInst *val = sp [fsig->param_count];
9858
9859                                         if (val->type == STACK_OBJ) {
9860                                                 MonoInst *iargs [2];
9861
9862                                                 iargs [0] = sp [0];
9863                                                 iargs [1] = val;
9864                                                 
9865                                                 mono_emit_jit_icall (cfg, mono_helper_stelem_ref_check, iargs);
9866                                         }
9867                                         
9868                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, TRUE);
9869                                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, fsig->params [fsig->param_count - 1], addr->dreg, 0, val->dreg);
9870                                         if (cfg->gen_write_barriers && val->type == STACK_OBJ && !(val->opcode == OP_PCONST && val->inst_c0 == 0))
9871                                                 emit_write_barrier (cfg, addr, val);
9872                                         if (cfg->gen_write_barriers && mini_is_gsharedvt_klass (cmethod->klass))
9873                                                 GSHAREDVT_FAILURE (*ip);
9874                                 } else if (strcmp (cmethod->name, "Get") == 0) { /* array Get */
9875                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
9876
9877                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, addr->dreg, 0);
9878                                 } else if (strcmp (cmethod->name, "Address") == 0) { /* array Address */
9879                                         if (!cmethod->klass->element_class->valuetype && !readonly)
9880                                                 mini_emit_check_array_type (cfg, sp [0], cmethod->klass);
9881                                         CHECK_TYPELOAD (cmethod->klass);
9882                                         
9883                                         readonly = FALSE;
9884                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
9885                                         ins = addr;
9886                                 } else {
9887                                         g_assert_not_reached ();
9888                                 }
9889
9890                                 emit_widen = FALSE;
9891                                 goto call_end;
9892                         }
9893
9894                         ins = mini_redirect_call (cfg, cmethod, fsig, sp, virtual_ ? sp [0] : NULL);
9895                         if (ins)
9896                                 goto call_end;
9897
9898                         /* Tail prefix / tail call optimization */
9899
9900                         /* FIXME: Enabling TAILC breaks some inlining/stack trace/etc tests */
9901                         /* FIXME: runtime generic context pointer for jumps? */
9902                         /* FIXME: handle this for generic sharing eventually */
9903                         if ((ins_flag & MONO_INST_TAILCALL) &&
9904                                 !vtable_arg && !cfg->gshared && is_supported_tail_call (cfg, method, cmethod, fsig, call_opcode))
9905                                 supported_tail_call = TRUE;
9906
9907                         if (supported_tail_call) {
9908                                 MonoCallInst *call;
9909
9910                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
9911                                 INLINE_FAILURE ("tail call");
9912
9913                                 //printf ("HIT: %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
9914
9915                                 if (cfg->backend->have_op_tail_call) {
9916                                         /* Handle tail calls similarly to normal calls */
9917                                         tail_call = TRUE;
9918                                 } else {
9919                                         emit_instrumentation_call (cfg, mono_profiler_method_leave);
9920
9921                                         MONO_INST_NEW_CALL (cfg, call, OP_JMP);
9922                                         call->tail_call = TRUE;
9923                                         call->method = cmethod;
9924                                         call->signature = mono_method_signature (cmethod);
9925
9926                                         /*
9927                                          * We implement tail calls by storing the actual arguments into the 
9928                                          * argument variables, then emitting a CEE_JMP.
9929                                          */
9930                                         for (i = 0; i < n; ++i) {
9931                                                 /* Prevent argument from being register allocated */
9932                                                 arg_array [i]->flags |= MONO_INST_VOLATILE;
9933                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
9934                                         }
9935                                         ins = (MonoInst*)call;
9936                                         ins->inst_p0 = cmethod;
9937                                         ins->inst_p1 = arg_array [0];
9938                                         MONO_ADD_INS (cfg->cbb, ins);
9939                                         link_bblock (cfg, cfg->cbb, end_bblock);
9940                                         start_new_bblock = 1;
9941
9942                                         // FIXME: Eliminate unreachable epilogs
9943
9944                                         /*
9945                                          * OP_TAILCALL has no return value, so skip the CEE_RET if it is
9946                                          * only reachable from this call.
9947                                          */
9948                                         GET_BBLOCK (cfg, tblock, ip + 5);
9949                                         if (tblock == cfg->cbb || tblock->in_count == 0)
9950                                                 skip_ret = TRUE;
9951                                         push_res = FALSE;
9952
9953                                         goto call_end;
9954                                 }
9955                         }
9956
9957                         /* 
9958                          * Synchronized wrappers.
9959                          * Its hard to determine where to replace a method with its synchronized
9960                          * wrapper without causing an infinite recursion. The current solution is
9961                          * to add the synchronized wrapper in the trampolines, and to
9962                          * change the called method to a dummy wrapper, and resolve that wrapper
9963                          * to the real method in mono_jit_compile_method ().
9964                          */
9965                         if (cfg->method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
9966                                 MonoMethod *orig = mono_marshal_method_from_wrapper (cfg->method);
9967                                 if (cmethod == orig || (cmethod->is_inflated && mono_method_get_declaring_generic_method (cmethod) == orig))
9968                                         cmethod = mono_marshal_get_synchronized_inner_wrapper (cmethod);
9969                         }
9970
9971                         /*
9972                          * Virtual calls in llvm-only mode.
9973                          */
9974                         if (cfg->llvm_only && virtual_ && cmethod && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
9975                                 ins = emit_llvmonly_virtual_call (cfg, cmethod, fsig, context_used, sp);
9976                                 goto call_end;
9977                         }
9978
9979                         /* Common call */
9980                         INLINE_FAILURE ("call");
9981                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, tail_call, sp, virtual_ ? sp [0] : NULL,
9982                                                                                           imt_arg, vtable_arg);
9983
9984                         if (tail_call && !cfg->llvm_only) {
9985                                 link_bblock (cfg, cfg->cbb, end_bblock);
9986                                 start_new_bblock = 1;
9987
9988                                 // FIXME: Eliminate unreachable epilogs
9989
9990                                 /*
9991                                  * OP_TAILCALL has no return value, so skip the CEE_RET if it is
9992                                  * only reachable from this call.
9993                                  */
9994                                 GET_BBLOCK (cfg, tblock, ip + 5);
9995                                 if (tblock == cfg->cbb || tblock->in_count == 0)
9996                                         skip_ret = TRUE;
9997                                 push_res = FALSE;
9998                         }
9999
10000                         call_end:
10001
10002                         /* End of call, INS should contain the result of the call, if any */
10003
10004                         if (push_res && !MONO_TYPE_IS_VOID (fsig->ret)) {
10005                                 g_assert (ins);
10006                                 if (emit_widen)
10007                                         *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
10008                                 else
10009                                         *sp++ = ins;
10010                         }
10011
10012                         if (keep_this_alive) {
10013                                 MonoInst *dummy_use;
10014
10015                                 /* See mono_emit_method_call_full () */
10016                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, keep_this_alive);
10017                         }
10018
10019                         if (needs_calling_assembly) {
10020                                 /*
10021                                  * Clear the calling assembly.
10022                                  * This is not EH safe, but this is not a problem in practice, since
10023                                  * the null value is only used for error checking.
10024                                  */
10025                                 MonoInst *assembly_ins;
10026
10027                                 EMIT_NEW_PCONST (cfg, assembly_ins, NULL);
10028                                 ins = mono_emit_jit_icall (cfg, mono_llvmonly_set_calling_assembly, &assembly_ins);
10029                         }
10030
10031                         CHECK_CFG_EXCEPTION;
10032
10033                         ip += 5;
10034                         if (skip_ret) {
10035                                 g_assert (*ip == CEE_RET);
10036                                 ip += 1;
10037                         }
10038                         ins_flag = 0;
10039                         constrained_class = NULL;
10040                         if (need_seq_point)
10041                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
10042                         break;
10043                 }
10044                 case CEE_RET:
10045                         if (cfg->method != method) {
10046                                 /* return from inlined method */
10047                                 /* 
10048                                  * If in_count == 0, that means the ret is unreachable due to
10049                                  * being preceeded by a throw. In that case, inline_method () will
10050                                  * handle setting the return value 
10051                                  * (test case: test_0_inline_throw ()).
10052                                  */
10053                                 if (return_var && cfg->cbb->in_count) {
10054                                         MonoType *ret_type = mono_method_signature (method)->ret;
10055
10056                                         MonoInst *store;
10057                                         CHECK_STACK (1);
10058                                         --sp;
10059
10060                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
10061                                                 UNVERIFIED;
10062
10063                                         //g_assert (returnvar != -1);
10064                                         EMIT_NEW_TEMPSTORE (cfg, store, return_var->inst_c0, *sp);
10065                                         cfg->ret_var_set = TRUE;
10066                                 } 
10067                         } else {
10068                                 emit_instrumentation_call (cfg, mono_profiler_method_leave);
10069
10070                                 if (cfg->lmf_var && cfg->cbb->in_count && !cfg->llvm_only)
10071                                         emit_pop_lmf (cfg);
10072
10073                                 if (cfg->ret) {
10074                                         MonoType *ret_type = mini_get_underlying_type (mono_method_signature (method)->ret);
10075
10076                                         if (seq_points && !sym_seq_points) {
10077                                                 /* 
10078                                                  * Place a seq point here too even through the IL stack is not
10079                                                  * empty, so a step over on
10080                                                  * call <FOO>
10081                                                  * ret
10082                                                  * will work correctly.
10083                                                  */
10084                                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, TRUE);
10085                                                 MONO_ADD_INS (cfg->cbb, ins);
10086                                         }
10087
10088                                         g_assert (!return_var);
10089                                         CHECK_STACK (1);
10090                                         --sp;
10091
10092                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
10093                                                 UNVERIFIED;
10094
10095                                         emit_setret (cfg, *sp);
10096                                 }
10097                         }
10098                         if (sp != stack_start)
10099                                 UNVERIFIED;
10100                         MONO_INST_NEW (cfg, ins, OP_BR);
10101                         ip++;
10102                         ins->inst_target_bb = end_bblock;
10103                         MONO_ADD_INS (cfg->cbb, ins);
10104                         link_bblock (cfg, cfg->cbb, end_bblock);
10105                         start_new_bblock = 1;
10106                         break;
10107                 case CEE_BR_S:
10108                         CHECK_OPSIZE (2);
10109                         MONO_INST_NEW (cfg, ins, OP_BR);
10110                         ip++;
10111                         target = ip + 1 + (signed char)(*ip);
10112                         ++ip;
10113                         GET_BBLOCK (cfg, tblock, target);
10114                         link_bblock (cfg, cfg->cbb, tblock);
10115                         ins->inst_target_bb = tblock;
10116                         if (sp != stack_start) {
10117                                 handle_stack_args (cfg, stack_start, sp - stack_start);
10118                                 sp = stack_start;
10119                                 CHECK_UNVERIFIABLE (cfg);
10120                         }
10121                         MONO_ADD_INS (cfg->cbb, ins);
10122                         start_new_bblock = 1;
10123                         inline_costs += BRANCH_COST;
10124                         break;
10125                 case CEE_BEQ_S:
10126                 case CEE_BGE_S:
10127                 case CEE_BGT_S:
10128                 case CEE_BLE_S:
10129                 case CEE_BLT_S:
10130                 case CEE_BNE_UN_S:
10131                 case CEE_BGE_UN_S:
10132                 case CEE_BGT_UN_S:
10133                 case CEE_BLE_UN_S:
10134                 case CEE_BLT_UN_S:
10135                         CHECK_OPSIZE (2);
10136                         CHECK_STACK (2);
10137                         MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
10138                         ip++;
10139                         target = ip + 1 + *(signed char*)ip;
10140                         ip++;
10141
10142                         ADD_BINCOND (NULL);
10143
10144                         sp = stack_start;
10145                         inline_costs += BRANCH_COST;
10146                         break;
10147                 case CEE_BR:
10148                         CHECK_OPSIZE (5);
10149                         MONO_INST_NEW (cfg, ins, OP_BR);
10150                         ip++;
10151
10152                         target = ip + 4 + (gint32)read32(ip);
10153                         ip += 4;
10154                         GET_BBLOCK (cfg, tblock, target);
10155                         link_bblock (cfg, cfg->cbb, tblock);
10156                         ins->inst_target_bb = tblock;
10157                         if (sp != stack_start) {
10158                                 handle_stack_args (cfg, stack_start, sp - stack_start);
10159                                 sp = stack_start;
10160                                 CHECK_UNVERIFIABLE (cfg);
10161                         }
10162
10163                         MONO_ADD_INS (cfg->cbb, ins);
10164
10165                         start_new_bblock = 1;
10166                         inline_costs += BRANCH_COST;
10167                         break;
10168                 case CEE_BRFALSE_S:
10169                 case CEE_BRTRUE_S:
10170                 case CEE_BRFALSE:
10171                 case CEE_BRTRUE: {
10172                         MonoInst *cmp;
10173                         gboolean is_short = ((*ip) == CEE_BRFALSE_S) || ((*ip) == CEE_BRTRUE_S);
10174                         gboolean is_true = ((*ip) == CEE_BRTRUE_S) || ((*ip) == CEE_BRTRUE);
10175                         guint32 opsize = is_short ? 1 : 4;
10176
10177                         CHECK_OPSIZE (opsize);
10178                         CHECK_STACK (1);
10179                         if (sp [-1]->type == STACK_VTYPE || sp [-1]->type == STACK_R8)
10180                                 UNVERIFIED;
10181                         ip ++;
10182                         target = ip + opsize + (is_short ? *(signed char*)ip : (gint32)read32(ip));
10183                         ip += opsize;
10184
10185                         sp--;
10186
10187                         GET_BBLOCK (cfg, tblock, target);
10188                         link_bblock (cfg, cfg->cbb, tblock);
10189                         GET_BBLOCK (cfg, tblock, ip);
10190                         link_bblock (cfg, cfg->cbb, tblock);
10191
10192                         if (sp != stack_start) {
10193                                 handle_stack_args (cfg, stack_start, sp - stack_start);
10194                                 CHECK_UNVERIFIABLE (cfg);
10195                         }
10196
10197                         MONO_INST_NEW(cfg, cmp, OP_ICOMPARE_IMM);
10198                         cmp->sreg1 = sp [0]->dreg;
10199                         type_from_op (cfg, cmp, sp [0], NULL);
10200                         CHECK_TYPE (cmp);
10201
10202 #if SIZEOF_REGISTER == 4
10203                         if (cmp->opcode == OP_LCOMPARE_IMM) {
10204                                 /* Convert it to OP_LCOMPARE */
10205                                 MONO_INST_NEW (cfg, ins, OP_I8CONST);
10206                                 ins->type = STACK_I8;
10207                                 ins->dreg = alloc_dreg (cfg, STACK_I8);
10208                                 ins->inst_l = 0;
10209                                 MONO_ADD_INS (cfg->cbb, ins);
10210                                 cmp->opcode = OP_LCOMPARE;
10211                                 cmp->sreg2 = ins->dreg;
10212                         }
10213 #endif
10214                         MONO_ADD_INS (cfg->cbb, cmp);
10215
10216                         MONO_INST_NEW (cfg, ins, is_true ? CEE_BNE_UN : CEE_BEQ);
10217                         type_from_op (cfg, ins, sp [0], NULL);
10218                         MONO_ADD_INS (cfg->cbb, ins);
10219                         ins->inst_many_bb = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);
10220                         GET_BBLOCK (cfg, tblock, target);
10221                         ins->inst_true_bb = tblock;
10222                         GET_BBLOCK (cfg, tblock, ip);
10223                         ins->inst_false_bb = tblock;
10224                         start_new_bblock = 2;
10225
10226                         sp = stack_start;
10227                         inline_costs += BRANCH_COST;
10228                         break;
10229                 }
10230                 case CEE_BEQ:
10231                 case CEE_BGE:
10232                 case CEE_BGT:
10233                 case CEE_BLE:
10234                 case CEE_BLT:
10235                 case CEE_BNE_UN:
10236                 case CEE_BGE_UN:
10237                 case CEE_BGT_UN:
10238                 case CEE_BLE_UN:
10239                 case CEE_BLT_UN:
10240                         CHECK_OPSIZE (5);
10241                         CHECK_STACK (2);
10242                         MONO_INST_NEW (cfg, ins, *ip);
10243                         ip++;
10244                         target = ip + 4 + (gint32)read32(ip);
10245                         ip += 4;
10246
10247                         ADD_BINCOND (NULL);
10248
10249                         sp = stack_start;
10250                         inline_costs += BRANCH_COST;
10251                         break;
10252                 case CEE_SWITCH: {
10253                         MonoInst *src1;
10254                         MonoBasicBlock **targets;
10255                         MonoBasicBlock *default_bblock;
10256                         MonoJumpInfoBBTable *table;
10257                         int offset_reg = alloc_preg (cfg);
10258                         int target_reg = alloc_preg (cfg);
10259                         int table_reg = alloc_preg (cfg);
10260                         int sum_reg = alloc_preg (cfg);
10261                         gboolean use_op_switch;
10262
10263                         CHECK_OPSIZE (5);
10264                         CHECK_STACK (1);
10265                         n = read32 (ip + 1);
10266                         --sp;
10267                         src1 = sp [0];
10268                         if ((src1->type != STACK_I4) && (src1->type != STACK_PTR)) 
10269                                 UNVERIFIED;
10270
10271                         ip += 5;
10272                         CHECK_OPSIZE (n * sizeof (guint32));
10273                         target = ip + n * sizeof (guint32);
10274
10275                         GET_BBLOCK (cfg, default_bblock, target);
10276                         default_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
10277
10278                         targets = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * n);
10279                         for (i = 0; i < n; ++i) {
10280                                 GET_BBLOCK (cfg, tblock, target + (gint32)read32(ip));
10281                                 targets [i] = tblock;
10282                                 targets [i]->flags |= BB_INDIRECT_JUMP_TARGET;
10283                                 ip += 4;
10284                         }
10285
10286                         if (sp != stack_start) {
10287                                 /* 
10288                                  * Link the current bb with the targets as well, so handle_stack_args
10289                                  * will set their in_stack correctly.
10290                                  */
10291                                 link_bblock (cfg, cfg->cbb, default_bblock);
10292                                 for (i = 0; i < n; ++i)
10293                                         link_bblock (cfg, cfg->cbb, targets [i]);
10294
10295                                 handle_stack_args (cfg, stack_start, sp - stack_start);
10296                                 sp = stack_start;
10297                                 CHECK_UNVERIFIABLE (cfg);
10298
10299                                 /* Undo the links */
10300                                 mono_unlink_bblock (cfg, cfg->cbb, default_bblock);
10301                                 for (i = 0; i < n; ++i)
10302                                         mono_unlink_bblock (cfg, cfg->cbb, targets [i]);
10303                         }
10304
10305                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, src1->dreg, n);
10306                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBGE_UN, default_bblock);
10307
10308                         for (i = 0; i < n; ++i)
10309                                 link_bblock (cfg, cfg->cbb, targets [i]);
10310
10311                         table = (MonoJumpInfoBBTable *)mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfoBBTable));
10312                         table->table = targets;
10313                         table->table_size = n;
10314
10315                         use_op_switch = FALSE;
10316 #ifdef TARGET_ARM
10317                         /* ARM implements SWITCH statements differently */
10318                         /* FIXME: Make it use the generic implementation */
10319                         if (!cfg->compile_aot)
10320                                 use_op_switch = TRUE;
10321 #endif
10322
10323                         if (COMPILE_LLVM (cfg))
10324                                 use_op_switch = TRUE;
10325
10326                         cfg->cbb->has_jump_table = 1;
10327
10328                         if (use_op_switch) {
10329                                 MONO_INST_NEW (cfg, ins, OP_SWITCH);
10330                                 ins->sreg1 = src1->dreg;
10331                                 ins->inst_p0 = table;
10332                                 ins->inst_many_bb = targets;
10333                                 ins->klass = (MonoClass *)GUINT_TO_POINTER (n);
10334                                 MONO_ADD_INS (cfg->cbb, ins);
10335                         } else {
10336                                 if (sizeof (gpointer) == 8)
10337                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 3);
10338                                 else
10339                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 2);
10340
10341 #if SIZEOF_REGISTER == 8
10342                                 /* The upper word might not be zero, and we add it to a 64 bit address later */
10343                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, offset_reg, offset_reg);
10344 #endif
10345
10346                                 if (cfg->compile_aot) {
10347                                         MONO_EMIT_NEW_AOTCONST (cfg, table_reg, table, MONO_PATCH_INFO_SWITCH);
10348                                 } else {
10349                                         MONO_INST_NEW (cfg, ins, OP_JUMP_TABLE);
10350                                         ins->inst_c1 = MONO_PATCH_INFO_SWITCH;
10351                                         ins->inst_p0 = table;
10352                                         ins->dreg = table_reg;
10353                                         MONO_ADD_INS (cfg->cbb, ins);
10354                                 }
10355
10356                                 /* FIXME: Use load_memindex */
10357                                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, table_reg, offset_reg);
10358                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, target_reg, sum_reg, 0);
10359                                 MONO_EMIT_NEW_UNALU (cfg, OP_BR_REG, -1, target_reg);
10360                         }
10361                         start_new_bblock = 1;
10362                         inline_costs += (BRANCH_COST * 2);
10363                         break;
10364                 }
10365                 case CEE_LDIND_I1:
10366                 case CEE_LDIND_U1:
10367                 case CEE_LDIND_I2:
10368                 case CEE_LDIND_U2:
10369                 case CEE_LDIND_I4:
10370                 case CEE_LDIND_U4:
10371                 case CEE_LDIND_I8:
10372                 case CEE_LDIND_I:
10373                 case CEE_LDIND_R4:
10374                 case CEE_LDIND_R8:
10375                 case CEE_LDIND_REF:
10376                         CHECK_STACK (1);
10377                         --sp;
10378
10379                         switch (*ip) {
10380                         case CEE_LDIND_R4:
10381                         case CEE_LDIND_R8:
10382                                 dreg = alloc_freg (cfg);
10383                                 break;
10384                         case CEE_LDIND_I8:
10385                                 dreg = alloc_lreg (cfg);
10386                                 break;
10387                         case CEE_LDIND_REF:
10388                                 dreg = alloc_ireg_ref (cfg);
10389                                 break;
10390                         default:
10391                                 dreg = alloc_preg (cfg);
10392                         }
10393
10394                         NEW_LOAD_MEMBASE (cfg, ins, ldind_to_load_membase (*ip), dreg, sp [0]->dreg, 0);
10395                         ins->type = ldind_type [*ip - CEE_LDIND_I1];
10396                         if (*ip == CEE_LDIND_R4)
10397                                 ins->type = cfg->r4_stack_type;
10398                         ins->flags |= ins_flag;
10399                         MONO_ADD_INS (cfg->cbb, ins);
10400                         *sp++ = ins;
10401                         if (ins_flag & MONO_INST_VOLATILE) {
10402                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10403                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10404                         }
10405                         ins_flag = 0;
10406                         ++ip;
10407                         break;
10408                 case CEE_STIND_REF:
10409                 case CEE_STIND_I1:
10410                 case CEE_STIND_I2:
10411                 case CEE_STIND_I4:
10412                 case CEE_STIND_I8:
10413                 case CEE_STIND_R4:
10414                 case CEE_STIND_R8:
10415                 case CEE_STIND_I:
10416                         CHECK_STACK (2);
10417                         sp -= 2;
10418
10419                         if (ins_flag & MONO_INST_VOLATILE) {
10420                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
10421                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
10422                         }
10423
10424                         NEW_STORE_MEMBASE (cfg, ins, stind_to_store_membase (*ip), sp [0]->dreg, 0, sp [1]->dreg);
10425                         ins->flags |= ins_flag;
10426                         ins_flag = 0;
10427
10428                         MONO_ADD_INS (cfg->cbb, ins);
10429
10430                         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)))
10431                                 emit_write_barrier (cfg, sp [0], sp [1]);
10432
10433                         inline_costs += 1;
10434                         ++ip;
10435                         break;
10436
10437                 case CEE_MUL:
10438                         CHECK_STACK (2);
10439
10440                         MONO_INST_NEW (cfg, ins, (*ip));
10441                         sp -= 2;
10442                         ins->sreg1 = sp [0]->dreg;
10443                         ins->sreg2 = sp [1]->dreg;
10444                         type_from_op (cfg, ins, sp [0], sp [1]);
10445                         CHECK_TYPE (ins);
10446                         ins->dreg = alloc_dreg ((cfg), (MonoStackType)(ins)->type);
10447
10448                         /* Use the immediate opcodes if possible */
10449                         if ((sp [1]->opcode == OP_ICONST) && mono_arch_is_inst_imm (sp [1]->inst_c0)) {
10450                                 int imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
10451                                 if (imm_opcode != -1) {
10452                                         ins->opcode = imm_opcode;
10453                                         ins->inst_p1 = (gpointer)(gssize)(sp [1]->inst_c0);
10454                                         ins->sreg2 = -1;
10455
10456                                         NULLIFY_INS (sp [1]);
10457                                 }
10458                         }
10459
10460                         MONO_ADD_INS ((cfg)->cbb, (ins));
10461
10462                         *sp++ = mono_decompose_opcode (cfg, ins);
10463                         ip++;
10464                         break;
10465                 case CEE_ADD:
10466                 case CEE_SUB:
10467                 case CEE_DIV:
10468                 case CEE_DIV_UN:
10469                 case CEE_REM:
10470                 case CEE_REM_UN:
10471                 case CEE_AND:
10472                 case CEE_OR:
10473                 case CEE_XOR:
10474                 case CEE_SHL:
10475                 case CEE_SHR:
10476                 case CEE_SHR_UN:
10477                         CHECK_STACK (2);
10478
10479                         MONO_INST_NEW (cfg, ins, (*ip));
10480                         sp -= 2;
10481                         ins->sreg1 = sp [0]->dreg;
10482                         ins->sreg2 = sp [1]->dreg;
10483                         type_from_op (cfg, ins, sp [0], sp [1]);
10484                         CHECK_TYPE (ins);
10485                         add_widen_op (cfg, ins, &sp [0], &sp [1]);
10486                         ins->dreg = alloc_dreg ((cfg), (MonoStackType)(ins)->type);
10487
10488                         /* FIXME: Pass opcode to is_inst_imm */
10489
10490                         /* Use the immediate opcodes if possible */
10491                         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)) {
10492                                 int imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
10493                                 if (imm_opcode != -1) {
10494                                         ins->opcode = imm_opcode;
10495                                         if (sp [1]->opcode == OP_I8CONST) {
10496 #if SIZEOF_REGISTER == 8
10497                                                 ins->inst_imm = sp [1]->inst_l;
10498 #else
10499                                                 ins->inst_ls_word = sp [1]->inst_ls_word;
10500                                                 ins->inst_ms_word = sp [1]->inst_ms_word;
10501 #endif
10502                                         }
10503                                         else
10504                                                 ins->inst_imm = (gssize)(sp [1]->inst_c0);
10505                                         ins->sreg2 = -1;
10506
10507                                         /* Might be followed by an instruction added by add_widen_op */
10508                                         if (sp [1]->next == NULL)
10509                                                 NULLIFY_INS (sp [1]);
10510                                 }
10511                         }
10512                         MONO_ADD_INS ((cfg)->cbb, (ins));
10513
10514                         *sp++ = mono_decompose_opcode (cfg, ins);
10515                         ip++;
10516                         break;
10517                 case CEE_NEG:
10518                 case CEE_NOT:
10519                 case CEE_CONV_I1:
10520                 case CEE_CONV_I2:
10521                 case CEE_CONV_I4:
10522                 case CEE_CONV_R4:
10523                 case CEE_CONV_R8:
10524                 case CEE_CONV_U4:
10525                 case CEE_CONV_I8:
10526                 case CEE_CONV_U8:
10527                 case CEE_CONV_OVF_I8:
10528                 case CEE_CONV_OVF_U8:
10529                 case CEE_CONV_R_UN:
10530                         CHECK_STACK (1);
10531
10532                         /* Special case this earlier so we have long constants in the IR */
10533                         if ((((*ip) == CEE_CONV_I8) || ((*ip) == CEE_CONV_U8)) && (sp [-1]->opcode == OP_ICONST)) {
10534                                 int data = sp [-1]->inst_c0;
10535                                 sp [-1]->opcode = OP_I8CONST;
10536                                 sp [-1]->type = STACK_I8;
10537 #if SIZEOF_REGISTER == 8
10538                                 if ((*ip) == CEE_CONV_U8)
10539                                         sp [-1]->inst_c0 = (guint32)data;
10540                                 else
10541                                         sp [-1]->inst_c0 = data;
10542 #else
10543                                 sp [-1]->inst_ls_word = data;
10544                                 if ((*ip) == CEE_CONV_U8)
10545                                         sp [-1]->inst_ms_word = 0;
10546                                 else
10547                                         sp [-1]->inst_ms_word = (data < 0) ? -1 : 0;
10548 #endif
10549                                 sp [-1]->dreg = alloc_dreg (cfg, STACK_I8);
10550                         }
10551                         else {
10552                                 ADD_UNOP (*ip);
10553                         }
10554                         ip++;
10555                         break;
10556                 case CEE_CONV_OVF_I4:
10557                 case CEE_CONV_OVF_I1:
10558                 case CEE_CONV_OVF_I2:
10559                 case CEE_CONV_OVF_I:
10560                 case CEE_CONV_OVF_U:
10561                         CHECK_STACK (1);
10562
10563                         if (sp [-1]->type == STACK_R8 || sp [-1]->type == STACK_R4) {
10564                                 ADD_UNOP (CEE_CONV_OVF_I8);
10565                                 ADD_UNOP (*ip);
10566                         } else {
10567                                 ADD_UNOP (*ip);
10568                         }
10569                         ip++;
10570                         break;
10571                 case CEE_CONV_OVF_U1:
10572                 case CEE_CONV_OVF_U2:
10573                 case CEE_CONV_OVF_U4:
10574                         CHECK_STACK (1);
10575
10576                         if (sp [-1]->type == STACK_R8 || sp [-1]->type == STACK_R4) {
10577                                 ADD_UNOP (CEE_CONV_OVF_U8);
10578                                 ADD_UNOP (*ip);
10579                         } else {
10580                                 ADD_UNOP (*ip);
10581                         }
10582                         ip++;
10583                         break;
10584                 case CEE_CONV_OVF_I1_UN:
10585                 case CEE_CONV_OVF_I2_UN:
10586                 case CEE_CONV_OVF_I4_UN:
10587                 case CEE_CONV_OVF_I8_UN:
10588                 case CEE_CONV_OVF_U1_UN:
10589                 case CEE_CONV_OVF_U2_UN:
10590                 case CEE_CONV_OVF_U4_UN:
10591                 case CEE_CONV_OVF_U8_UN:
10592                 case CEE_CONV_OVF_I_UN:
10593                 case CEE_CONV_OVF_U_UN:
10594                 case CEE_CONV_U2:
10595                 case CEE_CONV_U1:
10596                 case CEE_CONV_I:
10597                 case CEE_CONV_U:
10598                         CHECK_STACK (1);
10599                         ADD_UNOP (*ip);
10600                         CHECK_CFG_EXCEPTION;
10601                         ip++;
10602                         break;
10603                 case CEE_ADD_OVF:
10604                 case CEE_ADD_OVF_UN:
10605                 case CEE_MUL_OVF:
10606                 case CEE_MUL_OVF_UN:
10607                 case CEE_SUB_OVF:
10608                 case CEE_SUB_OVF_UN:
10609                         CHECK_STACK (2);
10610                         ADD_BINOP (*ip);
10611                         ip++;
10612                         break;
10613                 case CEE_CPOBJ:
10614                         GSHAREDVT_FAILURE (*ip);
10615                         CHECK_OPSIZE (5);
10616                         CHECK_STACK (2);
10617                         token = read32 (ip + 1);
10618                         klass = mini_get_class (method, token, generic_context);
10619                         CHECK_TYPELOAD (klass);
10620                         sp -= 2;
10621                         if (generic_class_is_reference_type (cfg, klass)) {
10622                                 MonoInst *store, *load;
10623                                 int dreg = alloc_ireg_ref (cfg);
10624
10625                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, dreg, sp [1]->dreg, 0);
10626                                 load->flags |= ins_flag;
10627                                 MONO_ADD_INS (cfg->cbb, load);
10628
10629                                 NEW_STORE_MEMBASE (cfg, store, OP_STORE_MEMBASE_REG, sp [0]->dreg, 0, dreg);
10630                                 store->flags |= ins_flag;
10631                                 MONO_ADD_INS (cfg->cbb, store);
10632
10633                                 if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER)
10634                                         emit_write_barrier (cfg, sp [0], sp [1]);
10635                         } else {
10636                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
10637                         }
10638                         ins_flag = 0;
10639                         ip += 5;
10640                         break;
10641                 case CEE_LDOBJ: {
10642                         int loc_index = -1;
10643                         int stloc_len = 0;
10644
10645                         CHECK_OPSIZE (5);
10646                         CHECK_STACK (1);
10647                         --sp;
10648                         token = read32 (ip + 1);
10649                         klass = mini_get_class (method, token, generic_context);
10650                         CHECK_TYPELOAD (klass);
10651
10652                         /* Optimize the common ldobj+stloc combination */
10653                         switch (ip [5]) {
10654                         case CEE_STLOC_S:
10655                                 loc_index = ip [6];
10656                                 stloc_len = 2;
10657                                 break;
10658                         case CEE_STLOC_0:
10659                         case CEE_STLOC_1:
10660                         case CEE_STLOC_2:
10661                         case CEE_STLOC_3:
10662                                 loc_index = ip [5] - CEE_STLOC_0;
10663                                 stloc_len = 1;
10664                                 break;
10665                         default:
10666                                 break;
10667                         }
10668
10669                         if ((loc_index != -1) && ip_in_bb (cfg, cfg->cbb, ip + 5)) {
10670                                 CHECK_LOCAL (loc_index);
10671
10672                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
10673                                 ins->dreg = cfg->locals [loc_index]->dreg;
10674                                 ins->flags |= ins_flag;
10675                                 ip += 5;
10676                                 ip += stloc_len;
10677                                 if (ins_flag & MONO_INST_VOLATILE) {
10678                                         /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10679                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10680                                 }
10681                                 ins_flag = 0;
10682                                 break;
10683                         }
10684
10685                         /* Optimize the ldobj+stobj combination */
10686                         /* The reference case ends up being a load+store anyway */
10687                         /* Skip this if the operation is volatile. */
10688                         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)) {
10689                                 CHECK_STACK (1);
10690
10691                                 sp --;
10692
10693                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
10694
10695                                 ip += 5 + 5;
10696                                 ins_flag = 0;
10697                                 break;
10698                         }
10699
10700                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
10701                         ins->flags |= ins_flag;
10702                         *sp++ = ins;
10703
10704                         if (ins_flag & MONO_INST_VOLATILE) {
10705                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10706                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10707                         }
10708
10709                         ip += 5;
10710                         ins_flag = 0;
10711                         inline_costs += 1;
10712                         break;
10713                 }
10714                 case CEE_LDSTR:
10715                         CHECK_STACK_OVF (1);
10716                         CHECK_OPSIZE (5);
10717                         n = read32 (ip + 1);
10718
10719                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
10720                                 EMIT_NEW_PCONST (cfg, ins, mono_method_get_wrapper_data (method, n));
10721                                 ins->type = STACK_OBJ;
10722                                 *sp = ins;
10723                         }
10724                         else if (method->wrapper_type != MONO_WRAPPER_NONE) {
10725                                 MonoInst *iargs [1];
10726                                 char *str = (char *)mono_method_get_wrapper_data (method, n);
10727
10728                                 if (cfg->compile_aot)
10729                                         EMIT_NEW_LDSTRLITCONST (cfg, iargs [0], str);
10730                                 else
10731                                         EMIT_NEW_PCONST (cfg, iargs [0], str);
10732                                 *sp = mono_emit_jit_icall (cfg, mono_string_new_wrapper, iargs);
10733                         } else {
10734                                 if (cfg->opt & MONO_OPT_SHARED) {
10735                                         MonoInst *iargs [3];
10736
10737                                         if (cfg->compile_aot) {
10738                                                 cfg->ldstr_list = g_list_prepend (cfg->ldstr_list, GINT_TO_POINTER (n));
10739                                         }
10740                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
10741                                         EMIT_NEW_IMAGECONST (cfg, iargs [1], image);
10742                                         EMIT_NEW_ICONST (cfg, iargs [2], mono_metadata_token_index (n));
10743                                         *sp = mono_emit_jit_icall (cfg, mono_ldstr, iargs);
10744                                         mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
10745                                 } else {
10746                                         if (cfg->cbb->out_of_line) {
10747                                                 MonoInst *iargs [2];
10748
10749                                                 if (image == mono_defaults.corlib) {
10750                                                         /* 
10751                                                          * Avoid relocations in AOT and save some space by using a 
10752                                                          * version of helper_ldstr specialized to mscorlib.
10753                                                          */
10754                                                         EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (n));
10755                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr_mscorlib, iargs);
10756                                                 } else {
10757                                                         /* Avoid creating the string object */
10758                                                         EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
10759                                                         EMIT_NEW_ICONST (cfg, iargs [1], mono_metadata_token_index (n));
10760                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr, iargs);
10761                                                 }
10762                                         } 
10763                                         else
10764                                         if (cfg->compile_aot) {
10765                                                 NEW_LDSTRCONST (cfg, ins, image, n);
10766                                                 *sp = ins;
10767                                                 MONO_ADD_INS (cfg->cbb, ins);
10768                                         } 
10769                                         else {
10770                                                 NEW_PCONST (cfg, ins, NULL);
10771                                                 ins->type = STACK_OBJ;
10772                                                 ins->inst_p0 = mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
10773                                                 if (!ins->inst_p0)
10774                                                         OUT_OF_MEMORY_FAILURE;
10775
10776                                                 *sp = ins;
10777                                                 MONO_ADD_INS (cfg->cbb, ins);
10778                                         }
10779                                 }
10780                         }
10781
10782                         sp++;
10783                         ip += 5;
10784                         break;
10785                 case CEE_NEWOBJ: {
10786                         MonoInst *iargs [2];
10787                         MonoMethodSignature *fsig;
10788                         MonoInst this_ins;
10789                         MonoInst *alloc;
10790                         MonoInst *vtable_arg = NULL;
10791
10792                         CHECK_OPSIZE (5);
10793                         token = read32 (ip + 1);
10794                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
10795                         CHECK_CFG_ERROR;
10796
10797                         fsig = mono_method_get_signature_checked (cmethod, image, token, generic_context, &cfg->error);
10798                         CHECK_CFG_ERROR;
10799
10800                         mono_save_token_info (cfg, image, token, cmethod);
10801
10802                         if (!mono_class_init (cmethod->klass))
10803                                 TYPE_LOAD_ERROR (cmethod->klass);
10804
10805                         context_used = mini_method_check_context_used (cfg, cmethod);
10806
10807                         if (mono_security_core_clr_enabled ())
10808                                 ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
10809
10810                         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)) {
10811                                 emit_class_init (cfg, cmethod->klass);
10812                                 CHECK_TYPELOAD (cmethod->klass);
10813                         }
10814
10815                         /*
10816                         if (cfg->gsharedvt) {
10817                                 if (mini_is_gsharedvt_variable_signature (sig))
10818                                         GSHAREDVT_FAILURE (*ip);
10819                         }
10820                         */
10821
10822                         n = fsig->param_count;
10823                         CHECK_STACK (n);
10824
10825                         /* 
10826                          * Generate smaller code for the common newobj <exception> instruction in
10827                          * argument checking code.
10828                          */
10829                         if (cfg->cbb->out_of_line && cmethod->klass->image == mono_defaults.corlib &&
10830                                 is_exception_class (cmethod->klass) && n <= 2 &&
10831                                 ((n < 1) || (!fsig->params [0]->byref && fsig->params [0]->type == MONO_TYPE_STRING)) && 
10832                                 ((n < 2) || (!fsig->params [1]->byref && fsig->params [1]->type == MONO_TYPE_STRING))) {
10833                                 MonoInst *iargs [3];
10834
10835                                 sp -= n;
10836
10837                                 EMIT_NEW_ICONST (cfg, iargs [0], cmethod->klass->type_token);
10838                                 switch (n) {
10839                                 case 0:
10840                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_0, iargs);
10841                                         break;
10842                                 case 1:
10843                                         iargs [1] = sp [0];
10844                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_1, iargs);
10845                                         break;
10846                                 case 2:
10847                                         iargs [1] = sp [0];
10848                                         iargs [2] = sp [1];
10849                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_2, iargs);
10850                                         break;
10851                                 default:
10852                                         g_assert_not_reached ();
10853                                 }
10854
10855                                 ip += 5;
10856                                 inline_costs += 5;
10857                                 break;
10858                         }
10859
10860                         /* move the args to allow room for 'this' in the first position */
10861                         while (n--) {
10862                                 --sp;
10863                                 sp [1] = sp [0];
10864                         }
10865
10866                         /* check_call_signature () requires sp[0] to be set */
10867                         this_ins.type = STACK_OBJ;
10868                         sp [0] = &this_ins;
10869                         if (check_call_signature (cfg, fsig, sp))
10870                                 UNVERIFIED;
10871
10872                         iargs [0] = NULL;
10873
10874                         if (mini_class_is_system_array (cmethod->klass)) {
10875                                 *sp = emit_get_rgctx_method (cfg, context_used,
10876                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
10877
10878                                 /* Avoid varargs in the common case */
10879                                 if (fsig->param_count == 1)
10880                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_1, sp);
10881                                 else if (fsig->param_count == 2)
10882                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_2, sp);
10883                                 else if (fsig->param_count == 3)
10884                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_3, sp);
10885                                 else if (fsig->param_count == 4)
10886                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_4, sp);
10887                                 else
10888                                         alloc = handle_array_new (cfg, fsig->param_count, sp, ip);
10889                         } else if (cmethod->string_ctor) {
10890                                 g_assert (!context_used);
10891                                 g_assert (!vtable_arg);
10892                                 /* we simply pass a null pointer */
10893                                 EMIT_NEW_PCONST (cfg, *sp, NULL); 
10894                                 /* now call the string ctor */
10895                                 alloc = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, NULL, NULL, NULL);
10896                         } else {
10897                                 if (cmethod->klass->valuetype) {
10898                                         iargs [0] = mono_compile_create_var (cfg, &cmethod->klass->byval_arg, OP_LOCAL);
10899                                         emit_init_rvar (cfg, iargs [0]->dreg, &cmethod->klass->byval_arg);
10900                                         EMIT_NEW_TEMPLOADA (cfg, *sp, iargs [0]->inst_c0);
10901
10902                                         alloc = NULL;
10903
10904                                         /* 
10905                                          * The code generated by mini_emit_virtual_call () expects
10906                                          * iargs [0] to be a boxed instance, but luckily the vcall
10907                                          * will be transformed into a normal call there.
10908                                          */
10909                                 } else if (context_used) {
10910                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, context_used);
10911                                         *sp = alloc;
10912                                 } else {
10913                                         MonoVTable *vtable = NULL;
10914
10915                                         if (!cfg->compile_aot)
10916                                                 vtable = mono_class_vtable (cfg->domain, cmethod->klass);
10917                                         CHECK_TYPELOAD (cmethod->klass);
10918
10919                                         /*
10920                                          * TypeInitializationExceptions thrown from the mono_runtime_class_init
10921                                          * call in mono_jit_runtime_invoke () can abort the finalizer thread.
10922                                          * As a workaround, we call class cctors before allocating objects.
10923                                          */
10924                                         if (mini_field_access_needs_cctor_run (cfg, method, cmethod->klass, vtable) && !(g_slist_find (class_inits, cmethod->klass))) {
10925                                                 emit_class_init (cfg, cmethod->klass);
10926                                                 if (cfg->verbose_level > 2)
10927                                                         printf ("class %s.%s needs init call for ctor\n", cmethod->klass->name_space, cmethod->klass->name);
10928                                                 class_inits = g_slist_prepend (class_inits, cmethod->klass);
10929                                         }
10930
10931                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, 0);
10932                                         *sp = alloc;
10933                                 }
10934                                 CHECK_CFG_EXCEPTION; /*for handle_alloc*/
10935
10936                                 if (alloc)
10937                                         MONO_EMIT_NEW_UNALU (cfg, OP_NOT_NULL, -1, alloc->dreg);
10938
10939                                 /* Now call the actual ctor */
10940                                 handle_ctor_call (cfg, cmethod, fsig, context_used, sp, ip, &inline_costs);
10941                                 CHECK_CFG_EXCEPTION;
10942                         }
10943
10944                         if (alloc == NULL) {
10945                                 /* Valuetype */
10946                                 EMIT_NEW_TEMPLOAD (cfg, ins, iargs [0]->inst_c0);
10947                                 type_to_eval_stack_type (cfg, &ins->klass->byval_arg, ins);
10948                                 *sp++= ins;
10949                         } else {
10950                                 *sp++ = alloc;
10951                         }
10952                         
10953                         ip += 5;
10954                         inline_costs += 5;
10955                         if (!(seq_point_locs && mono_bitset_test_fast (seq_point_locs, ip - header->code)))
10956                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
10957                         break;
10958                 }
10959                 case CEE_CASTCLASS:
10960                         CHECK_STACK (1);
10961                         --sp;
10962                         CHECK_OPSIZE (5);
10963                         token = read32 (ip + 1);
10964                         klass = mini_get_class (method, token, generic_context);
10965                         CHECK_TYPELOAD (klass);
10966                         if (sp [0]->type != STACK_OBJ)
10967                                 UNVERIFIED;
10968
10969                         ins = handle_castclass (cfg, klass, *sp, ip, &inline_costs);
10970                         CHECK_CFG_EXCEPTION;
10971
10972                         *sp ++ = ins;
10973                         ip += 5;
10974                         break;
10975                 case CEE_ISINST: {
10976                         CHECK_STACK (1);
10977                         --sp;
10978                         CHECK_OPSIZE (5);
10979                         token = read32 (ip + 1);
10980                         klass = mini_get_class (method, token, generic_context);
10981                         CHECK_TYPELOAD (klass);
10982                         if (sp [0]->type != STACK_OBJ)
10983                                 UNVERIFIED;
10984  
10985                         context_used = mini_class_check_context_used (cfg, klass);
10986
10987                         if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
10988                                 MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
10989                                 MonoInst *args [3];
10990                                 int idx;
10991
10992                                 /* obj */
10993                                 args [0] = *sp;
10994
10995                                 /* klass */
10996                                 EMIT_NEW_CLASSCONST (cfg, args [1], klass);
10997
10998                                 /* inline cache*/
10999                                 idx = get_castclass_cache_idx (cfg);
11000                                 args [2] = emit_runtime_constant (cfg, MONO_PATCH_INFO_CASTCLASS_CACHE, GINT_TO_POINTER (idx));
11001
11002                                 *sp++ = mono_emit_method_call (cfg, mono_isinst, args, NULL);
11003                                 ip += 5;
11004                                 inline_costs += 2;
11005                         } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
11006                                 MonoMethod *mono_isinst;
11007                                 MonoInst *iargs [1];
11008                                 int costs;
11009
11010                                 mono_isinst = mono_marshal_get_isinst (klass); 
11011                                 iargs [0] = sp [0];
11012
11013                                 costs = inline_method (cfg, mono_isinst, mono_method_signature (mono_isinst), 
11014                                                                            iargs, ip, cfg->real_offset, TRUE);
11015                                 CHECK_CFG_EXCEPTION;
11016                                 g_assert (costs > 0);
11017                                 
11018                                 ip += 5;
11019                                 cfg->real_offset += 5;
11020
11021                                 *sp++= iargs [0];
11022
11023                                 inline_costs += costs;
11024                         }
11025                         else {
11026                                 ins = handle_isinst (cfg, klass, *sp, context_used);
11027                                 CHECK_CFG_EXCEPTION;
11028                                 *sp ++ = ins;
11029                                 ip += 5;
11030                         }
11031                         break;
11032                 }
11033                 case CEE_UNBOX_ANY: {
11034                         MonoInst *res, *addr;
11035
11036                         CHECK_STACK (1);
11037                         --sp;
11038                         CHECK_OPSIZE (5);
11039                         token = read32 (ip + 1);
11040                         klass = mini_get_class (method, token, generic_context);
11041                         CHECK_TYPELOAD (klass);
11042
11043                         mono_save_token_info (cfg, image, token, klass);
11044
11045                         context_used = mini_class_check_context_used (cfg, klass);
11046
11047                         if (mini_is_gsharedvt_klass (klass)) {
11048                                 res = handle_unbox_gsharedvt (cfg, klass, *sp);
11049                                 inline_costs += 2;
11050                         } else if (generic_class_is_reference_type (cfg, klass)) {
11051                                 res = handle_castclass (cfg, klass, *sp, ip, &inline_costs);
11052                                 CHECK_CFG_EXCEPTION;
11053                         } else if (mono_class_is_nullable (klass)) {
11054                                 res = handle_unbox_nullable (cfg, *sp, klass, context_used);
11055                         } else {
11056                                 addr = handle_unbox (cfg, klass, sp, context_used);
11057                                 /* LDOBJ */
11058                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
11059                                 res = ins;
11060                                 inline_costs += 2;
11061                         }
11062
11063                         *sp ++ = res;
11064                         ip += 5;
11065                         break;
11066                 }
11067                 case CEE_BOX: {
11068                         MonoInst *val;
11069                         MonoClass *enum_class;
11070                         MonoMethod *has_flag;
11071
11072                         CHECK_STACK (1);
11073                         --sp;
11074                         val = *sp;
11075                         CHECK_OPSIZE (5);
11076                         token = read32 (ip + 1);
11077                         klass = mini_get_class (method, token, generic_context);
11078                         CHECK_TYPELOAD (klass);
11079
11080                         mono_save_token_info (cfg, image, token, klass);
11081
11082                         context_used = mini_class_check_context_used (cfg, klass);
11083
11084                         if (generic_class_is_reference_type (cfg, klass)) {
11085                                 *sp++ = val;
11086                                 ip += 5;
11087                                 break;
11088                         }
11089
11090                         if (klass == mono_defaults.void_class)
11091                                 UNVERIFIED;
11092                         if (target_type_is_incompatible (cfg, &klass->byval_arg, *sp))
11093                                 UNVERIFIED;
11094                         /* frequent check in generic code: box (struct), brtrue */
11095
11096                         /*
11097                          * Look for:
11098                          *
11099                          *   <push int/long ptr>
11100                          *   <push int/long>
11101                          *   box MyFlags
11102                          *   constrained. MyFlags
11103                          *   callvirt instace bool class [mscorlib] System.Enum::HasFlag (class [mscorlib] System.Enum)
11104                          *
11105                          * If we find this sequence and the operand types on box and constrained
11106                          * are equal, we can emit a specialized instruction sequence instead of
11107                          * the very slow HasFlag () call.
11108                          */
11109                         if ((cfg->opt & MONO_OPT_INTRINS) &&
11110                             /* Cheap checks first. */
11111                             ip + 5 + 6 + 5 < end &&
11112                             ip [5] == CEE_PREFIX1 &&
11113                             ip [6] == CEE_CONSTRAINED_ &&
11114                             ip [11] == CEE_CALLVIRT &&
11115                             ip_in_bb (cfg, cfg->cbb, ip + 5 + 6 + 5) &&
11116                             mono_class_is_enum (klass) &&
11117                             (enum_class = mini_get_class (method, read32 (ip + 7), generic_context)) &&
11118                             (has_flag = mini_get_method (cfg, method, read32 (ip + 12), NULL, generic_context)) &&
11119                             has_flag->klass == mono_defaults.enum_class &&
11120                             !strcmp (has_flag->name, "HasFlag") &&
11121                             has_flag->signature->hasthis &&
11122                             has_flag->signature->param_count == 1) {
11123                                 CHECK_TYPELOAD (enum_class);
11124
11125                                 if (enum_class == klass) {
11126                                         MonoInst *enum_this, *enum_flag;
11127
11128                                         ip += 5 + 6 + 5;
11129                                         --sp;
11130
11131                                         enum_this = sp [0];
11132                                         enum_flag = sp [1];
11133
11134                                         *sp++ = handle_enum_has_flag (cfg, klass, enum_this, enum_flag);
11135                                         break;
11136                                 }
11137                         }
11138
11139                         // FIXME: LLVM can't handle the inconsistent bb linking
11140                         if (!mono_class_is_nullable (klass) &&
11141                                 !mini_is_gsharedvt_klass (klass) &&
11142                                 ip + 5 < end && ip_in_bb (cfg, cfg->cbb, ip + 5) &&
11143                                 (ip [5] == CEE_BRTRUE || 
11144                                  ip [5] == CEE_BRTRUE_S ||
11145                                  ip [5] == CEE_BRFALSE ||
11146                                  ip [5] == CEE_BRFALSE_S)) {
11147                                 gboolean is_true = ip [5] == CEE_BRTRUE || ip [5] == CEE_BRTRUE_S;
11148                                 int dreg;
11149                                 MonoBasicBlock *true_bb, *false_bb;
11150
11151                                 ip += 5;
11152
11153                                 if (cfg->verbose_level > 3) {
11154                                         printf ("converting (in B%d: stack: %d) %s", cfg->cbb->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
11155                                         printf ("<box+brtrue opt>\n");
11156                                 }
11157
11158                                 switch (*ip) {
11159                                 case CEE_BRTRUE_S:
11160                                 case CEE_BRFALSE_S:
11161                                         CHECK_OPSIZE (2);
11162                                         ip++;
11163                                         target = ip + 1 + (signed char)(*ip);
11164                                         ip++;
11165                                         break;
11166                                 case CEE_BRTRUE:
11167                                 case CEE_BRFALSE:
11168                                         CHECK_OPSIZE (5);
11169                                         ip++;
11170                                         target = ip + 4 + (gint)(read32 (ip));
11171                                         ip += 4;
11172                                         break;
11173                                 default:
11174                                         g_assert_not_reached ();
11175                                 }
11176
11177                                 /* 
11178                                  * We need to link both bblocks, since it is needed for handling stack
11179                                  * arguments correctly (See test_0_box_brtrue_opt_regress_81102).
11180                                  * Branching to only one of them would lead to inconsistencies, so
11181                                  * generate an ICONST+BRTRUE, the branch opts will get rid of them.
11182                                  */
11183                                 GET_BBLOCK (cfg, true_bb, target);
11184                                 GET_BBLOCK (cfg, false_bb, ip);
11185
11186                                 mono_link_bblock (cfg, cfg->cbb, true_bb);
11187                                 mono_link_bblock (cfg, cfg->cbb, false_bb);
11188
11189                                 if (sp != stack_start) {
11190                                         handle_stack_args (cfg, stack_start, sp - stack_start);
11191                                         sp = stack_start;
11192                                         CHECK_UNVERIFIABLE (cfg);
11193                                 }
11194
11195                                 if (COMPILE_LLVM (cfg)) {
11196                                         dreg = alloc_ireg (cfg);
11197                                         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
11198                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, dreg, is_true ? 0 : 1);
11199
11200                                         MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, OP_IBEQ, true_bb, false_bb);
11201                                 } else {
11202                                         /* The JIT can't eliminate the iconst+compare */
11203                                         MONO_INST_NEW (cfg, ins, OP_BR);
11204                                         ins->inst_target_bb = is_true ? true_bb : false_bb;
11205                                         MONO_ADD_INS (cfg->cbb, ins);
11206                                 }
11207
11208                                 start_new_bblock = 1;
11209                                 break;
11210                         }
11211
11212                         *sp++ = handle_box (cfg, val, klass, context_used);
11213
11214                         CHECK_CFG_EXCEPTION;
11215                         ip += 5;
11216                         inline_costs += 1;
11217                         break;
11218                 }
11219                 case CEE_UNBOX: {
11220                         CHECK_STACK (1);
11221                         --sp;
11222                         CHECK_OPSIZE (5);
11223                         token = read32 (ip + 1);
11224                         klass = mini_get_class (method, token, generic_context);
11225                         CHECK_TYPELOAD (klass);
11226
11227                         mono_save_token_info (cfg, image, token, klass);
11228
11229                         context_used = mini_class_check_context_used (cfg, klass);
11230
11231                         if (mono_class_is_nullable (klass)) {
11232                                 MonoInst *val;
11233
11234                                 val = handle_unbox_nullable (cfg, *sp, klass, context_used);
11235                                 EMIT_NEW_VARLOADA (cfg, ins, get_vreg_to_inst (cfg, val->dreg), &val->klass->byval_arg);
11236
11237                                 *sp++= ins;
11238                         } else {
11239                                 ins = handle_unbox (cfg, klass, sp, context_used);
11240                                 *sp++ = ins;
11241                         }
11242                         ip += 5;
11243                         inline_costs += 2;
11244                         break;
11245                 }
11246                 case CEE_LDFLD:
11247                 case CEE_LDFLDA:
11248                 case CEE_STFLD:
11249                 case CEE_LDSFLD:
11250                 case CEE_LDSFLDA:
11251                 case CEE_STSFLD: {
11252                         MonoClassField *field;
11253 #ifndef DISABLE_REMOTING
11254                         int costs;
11255 #endif
11256                         guint foffset;
11257                         gboolean is_instance;
11258                         int op;
11259                         gpointer addr = NULL;
11260                         gboolean is_special_static;
11261                         MonoType *ftype;
11262                         MonoInst *store_val = NULL;
11263                         MonoInst *thread_ins;
11264
11265                         op = *ip;
11266                         is_instance = (op == CEE_LDFLD || op == CEE_LDFLDA || op == CEE_STFLD);
11267                         if (is_instance) {
11268                                 if (op == CEE_STFLD) {
11269                                         CHECK_STACK (2);
11270                                         sp -= 2;
11271                                         store_val = sp [1];
11272                                 } else {
11273                                         CHECK_STACK (1);
11274                                         --sp;
11275                                 }
11276                                 if (sp [0]->type == STACK_I4 || sp [0]->type == STACK_I8 || sp [0]->type == STACK_R8)
11277                                         UNVERIFIED;
11278                                 if (*ip != CEE_LDFLD && sp [0]->type == STACK_VTYPE)
11279                                         UNVERIFIED;
11280                         } else {
11281                                 if (op == CEE_STSFLD) {
11282                                         CHECK_STACK (1);
11283                                         sp--;
11284                                         store_val = sp [0];
11285                                 }
11286                         }
11287
11288                         CHECK_OPSIZE (5);
11289                         token = read32 (ip + 1);
11290                         if (method->wrapper_type != MONO_WRAPPER_NONE) {
11291                                 field = (MonoClassField *)mono_method_get_wrapper_data (method, token);
11292                                 klass = field->parent;
11293                         }
11294                         else {
11295                                 field = mono_field_from_token_checked (image, token, &klass, generic_context, &cfg->error);
11296                                 CHECK_CFG_ERROR;
11297                         }
11298                         if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_field (method, field))
11299                                 FIELD_ACCESS_FAILURE (method, field);
11300                         mono_class_init (klass);
11301
11302                         /* if the class is Critical then transparent code cannot access it's fields */
11303                         if (!is_instance && mono_security_core_clr_enabled ())
11304                                 ensure_method_is_allowed_to_access_field (cfg, method, field);
11305
11306                         /* XXX this is technically required but, so far (SL2), no [SecurityCritical] types (not many exists) have
11307                            any visible *instance* field  (in fact there's a single case for a static field in Marshal) XXX
11308                         if (mono_security_core_clr_enabled ())
11309                                 ensure_method_is_allowed_to_access_field (cfg, method, field);
11310                         */
11311
11312                         ftype = mono_field_get_type (field);
11313
11314                         /*
11315                          * LDFLD etc. is usable on static fields as well, so convert those cases to
11316                          * the static case.
11317                          */
11318                         if (is_instance && ftype->attrs & FIELD_ATTRIBUTE_STATIC) {
11319                                 switch (op) {
11320                                 case CEE_LDFLD:
11321                                         op = CEE_LDSFLD;
11322                                         break;
11323                                 case CEE_STFLD:
11324                                         op = CEE_STSFLD;
11325                                         break;
11326                                 case CEE_LDFLDA:
11327                                         op = CEE_LDSFLDA;
11328                                         break;
11329                                 default:
11330                                         g_assert_not_reached ();
11331                                 }
11332                                 is_instance = FALSE;
11333                         }
11334
11335                         context_used = mini_class_check_context_used (cfg, klass);
11336
11337                         /* INSTANCE CASE */
11338
11339                         foffset = klass->valuetype? field->offset - sizeof (MonoObject): field->offset;
11340                         if (op == CEE_STFLD) {
11341                                 if (target_type_is_incompatible (cfg, field->type, sp [1]))
11342                                         UNVERIFIED;
11343 #ifndef DISABLE_REMOTING
11344                                 if ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class) {
11345                                         MonoMethod *stfld_wrapper = mono_marshal_get_stfld_wrapper (field->type); 
11346                                         MonoInst *iargs [5];
11347
11348                                         GSHAREDVT_FAILURE (op);
11349
11350                                         iargs [0] = sp [0];
11351                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
11352                                         EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
11353                                         EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : 
11354                                                     field->offset);
11355                                         iargs [4] = sp [1];
11356
11357                                         if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
11358                                                 costs = inline_method (cfg, stfld_wrapper, mono_method_signature (stfld_wrapper), 
11359                                                                                            iargs, ip, cfg->real_offset, TRUE);
11360                                                 CHECK_CFG_EXCEPTION;
11361                                                 g_assert (costs > 0);
11362                                                       
11363                                                 cfg->real_offset += 5;
11364
11365                                                 inline_costs += costs;
11366                                         } else {
11367                                                 mono_emit_method_call (cfg, stfld_wrapper, iargs, NULL);
11368                                         }
11369                                 } else
11370 #endif
11371                                 {
11372                                         MonoInst *store;
11373
11374                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
11375
11376                                         if (mini_is_gsharedvt_klass (klass)) {
11377                                                 MonoInst *offset_ins;
11378
11379                                                 context_used = mini_class_check_context_used (cfg, klass);
11380
11381                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11382                                                 /* The value is offset by 1 */
11383                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
11384                                                 dreg = alloc_ireg_mp (cfg);
11385                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
11386                                                 /* The decomposition will call mini_emit_stobj () which will emit a wbarrier if needed */
11387                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, dreg, 0, sp [1]->dreg);
11388                                         } else {
11389                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, sp [0]->dreg, foffset, sp [1]->dreg);
11390                                         }
11391                                         if (sp [0]->opcode != OP_LDADDR)
11392                                                 store->flags |= MONO_INST_FAULT;
11393
11394                                 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)) {
11395                                         /* insert call to write barrier */
11396                                         MonoInst *ptr;
11397                                         int dreg;
11398
11399                                         dreg = alloc_ireg_mp (cfg);
11400                                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
11401                                         emit_write_barrier (cfg, ptr, sp [1]);
11402                                 }
11403
11404                                         store->flags |= ins_flag;
11405                                 }
11406                                 ins_flag = 0;
11407                                 ip += 5;
11408                                 break;
11409                         }
11410
11411 #ifndef DISABLE_REMOTING
11412                         if (is_instance && ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class)) {
11413                                 MonoMethod *wrapper = (op == CEE_LDFLDA) ? mono_marshal_get_ldflda_wrapper (field->type) : mono_marshal_get_ldfld_wrapper (field->type); 
11414                                 MonoInst *iargs [4];
11415
11416                                 GSHAREDVT_FAILURE (op);
11417
11418                                 iargs [0] = sp [0];
11419                                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
11420                                 EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
11421                                 EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset);
11422                                 if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
11423                                         costs = inline_method (cfg, wrapper, mono_method_signature (wrapper), 
11424                                                                                    iargs, ip, cfg->real_offset, TRUE);
11425                                         CHECK_CFG_EXCEPTION;
11426                                         g_assert (costs > 0);
11427                                                       
11428                                         cfg->real_offset += 5;
11429
11430                                         *sp++ = iargs [0];
11431
11432                                         inline_costs += costs;
11433                                 } else {
11434                                         ins = mono_emit_method_call (cfg, wrapper, iargs, NULL);
11435                                         *sp++ = ins;
11436                                 }
11437                         } else 
11438 #endif
11439                         if (is_instance) {
11440                                 if (sp [0]->type == STACK_VTYPE) {
11441                                         MonoInst *var;
11442
11443                                         /* Have to compute the address of the variable */
11444
11445                                         var = get_vreg_to_inst (cfg, sp [0]->dreg);
11446                                         if (!var)
11447                                                 var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, sp [0]->dreg);
11448                                         else
11449                                                 g_assert (var->klass == klass);
11450                                         
11451                                         EMIT_NEW_VARLOADA (cfg, ins, var, &var->klass->byval_arg);
11452                                         sp [0] = ins;
11453                                 }
11454
11455                                 if (op == CEE_LDFLDA) {
11456                                         if (sp [0]->type == STACK_OBJ) {
11457                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, sp [0]->dreg, 0);
11458                                                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "NullReferenceException");
11459                                         }
11460
11461                                         dreg = alloc_ireg_mp (cfg);
11462
11463                                         if (mini_is_gsharedvt_klass (klass)) {
11464                                                 MonoInst *offset_ins;
11465
11466                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11467                                                 /* The value is offset by 1 */
11468                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
11469                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
11470                                         } else {
11471                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
11472                                         }
11473                                         ins->klass = mono_class_from_mono_type (field->type);
11474                                         ins->type = STACK_MP;
11475                                         *sp++ = ins;
11476                                 } else {
11477                                         MonoInst *load;
11478
11479                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
11480
11481                                         if (mini_is_gsharedvt_klass (klass)) {
11482                                                 MonoInst *offset_ins;
11483
11484                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11485                                                 /* The value is offset by 1 */
11486                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
11487                                                 dreg = alloc_ireg_mp (cfg);
11488                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
11489                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, dreg, 0);
11490                                         } else {
11491                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, sp [0]->dreg, foffset);
11492                                         }
11493                                         load->flags |= ins_flag;
11494                                         if (sp [0]->opcode != OP_LDADDR)
11495                                                 load->flags |= MONO_INST_FAULT;
11496                                         *sp++ = load;
11497                                 }
11498                         }
11499
11500                         if (is_instance) {
11501                                 ins_flag = 0;
11502                                 ip += 5;
11503                                 break;
11504                         }
11505
11506                         /* STATIC CASE */
11507                         context_used = mini_class_check_context_used (cfg, klass);
11508
11509                         if (ftype->attrs & FIELD_ATTRIBUTE_LITERAL)
11510                                 UNVERIFIED;
11511
11512                         /* The special_static_fields field is init'd in mono_class_vtable, so it needs
11513                          * to be called here.
11514                          */
11515                         if (!context_used && !(cfg->opt & MONO_OPT_SHARED)) {
11516                                 mono_class_vtable (cfg->domain, klass);
11517                                 CHECK_TYPELOAD (klass);
11518                         }
11519                         mono_domain_lock (cfg->domain);
11520                         if (cfg->domain->special_static_fields)
11521                                 addr = g_hash_table_lookup (cfg->domain->special_static_fields, field);
11522                         mono_domain_unlock (cfg->domain);
11523
11524                         is_special_static = mono_class_field_is_special_static (field);
11525
11526                         if (is_special_static && ((gsize)addr & 0x80000000) == 0)
11527                                 thread_ins = mono_get_thread_intrinsic (cfg);
11528                         else
11529                                 thread_ins = NULL;
11530
11531                         /* Generate IR to compute the field address */
11532                         if (is_special_static && ((gsize)addr & 0x80000000) == 0 && thread_ins && !(cfg->opt & MONO_OPT_SHARED) && !context_used) {
11533                                 /*
11534                                  * Fast access to TLS data
11535                                  * Inline version of get_thread_static_data () in
11536                                  * threads.c.
11537                                  */
11538                                 guint32 offset;
11539                                 int idx, static_data_reg, array_reg, dreg;
11540
11541                                 GSHAREDVT_FAILURE (op);
11542
11543                                 MONO_ADD_INS (cfg->cbb, thread_ins);
11544                                 static_data_reg = alloc_ireg (cfg);
11545                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, static_data_reg, thread_ins->dreg, MONO_STRUCT_OFFSET (MonoInternalThread, static_data));
11546
11547                                 if (cfg->compile_aot) {
11548                                         int offset_reg, offset2_reg, idx_reg;
11549
11550                                         /* For TLS variables, this will return the TLS offset */
11551                                         EMIT_NEW_SFLDACONST (cfg, ins, field);
11552                                         offset_reg = ins->dreg;
11553                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset_reg, offset_reg, 0x7fffffff);
11554                                         idx_reg = alloc_ireg (cfg);
11555                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, idx_reg, offset_reg, 0x3f);
11556                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHL_IMM, idx_reg, idx_reg, sizeof (gpointer) == 8 ? 3 : 2);
11557                                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, static_data_reg, static_data_reg, idx_reg);
11558                                         array_reg = alloc_ireg (cfg);
11559                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, 0);
11560                                         offset2_reg = alloc_ireg (cfg);
11561                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, offset2_reg, offset_reg, 6);
11562                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset2_reg, offset2_reg, 0x1ffffff);
11563                                         dreg = alloc_ireg (cfg);
11564                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, array_reg, offset2_reg);
11565                                 } else {
11566                                         offset = (gsize)addr & 0x7fffffff;
11567                                         idx = offset & 0x3f;
11568
11569                                         array_reg = alloc_ireg (cfg);
11570                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, idx * sizeof (gpointer));
11571                                         dreg = alloc_ireg (cfg);
11572                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_ADD_IMM, dreg, array_reg, ((offset >> 6) & 0x1ffffff));
11573                                 }
11574                         } else if ((cfg->opt & MONO_OPT_SHARED) ||
11575                                         (cfg->compile_aot && is_special_static) ||
11576                                         (context_used && is_special_static)) {
11577                                 MonoInst *iargs [2];
11578
11579                                 g_assert (field->parent);
11580                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11581                                 if (context_used) {
11582                                         iargs [1] = emit_get_rgctx_field (cfg, context_used,
11583                                                 field, MONO_RGCTX_INFO_CLASS_FIELD);
11584                                 } else {
11585                                         EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
11586                                 }
11587                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
11588                         } else if (context_used) {
11589                                 MonoInst *static_data;
11590
11591                                 /*
11592                                 g_print ("sharing static field access in %s.%s.%s - depth %d offset %d\n",
11593                                         method->klass->name_space, method->klass->name, method->name,
11594                                         depth, field->offset);
11595                                 */
11596
11597                                 if (mono_class_needs_cctor_run (klass, method))
11598                                         emit_class_init (cfg, klass);
11599
11600                                 /*
11601                                  * The pointer we're computing here is
11602                                  *
11603                                  *   super_info.static_data + field->offset
11604                                  */
11605                                 static_data = emit_get_rgctx_klass (cfg, context_used,
11606                                         klass, MONO_RGCTX_INFO_STATIC_DATA);
11607
11608                                 if (mini_is_gsharedvt_klass (klass)) {
11609                                         MonoInst *offset_ins;
11610
11611                                         offset_ins = emit_get_rgctx_field (cfg, context_used, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11612                                         /* The value is offset by 1 */
11613                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
11614                                         dreg = alloc_ireg_mp (cfg);
11615                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, static_data->dreg, offset_ins->dreg);
11616                                 } else if (field->offset == 0) {
11617                                         ins = static_data;
11618                                 } else {
11619                                         int addr_reg = mono_alloc_preg (cfg);
11620                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, addr_reg, static_data->dreg, field->offset);
11621                                 }
11622                                 } else if ((cfg->opt & MONO_OPT_SHARED) || (cfg->compile_aot && addr)) {
11623                                 MonoInst *iargs [2];
11624
11625                                 g_assert (field->parent);
11626                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11627                                 EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
11628                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
11629                         } else {
11630                                 MonoVTable *vtable = NULL;
11631
11632                                 if (!cfg->compile_aot)
11633                                         vtable = mono_class_vtable (cfg->domain, klass);
11634                                 CHECK_TYPELOAD (klass);
11635
11636                                 if (!addr) {
11637                                         if (mini_field_access_needs_cctor_run (cfg, method, klass, vtable)) {
11638                                                 if (!(g_slist_find (class_inits, klass))) {
11639                                                         emit_class_init (cfg, klass);
11640                                                         if (cfg->verbose_level > 2)
11641                                                                 printf ("class %s.%s needs init call for %s\n", klass->name_space, klass->name, mono_field_get_name (field));
11642                                                         class_inits = g_slist_prepend (class_inits, klass);
11643                                                 }
11644                                         } else {
11645                                                 if (cfg->run_cctors) {
11646                                                         MonoException *ex;
11647                                                         /* This makes so that inline cannot trigger */
11648                                                         /* .cctors: too many apps depend on them */
11649                                                         /* running with a specific order... */
11650                                                         g_assert (vtable);
11651                                                         if (! vtable->initialized)
11652                                                                 INLINE_FAILURE ("class init");
11653                                                         ex = mono_runtime_class_init_full (vtable, FALSE);
11654                                                         if (ex) {
11655                                                                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
11656                                                                 mono_error_set_exception_instance (&cfg->error, ex);
11657                                                                 g_assert_not_reached ();
11658                                                                 goto exception_exit;
11659                                                         }
11660                                                 }
11661                                         }
11662                                         if (cfg->compile_aot)
11663                                                 EMIT_NEW_SFLDACONST (cfg, ins, field);
11664                                         else {
11665                                                 g_assert (vtable);
11666                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
11667                                                 g_assert (addr);
11668                                                 EMIT_NEW_PCONST (cfg, ins, addr);
11669                                         }
11670                                 } else {
11671                                         MonoInst *iargs [1];
11672                                         EMIT_NEW_ICONST (cfg, iargs [0], GPOINTER_TO_UINT (addr));
11673                                         ins = mono_emit_jit_icall (cfg, mono_get_special_static_data, iargs);
11674                                 }
11675                         }
11676
11677                         /* Generate IR to do the actual load/store operation */
11678
11679                         if ((op == CEE_STFLD || op == CEE_STSFLD) && (ins_flag & MONO_INST_VOLATILE)) {
11680                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
11681                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
11682                         }
11683
11684                         if (op == CEE_LDSFLDA) {
11685                                 ins->klass = mono_class_from_mono_type (ftype);
11686                                 ins->type = STACK_PTR;
11687                                 *sp++ = ins;
11688                         } else if (op == CEE_STSFLD) {
11689                                 MonoInst *store;
11690
11691                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, ftype, ins->dreg, 0, store_val->dreg);
11692                                 store->flags |= ins_flag;
11693                         } else {
11694                                 gboolean is_const = FALSE;
11695                                 MonoVTable *vtable = NULL;
11696                                 gpointer addr = NULL;
11697
11698                                 if (!context_used) {
11699                                         vtable = mono_class_vtable (cfg->domain, klass);
11700                                         CHECK_TYPELOAD (klass);
11701                                 }
11702                                 if ((ftype->attrs & FIELD_ATTRIBUTE_INIT_ONLY) && (((addr = mono_aot_readonly_field_override (field)) != NULL) ||
11703                                                 (!context_used && !((cfg->opt & MONO_OPT_SHARED) || cfg->compile_aot) && vtable->initialized))) {
11704                                         int ro_type = ftype->type;
11705                                         if (!addr)
11706                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
11707                                         if (ro_type == MONO_TYPE_VALUETYPE && ftype->data.klass->enumtype) {
11708                                                 ro_type = mono_class_enum_basetype (ftype->data.klass)->type;
11709                                         }
11710
11711                                         GSHAREDVT_FAILURE (op);
11712
11713                                         /* printf ("RO-FIELD %s.%s:%s\n", klass->name_space, klass->name, mono_field_get_name (field));*/
11714                                         is_const = TRUE;
11715                                         switch (ro_type) {
11716                                         case MONO_TYPE_BOOLEAN:
11717                                         case MONO_TYPE_U1:
11718                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint8 *)addr));
11719                                                 sp++;
11720                                                 break;
11721                                         case MONO_TYPE_I1:
11722                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint8 *)addr));
11723                                                 sp++;
11724                                                 break;                                          
11725                                         case MONO_TYPE_CHAR:
11726                                         case MONO_TYPE_U2:
11727                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint16 *)addr));
11728                                                 sp++;
11729                                                 break;
11730                                         case MONO_TYPE_I2:
11731                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint16 *)addr));
11732                                                 sp++;
11733                                                 break;
11734                                                 break;
11735                                         case MONO_TYPE_I4:
11736                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint32 *)addr));
11737                                                 sp++;
11738                                                 break;                                          
11739                                         case MONO_TYPE_U4:
11740                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint32 *)addr));
11741                                                 sp++;
11742                                                 break;
11743                                         case MONO_TYPE_I:
11744                                         case MONO_TYPE_U:
11745                                         case MONO_TYPE_PTR:
11746                                         case MONO_TYPE_FNPTR:
11747                                                 EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
11748                                                 type_to_eval_stack_type ((cfg), field->type, *sp);
11749                                                 sp++;
11750                                                 break;
11751                                         case MONO_TYPE_STRING:
11752                                         case MONO_TYPE_OBJECT:
11753                                         case MONO_TYPE_CLASS:
11754                                         case MONO_TYPE_SZARRAY:
11755                                         case MONO_TYPE_ARRAY:
11756                                                 if (!mono_gc_is_moving ()) {
11757                                                         EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
11758                                                         type_to_eval_stack_type ((cfg), field->type, *sp);
11759                                                         sp++;
11760                                                 } else {
11761                                                         is_const = FALSE;
11762                                                 }
11763                                                 break;
11764                                         case MONO_TYPE_I8:
11765                                         case MONO_TYPE_U8:
11766                                                 EMIT_NEW_I8CONST (cfg, *sp, *((gint64 *)addr));
11767                                                 sp++;
11768                                                 break;
11769                                         case MONO_TYPE_R4:
11770                                         case MONO_TYPE_R8:
11771                                         case MONO_TYPE_VALUETYPE:
11772                                         default:
11773                                                 is_const = FALSE;
11774                                                 break;
11775                                         }
11776                                 }
11777
11778                                 if (!is_const) {
11779                                         MonoInst *load;
11780
11781                                         CHECK_STACK_OVF (1);
11782
11783                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, ins->dreg, 0);
11784                                         load->flags |= ins_flag;
11785                                         ins_flag = 0;
11786                                         *sp++ = load;
11787                                 }
11788                         }
11789
11790                         if ((op == CEE_LDFLD || op == CEE_LDSFLD) && (ins_flag & MONO_INST_VOLATILE)) {
11791                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
11792                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
11793                         }
11794
11795                         ins_flag = 0;
11796                         ip += 5;
11797                         break;
11798                 }
11799                 case CEE_STOBJ:
11800                         CHECK_STACK (2);
11801                         sp -= 2;
11802                         CHECK_OPSIZE (5);
11803                         token = read32 (ip + 1);
11804                         klass = mini_get_class (method, token, generic_context);
11805                         CHECK_TYPELOAD (klass);
11806                         if (ins_flag & MONO_INST_VOLATILE) {
11807                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
11808                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
11809                         }
11810                         /* FIXME: should check item at sp [1] is compatible with the type of the store. */
11811                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0, sp [1]->dreg);
11812                         ins->flags |= ins_flag;
11813                         if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER &&
11814                                         generic_class_is_reference_type (cfg, klass)) {
11815                                 /* insert call to write barrier */
11816                                 emit_write_barrier (cfg, sp [0], sp [1]);
11817                         }
11818                         ins_flag = 0;
11819                         ip += 5;
11820                         inline_costs += 1;
11821                         break;
11822
11823                         /*
11824                          * Array opcodes
11825                          */
11826                 case CEE_NEWARR: {
11827                         MonoInst *len_ins;
11828                         const char *data_ptr;
11829                         int data_size = 0;
11830                         guint32 field_token;
11831
11832                         CHECK_STACK (1);
11833                         --sp;
11834
11835                         CHECK_OPSIZE (5);
11836                         token = read32 (ip + 1);
11837
11838                         klass = mini_get_class (method, token, generic_context);
11839                         CHECK_TYPELOAD (klass);
11840
11841                         context_used = mini_class_check_context_used (cfg, klass);
11842
11843                         if (sp [0]->type == STACK_I8 || (SIZEOF_VOID_P == 8 && sp [0]->type == STACK_PTR)) {
11844                                 MONO_INST_NEW (cfg, ins, OP_LCONV_TO_OVF_U4);
11845                                 ins->sreg1 = sp [0]->dreg;
11846                                 ins->type = STACK_I4;
11847                                 ins->dreg = alloc_ireg (cfg);
11848                                 MONO_ADD_INS (cfg->cbb, ins);
11849                                 *sp = mono_decompose_opcode (cfg, ins);
11850                         }
11851
11852                         if (context_used) {
11853                                 MonoInst *args [3];
11854                                 MonoClass *array_class = mono_array_class_get (klass, 1);
11855                                 MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (array_class);
11856
11857                                 /* FIXME: Use OP_NEWARR and decompose later to help abcrem */
11858
11859                                 /* vtable */
11860                                 args [0] = emit_get_rgctx_klass (cfg, context_used,
11861                                         array_class, MONO_RGCTX_INFO_VTABLE);
11862                                 /* array len */
11863                                 args [1] = sp [0];
11864
11865                                 if (managed_alloc)
11866                                         ins = mono_emit_method_call (cfg, managed_alloc, args, NULL);
11867                                 else
11868                                         ins = mono_emit_jit_icall (cfg, ves_icall_array_new_specific, args);
11869                         } else {
11870                                 if (cfg->opt & MONO_OPT_SHARED) {
11871                                         /* Decompose now to avoid problems with references to the domainvar */
11872                                         MonoInst *iargs [3];
11873
11874                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11875                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
11876                                         iargs [2] = sp [0];
11877
11878                                         ins = mono_emit_jit_icall (cfg, mono_array_new, iargs);
11879                                 } else {
11880                                         /* Decompose later since it is needed by abcrem */
11881                                         MonoClass *array_type = mono_array_class_get (klass, 1);
11882                                         mono_class_vtable (cfg->domain, array_type);
11883                                         CHECK_TYPELOAD (array_type);
11884
11885                                         MONO_INST_NEW (cfg, ins, OP_NEWARR);
11886                                         ins->dreg = alloc_ireg_ref (cfg);
11887                                         ins->sreg1 = sp [0]->dreg;
11888                                         ins->inst_newa_class = klass;
11889                                         ins->type = STACK_OBJ;
11890                                         ins->klass = array_type;
11891                                         MONO_ADD_INS (cfg->cbb, ins);
11892                                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
11893                                         cfg->cbb->has_array_access = TRUE;
11894
11895                                         /* Needed so mono_emit_load_get_addr () gets called */
11896                                         mono_get_got_var (cfg);
11897                                 }
11898                         }
11899
11900                         len_ins = sp [0];
11901                         ip += 5;
11902                         *sp++ = ins;
11903                         inline_costs += 1;
11904
11905                         /* 
11906                          * we inline/optimize the initialization sequence if possible.
11907                          * we should also allocate the array as not cleared, since we spend as much time clearing to 0 as initializing
11908                          * for small sizes open code the memcpy
11909                          * ensure the rva field is big enough
11910                          */
11911                         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))) {
11912                                 MonoMethod *memcpy_method = get_memcpy_method ();
11913                                 MonoInst *iargs [3];
11914                                 int add_reg = alloc_ireg_mp (cfg);
11915
11916                                 EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, add_reg, ins->dreg, MONO_STRUCT_OFFSET (MonoArray, vector));
11917                                 if (cfg->compile_aot) {
11918                                         EMIT_NEW_AOTCONST_TOKEN (cfg, iargs [1], MONO_PATCH_INFO_RVA, method->klass->image, GPOINTER_TO_UINT(field_token), STACK_PTR, NULL);
11919                                 } else {
11920                                         EMIT_NEW_PCONST (cfg, iargs [1], (char*)data_ptr);
11921                                 }
11922                                 EMIT_NEW_ICONST (cfg, iargs [2], data_size);
11923                                 mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
11924                                 ip += 11;
11925                         }
11926
11927                         break;
11928                 }
11929                 case CEE_LDLEN:
11930                         CHECK_STACK (1);
11931                         --sp;
11932                         if (sp [0]->type != STACK_OBJ)
11933                                 UNVERIFIED;
11934
11935                         MONO_INST_NEW (cfg, ins, OP_LDLEN);
11936                         ins->dreg = alloc_preg (cfg);
11937                         ins->sreg1 = sp [0]->dreg;
11938                         ins->type = STACK_I4;
11939                         /* This flag will be inherited by the decomposition */
11940                         ins->flags |= MONO_INST_FAULT;
11941                         MONO_ADD_INS (cfg->cbb, ins);
11942                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
11943                         cfg->cbb->has_array_access = TRUE;
11944                         ip ++;
11945                         *sp++ = ins;
11946                         break;
11947                 case CEE_LDELEMA:
11948                         CHECK_STACK (2);
11949                         sp -= 2;
11950                         CHECK_OPSIZE (5);
11951                         if (sp [0]->type != STACK_OBJ)
11952                                 UNVERIFIED;
11953
11954                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11955
11956                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
11957                         CHECK_TYPELOAD (klass);
11958                         /* we need to make sure that this array is exactly the type it needs
11959                          * to be for correctness. the wrappers are lax with their usage
11960                          * so we need to ignore them here
11961                          */
11962                         if (!klass->valuetype && method->wrapper_type == MONO_WRAPPER_NONE && !readonly) {
11963                                 MonoClass *array_class = mono_array_class_get (klass, 1);
11964                                 mini_emit_check_array_type (cfg, sp [0], array_class);
11965                                 CHECK_TYPELOAD (array_class);
11966                         }
11967
11968                         readonly = FALSE;
11969                         ins = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11970                         *sp++ = ins;
11971                         ip += 5;
11972                         break;
11973                 case CEE_LDELEM:
11974                 case CEE_LDELEM_I1:
11975                 case CEE_LDELEM_U1:
11976                 case CEE_LDELEM_I2:
11977                 case CEE_LDELEM_U2:
11978                 case CEE_LDELEM_I4:
11979                 case CEE_LDELEM_U4:
11980                 case CEE_LDELEM_I8:
11981                 case CEE_LDELEM_I:
11982                 case CEE_LDELEM_R4:
11983                 case CEE_LDELEM_R8:
11984                 case CEE_LDELEM_REF: {
11985                         MonoInst *addr;
11986
11987                         CHECK_STACK (2);
11988                         sp -= 2;
11989
11990                         if (*ip == CEE_LDELEM) {
11991                                 CHECK_OPSIZE (5);
11992                                 token = read32 (ip + 1);
11993                                 klass = mini_get_class (method, token, generic_context);
11994                                 CHECK_TYPELOAD (klass);
11995                                 mono_class_init (klass);
11996                         }
11997                         else
11998                                 klass = array_access_to_klass (*ip);
11999
12000                         if (sp [0]->type != STACK_OBJ)
12001                                 UNVERIFIED;
12002
12003                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
12004
12005                         if (mini_is_gsharedvt_variable_klass (klass)) {
12006                                 // FIXME-VT: OP_ICONST optimization
12007                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
12008                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
12009                                 ins->opcode = OP_LOADV_MEMBASE;
12010                         } else if (sp [1]->opcode == OP_ICONST) {
12011                                 int array_reg = sp [0]->dreg;
12012                                 int index_reg = sp [1]->dreg;
12013                                 int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + MONO_STRUCT_OFFSET (MonoArray, vector);
12014
12015                                 if (SIZEOF_REGISTER == 8 && COMPILE_LLVM (cfg))
12016                                         MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, index_reg, index_reg);
12017
12018                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
12019                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset);
12020                         } else {
12021                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
12022                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
12023                         }
12024                         *sp++ = ins;
12025                         if (*ip == CEE_LDELEM)
12026                                 ip += 5;
12027                         else
12028                                 ++ip;
12029                         break;
12030                 }
12031                 case CEE_STELEM_I:
12032                 case CEE_STELEM_I1:
12033                 case CEE_STELEM_I2:
12034                 case CEE_STELEM_I4:
12035                 case CEE_STELEM_I8:
12036                 case CEE_STELEM_R4:
12037                 case CEE_STELEM_R8:
12038                 case CEE_STELEM_REF:
12039                 case CEE_STELEM: {
12040                         CHECK_STACK (3);
12041                         sp -= 3;
12042
12043                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
12044
12045                         if (*ip == CEE_STELEM) {
12046                                 CHECK_OPSIZE (5);
12047                                 token = read32 (ip + 1);
12048                                 klass = mini_get_class (method, token, generic_context);
12049                                 CHECK_TYPELOAD (klass);
12050                                 mono_class_init (klass);
12051                         }
12052                         else
12053                                 klass = array_access_to_klass (*ip);
12054
12055                         if (sp [0]->type != STACK_OBJ)
12056                                 UNVERIFIED;
12057
12058                         emit_array_store (cfg, klass, sp, TRUE);
12059
12060                         if (*ip == CEE_STELEM)
12061                                 ip += 5;
12062                         else
12063                                 ++ip;
12064                         inline_costs += 1;
12065                         break;
12066                 }
12067                 case CEE_CKFINITE: {
12068                         CHECK_STACK (1);
12069                         --sp;
12070
12071                         if (cfg->llvm_only) {
12072                                 MonoInst *iargs [1];
12073
12074                                 iargs [0] = sp [0];
12075                                 *sp++ = mono_emit_jit_icall (cfg, mono_ckfinite, iargs);
12076                         } else  {
12077                                 MONO_INST_NEW (cfg, ins, OP_CKFINITE);
12078                                 ins->sreg1 = sp [0]->dreg;
12079                                 ins->dreg = alloc_freg (cfg);
12080                                 ins->type = STACK_R8;
12081                                 MONO_ADD_INS (cfg->cbb, ins);
12082
12083                                 *sp++ = mono_decompose_opcode (cfg, ins);
12084                         }
12085
12086                         ++ip;
12087                         break;
12088                 }
12089                 case CEE_REFANYVAL: {
12090                         MonoInst *src_var, *src;
12091
12092                         int klass_reg = alloc_preg (cfg);
12093                         int dreg = alloc_preg (cfg);
12094
12095                         GSHAREDVT_FAILURE (*ip);
12096
12097                         CHECK_STACK (1);
12098                         MONO_INST_NEW (cfg, ins, *ip);
12099                         --sp;
12100                         CHECK_OPSIZE (5);
12101                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
12102                         CHECK_TYPELOAD (klass);
12103
12104                         context_used = mini_class_check_context_used (cfg, klass);
12105
12106                         // FIXME:
12107                         src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
12108                         if (!src_var)
12109                                 src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
12110                         EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
12111                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass));
12112
12113                         if (context_used) {
12114                                 MonoInst *klass_ins;
12115
12116                                 klass_ins = emit_get_rgctx_klass (cfg, context_used,
12117                                                 klass, MONO_RGCTX_INFO_KLASS);
12118
12119                                 // FIXME:
12120                                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_ins->dreg);
12121                                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
12122                         } else {
12123                                 mini_emit_class_check (cfg, klass_reg, klass);
12124                         }
12125                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, value));
12126                         ins->type = STACK_MP;
12127                         ins->klass = klass;
12128                         *sp++ = ins;
12129                         ip += 5;
12130                         break;
12131                 }
12132                 case CEE_MKREFANY: {
12133                         MonoInst *loc, *addr;
12134
12135                         GSHAREDVT_FAILURE (*ip);
12136
12137                         CHECK_STACK (1);
12138                         MONO_INST_NEW (cfg, ins, *ip);
12139                         --sp;
12140                         CHECK_OPSIZE (5);
12141                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
12142                         CHECK_TYPELOAD (klass);
12143
12144                         context_used = mini_class_check_context_used (cfg, klass);
12145
12146                         loc = mono_compile_create_var (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL);
12147                         EMIT_NEW_TEMPLOADA (cfg, addr, loc->inst_c0);
12148
12149                         if (context_used) {
12150                                 MonoInst *const_ins;
12151                                 int type_reg = alloc_preg (cfg);
12152
12153                                 const_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
12154                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), const_ins->dreg);
12155                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_ins->dreg, MONO_STRUCT_OFFSET (MonoClass, byval_arg));
12156                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
12157                         } else if (cfg->compile_aot) {
12158                                 int const_reg = alloc_preg (cfg);
12159                                 int type_reg = alloc_preg (cfg);
12160
12161                                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
12162                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), const_reg);
12163                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_reg, MONO_STRUCT_OFFSET (MonoClass, byval_arg));
12164                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
12165                         } else {
12166                                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), &klass->byval_arg);
12167                                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), klass);
12168                         }
12169                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, value), sp [0]->dreg);
12170
12171                         EMIT_NEW_TEMPLOAD (cfg, ins, loc->inst_c0);
12172                         ins->type = STACK_VTYPE;
12173                         ins->klass = mono_defaults.typed_reference_class;
12174                         *sp++ = ins;
12175                         ip += 5;
12176                         break;
12177                 }
12178                 case CEE_LDTOKEN: {
12179                         gpointer handle;
12180                         MonoClass *handle_class;
12181
12182                         CHECK_STACK_OVF (1);
12183
12184                         CHECK_OPSIZE (5);
12185                         n = read32 (ip + 1);
12186
12187                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD ||
12188                                         method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
12189                                 handle = mono_method_get_wrapper_data (method, n);
12190                                 handle_class = (MonoClass *)mono_method_get_wrapper_data (method, n + 1);
12191                                 if (handle_class == mono_defaults.typehandle_class)
12192                                         handle = &((MonoClass*)handle)->byval_arg;
12193                         }
12194                         else {
12195                                 handle = mono_ldtoken_checked (image, n, &handle_class, generic_context, &cfg->error);
12196                                 CHECK_CFG_ERROR;
12197                         }
12198                         if (!handle)
12199                                 LOAD_ERROR;
12200                         mono_class_init (handle_class);
12201                         if (cfg->gshared) {
12202                                 if (mono_metadata_token_table (n) == MONO_TABLE_TYPEDEF ||
12203                                                 mono_metadata_token_table (n) == MONO_TABLE_TYPEREF) {
12204                                         /* This case handles ldtoken
12205                                            of an open type, like for
12206                                            typeof(Gen<>). */
12207                                         context_used = 0;
12208                                 } else if (handle_class == mono_defaults.typehandle_class) {
12209                                         context_used = mini_class_check_context_used (cfg, mono_class_from_mono_type ((MonoType *)handle));
12210                                 } else if (handle_class == mono_defaults.fieldhandle_class)
12211                                         context_used = mini_class_check_context_used (cfg, ((MonoClassField*)handle)->parent);
12212                                 else if (handle_class == mono_defaults.methodhandle_class)
12213                                         context_used = mini_method_check_context_used (cfg, (MonoMethod *)handle);
12214                                 else
12215                                         g_assert_not_reached ();
12216                         }
12217
12218                         if ((cfg->opt & MONO_OPT_SHARED) &&
12219                                         method->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD &&
12220                                         method->wrapper_type != MONO_WRAPPER_SYNCHRONIZED) {
12221                                 MonoInst *addr, *vtvar, *iargs [3];
12222                                 int method_context_used;
12223
12224                                 method_context_used = mini_method_check_context_used (cfg, method);
12225
12226                                 vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL); 
12227
12228                                 EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
12229                                 EMIT_NEW_ICONST (cfg, iargs [1], n);
12230                                 if (method_context_used) {
12231                                         iargs [2] = emit_get_rgctx_method (cfg, method_context_used,
12232                                                 method, MONO_RGCTX_INFO_METHOD);
12233                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper_generic_shared, iargs);
12234                                 } else {
12235                                         EMIT_NEW_PCONST (cfg, iargs [2], generic_context);
12236                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper, iargs);
12237                                 }
12238                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
12239
12240                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
12241
12242                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
12243                         } else {
12244                                 if ((ip + 5 < end) && ip_in_bb (cfg, cfg->cbb, ip + 5) && 
12245                                         ((ip [5] == CEE_CALL) || (ip [5] == CEE_CALLVIRT)) && 
12246                                         (cmethod = mini_get_method (cfg, method, read32 (ip + 6), NULL, generic_context)) &&
12247                                         (cmethod->klass == mono_defaults.systemtype_class) &&
12248                                         (strcmp (cmethod->name, "GetTypeFromHandle") == 0)) {
12249                                         MonoClass *tclass = mono_class_from_mono_type ((MonoType *)handle);
12250
12251                                         mono_class_init (tclass);
12252                                         if (context_used) {
12253                                                 ins = emit_get_rgctx_klass (cfg, context_used,
12254                                                         tclass, MONO_RGCTX_INFO_REFLECTION_TYPE);
12255                                         } else if (cfg->compile_aot) {
12256                                                 if (method->wrapper_type) {
12257                                                         mono_error_init (&error); //got to do it since there are multiple conditionals below
12258                                                         if (mono_class_get_checked (tclass->image, tclass->type_token, &error) == tclass && !generic_context) {
12259                                                                 /* Special case for static synchronized wrappers */
12260                                                                 EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, tclass->image, tclass->type_token, generic_context);
12261                                                         } else {
12262                                                                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
12263                                                                 /* FIXME: n is not a normal token */
12264                                                                 DISABLE_AOT (cfg);
12265                                                                 EMIT_NEW_PCONST (cfg, ins, NULL);
12266                                                         }
12267                                                 } else {
12268                                                         EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, image, n, generic_context);
12269                                                 }
12270                                         } else {
12271                                                 MonoError error;
12272                                                 MonoReflectionType *rt = mono_type_get_object_checked (cfg->domain, (MonoType *)handle, &error);
12273                                                 mono_error_raise_exception (&error); /* FIXME don't raise here */
12274
12275                                                 EMIT_NEW_PCONST (cfg, ins, rt);
12276                                         }
12277                                         ins->type = STACK_OBJ;
12278                                         ins->klass = cmethod->klass;
12279                                         ip += 5;
12280                                 } else {
12281                                         MonoInst *addr, *vtvar;
12282
12283                                         vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL);
12284
12285                                         if (context_used) {
12286                                                 if (handle_class == mono_defaults.typehandle_class) {
12287                                                         ins = emit_get_rgctx_klass (cfg, context_used,
12288                                                                         mono_class_from_mono_type ((MonoType *)handle),
12289                                                                         MONO_RGCTX_INFO_TYPE);
12290                                                 } else if (handle_class == mono_defaults.methodhandle_class) {
12291                                                         ins = emit_get_rgctx_method (cfg, context_used,
12292                                                                         (MonoMethod *)handle, MONO_RGCTX_INFO_METHOD);
12293                                                 } else if (handle_class == mono_defaults.fieldhandle_class) {
12294                                                         ins = emit_get_rgctx_field (cfg, context_used,
12295                                                                         (MonoClassField *)handle, MONO_RGCTX_INFO_CLASS_FIELD);
12296                                                 } else {
12297                                                         g_assert_not_reached ();
12298                                                 }
12299                                         } else if (cfg->compile_aot) {
12300                                                 EMIT_NEW_LDTOKENCONST (cfg, ins, image, n, generic_context);
12301                                         } else {
12302                                                 EMIT_NEW_PCONST (cfg, ins, handle);
12303                                         }
12304                                         EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
12305                                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
12306                                         EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
12307                                 }
12308                         }
12309
12310                         *sp++ = ins;
12311                         ip += 5;
12312                         break;
12313                 }
12314                 case CEE_THROW:
12315                         CHECK_STACK (1);
12316                         MONO_INST_NEW (cfg, ins, OP_THROW);
12317                         --sp;
12318                         ins->sreg1 = sp [0]->dreg;
12319                         ip++;
12320                         cfg->cbb->out_of_line = TRUE;
12321                         MONO_ADD_INS (cfg->cbb, ins);
12322                         MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
12323                         MONO_ADD_INS (cfg->cbb, ins);
12324                         sp = stack_start;
12325                         
12326                         link_bblock (cfg, cfg->cbb, end_bblock);
12327                         start_new_bblock = 1;
12328                         /* This can complicate code generation for llvm since the return value might not be defined */
12329                         if (COMPILE_LLVM (cfg))
12330                                 INLINE_FAILURE ("throw");
12331                         break;
12332                 case CEE_ENDFINALLY:
12333                         /* mono_save_seq_point_info () depends on this */
12334                         if (sp != stack_start)
12335                                 emit_seq_point (cfg, method, ip, FALSE, FALSE);
12336                         MONO_INST_NEW (cfg, ins, OP_ENDFINALLY);
12337                         MONO_ADD_INS (cfg->cbb, ins);
12338                         ip++;
12339                         start_new_bblock = 1;
12340
12341                         /*
12342                          * Control will leave the method so empty the stack, otherwise
12343                          * the next basic block will start with a nonempty stack.
12344                          */
12345                         while (sp != stack_start) {
12346                                 sp--;
12347                         }
12348                         break;
12349                 case CEE_LEAVE:
12350                 case CEE_LEAVE_S: {
12351                         GList *handlers;
12352
12353                         if (*ip == CEE_LEAVE) {
12354                                 CHECK_OPSIZE (5);
12355                                 target = ip + 5 + (gint32)read32(ip + 1);
12356                         } else {
12357                                 CHECK_OPSIZE (2);
12358                                 target = ip + 2 + (signed char)(ip [1]);
12359                         }
12360
12361                         /* empty the stack */
12362                         while (sp != stack_start) {
12363                                 sp--;
12364                         }
12365
12366                         /* 
12367                          * If this leave statement is in a catch block, check for a
12368                          * pending exception, and rethrow it if necessary.
12369                          * We avoid doing this in runtime invoke wrappers, since those are called
12370                          * by native code which excepts the wrapper to catch all exceptions.
12371                          */
12372                         for (i = 0; i < header->num_clauses; ++i) {
12373                                 MonoExceptionClause *clause = &header->clauses [i];
12374
12375                                 /* 
12376                                  * Use <= in the final comparison to handle clauses with multiple
12377                                  * leave statements, like in bug #78024.
12378                                  * The ordering of the exception clauses guarantees that we find the
12379                                  * innermost clause.
12380                                  */
12381                                 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) {
12382                                         MonoInst *exc_ins;
12383                                         MonoBasicBlock *dont_throw;
12384
12385                                         /*
12386                                           MonoInst *load;
12387
12388                                           NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, clause->handler_offset)->inst_c0);
12389                                         */
12390
12391                                         exc_ins = mono_emit_jit_icall (cfg, mono_thread_get_undeniable_exception, NULL);
12392
12393                                         NEW_BBLOCK (cfg, dont_throw);
12394
12395                                         /*
12396                                          * Currently, we always rethrow the abort exception, despite the 
12397                                          * fact that this is not correct. See thread6.cs for an example. 
12398                                          * But propagating the abort exception is more important than 
12399                                          * getting the sematics right.
12400                                          */
12401                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, exc_ins->dreg, 0);
12402                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, dont_throw);
12403                                         MONO_EMIT_NEW_UNALU (cfg, OP_THROW, -1, exc_ins->dreg);
12404
12405                                         MONO_START_BB (cfg, dont_throw);
12406                                 }
12407                         }
12408
12409 #ifdef ENABLE_LLVM
12410                         cfg->cbb->try_end = (intptr_t)(ip - header->code);
12411 #endif
12412
12413                         if ((handlers = mono_find_final_block (cfg, ip, target, MONO_EXCEPTION_CLAUSE_FINALLY))) {
12414                                 GList *tmp;
12415                                 MonoExceptionClause *clause;
12416
12417                                 for (tmp = handlers; tmp; tmp = tmp->next) {
12418                                         clause = (MonoExceptionClause *)tmp->data;
12419                                         tblock = cfg->cil_offset_to_bb [clause->handler_offset];
12420                                         g_assert (tblock);
12421                                         link_bblock (cfg, cfg->cbb, tblock);
12422                                         MONO_INST_NEW (cfg, ins, OP_CALL_HANDLER);
12423                                         ins->inst_target_bb = tblock;
12424                                         ins->inst_eh_block = clause;
12425                                         MONO_ADD_INS (cfg->cbb, ins);
12426                                         cfg->cbb->has_call_handler = 1;
12427                                         if (COMPILE_LLVM (cfg)) {
12428                                                 MonoBasicBlock *target_bb;
12429
12430                                                 /* 
12431                                                  * Link the finally bblock with the target, since it will
12432                                                  * conceptually branch there.
12433                                                  */
12434                                                 GET_BBLOCK (cfg, tblock, cfg->cil_start + clause->handler_offset + clause->handler_len - 1);
12435                                                 GET_BBLOCK (cfg, target_bb, target);
12436                                                 link_bblock (cfg, tblock, target_bb);
12437                                         }
12438                                 }
12439                                 g_list_free (handlers);
12440                         } 
12441
12442                         MONO_INST_NEW (cfg, ins, OP_BR);
12443                         MONO_ADD_INS (cfg->cbb, ins);
12444                         GET_BBLOCK (cfg, tblock, target);
12445                         link_bblock (cfg, cfg->cbb, tblock);
12446                         ins->inst_target_bb = tblock;
12447
12448                         start_new_bblock = 1;
12449
12450                         if (*ip == CEE_LEAVE)
12451                                 ip += 5;
12452                         else
12453                                 ip += 2;
12454
12455                         break;
12456                 }
12457
12458                         /*
12459                          * Mono specific opcodes
12460                          */
12461                 case MONO_CUSTOM_PREFIX: {
12462
12463                         g_assert (method->wrapper_type != MONO_WRAPPER_NONE);
12464
12465                         CHECK_OPSIZE (2);
12466                         switch (ip [1]) {
12467                         case CEE_MONO_ICALL: {
12468                                 gpointer func;
12469                                 MonoJitICallInfo *info;
12470
12471                                 token = read32 (ip + 2);
12472                                 func = mono_method_get_wrapper_data (method, token);
12473                                 info = mono_find_jit_icall_by_addr (func);
12474                                 if (!info)
12475                                         g_error ("Could not find icall address in wrapper %s", mono_method_full_name (method, 1));
12476                                 g_assert (info);
12477
12478                                 CHECK_STACK (info->sig->param_count);
12479                                 sp -= info->sig->param_count;
12480
12481                                 ins = mono_emit_jit_icall (cfg, info->func, sp);
12482                                 if (!MONO_TYPE_IS_VOID (info->sig->ret))
12483                                         *sp++ = ins;
12484
12485                                 ip += 6;
12486                                 inline_costs += 10 * num_calls++;
12487
12488                                 break;
12489                         }
12490                         case CEE_MONO_LDPTR_CARD_TABLE:
12491                         case CEE_MONO_LDPTR_NURSERY_START:
12492                         case CEE_MONO_LDPTR_NURSERY_BITS:
12493                         case CEE_MONO_LDPTR_INT_REQ_FLAG: {
12494                                 CHECK_STACK_OVF (1);
12495
12496                                 switch (ip [1]) {
12497                                         case CEE_MONO_LDPTR_CARD_TABLE:
12498                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_CARD_TABLE_ADDR, NULL);
12499                                                 break;
12500                                         case CEE_MONO_LDPTR_NURSERY_START:
12501                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_NURSERY_START, NULL);
12502                                                 break;
12503                                         case CEE_MONO_LDPTR_NURSERY_BITS:
12504                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_NURSERY_BITS, NULL);
12505                                                 break;
12506                                         case CEE_MONO_LDPTR_INT_REQ_FLAG:
12507                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG, NULL);
12508                                                 break;
12509                                 }
12510
12511                                 *sp++ = ins;
12512                                 ip += 2;
12513                                 inline_costs += 10 * num_calls++;
12514                                 break;
12515                         }
12516                         case CEE_MONO_LDPTR: {
12517                                 gpointer ptr;
12518
12519                                 CHECK_STACK_OVF (1);
12520                                 CHECK_OPSIZE (6);
12521                                 token = read32 (ip + 2);
12522
12523                                 ptr = mono_method_get_wrapper_data (method, token);
12524                                 EMIT_NEW_PCONST (cfg, ins, ptr);
12525                                 *sp++ = ins;
12526                                 ip += 6;
12527                                 inline_costs += 10 * num_calls++;
12528                                 /* Can't embed random pointers into AOT code */
12529                                 DISABLE_AOT (cfg);
12530                                 break;
12531                         }
12532                         case CEE_MONO_JIT_ICALL_ADDR: {
12533                                 MonoJitICallInfo *callinfo;
12534                                 gpointer ptr;
12535
12536                                 CHECK_STACK_OVF (1);
12537                                 CHECK_OPSIZE (6);
12538                                 token = read32 (ip + 2);
12539
12540                                 ptr = mono_method_get_wrapper_data (method, token);
12541                                 callinfo = mono_find_jit_icall_by_addr (ptr);
12542                                 g_assert (callinfo);
12543                                 EMIT_NEW_JIT_ICALL_ADDRCONST (cfg, ins, (char*)callinfo->name);
12544                                 *sp++ = ins;
12545                                 ip += 6;
12546                                 inline_costs += 10 * num_calls++;
12547                                 break;
12548                         }
12549                         case CEE_MONO_ICALL_ADDR: {
12550                                 MonoMethod *cmethod;
12551                                 gpointer ptr;
12552
12553                                 CHECK_STACK_OVF (1);
12554                                 CHECK_OPSIZE (6);
12555                                 token = read32 (ip + 2);
12556
12557                                 cmethod = (MonoMethod *)mono_method_get_wrapper_data (method, token);
12558
12559                                 if (cfg->compile_aot) {
12560                                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_ICALL_ADDR, cmethod);
12561                                 } else {
12562                                         ptr = mono_lookup_internal_call (cmethod);
12563                                         g_assert (ptr);
12564                                         EMIT_NEW_PCONST (cfg, ins, ptr);
12565                                 }
12566                                 *sp++ = ins;
12567                                 ip += 6;
12568                                 break;
12569                         }
12570                         case CEE_MONO_VTADDR: {
12571                                 MonoInst *src_var, *src;
12572
12573                                 CHECK_STACK (1);
12574                                 --sp;
12575
12576                                 // FIXME:
12577                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
12578                                 EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
12579                                 *sp++ = src;
12580                                 ip += 2;
12581                                 break;
12582                         }
12583                         case CEE_MONO_NEWOBJ: {
12584                                 MonoInst *iargs [2];
12585
12586                                 CHECK_STACK_OVF (1);
12587                                 CHECK_OPSIZE (6);
12588                                 token = read32 (ip + 2);
12589                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12590                                 mono_class_init (klass);
12591                                 NEW_DOMAINCONST (cfg, iargs [0]);
12592                                 MONO_ADD_INS (cfg->cbb, iargs [0]);
12593                                 NEW_CLASSCONST (cfg, iargs [1], klass);
12594                                 MONO_ADD_INS (cfg->cbb, iargs [1]);
12595                                 *sp++ = mono_emit_jit_icall (cfg, ves_icall_object_new, iargs);
12596                                 ip += 6;
12597                                 inline_costs += 10 * num_calls++;
12598                                 break;
12599                         }
12600                         case CEE_MONO_OBJADDR:
12601                                 CHECK_STACK (1);
12602                                 --sp;
12603                                 MONO_INST_NEW (cfg, ins, OP_MOVE);
12604                                 ins->dreg = alloc_ireg_mp (cfg);
12605                                 ins->sreg1 = sp [0]->dreg;
12606                                 ins->type = STACK_MP;
12607                                 MONO_ADD_INS (cfg->cbb, ins);
12608                                 *sp++ = ins;
12609                                 ip += 2;
12610                                 break;
12611                         case CEE_MONO_LDNATIVEOBJ:
12612                                 /*
12613                                  * Similar to LDOBJ, but instead load the unmanaged 
12614                                  * representation of the vtype to the stack.
12615                                  */
12616                                 CHECK_STACK (1);
12617                                 CHECK_OPSIZE (6);
12618                                 --sp;
12619                                 token = read32 (ip + 2);
12620                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12621                                 g_assert (klass->valuetype);
12622                                 mono_class_init (klass);
12623
12624                                 {
12625                                         MonoInst *src, *dest, *temp;
12626
12627                                         src = sp [0];
12628                                         temp = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
12629                                         temp->backend.is_pinvoke = 1;
12630                                         EMIT_NEW_TEMPLOADA (cfg, dest, temp->inst_c0);
12631                                         mini_emit_stobj (cfg, dest, src, klass, TRUE);
12632
12633                                         EMIT_NEW_TEMPLOAD (cfg, dest, temp->inst_c0);
12634                                         dest->type = STACK_VTYPE;
12635                                         dest->klass = klass;
12636
12637                                         *sp ++ = dest;
12638                                         ip += 6;
12639                                 }
12640                                 break;
12641                         case CEE_MONO_RETOBJ: {
12642                                 /*
12643                                  * Same as RET, but return the native representation of a vtype
12644                                  * to the caller.
12645                                  */
12646                                 g_assert (cfg->ret);
12647                                 g_assert (mono_method_signature (method)->pinvoke); 
12648                                 CHECK_STACK (1);
12649                                 --sp;
12650                                 
12651                                 CHECK_OPSIZE (6);
12652                                 token = read32 (ip + 2);    
12653                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12654
12655                                 if (!cfg->vret_addr) {
12656                                         g_assert (cfg->ret_var_is_local);
12657
12658                                         EMIT_NEW_VARLOADA (cfg, ins, cfg->ret, cfg->ret->inst_vtype);
12659                                 } else {
12660                                         EMIT_NEW_RETLOADA (cfg, ins);
12661                                 }
12662                                 mini_emit_stobj (cfg, ins, sp [0], klass, TRUE);
12663                                 
12664                                 if (sp != stack_start)
12665                                         UNVERIFIED;
12666                                 
12667                                 MONO_INST_NEW (cfg, ins, OP_BR);
12668                                 ins->inst_target_bb = end_bblock;
12669                                 MONO_ADD_INS (cfg->cbb, ins);
12670                                 link_bblock (cfg, cfg->cbb, end_bblock);
12671                                 start_new_bblock = 1;
12672                                 ip += 6;
12673                                 break;
12674                         }
12675                         case CEE_MONO_CISINST:
12676                         case CEE_MONO_CCASTCLASS: {
12677                                 int token;
12678                                 CHECK_STACK (1);
12679                                 --sp;
12680                                 CHECK_OPSIZE (6);
12681                                 token = read32 (ip + 2);
12682                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12683                                 if (ip [1] == CEE_MONO_CISINST)
12684                                         ins = handle_cisinst (cfg, klass, sp [0]);
12685                                 else
12686                                         ins = handle_ccastclass (cfg, klass, sp [0]);
12687                                 *sp++ = ins;
12688                                 ip += 6;
12689                                 break;
12690                         }
12691                         case CEE_MONO_SAVE_LMF:
12692                         case CEE_MONO_RESTORE_LMF:
12693                                 ip += 2;
12694                                 break;
12695                         case CEE_MONO_CLASSCONST:
12696                                 CHECK_STACK_OVF (1);
12697                                 CHECK_OPSIZE (6);
12698                                 token = read32 (ip + 2);
12699                                 EMIT_NEW_CLASSCONST (cfg, ins, mono_method_get_wrapper_data (method, token));
12700                                 *sp++ = ins;
12701                                 ip += 6;
12702                                 inline_costs += 10 * num_calls++;
12703                                 break;
12704                         case CEE_MONO_NOT_TAKEN:
12705                                 cfg->cbb->out_of_line = TRUE;
12706                                 ip += 2;
12707                                 break;
12708                         case CEE_MONO_TLS: {
12709                                 MonoTlsKey key;
12710
12711                                 CHECK_STACK_OVF (1);
12712                                 CHECK_OPSIZE (6);
12713                                 key = (MonoTlsKey)read32 (ip + 2);
12714                                 g_assert (key < TLS_KEY_NUM);
12715
12716                                 ins = mono_create_tls_get (cfg, key);
12717                                 if (!ins) {
12718                                         if (cfg->compile_aot) {
12719                                                 DISABLE_AOT (cfg);
12720                                                 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
12721                                                 ins->dreg = alloc_preg (cfg);
12722                                                 ins->type = STACK_PTR;
12723                                         } else {
12724                                                 g_assert_not_reached ();
12725                                         }
12726                                 }
12727                                 ins->type = STACK_PTR;
12728                                 MONO_ADD_INS (cfg->cbb, ins);
12729                                 *sp++ = ins;
12730                                 ip += 6;
12731                                 break;
12732                         }
12733                         case CEE_MONO_DYN_CALL: {
12734                                 MonoCallInst *call;
12735
12736                                 /* It would be easier to call a trampoline, but that would put an
12737                                  * extra frame on the stack, confusing exception handling. So
12738                                  * implement it inline using an opcode for now.
12739                                  */
12740
12741                                 if (!cfg->dyn_call_var) {
12742                                         cfg->dyn_call_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
12743                                         /* prevent it from being register allocated */
12744                                         cfg->dyn_call_var->flags |= MONO_INST_VOLATILE;
12745                                 }
12746
12747                                 /* Has to use a call inst since it local regalloc expects it */
12748                                 MONO_INST_NEW_CALL (cfg, call, OP_DYN_CALL);
12749                                 ins = (MonoInst*)call;
12750                                 sp -= 2;
12751                                 ins->sreg1 = sp [0]->dreg;
12752                                 ins->sreg2 = sp [1]->dreg;
12753                                 MONO_ADD_INS (cfg->cbb, ins);
12754
12755                                 cfg->param_area = MAX (cfg->param_area, cfg->backend->dyn_call_param_area);
12756
12757                                 ip += 2;
12758                                 inline_costs += 10 * num_calls++;
12759
12760                                 break;
12761                         }
12762                         case CEE_MONO_MEMORY_BARRIER: {
12763                                 CHECK_OPSIZE (6);
12764                                 emit_memory_barrier (cfg, (int)read32 (ip + 2));
12765                                 ip += 6;
12766                                 break;
12767                         }
12768                         case CEE_MONO_JIT_ATTACH: {
12769                                 MonoInst *args [16], *domain_ins;
12770                                 MonoInst *ad_ins, *jit_tls_ins;
12771                                 MonoBasicBlock *next_bb = NULL, *call_bb = NULL;
12772
12773                                 cfg->orig_domain_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
12774
12775                                 EMIT_NEW_PCONST (cfg, ins, NULL);
12776                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
12777
12778                                 ad_ins = mono_get_domain_intrinsic (cfg);
12779                                 jit_tls_ins = mono_get_jit_tls_intrinsic (cfg);
12780
12781                                 if (cfg->backend->have_tls_get && ad_ins && jit_tls_ins) {
12782                                         NEW_BBLOCK (cfg, next_bb);
12783                                         NEW_BBLOCK (cfg, call_bb);
12784
12785                                         if (cfg->compile_aot) {
12786                                                 /* AOT code is only used in the root domain */
12787                                                 EMIT_NEW_PCONST (cfg, domain_ins, NULL);
12788                                         } else {
12789                                                 EMIT_NEW_PCONST (cfg, domain_ins, cfg->domain);
12790                                         }
12791                                         MONO_ADD_INS (cfg->cbb, ad_ins);
12792                                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, ad_ins->dreg, domain_ins->dreg);
12793                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, call_bb);
12794
12795                                         MONO_ADD_INS (cfg->cbb, jit_tls_ins);
12796                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, jit_tls_ins->dreg, 0);
12797                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, call_bb);
12798
12799                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, next_bb);
12800                                         MONO_START_BB (cfg, call_bb);
12801                                 }
12802
12803                                 if (cfg->compile_aot) {
12804                                         /* AOT code is only used in the root domain */
12805                                         EMIT_NEW_PCONST (cfg, args [0], NULL);
12806                                 } else {
12807                                         EMIT_NEW_PCONST (cfg, args [0], cfg->domain);
12808                                 }
12809                                 ins = mono_emit_jit_icall (cfg, mono_jit_thread_attach, args);
12810                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
12811
12812                                 if (next_bb)
12813                                         MONO_START_BB (cfg, next_bb);
12814                                 ip += 2;
12815                                 break;
12816                         }
12817                         case CEE_MONO_JIT_DETACH: {
12818                                 MonoInst *args [16];
12819
12820                                 /* Restore the original domain */
12821                                 dreg = alloc_ireg (cfg);
12822                                 EMIT_NEW_UNALU (cfg, args [0], OP_MOVE, dreg, cfg->orig_domain_var->dreg);
12823                                 mono_emit_jit_icall (cfg, mono_jit_set_domain, args);
12824                                 ip += 2;
12825                                 break;
12826                         }
12827                         case CEE_MONO_CALLI_EXTRA_ARG: {
12828                                 MonoInst *addr;
12829                                 MonoMethodSignature *fsig;
12830                                 MonoInst *arg;
12831
12832                                 /*
12833                                  * This is the same as CEE_CALLI, but passes an additional argument
12834                                  * to the called method in llvmonly mode.
12835                                  * This is only used by delegate invoke wrappers to call the
12836                                  * actual delegate method.
12837                                  */
12838                                 g_assert (method->wrapper_type == MONO_WRAPPER_DELEGATE_INVOKE);
12839
12840                                 CHECK_OPSIZE (6);
12841                                 token = read32 (ip + 2);
12842
12843                                 ins = NULL;
12844
12845                                 cmethod = NULL;
12846                                 CHECK_STACK (1);
12847                                 --sp;
12848                                 addr = *sp;
12849                                 fsig = mini_get_signature (method, token, generic_context);
12850
12851                                 if (cfg->llvm_only)
12852                                         cfg->signatures = g_slist_prepend_mempool (cfg->mempool, cfg->signatures, fsig);
12853
12854                                 n = fsig->param_count + fsig->hasthis + 1;
12855
12856                                 CHECK_STACK (n);
12857
12858                                 sp -= n;
12859                                 arg = sp [n - 1];
12860
12861                                 if (cfg->llvm_only) {
12862                                         /*
12863                                          * The lowest bit of 'arg' determines whenever the callee uses the gsharedvt
12864                                          * cconv. This is set by mono_init_delegate ().
12865                                          */
12866                                         if (cfg->gsharedvt && mini_is_gsharedvt_variable_signature (fsig)) {
12867                                                 MonoInst *callee = addr;
12868                                                 MonoInst *call, *localloc_ins;
12869                                                 MonoBasicBlock *is_gsharedvt_bb, *end_bb;
12870                                                 int low_bit_reg = alloc_preg (cfg);
12871
12872                                                 NEW_BBLOCK (cfg, is_gsharedvt_bb);
12873                                                 NEW_BBLOCK (cfg, end_bb);
12874
12875                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, low_bit_reg, arg->dreg, 1);
12876                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_bit_reg, 0);
12877                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, is_gsharedvt_bb);
12878
12879                                                 /* Normal case: callee uses a normal cconv, have to add an out wrapper */
12880                                                 addr = emit_get_rgctx_sig (cfg, context_used,
12881                                                                                                    fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
12882                                                 /*
12883                                                  * ADDR points to a gsharedvt-out wrapper, have to pass <callee, arg> as an extra arg.
12884                                                  */
12885                                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
12886                                                 ins->dreg = alloc_preg (cfg);
12887                                                 ins->inst_imm = 2 * SIZEOF_VOID_P;
12888                                                 MONO_ADD_INS (cfg->cbb, ins);
12889                                                 localloc_ins = ins;
12890                                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
12891                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, 0, callee->dreg);
12892                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, SIZEOF_VOID_P, arg->dreg);
12893
12894                                                 call = emit_extra_arg_calli (cfg, fsig, sp, localloc_ins->dreg, addr);
12895                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
12896
12897                                                 /* Gsharedvt case: callee uses a gsharedvt cconv, no conversion is needed */
12898                                                 MONO_START_BB (cfg, is_gsharedvt_bb);
12899                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PXOR_IMM, arg->dreg, arg->dreg, 1);
12900                                                 ins = emit_extra_arg_calli (cfg, fsig, sp, arg->dreg, callee);
12901                                                 ins->dreg = call->dreg;
12902
12903                                                 MONO_START_BB (cfg, end_bb);
12904                                         } else {
12905                                                 /* Caller uses a normal calling conv */
12906
12907                                                 MonoInst *callee = addr;
12908                                                 MonoInst *call, *localloc_ins;
12909                                                 MonoBasicBlock *is_gsharedvt_bb, *end_bb;
12910                                                 int low_bit_reg = alloc_preg (cfg);
12911
12912                                                 NEW_BBLOCK (cfg, is_gsharedvt_bb);
12913                                                 NEW_BBLOCK (cfg, end_bb);
12914
12915                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, low_bit_reg, arg->dreg, 1);
12916                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_bit_reg, 0);
12917                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, is_gsharedvt_bb);
12918
12919                                                 /* Normal case: callee uses a normal cconv, no conversion is needed */
12920                                                 call = emit_extra_arg_calli (cfg, fsig, sp, arg->dreg, callee);
12921                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
12922                                                 /* Gsharedvt case: callee uses a gsharedvt cconv, have to add an in wrapper */
12923                                                 MONO_START_BB (cfg, is_gsharedvt_bb);
12924                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PXOR_IMM, arg->dreg, arg->dreg, 1);
12925                                                 NEW_AOTCONST (cfg, addr, MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER, fsig);
12926                                                 MONO_ADD_INS (cfg->cbb, addr);
12927                                                 /*
12928                                                  * ADDR points to a gsharedvt-in wrapper, have to pass <callee, arg> as an extra arg.
12929                                                  */
12930                                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
12931                                                 ins->dreg = alloc_preg (cfg);
12932                                                 ins->inst_imm = 2 * SIZEOF_VOID_P;
12933                                                 MONO_ADD_INS (cfg->cbb, ins);
12934                                                 localloc_ins = ins;
12935                                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
12936                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, 0, callee->dreg);
12937                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, SIZEOF_VOID_P, arg->dreg);
12938
12939                                                 ins = emit_extra_arg_calli (cfg, fsig, sp, localloc_ins->dreg, addr);
12940                                                 ins->dreg = call->dreg;
12941                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
12942
12943                                                 MONO_START_BB (cfg, end_bb);
12944                                         }
12945                                 } else {
12946                                         /* Same as CEE_CALLI */
12947                                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) {
12948                                                 /*
12949                                                  * We pass the address to the gsharedvt trampoline in the rgctx reg
12950                                                  */
12951                                                 MonoInst *callee = addr;
12952
12953                                                 addr = emit_get_rgctx_sig (cfg, context_used,
12954                                                                                                    fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
12955                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, callee);
12956                                         } else {
12957                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
12958                                         }
12959                                 }
12960
12961                                 if (!MONO_TYPE_IS_VOID (fsig->ret))
12962                                         *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
12963
12964                                 CHECK_CFG_EXCEPTION;
12965
12966                                 ip += 6;
12967                                 ins_flag = 0;
12968                                 constrained_class = NULL;
12969                                 break;
12970                         }
12971                         default:
12972                                 g_error ("opcode 0x%02x 0x%02x not handled", MONO_CUSTOM_PREFIX, ip [1]);
12973                                 break;
12974                         }
12975                         break;
12976                 }
12977
12978                 case CEE_PREFIX1: {
12979                         CHECK_OPSIZE (2);
12980                         switch (ip [1]) {
12981                         case CEE_ARGLIST: {
12982                                 /* somewhat similar to LDTOKEN */
12983                                 MonoInst *addr, *vtvar;
12984                                 CHECK_STACK_OVF (1);
12985                                 vtvar = mono_compile_create_var (cfg, &mono_defaults.argumenthandle_class->byval_arg, OP_LOCAL); 
12986
12987                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
12988                                 EMIT_NEW_UNALU (cfg, ins, OP_ARGLIST, -1, addr->dreg);
12989
12990                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
12991                                 ins->type = STACK_VTYPE;
12992                                 ins->klass = mono_defaults.argumenthandle_class;
12993                                 *sp++ = ins;
12994                                 ip += 2;
12995                                 break;
12996                         }
12997                         case CEE_CEQ:
12998                         case CEE_CGT:
12999                         case CEE_CGT_UN:
13000                         case CEE_CLT:
13001                         case CEE_CLT_UN: {
13002                                 MonoInst *cmp, *arg1, *arg2;
13003
13004                                 CHECK_STACK (2);
13005                                 sp -= 2;
13006                                 arg1 = sp [0];
13007                                 arg2 = sp [1];
13008
13009                                 /*
13010                                  * The following transforms:
13011                                  *    CEE_CEQ    into OP_CEQ
13012                                  *    CEE_CGT    into OP_CGT
13013                                  *    CEE_CGT_UN into OP_CGT_UN
13014                                  *    CEE_CLT    into OP_CLT
13015                                  *    CEE_CLT_UN into OP_CLT_UN
13016                                  */
13017                                 MONO_INST_NEW (cfg, cmp, (OP_CEQ - CEE_CEQ) + ip [1]);
13018
13019                                 MONO_INST_NEW (cfg, ins, cmp->opcode);
13020                                 cmp->sreg1 = arg1->dreg;
13021                                 cmp->sreg2 = arg2->dreg;
13022                                 type_from_op (cfg, cmp, arg1, arg2);
13023                                 CHECK_TYPE (cmp);
13024                                 add_widen_op (cfg, cmp, &arg1, &arg2);
13025                                 if ((arg1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((arg1->type == STACK_PTR) || (arg1->type == STACK_OBJ) || (arg1->type == STACK_MP))))
13026                                         cmp->opcode = OP_LCOMPARE;
13027                                 else if (arg1->type == STACK_R4)
13028                                         cmp->opcode = OP_RCOMPARE;
13029                                 else if (arg1->type == STACK_R8)
13030                                         cmp->opcode = OP_FCOMPARE;
13031                                 else
13032                                         cmp->opcode = OP_ICOMPARE;
13033                                 MONO_ADD_INS (cfg->cbb, cmp);
13034                                 ins->type = STACK_I4;
13035                                 ins->dreg = alloc_dreg (cfg, (MonoStackType)ins->type);
13036                                 type_from_op (cfg, ins, arg1, arg2);
13037
13038                                 if (cmp->opcode == OP_FCOMPARE || cmp->opcode == OP_RCOMPARE) {
13039                                         /*
13040                                          * The backends expect the fceq opcodes to do the
13041                                          * comparison too.
13042                                          */
13043                                         ins->sreg1 = cmp->sreg1;
13044                                         ins->sreg2 = cmp->sreg2;
13045                                         NULLIFY_INS (cmp);
13046                                 }
13047                                 MONO_ADD_INS (cfg->cbb, ins);
13048                                 *sp++ = ins;
13049                                 ip += 2;
13050                                 break;
13051                         }
13052                         case CEE_LDFTN: {
13053                                 MonoInst *argconst;
13054                                 MonoMethod *cil_method;
13055
13056                                 CHECK_STACK_OVF (1);
13057                                 CHECK_OPSIZE (6);
13058                                 n = read32 (ip + 2);
13059                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
13060                                 CHECK_CFG_ERROR;
13061
13062                                 mono_class_init (cmethod->klass);
13063
13064                                 mono_save_token_info (cfg, image, n, cmethod);
13065
13066                                 context_used = mini_method_check_context_used (cfg, cmethod);
13067
13068                                 cil_method = cmethod;
13069                                 if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_method (method, cmethod))
13070                                         METHOD_ACCESS_FAILURE (method, cil_method);
13071
13072                                 if (mono_security_core_clr_enabled ())
13073                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
13074
13075                                 /* 
13076                                  * Optimize the common case of ldftn+delegate creation
13077                                  */
13078                                 if ((sp > stack_start) && (ip + 6 + 5 < end) && ip_in_bb (cfg, cfg->cbb, ip + 6) && (ip [6] == CEE_NEWOBJ)) {
13079                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
13080                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
13081                                                 MonoInst *target_ins, *handle_ins;
13082                                                 MonoMethod *invoke;
13083                                                 int invoke_context_used;
13084
13085                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
13086                                                 if (!invoke || !mono_method_signature (invoke))
13087                                                         LOAD_ERROR;
13088
13089                                                 invoke_context_used = mini_method_check_context_used (cfg, invoke);
13090
13091                                                 target_ins = sp [-1];
13092
13093                                                 if (mono_security_core_clr_enabled ())
13094                                                         ensure_method_is_allowed_to_call_method (cfg, method, ctor_method);
13095
13096                                                 if (!(cmethod->flags & METHOD_ATTRIBUTE_STATIC)) {
13097                                                         /*LAME IMPL: We must not add a null check for virtual invoke delegates.*/
13098                                                         if (mono_method_signature (invoke)->param_count == mono_method_signature (cmethod)->param_count) {
13099                                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, target_ins->dreg, 0);
13100                                                                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "ArgumentException");
13101                                                         }
13102                                                 }
13103
13104                                                 /* FIXME: SGEN support */
13105                                                 if (invoke_context_used == 0 || cfg->llvm_only) {
13106                                                         ip += 6;
13107                                                         if (cfg->verbose_level > 3)
13108                                                                 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));
13109                                                         if ((handle_ins = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used, FALSE))) {
13110                                                                 sp --;
13111                                                                 *sp = handle_ins;
13112                                                                 CHECK_CFG_EXCEPTION;
13113                                                                 ip += 5;
13114                                                                 sp ++;
13115                                                                 break;
13116                                                         }
13117                                                         ip -= 6;
13118                                                 }
13119                                         }
13120                                 }
13121
13122                                 argconst = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD);
13123                                 ins = mono_emit_jit_icall (cfg, mono_ldftn, &argconst);
13124                                 *sp++ = ins;
13125                                 
13126                                 ip += 6;
13127                                 inline_costs += 10 * num_calls++;
13128                                 break;
13129                         }
13130                         case CEE_LDVIRTFTN: {
13131                                 MonoInst *args [2];
13132
13133                                 CHECK_STACK (1);
13134                                 CHECK_OPSIZE (6);
13135                                 n = read32 (ip + 2);
13136                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
13137                                 CHECK_CFG_ERROR;
13138
13139                                 mono_class_init (cmethod->klass);
13140  
13141                                 context_used = mini_method_check_context_used (cfg, cmethod);
13142
13143                                 if (mono_security_core_clr_enabled ())
13144                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
13145
13146                                 /*
13147                                  * Optimize the common case of ldvirtftn+delegate creation
13148                                  */
13149                                 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)) {
13150                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
13151                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
13152                                                 MonoInst *target_ins, *handle_ins;
13153                                                 MonoMethod *invoke;
13154                                                 int invoke_context_used;
13155                                                 gboolean is_virtual = cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL;
13156
13157                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
13158                                                 if (!invoke || !mono_method_signature (invoke))
13159                                                         LOAD_ERROR;
13160
13161                                                 invoke_context_used = mini_method_check_context_used (cfg, invoke);
13162
13163                                                 target_ins = sp [-1];
13164
13165                                                 if (mono_security_core_clr_enabled ())
13166                                                         ensure_method_is_allowed_to_call_method (cfg, method, ctor_method);
13167
13168                                                 /* FIXME: SGEN support */
13169                                                 if (invoke_context_used == 0 || cfg->llvm_only) {
13170                                                         ip += 6;
13171                                                         if (cfg->verbose_level > 3)
13172                                                                 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));
13173                                                         if ((handle_ins = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used, is_virtual))) {
13174                                                                 sp -= 2;
13175                                                                 *sp = handle_ins;
13176                                                                 CHECK_CFG_EXCEPTION;
13177                                                                 ip += 5;
13178                                                                 sp ++;
13179                                                                 break;
13180                                                         }
13181                                                         ip -= 6;
13182                                                 }
13183                                         }
13184                                 }
13185
13186                                 --sp;
13187                                 args [0] = *sp;
13188
13189                                 args [1] = emit_get_rgctx_method (cfg, context_used,
13190                                                                                                   cmethod, MONO_RGCTX_INFO_METHOD);
13191
13192                                 if (context_used)
13193                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn_gshared, args);
13194                                 else
13195                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn, args);
13196
13197                                 ip += 6;
13198                                 inline_costs += 10 * num_calls++;
13199                                 break;
13200                         }
13201                         case CEE_LDARG:
13202                                 CHECK_STACK_OVF (1);
13203                                 CHECK_OPSIZE (4);
13204                                 n = read16 (ip + 2);
13205                                 CHECK_ARG (n);
13206                                 EMIT_NEW_ARGLOAD (cfg, ins, n);
13207                                 *sp++ = ins;
13208                                 ip += 4;
13209                                 break;
13210                         case CEE_LDARGA:
13211                                 CHECK_STACK_OVF (1);
13212                                 CHECK_OPSIZE (4);
13213                                 n = read16 (ip + 2);
13214                                 CHECK_ARG (n);
13215                                 NEW_ARGLOADA (cfg, ins, n);
13216                                 MONO_ADD_INS (cfg->cbb, ins);
13217                                 *sp++ = ins;
13218                                 ip += 4;
13219                                 break;
13220                         case CEE_STARG:
13221                                 CHECK_STACK (1);
13222                                 --sp;
13223                                 CHECK_OPSIZE (4);
13224                                 n = read16 (ip + 2);
13225                                 CHECK_ARG (n);
13226                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [n], *sp))
13227                                         UNVERIFIED;
13228                                 EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
13229                                 ip += 4;
13230                                 break;
13231                         case CEE_LDLOC:
13232                                 CHECK_STACK_OVF (1);
13233                                 CHECK_OPSIZE (4);
13234                                 n = read16 (ip + 2);
13235                                 CHECK_LOCAL (n);
13236                                 EMIT_NEW_LOCLOAD (cfg, ins, n);
13237                                 *sp++ = ins;
13238                                 ip += 4;
13239                                 break;
13240                         case CEE_LDLOCA: {
13241                                 unsigned char *tmp_ip;
13242                                 CHECK_STACK_OVF (1);
13243                                 CHECK_OPSIZE (4);
13244                                 n = read16 (ip + 2);
13245                                 CHECK_LOCAL (n);
13246
13247                                 if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 2))) {
13248                                         ip = tmp_ip;
13249                                         inline_costs += 1;
13250                                         break;
13251                                 }                       
13252                                 
13253                                 EMIT_NEW_LOCLOADA (cfg, ins, n);
13254                                 *sp++ = ins;
13255                                 ip += 4;
13256                                 break;
13257                         }
13258                         case CEE_STLOC:
13259                                 CHECK_STACK (1);
13260                                 --sp;
13261                                 CHECK_OPSIZE (4);
13262                                 n = read16 (ip + 2);
13263                                 CHECK_LOCAL (n);
13264                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
13265                                         UNVERIFIED;
13266                                 emit_stloc_ir (cfg, sp, header, n);
13267                                 ip += 4;
13268                                 inline_costs += 1;
13269                                 break;
13270                         case CEE_LOCALLOC:
13271                                 CHECK_STACK (1);
13272                                 --sp;
13273                                 if (sp != stack_start) 
13274                                         UNVERIFIED;
13275                                 if (cfg->method != method) 
13276                                         /* 
13277                                          * Inlining this into a loop in a parent could lead to 
13278                                          * stack overflows which is different behavior than the
13279                                          * non-inlined case, thus disable inlining in this case.
13280                                          */
13281                                         INLINE_FAILURE("localloc");
13282
13283                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
13284                                 ins->dreg = alloc_preg (cfg);
13285                                 ins->sreg1 = sp [0]->dreg;
13286                                 ins->type = STACK_PTR;
13287                                 MONO_ADD_INS (cfg->cbb, ins);
13288
13289                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
13290                                 if (init_locals)
13291                                         ins->flags |= MONO_INST_INIT;
13292
13293                                 *sp++ = ins;
13294                                 ip += 2;
13295                                 break;
13296                         case CEE_ENDFILTER: {
13297                                 MonoExceptionClause *clause, *nearest;
13298                                 int cc;
13299
13300                                 CHECK_STACK (1);
13301                                 --sp;
13302                                 if ((sp != stack_start) || (sp [0]->type != STACK_I4)) 
13303                                         UNVERIFIED;
13304                                 MONO_INST_NEW (cfg, ins, OP_ENDFILTER);
13305                                 ins->sreg1 = (*sp)->dreg;
13306                                 MONO_ADD_INS (cfg->cbb, ins);
13307                                 start_new_bblock = 1;
13308                                 ip += 2;
13309
13310                                 nearest = NULL;
13311                                 for (cc = 0; cc < header->num_clauses; ++cc) {
13312                                         clause = &header->clauses [cc];
13313                                         if ((clause->flags & MONO_EXCEPTION_CLAUSE_FILTER) &&
13314                                                 ((ip - header->code) > clause->data.filter_offset && (ip - header->code) <= clause->handler_offset) &&
13315                                             (!nearest || (clause->data.filter_offset < nearest->data.filter_offset)))
13316                                                 nearest = clause;
13317                                 }
13318                                 g_assert (nearest);
13319                                 if ((ip - header->code) != nearest->handler_offset)
13320                                         UNVERIFIED;
13321
13322                                 break;
13323                         }
13324                         case CEE_UNALIGNED_:
13325                                 ins_flag |= MONO_INST_UNALIGNED;
13326                                 /* FIXME: record alignment? we can assume 1 for now */
13327                                 CHECK_OPSIZE (3);
13328                                 ip += 3;
13329                                 break;
13330                         case CEE_VOLATILE_:
13331                                 ins_flag |= MONO_INST_VOLATILE;
13332                                 ip += 2;
13333                                 break;
13334                         case CEE_TAIL_:
13335                                 ins_flag   |= MONO_INST_TAILCALL;
13336                                 cfg->flags |= MONO_CFG_HAS_TAIL;
13337                                 /* Can't inline tail calls at this time */
13338                                 inline_costs += 100000;
13339                                 ip += 2;
13340                                 break;
13341                         case CEE_INITOBJ:
13342                                 CHECK_STACK (1);
13343                                 --sp;
13344                                 CHECK_OPSIZE (6);
13345                                 token = read32 (ip + 2);
13346                                 klass = mini_get_class (method, token, generic_context);
13347                                 CHECK_TYPELOAD (klass);
13348                                 if (generic_class_is_reference_type (cfg, klass))
13349                                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, sp [0]->dreg, 0, 0);
13350                                 else
13351                                         mini_emit_initobj (cfg, *sp, NULL, klass);
13352                                 ip += 6;
13353                                 inline_costs += 1;
13354                                 break;
13355                         case CEE_CONSTRAINED_:
13356                                 CHECK_OPSIZE (6);
13357                                 token = read32 (ip + 2);
13358                                 constrained_class = mini_get_class (method, token, generic_context);
13359                                 CHECK_TYPELOAD (constrained_class);
13360                                 ip += 6;
13361                                 break;
13362                         case CEE_CPBLK:
13363                         case CEE_INITBLK: {
13364                                 MonoInst *iargs [3];
13365                                 CHECK_STACK (3);
13366                                 sp -= 3;
13367
13368                                 /* Skip optimized paths for volatile operations. */
13369                                 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)) {
13370                                         mini_emit_memcpy (cfg, sp [0]->dreg, 0, sp [1]->dreg, 0, sp [2]->inst_c0, 0);
13371                                 } 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)) {
13372                                         /* emit_memset only works when val == 0 */
13373                                         mini_emit_memset (cfg, sp [0]->dreg, 0, sp [2]->inst_c0, sp [1]->inst_c0, 0);
13374                                 } else {
13375                                         MonoInst *call;
13376                                         iargs [0] = sp [0];
13377                                         iargs [1] = sp [1];
13378                                         iargs [2] = sp [2];
13379                                         if (ip [1] == CEE_CPBLK) {
13380                                                 /*
13381                                                  * FIXME: It's unclear whether we should be emitting both the acquire
13382                                                  * and release barriers for cpblk. It is technically both a load and
13383                                                  * store operation, so it seems like that's the sensible thing to do.
13384                                                  *
13385                                                  * FIXME: We emit full barriers on both sides of the operation for
13386                                                  * simplicity. We should have a separate atomic memcpy method instead.
13387                                                  */
13388                                                 MonoMethod *memcpy_method = get_memcpy_method ();
13389
13390                                                 if (ins_flag & MONO_INST_VOLATILE)
13391                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
13392
13393                                                 call = mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
13394                                                 call->flags |= ins_flag;
13395
13396                                                 if (ins_flag & MONO_INST_VOLATILE)
13397                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
13398                                         } else {
13399                                                 MonoMethod *memset_method = get_memset_method ();
13400                                                 if (ins_flag & MONO_INST_VOLATILE) {
13401                                                         /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
13402                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
13403                                                 }
13404                                                 call = mono_emit_method_call (cfg, memset_method, iargs, NULL);
13405                                                 call->flags |= ins_flag;
13406                                         }
13407                                 }
13408                                 ip += 2;
13409                                 ins_flag = 0;
13410                                 inline_costs += 1;
13411                                 break;
13412                         }
13413                         case CEE_NO_:
13414                                 CHECK_OPSIZE (3);
13415                                 if (ip [2] & 0x1)
13416                                         ins_flag |= MONO_INST_NOTYPECHECK;
13417                                 if (ip [2] & 0x2)
13418                                         ins_flag |= MONO_INST_NORANGECHECK;
13419                                 /* we ignore the no-nullcheck for now since we
13420                                  * really do it explicitly only when doing callvirt->call
13421                                  */
13422                                 ip += 3;
13423                                 break;
13424                         case CEE_RETHROW: {
13425                                 MonoInst *load;
13426                                 int handler_offset = -1;
13427
13428                                 for (i = 0; i < header->num_clauses; ++i) {
13429                                         MonoExceptionClause *clause = &header->clauses [i];
13430                                         if (MONO_OFFSET_IN_HANDLER (clause, ip - header->code) && !(clause->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
13431                                                 handler_offset = clause->handler_offset;
13432                                                 break;
13433                                         }
13434                                 }
13435
13436                                 cfg->cbb->flags |= BB_EXCEPTION_UNSAFE;
13437
13438                                 if (handler_offset == -1)
13439                                         UNVERIFIED;
13440
13441                                 EMIT_NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, handler_offset)->inst_c0);
13442                                 MONO_INST_NEW (cfg, ins, OP_RETHROW);
13443                                 ins->sreg1 = load->dreg;
13444                                 MONO_ADD_INS (cfg->cbb, ins);
13445
13446                                 MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
13447                                 MONO_ADD_INS (cfg->cbb, ins);
13448
13449                                 sp = stack_start;
13450                                 link_bblock (cfg, cfg->cbb, end_bblock);
13451                                 start_new_bblock = 1;
13452                                 ip += 2;
13453                                 break;
13454                         }
13455                         case CEE_SIZEOF: {
13456                                 guint32 val;
13457                                 int ialign;
13458
13459                                 CHECK_STACK_OVF (1);
13460                                 CHECK_OPSIZE (6);
13461                                 token = read32 (ip + 2);
13462                                 if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC && !image_is_dynamic (method->klass->image) && !generic_context) {
13463                                         MonoType *type = mono_type_create_from_typespec_checked (image, token, &cfg->error);
13464                                         CHECK_CFG_ERROR;
13465
13466                                         val = mono_type_size (type, &ialign);
13467                                 } else {
13468                                         MonoClass *klass = mini_get_class (method, token, generic_context);
13469                                         CHECK_TYPELOAD (klass);
13470
13471                                         val = mono_type_size (&klass->byval_arg, &ialign);
13472
13473                                         if (mini_is_gsharedvt_klass (klass))
13474                                                 GSHAREDVT_FAILURE (*ip);
13475                                 }
13476                                 EMIT_NEW_ICONST (cfg, ins, val);
13477                                 *sp++= ins;
13478                                 ip += 6;
13479                                 break;
13480                         }
13481                         case CEE_REFANYTYPE: {
13482                                 MonoInst *src_var, *src;
13483
13484                                 GSHAREDVT_FAILURE (*ip);
13485
13486                                 CHECK_STACK (1);
13487                                 --sp;
13488
13489                                 // FIXME:
13490                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
13491                                 if (!src_var)
13492                                         src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
13493                                 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
13494                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &mono_defaults.typehandle_class->byval_arg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type));
13495                                 *sp++ = ins;
13496                                 ip += 2;
13497                                 break;
13498                         }
13499                         case CEE_READONLY_:
13500                                 readonly = TRUE;
13501                                 ip += 2;
13502                                 break;
13503
13504                         case CEE_UNUSED56:
13505                         case CEE_UNUSED57:
13506                         case CEE_UNUSED70:
13507                         case CEE_UNUSED:
13508                         case CEE_UNUSED99:
13509                                 UNVERIFIED;
13510                                 
13511                         default:
13512                                 g_warning ("opcode 0xfe 0x%02x not handled", ip [1]);
13513                                 UNVERIFIED;
13514                         }
13515                         break;
13516                 }
13517                 case CEE_UNUSED58:
13518                 case CEE_UNUSED1:
13519                         UNVERIFIED;
13520
13521                 default:
13522                         g_warning ("opcode 0x%02x not handled", *ip);
13523                         UNVERIFIED;
13524                 }
13525         }
13526         if (start_new_bblock != 1)
13527                 UNVERIFIED;
13528
13529         cfg->cbb->cil_length = ip - cfg->cbb->cil_code;
13530         if (cfg->cbb->next_bb) {
13531                 /* This could already be set because of inlining, #693905 */
13532                 MonoBasicBlock *bb = cfg->cbb;
13533
13534                 while (bb->next_bb)
13535                         bb = bb->next_bb;
13536                 bb->next_bb = end_bblock;
13537         } else {
13538                 cfg->cbb->next_bb = end_bblock;
13539         }
13540
13541         if (cfg->method == method && cfg->domainvar) {
13542                 MonoInst *store;
13543                 MonoInst *get_domain;
13544
13545                 cfg->cbb = init_localsbb;
13546
13547                 if ((get_domain = mono_get_domain_intrinsic (cfg))) {
13548                         MONO_ADD_INS (cfg->cbb, get_domain);
13549                 } else {
13550                         get_domain = mono_emit_jit_icall (cfg, mono_domain_get, NULL);
13551                 }
13552                 NEW_TEMPSTORE (cfg, store, cfg->domainvar->inst_c0, get_domain);
13553                 MONO_ADD_INS (cfg->cbb, store);
13554         }
13555
13556 #if defined(TARGET_POWERPC) || defined(TARGET_X86)
13557         if (cfg->compile_aot)
13558                 /* FIXME: The plt slots require a GOT var even if the method doesn't use it */
13559                 mono_get_got_var (cfg);
13560 #endif
13561
13562         if (cfg->method == method && cfg->got_var)
13563                 mono_emit_load_got_addr (cfg);
13564
13565         if (init_localsbb) {
13566                 cfg->cbb = init_localsbb;
13567                 cfg->ip = NULL;
13568                 for (i = 0; i < header->num_locals; ++i) {
13569                         emit_init_local (cfg, i, header->locals [i], init_locals);
13570                 }
13571         }
13572
13573         if (cfg->init_ref_vars && cfg->method == method) {
13574                 /* Emit initialization for ref vars */
13575                 // FIXME: Avoid duplication initialization for IL locals.
13576                 for (i = 0; i < cfg->num_varinfo; ++i) {
13577                         MonoInst *ins = cfg->varinfo [i];
13578
13579                         if (ins->opcode == OP_LOCAL && ins->type == STACK_OBJ)
13580                                 MONO_EMIT_NEW_PCONST (cfg, ins->dreg, NULL);
13581                 }
13582         }
13583
13584         if (cfg->lmf_var && cfg->method == method && !cfg->llvm_only) {
13585                 cfg->cbb = init_localsbb;
13586                 emit_push_lmf (cfg);
13587         }
13588
13589         cfg->cbb = init_localsbb;
13590         emit_instrumentation_call (cfg, mono_profiler_method_enter);
13591
13592         if (seq_points) {
13593                 MonoBasicBlock *bb;
13594
13595                 /*
13596                  * Make seq points at backward branch targets interruptable.
13597                  */
13598                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
13599                         if (bb->code && bb->in_count > 1 && bb->code->opcode == OP_SEQ_POINT)
13600                                 bb->code->flags |= MONO_INST_SINGLE_STEP_LOC;
13601         }
13602
13603         /* Add a sequence point for method entry/exit events */
13604         if (seq_points && cfg->gen_sdb_seq_points) {
13605                 NEW_SEQ_POINT (cfg, ins, METHOD_ENTRY_IL_OFFSET, FALSE);
13606                 MONO_ADD_INS (init_localsbb, ins);
13607                 NEW_SEQ_POINT (cfg, ins, METHOD_EXIT_IL_OFFSET, FALSE);
13608                 MONO_ADD_INS (cfg->bb_exit, ins);
13609         }
13610
13611         /*
13612          * Add seq points for IL offsets which have line number info, but wasn't generated a seq point during JITting because
13613          * the code they refer to was dead (#11880).
13614          */
13615         if (sym_seq_points) {
13616                 for (i = 0; i < header->code_size; ++i) {
13617                         if (mono_bitset_test_fast (seq_point_locs, i) && !mono_bitset_test_fast (seq_point_set_locs, i)) {
13618                                 MonoInst *ins;
13619
13620                                 NEW_SEQ_POINT (cfg, ins, i, FALSE);
13621                                 mono_add_seq_point (cfg, NULL, ins, SEQ_POINT_NATIVE_OFFSET_DEAD_CODE);
13622                         }
13623                 }
13624         }
13625
13626         cfg->ip = NULL;
13627
13628         if (cfg->method == method) {
13629                 MonoBasicBlock *bb;
13630                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
13631                         bb->region = mono_find_block_region (cfg, bb->real_offset);
13632                         if (cfg->spvars)
13633                                 mono_create_spvar_for_region (cfg, bb->region);
13634                         if (cfg->verbose_level > 2)
13635                                 printf ("REGION BB%d IL_%04x ID_%08X\n", bb->block_num, bb->real_offset, bb->region);
13636                 }
13637         }
13638
13639         if (inline_costs < 0) {
13640                 char *mname;
13641
13642                 /* Method is too large */
13643                 mname = mono_method_full_name (method, TRUE);
13644                 mono_cfg_set_exception_invalid_program (cfg, g_strdup_printf ("Method %s is too complex.", mname));
13645                 g_free (mname);
13646         }
13647
13648         if ((cfg->verbose_level > 2) && (cfg->method == method)) 
13649                 mono_print_code (cfg, "AFTER METHOD-TO-IR");
13650
13651         goto cleanup;
13652
13653 mono_error_exit:
13654         g_assert (!mono_error_ok (&cfg->error));
13655         goto cleanup;
13656  
13657  exception_exit:
13658         g_assert (cfg->exception_type != MONO_EXCEPTION_NONE);
13659         goto cleanup;
13660
13661  unverified:
13662         set_exception_type_from_invalid_il (cfg, method, ip);
13663         goto cleanup;
13664
13665  cleanup:
13666         g_slist_free (class_inits);
13667         mono_basic_block_free (original_bb);
13668         cfg->dont_inline = g_list_remove (cfg->dont_inline, method);
13669         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
13670         if (cfg->exception_type)
13671                 return -1;
13672         else
13673                 return inline_costs;
13674 }
13675
13676 static int
13677 store_membase_reg_to_store_membase_imm (int opcode)
13678 {
13679         switch (opcode) {
13680         case OP_STORE_MEMBASE_REG:
13681                 return OP_STORE_MEMBASE_IMM;
13682         case OP_STOREI1_MEMBASE_REG:
13683                 return OP_STOREI1_MEMBASE_IMM;
13684         case OP_STOREI2_MEMBASE_REG:
13685                 return OP_STOREI2_MEMBASE_IMM;
13686         case OP_STOREI4_MEMBASE_REG:
13687                 return OP_STOREI4_MEMBASE_IMM;
13688         case OP_STOREI8_MEMBASE_REG:
13689                 return OP_STOREI8_MEMBASE_IMM;
13690         default:
13691                 g_assert_not_reached ();
13692         }
13693
13694         return -1;
13695 }               
13696
13697 int
13698 mono_op_to_op_imm (int opcode)
13699 {
13700         switch (opcode) {
13701         case OP_IADD:
13702                 return OP_IADD_IMM;
13703         case OP_ISUB:
13704                 return OP_ISUB_IMM;
13705         case OP_IDIV:
13706                 return OP_IDIV_IMM;
13707         case OP_IDIV_UN:
13708                 return OP_IDIV_UN_IMM;
13709         case OP_IREM:
13710                 return OP_IREM_IMM;
13711         case OP_IREM_UN:
13712                 return OP_IREM_UN_IMM;
13713         case OP_IMUL:
13714                 return OP_IMUL_IMM;
13715         case OP_IAND:
13716                 return OP_IAND_IMM;
13717         case OP_IOR:
13718                 return OP_IOR_IMM;
13719         case OP_IXOR:
13720                 return OP_IXOR_IMM;
13721         case OP_ISHL:
13722                 return OP_ISHL_IMM;
13723         case OP_ISHR:
13724                 return OP_ISHR_IMM;
13725         case OP_ISHR_UN:
13726                 return OP_ISHR_UN_IMM;
13727
13728         case OP_LADD:
13729                 return OP_LADD_IMM;
13730         case OP_LSUB:
13731                 return OP_LSUB_IMM;
13732         case OP_LAND:
13733                 return OP_LAND_IMM;
13734         case OP_LOR:
13735                 return OP_LOR_IMM;
13736         case OP_LXOR:
13737                 return OP_LXOR_IMM;
13738         case OP_LSHL:
13739                 return OP_LSHL_IMM;
13740         case OP_LSHR:
13741                 return OP_LSHR_IMM;
13742         case OP_LSHR_UN:
13743                 return OP_LSHR_UN_IMM;
13744 #if SIZEOF_REGISTER == 8
13745         case OP_LREM:
13746                 return OP_LREM_IMM;
13747 #endif
13748
13749         case OP_COMPARE:
13750                 return OP_COMPARE_IMM;
13751         case OP_ICOMPARE:
13752                 return OP_ICOMPARE_IMM;
13753         case OP_LCOMPARE:
13754                 return OP_LCOMPARE_IMM;
13755
13756         case OP_STORE_MEMBASE_REG:
13757                 return OP_STORE_MEMBASE_IMM;
13758         case OP_STOREI1_MEMBASE_REG:
13759                 return OP_STOREI1_MEMBASE_IMM;
13760         case OP_STOREI2_MEMBASE_REG:
13761                 return OP_STOREI2_MEMBASE_IMM;
13762         case OP_STOREI4_MEMBASE_REG:
13763                 return OP_STOREI4_MEMBASE_IMM;
13764
13765 #if defined(TARGET_X86) || defined (TARGET_AMD64)
13766         case OP_X86_PUSH:
13767                 return OP_X86_PUSH_IMM;
13768         case OP_X86_COMPARE_MEMBASE_REG:
13769                 return OP_X86_COMPARE_MEMBASE_IMM;
13770 #endif
13771 #if defined(TARGET_AMD64)
13772         case OP_AMD64_ICOMPARE_MEMBASE_REG:
13773                 return OP_AMD64_ICOMPARE_MEMBASE_IMM;
13774 #endif
13775         case OP_VOIDCALL_REG:
13776                 return OP_VOIDCALL;
13777         case OP_CALL_REG:
13778                 return OP_CALL;
13779         case OP_LCALL_REG:
13780                 return OP_LCALL;
13781         case OP_FCALL_REG:
13782                 return OP_FCALL;
13783         case OP_LOCALLOC:
13784                 return OP_LOCALLOC_IMM;
13785         }
13786
13787         return -1;
13788 }
13789
13790 static int
13791 ldind_to_load_membase (int opcode)
13792 {
13793         switch (opcode) {
13794         case CEE_LDIND_I1:
13795                 return OP_LOADI1_MEMBASE;
13796         case CEE_LDIND_U1:
13797                 return OP_LOADU1_MEMBASE;
13798         case CEE_LDIND_I2:
13799                 return OP_LOADI2_MEMBASE;
13800         case CEE_LDIND_U2:
13801                 return OP_LOADU2_MEMBASE;
13802         case CEE_LDIND_I4:
13803                 return OP_LOADI4_MEMBASE;
13804         case CEE_LDIND_U4:
13805                 return OP_LOADU4_MEMBASE;
13806         case CEE_LDIND_I:
13807                 return OP_LOAD_MEMBASE;
13808         case CEE_LDIND_REF:
13809                 return OP_LOAD_MEMBASE;
13810         case CEE_LDIND_I8:
13811                 return OP_LOADI8_MEMBASE;
13812         case CEE_LDIND_R4:
13813                 return OP_LOADR4_MEMBASE;
13814         case CEE_LDIND_R8:
13815                 return OP_LOADR8_MEMBASE;
13816         default:
13817                 g_assert_not_reached ();
13818         }
13819
13820         return -1;
13821 }
13822
13823 static int
13824 stind_to_store_membase (int opcode)
13825 {
13826         switch (opcode) {
13827         case CEE_STIND_I1:
13828                 return OP_STOREI1_MEMBASE_REG;
13829         case CEE_STIND_I2:
13830                 return OP_STOREI2_MEMBASE_REG;
13831         case CEE_STIND_I4:
13832                 return OP_STOREI4_MEMBASE_REG;
13833         case CEE_STIND_I:
13834         case CEE_STIND_REF:
13835                 return OP_STORE_MEMBASE_REG;
13836         case CEE_STIND_I8:
13837                 return OP_STOREI8_MEMBASE_REG;
13838         case CEE_STIND_R4:
13839                 return OP_STORER4_MEMBASE_REG;
13840         case CEE_STIND_R8:
13841                 return OP_STORER8_MEMBASE_REG;
13842         default:
13843                 g_assert_not_reached ();
13844         }
13845
13846         return -1;
13847 }
13848
13849 int
13850 mono_load_membase_to_load_mem (int opcode)
13851 {
13852         // FIXME: Add a MONO_ARCH_HAVE_LOAD_MEM macro
13853 #if defined(TARGET_X86) || defined(TARGET_AMD64)
13854         switch (opcode) {
13855         case OP_LOAD_MEMBASE:
13856                 return OP_LOAD_MEM;
13857         case OP_LOADU1_MEMBASE:
13858                 return OP_LOADU1_MEM;
13859         case OP_LOADU2_MEMBASE:
13860                 return OP_LOADU2_MEM;
13861         case OP_LOADI4_MEMBASE:
13862                 return OP_LOADI4_MEM;
13863         case OP_LOADU4_MEMBASE:
13864                 return OP_LOADU4_MEM;
13865 #if SIZEOF_REGISTER == 8
13866         case OP_LOADI8_MEMBASE:
13867                 return OP_LOADI8_MEM;
13868 #endif
13869         }
13870 #endif
13871
13872         return -1;
13873 }
13874
13875 static inline int
13876 op_to_op_dest_membase (int store_opcode, int opcode)
13877 {
13878 #if defined(TARGET_X86)
13879         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG)))
13880                 return -1;
13881
13882         switch (opcode) {
13883         case OP_IADD:
13884                 return OP_X86_ADD_MEMBASE_REG;
13885         case OP_ISUB:
13886                 return OP_X86_SUB_MEMBASE_REG;
13887         case OP_IAND:
13888                 return OP_X86_AND_MEMBASE_REG;
13889         case OP_IOR:
13890                 return OP_X86_OR_MEMBASE_REG;
13891         case OP_IXOR:
13892                 return OP_X86_XOR_MEMBASE_REG;
13893         case OP_ADD_IMM:
13894         case OP_IADD_IMM:
13895                 return OP_X86_ADD_MEMBASE_IMM;
13896         case OP_SUB_IMM:
13897         case OP_ISUB_IMM:
13898                 return OP_X86_SUB_MEMBASE_IMM;
13899         case OP_AND_IMM:
13900         case OP_IAND_IMM:
13901                 return OP_X86_AND_MEMBASE_IMM;
13902         case OP_OR_IMM:
13903         case OP_IOR_IMM:
13904                 return OP_X86_OR_MEMBASE_IMM;
13905         case OP_XOR_IMM:
13906         case OP_IXOR_IMM:
13907                 return OP_X86_XOR_MEMBASE_IMM;
13908         case OP_MOVE:
13909                 return OP_NOP;
13910         }
13911 #endif
13912
13913 #if defined(TARGET_AMD64)
13914         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG) || (store_opcode == OP_STOREI8_MEMBASE_REG)))
13915                 return -1;
13916
13917         switch (opcode) {
13918         case OP_IADD:
13919                 return OP_X86_ADD_MEMBASE_REG;
13920         case OP_ISUB:
13921                 return OP_X86_SUB_MEMBASE_REG;
13922         case OP_IAND:
13923                 return OP_X86_AND_MEMBASE_REG;
13924         case OP_IOR:
13925                 return OP_X86_OR_MEMBASE_REG;
13926         case OP_IXOR:
13927                 return OP_X86_XOR_MEMBASE_REG;
13928         case OP_IADD_IMM:
13929                 return OP_X86_ADD_MEMBASE_IMM;
13930         case OP_ISUB_IMM:
13931                 return OP_X86_SUB_MEMBASE_IMM;
13932         case OP_IAND_IMM:
13933                 return OP_X86_AND_MEMBASE_IMM;
13934         case OP_IOR_IMM:
13935                 return OP_X86_OR_MEMBASE_IMM;
13936         case OP_IXOR_IMM:
13937                 return OP_X86_XOR_MEMBASE_IMM;
13938         case OP_LADD:
13939                 return OP_AMD64_ADD_MEMBASE_REG;
13940         case OP_LSUB:
13941                 return OP_AMD64_SUB_MEMBASE_REG;
13942         case OP_LAND:
13943                 return OP_AMD64_AND_MEMBASE_REG;
13944         case OP_LOR:
13945                 return OP_AMD64_OR_MEMBASE_REG;
13946         case OP_LXOR:
13947                 return OP_AMD64_XOR_MEMBASE_REG;
13948         case OP_ADD_IMM:
13949         case OP_LADD_IMM:
13950                 return OP_AMD64_ADD_MEMBASE_IMM;
13951         case OP_SUB_IMM:
13952         case OP_LSUB_IMM:
13953                 return OP_AMD64_SUB_MEMBASE_IMM;
13954         case OP_AND_IMM:
13955         case OP_LAND_IMM:
13956                 return OP_AMD64_AND_MEMBASE_IMM;
13957         case OP_OR_IMM:
13958         case OP_LOR_IMM:
13959                 return OP_AMD64_OR_MEMBASE_IMM;
13960         case OP_XOR_IMM:
13961         case OP_LXOR_IMM:
13962                 return OP_AMD64_XOR_MEMBASE_IMM;
13963         case OP_MOVE:
13964                 return OP_NOP;
13965         }
13966 #endif
13967
13968         return -1;
13969 }
13970
13971 static inline int
13972 op_to_op_store_membase (int store_opcode, int opcode)
13973 {
13974 #if defined(TARGET_X86) || defined(TARGET_AMD64)
13975         switch (opcode) {
13976         case OP_ICEQ:
13977                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
13978                         return OP_X86_SETEQ_MEMBASE;
13979         case OP_CNE:
13980                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
13981                         return OP_X86_SETNE_MEMBASE;
13982         }
13983 #endif
13984
13985         return -1;
13986 }
13987
13988 static inline int
13989 op_to_op_src1_membase (MonoCompile *cfg, int load_opcode, int opcode)
13990 {
13991 #ifdef TARGET_X86
13992         /* FIXME: This has sign extension issues */
13993         /*
13994         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
13995                 return OP_X86_COMPARE_MEMBASE8_IMM;
13996         */
13997
13998         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
13999                 return -1;
14000
14001         switch (opcode) {
14002         case OP_X86_PUSH:
14003                 return OP_X86_PUSH_MEMBASE;
14004         case OP_COMPARE_IMM:
14005         case OP_ICOMPARE_IMM:
14006                 return OP_X86_COMPARE_MEMBASE_IMM;
14007         case OP_COMPARE:
14008         case OP_ICOMPARE:
14009                 return OP_X86_COMPARE_MEMBASE_REG;
14010         }
14011 #endif
14012
14013 #ifdef TARGET_AMD64
14014         /* FIXME: This has sign extension issues */
14015         /*
14016         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
14017                 return OP_X86_COMPARE_MEMBASE8_IMM;
14018         */
14019
14020         switch (opcode) {
14021         case OP_X86_PUSH:
14022                 if ((load_opcode == OP_LOAD_MEMBASE && !cfg->backend->ilp32) || (load_opcode == OP_LOADI8_MEMBASE))
14023                         return OP_X86_PUSH_MEMBASE;
14024                 break;
14025                 /* FIXME: This only works for 32 bit immediates
14026         case OP_COMPARE_IMM:
14027         case OP_LCOMPARE_IMM:
14028                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
14029                         return OP_AMD64_COMPARE_MEMBASE_IMM;
14030                 */
14031         case OP_ICOMPARE_IMM:
14032                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
14033                         return OP_AMD64_ICOMPARE_MEMBASE_IMM;
14034                 break;
14035         case OP_COMPARE:
14036         case OP_LCOMPARE:
14037                 if (cfg->backend->ilp32 && load_opcode == OP_LOAD_MEMBASE)
14038                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
14039                 if ((load_opcode == OP_LOAD_MEMBASE && !cfg->backend->ilp32) || (load_opcode == OP_LOADI8_MEMBASE))
14040                         return OP_AMD64_COMPARE_MEMBASE_REG;
14041                 break;
14042         case OP_ICOMPARE:
14043                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
14044                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
14045                 break;
14046         }
14047 #endif
14048
14049         return -1;
14050 }
14051
14052 static inline int
14053 op_to_op_src2_membase (MonoCompile *cfg, int load_opcode, int opcode)
14054 {
14055 #ifdef TARGET_X86
14056         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
14057                 return -1;
14058         
14059         switch (opcode) {
14060         case OP_COMPARE:
14061         case OP_ICOMPARE:
14062                 return OP_X86_COMPARE_REG_MEMBASE;
14063         case OP_IADD:
14064                 return OP_X86_ADD_REG_MEMBASE;
14065         case OP_ISUB:
14066                 return OP_X86_SUB_REG_MEMBASE;
14067         case OP_IAND:
14068                 return OP_X86_AND_REG_MEMBASE;
14069         case OP_IOR:
14070                 return OP_X86_OR_REG_MEMBASE;
14071         case OP_IXOR:
14072                 return OP_X86_XOR_REG_MEMBASE;
14073         }
14074 #endif
14075
14076 #ifdef TARGET_AMD64
14077         if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE && cfg->backend->ilp32)) {
14078                 switch (opcode) {
14079                 case OP_ICOMPARE:
14080                         return OP_AMD64_ICOMPARE_REG_MEMBASE;
14081                 case OP_IADD:
14082                         return OP_X86_ADD_REG_MEMBASE;
14083                 case OP_ISUB:
14084                         return OP_X86_SUB_REG_MEMBASE;
14085                 case OP_IAND:
14086                         return OP_X86_AND_REG_MEMBASE;
14087                 case OP_IOR:
14088                         return OP_X86_OR_REG_MEMBASE;
14089                 case OP_IXOR:
14090                         return OP_X86_XOR_REG_MEMBASE;
14091                 }
14092         } else if ((load_opcode == OP_LOADI8_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE && !cfg->backend->ilp32)) {
14093                 switch (opcode) {
14094                 case OP_COMPARE:
14095                 case OP_LCOMPARE:
14096                         return OP_AMD64_COMPARE_REG_MEMBASE;
14097                 case OP_LADD:
14098                         return OP_AMD64_ADD_REG_MEMBASE;
14099                 case OP_LSUB:
14100                         return OP_AMD64_SUB_REG_MEMBASE;
14101                 case OP_LAND:
14102                         return OP_AMD64_AND_REG_MEMBASE;
14103                 case OP_LOR:
14104                         return OP_AMD64_OR_REG_MEMBASE;
14105                 case OP_LXOR:
14106                         return OP_AMD64_XOR_REG_MEMBASE;
14107                 }
14108         }
14109 #endif
14110
14111         return -1;
14112 }
14113
14114 int
14115 mono_op_to_op_imm_noemul (int opcode)
14116 {
14117         switch (opcode) {
14118 #if SIZEOF_REGISTER == 4 && !defined(MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS)
14119         case OP_LSHR:
14120         case OP_LSHL:
14121         case OP_LSHR_UN:
14122                 return -1;
14123 #endif
14124 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
14125         case OP_IDIV:
14126         case OP_IDIV_UN:
14127         case OP_IREM:
14128         case OP_IREM_UN:
14129                 return -1;
14130 #endif
14131 #if defined(MONO_ARCH_EMULATE_MUL_DIV)
14132         case OP_IMUL:
14133                 return -1;
14134 #endif
14135         default:
14136                 return mono_op_to_op_imm (opcode);
14137         }
14138 }
14139
14140 /**
14141  * mono_handle_global_vregs:
14142  *
14143  *   Make vregs used in more than one bblock 'global', i.e. allocate a variable
14144  * for them.
14145  */
14146 void
14147 mono_handle_global_vregs (MonoCompile *cfg)
14148 {
14149         gint32 *vreg_to_bb;
14150         MonoBasicBlock *bb;
14151         int i, pos;
14152
14153         vreg_to_bb = (gint32 *)mono_mempool_alloc0 (cfg->mempool, sizeof (gint32*) * cfg->next_vreg + 1);
14154
14155 #ifdef MONO_ARCH_SIMD_INTRINSICS
14156         if (cfg->uses_simd_intrinsics)
14157                 mono_simd_simplify_indirection (cfg);
14158 #endif
14159
14160         /* Find local vregs used in more than one bb */
14161         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
14162                 MonoInst *ins = bb->code;       
14163                 int block_num = bb->block_num;
14164
14165                 if (cfg->verbose_level > 2)
14166                         printf ("\nHANDLE-GLOBAL-VREGS BLOCK %d:\n", bb->block_num);
14167
14168                 cfg->cbb = bb;
14169                 for (; ins; ins = ins->next) {
14170                         const char *spec = INS_INFO (ins->opcode);
14171                         int regtype = 0, regindex;
14172                         gint32 prev_bb;
14173
14174                         if (G_UNLIKELY (cfg->verbose_level > 2))
14175                                 mono_print_ins (ins);
14176
14177                         g_assert (ins->opcode >= MONO_CEE_LAST);
14178
14179                         for (regindex = 0; regindex < 4; regindex ++) {
14180                                 int vreg = 0;
14181
14182                                 if (regindex == 0) {
14183                                         regtype = spec [MONO_INST_DEST];
14184                                         if (regtype == ' ')
14185                                                 continue;
14186                                         vreg = ins->dreg;
14187                                 } else if (regindex == 1) {
14188                                         regtype = spec [MONO_INST_SRC1];
14189                                         if (regtype == ' ')
14190                                                 continue;
14191                                         vreg = ins->sreg1;
14192                                 } else if (regindex == 2) {
14193                                         regtype = spec [MONO_INST_SRC2];
14194                                         if (regtype == ' ')
14195                                                 continue;
14196                                         vreg = ins->sreg2;
14197                                 } else if (regindex == 3) {
14198                                         regtype = spec [MONO_INST_SRC3];
14199                                         if (regtype == ' ')
14200                                                 continue;
14201                                         vreg = ins->sreg3;
14202                                 }
14203
14204 #if SIZEOF_REGISTER == 4
14205                                 /* In the LLVM case, the long opcodes are not decomposed */
14206                                 if (regtype == 'l' && !COMPILE_LLVM (cfg)) {
14207                                         /*
14208                                          * Since some instructions reference the original long vreg,
14209                                          * and some reference the two component vregs, it is quite hard
14210                                          * to determine when it needs to be global. So be conservative.
14211                                          */
14212                                         if (!get_vreg_to_inst (cfg, vreg)) {
14213                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
14214
14215                                                 if (cfg->verbose_level > 2)
14216                                                         printf ("LONG VREG R%d made global.\n", vreg);
14217                                         }
14218
14219                                         /*
14220                                          * Make the component vregs volatile since the optimizations can
14221                                          * get confused otherwise.
14222                                          */
14223                                         get_vreg_to_inst (cfg, MONO_LVREG_LS (vreg))->flags |= MONO_INST_VOLATILE;
14224                                         get_vreg_to_inst (cfg, MONO_LVREG_MS (vreg))->flags |= MONO_INST_VOLATILE;
14225                                 }
14226 #endif
14227
14228                                 g_assert (vreg != -1);
14229
14230                                 prev_bb = vreg_to_bb [vreg];
14231                                 if (prev_bb == 0) {
14232                                         /* 0 is a valid block num */
14233                                         vreg_to_bb [vreg] = block_num + 1;
14234                                 } else if ((prev_bb != block_num + 1) && (prev_bb != -1)) {
14235                                         if (((regtype == 'i' && (vreg < MONO_MAX_IREGS))) || (regtype == 'f' && (vreg < MONO_MAX_FREGS)))
14236                                                 continue;
14237
14238                                         if (!get_vreg_to_inst (cfg, vreg)) {
14239                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
14240                                                         printf ("VREG R%d used in BB%d and BB%d made global.\n", vreg, vreg_to_bb [vreg], block_num);
14241
14242                                                 switch (regtype) {
14243                                                 case 'i':
14244                                                         if (vreg_is_ref (cfg, vreg))
14245                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL, vreg);
14246                                                         else
14247                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL, vreg);
14248                                                         break;
14249                                                 case 'l':
14250                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
14251                                                         break;
14252                                                 case 'f':
14253                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.double_class->byval_arg, OP_LOCAL, vreg);
14254                                                         break;
14255                                                 case 'v':
14256                                                         mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, vreg);
14257                                                         break;
14258                                                 default:
14259                                                         g_assert_not_reached ();
14260                                                 }
14261                                         }
14262
14263                                         /* Flag as having been used in more than one bb */
14264                                         vreg_to_bb [vreg] = -1;
14265                                 }
14266                         }
14267                 }
14268         }
14269
14270         /* If a variable is used in only one bblock, convert it into a local vreg */
14271         for (i = 0; i < cfg->num_varinfo; i++) {
14272                 MonoInst *var = cfg->varinfo [i];
14273                 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
14274
14275                 switch (var->type) {
14276                 case STACK_I4:
14277                 case STACK_OBJ:
14278                 case STACK_PTR:
14279                 case STACK_MP:
14280                 case STACK_VTYPE:
14281 #if SIZEOF_REGISTER == 8
14282                 case STACK_I8:
14283 #endif
14284 #if !defined(TARGET_X86)
14285                 /* Enabling this screws up the fp stack on x86 */
14286                 case STACK_R8:
14287 #endif
14288                         if (mono_arch_is_soft_float ())
14289                                 break;
14290
14291                         /*
14292                         if (var->type == STACK_VTYPE && cfg->gsharedvt && mini_is_gsharedvt_variable_type (var->inst_vtype))
14293                                 break;
14294                         */
14295
14296                         /* Arguments are implicitly global */
14297                         /* Putting R4 vars into registers doesn't work currently */
14298                         /* The gsharedvt vars are implicitly referenced by ldaddr opcodes, but those opcodes are only generated later */
14299                         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) {
14300                                 /* 
14301                                  * Make that the variable's liveness interval doesn't contain a call, since
14302                                  * that would cause the lvreg to be spilled, making the whole optimization
14303                                  * useless.
14304                                  */
14305                                 /* This is too slow for JIT compilation */
14306 #if 0
14307                                 if (cfg->compile_aot && vreg_to_bb [var->dreg]) {
14308                                         MonoInst *ins;
14309                                         int def_index, call_index, ins_index;
14310                                         gboolean spilled = FALSE;
14311
14312                                         def_index = -1;
14313                                         call_index = -1;
14314                                         ins_index = 0;
14315                                         for (ins = vreg_to_bb [var->dreg]->code; ins; ins = ins->next) {
14316                                                 const char *spec = INS_INFO (ins->opcode);
14317
14318                                                 if ((spec [MONO_INST_DEST] != ' ') && (ins->dreg == var->dreg))
14319                                                         def_index = ins_index;
14320
14321                                                 if (((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg)) ||
14322                                                         ((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg))) {
14323                                                         if (call_index > def_index) {
14324                                                                 spilled = TRUE;
14325                                                                 break;
14326                                                         }
14327                                                 }
14328
14329                                                 if (MONO_IS_CALL (ins))
14330                                                         call_index = ins_index;
14331
14332                                                 ins_index ++;
14333                                         }
14334
14335                                         if (spilled)
14336                                                 break;
14337                                 }
14338 #endif
14339
14340                                 if (G_UNLIKELY (cfg->verbose_level > 2))
14341                                         printf ("CONVERTED R%d(%d) TO VREG.\n", var->dreg, vmv->idx);
14342                                 var->flags |= MONO_INST_IS_DEAD;
14343                                 cfg->vreg_to_inst [var->dreg] = NULL;
14344                         }
14345                         break;
14346                 }
14347         }
14348
14349         /* 
14350          * Compress the varinfo and vars tables so the liveness computation is faster and
14351          * takes up less space.
14352          */
14353         pos = 0;
14354         for (i = 0; i < cfg->num_varinfo; ++i) {
14355                 MonoInst *var = cfg->varinfo [i];
14356                 if (pos < i && cfg->locals_start == i)
14357                         cfg->locals_start = pos;
14358                 if (!(var->flags & MONO_INST_IS_DEAD)) {
14359                         if (pos < i) {
14360                                 cfg->varinfo [pos] = cfg->varinfo [i];
14361                                 cfg->varinfo [pos]->inst_c0 = pos;
14362                                 memcpy (&cfg->vars [pos], &cfg->vars [i], sizeof (MonoMethodVar));
14363                                 cfg->vars [pos].idx = pos;
14364 #if SIZEOF_REGISTER == 4
14365                                 if (cfg->varinfo [pos]->type == STACK_I8) {
14366                                         /* Modify the two component vars too */
14367                                         MonoInst *var1;
14368
14369                                         var1 = get_vreg_to_inst (cfg, MONO_LVREG_LS (cfg->varinfo [pos]->dreg));
14370                                         var1->inst_c0 = pos;
14371                                         var1 = get_vreg_to_inst (cfg, MONO_LVREG_MS (cfg->varinfo [pos]->dreg));
14372                                         var1->inst_c0 = pos;
14373                                 }
14374 #endif
14375                         }
14376                         pos ++;
14377                 }
14378         }
14379         cfg->num_varinfo = pos;
14380         if (cfg->locals_start > cfg->num_varinfo)
14381                 cfg->locals_start = cfg->num_varinfo;
14382 }
14383
14384 /*
14385  * mono_allocate_gsharedvt_vars:
14386  *
14387  *   Allocate variables with gsharedvt types to entries in the MonoGSharedVtMethodRuntimeInfo.entries array.
14388  * Initialize cfg->gsharedvt_vreg_to_idx with the mapping between vregs and indexes.
14389  */
14390 void
14391 mono_allocate_gsharedvt_vars (MonoCompile *cfg)
14392 {
14393         int i;
14394
14395         cfg->gsharedvt_vreg_to_idx = (int *)mono_mempool_alloc0 (cfg->mempool, sizeof (int) * cfg->next_vreg);
14396
14397         for (i = 0; i < cfg->num_varinfo; ++i) {
14398                 MonoInst *ins = cfg->varinfo [i];
14399                 int idx;
14400
14401                 if (mini_is_gsharedvt_variable_type (ins->inst_vtype)) {
14402                         if (i >= cfg->locals_start) {
14403                                 /* Local */
14404                                 idx = get_gsharedvt_info_slot (cfg, ins->inst_vtype, MONO_RGCTX_INFO_LOCAL_OFFSET);
14405                                 cfg->gsharedvt_vreg_to_idx [ins->dreg] = idx + 1;
14406                                 ins->opcode = OP_GSHAREDVT_LOCAL;
14407                                 ins->inst_imm = idx;
14408                         } else {
14409                                 /* Arg */
14410                                 cfg->gsharedvt_vreg_to_idx [ins->dreg] = -1;
14411                                 ins->opcode = OP_GSHAREDVT_ARG_REGOFFSET;
14412                         }
14413                 }
14414         }
14415 }
14416
14417 /**
14418  * mono_spill_global_vars:
14419  *
14420  *   Generate spill code for variables which are not allocated to registers, 
14421  * and replace vregs with their allocated hregs. *need_local_opts is set to TRUE if
14422  * code is generated which could be optimized by the local optimization passes.
14423  */
14424 void
14425 mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
14426 {
14427         MonoBasicBlock *bb;
14428         char spec2 [16];
14429         int orig_next_vreg;
14430         guint32 *vreg_to_lvreg;
14431         guint32 *lvregs;
14432         guint32 i, lvregs_len;
14433         gboolean dest_has_lvreg = FALSE;
14434         MonoStackType stacktypes [128];
14435         MonoInst **live_range_start, **live_range_end;
14436         MonoBasicBlock **live_range_start_bb, **live_range_end_bb;
14437
14438         *need_local_opts = FALSE;
14439
14440         memset (spec2, 0, sizeof (spec2));
14441
14442         /* FIXME: Move this function to mini.c */
14443         stacktypes ['i'] = STACK_PTR;
14444         stacktypes ['l'] = STACK_I8;
14445         stacktypes ['f'] = STACK_R8;
14446 #ifdef MONO_ARCH_SIMD_INTRINSICS
14447         stacktypes ['x'] = STACK_VTYPE;
14448 #endif
14449
14450 #if SIZEOF_REGISTER == 4
14451         /* Create MonoInsts for longs */
14452         for (i = 0; i < cfg->num_varinfo; i++) {
14453                 MonoInst *ins = cfg->varinfo [i];
14454
14455                 if ((ins->opcode != OP_REGVAR) && !(ins->flags & MONO_INST_IS_DEAD)) {
14456                         switch (ins->type) {
14457                         case STACK_R8:
14458                         case STACK_I8: {
14459                                 MonoInst *tree;
14460
14461                                 if (ins->type == STACK_R8 && !COMPILE_SOFT_FLOAT (cfg))
14462                                         break;
14463
14464                                 g_assert (ins->opcode == OP_REGOFFSET);
14465
14466                                 tree = get_vreg_to_inst (cfg, MONO_LVREG_LS (ins->dreg));
14467                                 g_assert (tree);
14468                                 tree->opcode = OP_REGOFFSET;
14469                                 tree->inst_basereg = ins->inst_basereg;
14470                                 tree->inst_offset = ins->inst_offset + MINI_LS_WORD_OFFSET;
14471
14472                                 tree = get_vreg_to_inst (cfg, MONO_LVREG_MS (ins->dreg));
14473                                 g_assert (tree);
14474                                 tree->opcode = OP_REGOFFSET;
14475                                 tree->inst_basereg = ins->inst_basereg;
14476                                 tree->inst_offset = ins->inst_offset + MINI_MS_WORD_OFFSET;
14477                                 break;
14478                         }
14479                         default:
14480                                 break;
14481                         }
14482                 }
14483         }
14484 #endif
14485
14486         if (cfg->compute_gc_maps) {
14487                 /* registers need liveness info even for !non refs */
14488                 for (i = 0; i < cfg->num_varinfo; i++) {
14489                         MonoInst *ins = cfg->varinfo [i];
14490
14491                         if (ins->opcode == OP_REGVAR)
14492                                 ins->flags |= MONO_INST_GC_TRACK;
14493                 }
14494         }
14495                 
14496         /* FIXME: widening and truncation */
14497
14498         /*
14499          * As an optimization, when a variable allocated to the stack is first loaded into 
14500          * an lvreg, we will remember the lvreg and use it the next time instead of loading
14501          * the variable again.
14502          */
14503         orig_next_vreg = cfg->next_vreg;
14504         vreg_to_lvreg = (guint32 *)mono_mempool_alloc0 (cfg->mempool, sizeof (guint32) * cfg->next_vreg);
14505         lvregs = (guint32 *)mono_mempool_alloc (cfg->mempool, sizeof (guint32) * 1024);
14506         lvregs_len = 0;
14507
14508         /* 
14509          * These arrays contain the first and last instructions accessing a given
14510          * variable.
14511          * Since we emit bblocks in the same order we process them here, and we
14512          * don't split live ranges, these will precisely describe the live range of
14513          * the variable, i.e. the instruction range where a valid value can be found
14514          * in the variables location.
14515          * The live range is computed using the liveness info computed by the liveness pass.
14516          * We can't use vmv->range, since that is an abstract live range, and we need
14517          * one which is instruction precise.
14518          * FIXME: Variables used in out-of-line bblocks have a hole in their live range.
14519          */
14520         /* FIXME: Only do this if debugging info is requested */
14521         live_range_start = g_new0 (MonoInst*, cfg->next_vreg);
14522         live_range_end = g_new0 (MonoInst*, cfg->next_vreg);
14523         live_range_start_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
14524         live_range_end_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
14525         
14526         /* Add spill loads/stores */
14527         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
14528                 MonoInst *ins;
14529
14530                 if (cfg->verbose_level > 2)
14531                         printf ("\nSPILL BLOCK %d:\n", bb->block_num);
14532
14533                 /* Clear vreg_to_lvreg array */
14534                 for (i = 0; i < lvregs_len; i++)
14535                         vreg_to_lvreg [lvregs [i]] = 0;
14536                 lvregs_len = 0;
14537
14538                 cfg->cbb = bb;
14539                 MONO_BB_FOR_EACH_INS (bb, ins) {
14540                         const char *spec = INS_INFO (ins->opcode);
14541                         int regtype, srcindex, sreg, tmp_reg, prev_dreg, num_sregs;
14542                         gboolean store, no_lvreg;
14543                         int sregs [MONO_MAX_SRC_REGS];
14544
14545                         if (G_UNLIKELY (cfg->verbose_level > 2))
14546                                 mono_print_ins (ins);
14547
14548                         if (ins->opcode == OP_NOP)
14549                                 continue;
14550
14551                         /* 
14552                          * We handle LDADDR here as well, since it can only be decomposed
14553                          * when variable addresses are known.
14554                          */
14555                         if (ins->opcode == OP_LDADDR) {
14556                                 MonoInst *var = (MonoInst *)ins->inst_p0;
14557
14558                                 if (var->opcode == OP_VTARG_ADDR) {
14559                                         /* Happens on SPARC/S390 where vtypes are passed by reference */
14560                                         MonoInst *vtaddr = var->inst_left;
14561                                         if (vtaddr->opcode == OP_REGVAR) {
14562                                                 ins->opcode = OP_MOVE;
14563                                                 ins->sreg1 = vtaddr->dreg;
14564                                         }
14565                                         else if (var->inst_left->opcode == OP_REGOFFSET) {
14566                                                 ins->opcode = OP_LOAD_MEMBASE;
14567                                                 ins->inst_basereg = vtaddr->inst_basereg;
14568                                                 ins->inst_offset = vtaddr->inst_offset;
14569                                         } else
14570                                                 NOT_IMPLEMENTED;
14571                                 } else if (cfg->gsharedvt && cfg->gsharedvt_vreg_to_idx [var->dreg] < 0) {
14572                                         /* gsharedvt arg passed by ref */
14573                                         g_assert (var->opcode == OP_GSHAREDVT_ARG_REGOFFSET);
14574
14575                                         ins->opcode = OP_LOAD_MEMBASE;
14576                                         ins->inst_basereg = var->inst_basereg;
14577                                         ins->inst_offset = var->inst_offset;
14578                                 } else if (cfg->gsharedvt && cfg->gsharedvt_vreg_to_idx [var->dreg]) {
14579                                         MonoInst *load, *load2, *load3;
14580                                         int idx = cfg->gsharedvt_vreg_to_idx [var->dreg] - 1;
14581                                         int reg1, reg2, reg3;
14582                                         MonoInst *info_var = cfg->gsharedvt_info_var;
14583                                         MonoInst *locals_var = cfg->gsharedvt_locals_var;
14584
14585                                         /*
14586                                          * gsharedvt local.
14587                                          * Compute the address of the local as gsharedvt_locals_var + gsharedvt_info_var->locals_offsets [idx].
14588                                          */
14589
14590                                         g_assert (var->opcode == OP_GSHAREDVT_LOCAL);
14591
14592                                         g_assert (info_var);
14593                                         g_assert (locals_var);
14594
14595                                         /* Mark the instruction used to compute the locals var as used */
14596                                         cfg->gsharedvt_locals_var_ins = NULL;
14597
14598                                         /* Load the offset */
14599                                         if (info_var->opcode == OP_REGOFFSET) {
14600                                                 reg1 = alloc_ireg (cfg);
14601                                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, reg1, info_var->inst_basereg, info_var->inst_offset);
14602                                         } else if (info_var->opcode == OP_REGVAR) {
14603                                                 load = NULL;
14604                                                 reg1 = info_var->dreg;
14605                                         } else {
14606                                                 g_assert_not_reached ();
14607                                         }
14608                                         reg2 = alloc_ireg (cfg);
14609                                         NEW_LOAD_MEMBASE (cfg, load2, OP_LOADI4_MEMBASE, reg2, reg1, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, entries) + (idx * sizeof (gpointer)));
14610                                         /* Load the locals area address */
14611                                         reg3 = alloc_ireg (cfg);
14612                                         if (locals_var->opcode == OP_REGOFFSET) {
14613                                                 NEW_LOAD_MEMBASE (cfg, load3, OP_LOAD_MEMBASE, reg3, locals_var->inst_basereg, locals_var->inst_offset);
14614                                         } else if (locals_var->opcode == OP_REGVAR) {
14615                                                 NEW_UNALU (cfg, load3, OP_MOVE, reg3, locals_var->dreg);
14616                                         } else {
14617                                                 g_assert_not_reached ();
14618                                         }
14619                                         /* Compute the address */
14620                                         ins->opcode = OP_PADD;
14621                                         ins->sreg1 = reg3;
14622                                         ins->sreg2 = reg2;
14623
14624                                         mono_bblock_insert_before_ins (bb, ins, load3);
14625                                         mono_bblock_insert_before_ins (bb, load3, load2);
14626                                         if (load)
14627                                                 mono_bblock_insert_before_ins (bb, load2, load);
14628                                 } else {
14629                                         g_assert (var->opcode == OP_REGOFFSET);
14630
14631                                         ins->opcode = OP_ADD_IMM;
14632                                         ins->sreg1 = var->inst_basereg;
14633                                         ins->inst_imm = var->inst_offset;
14634                                 }
14635
14636                                 *need_local_opts = TRUE;
14637                                 spec = INS_INFO (ins->opcode);
14638                         }
14639
14640                         if (ins->opcode < MONO_CEE_LAST) {
14641                                 mono_print_ins (ins);
14642                                 g_assert_not_reached ();
14643                         }
14644
14645                         /*
14646                          * Store opcodes have destbasereg in the dreg, but in reality, it is an
14647                          * src register.
14648                          * FIXME:
14649                          */
14650                         if (MONO_IS_STORE_MEMBASE (ins)) {
14651                                 tmp_reg = ins->dreg;
14652                                 ins->dreg = ins->sreg2;
14653                                 ins->sreg2 = tmp_reg;
14654                                 store = TRUE;
14655
14656                                 spec2 [MONO_INST_DEST] = ' ';
14657                                 spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
14658                                 spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
14659                                 spec2 [MONO_INST_SRC3] = ' ';
14660                                 spec = spec2;
14661                         } else if (MONO_IS_STORE_MEMINDEX (ins))
14662                                 g_assert_not_reached ();
14663                         else
14664                                 store = FALSE;
14665                         no_lvreg = FALSE;
14666
14667                         if (G_UNLIKELY (cfg->verbose_level > 2)) {
14668                                 printf ("\t %.3s %d", spec, ins->dreg);
14669                                 num_sregs = mono_inst_get_src_registers (ins, sregs);
14670                                 for (srcindex = 0; srcindex < num_sregs; ++srcindex)
14671                                         printf (" %d", sregs [srcindex]);
14672                                 printf ("\n");
14673                         }
14674
14675                         /***************/
14676                         /*    DREG     */
14677                         /***************/
14678                         regtype = spec [MONO_INST_DEST];
14679                         g_assert (((ins->dreg == -1) && (regtype == ' ')) || ((ins->dreg != -1) && (regtype != ' ')));
14680                         prev_dreg = -1;
14681
14682                         if ((ins->dreg != -1) && get_vreg_to_inst (cfg, ins->dreg)) {
14683                                 MonoInst *var = get_vreg_to_inst (cfg, ins->dreg);
14684                                 MonoInst *store_ins;
14685                                 int store_opcode;
14686                                 MonoInst *def_ins = ins;
14687                                 int dreg = ins->dreg; /* The original vreg */
14688
14689                                 store_opcode = mono_type_to_store_membase (cfg, var->inst_vtype);
14690
14691                                 if (var->opcode == OP_REGVAR) {
14692                                         ins->dreg = var->dreg;
14693                                 } 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)) {
14694                                         /* 
14695                                          * Instead of emitting a load+store, use a _membase opcode.
14696                                          */
14697                                         g_assert (var->opcode == OP_REGOFFSET);
14698                                         if (ins->opcode == OP_MOVE) {
14699                                                 NULLIFY_INS (ins);
14700                                                 def_ins = NULL;
14701                                         } else {
14702                                                 ins->opcode = op_to_op_dest_membase (store_opcode, ins->opcode);
14703                                                 ins->inst_basereg = var->inst_basereg;
14704                                                 ins->inst_offset = var->inst_offset;
14705                                                 ins->dreg = -1;
14706                                         }
14707                                         spec = INS_INFO (ins->opcode);
14708                                 } else {
14709                                         guint32 lvreg;
14710
14711                                         g_assert (var->opcode == OP_REGOFFSET);
14712
14713                                         prev_dreg = ins->dreg;
14714
14715                                         /* Invalidate any previous lvreg for this vreg */
14716                                         vreg_to_lvreg [ins->dreg] = 0;
14717
14718                                         lvreg = 0;
14719
14720                                         if (COMPILE_SOFT_FLOAT (cfg) && store_opcode == OP_STORER8_MEMBASE_REG) {
14721                                                 regtype = 'l';
14722                                                 store_opcode = OP_STOREI8_MEMBASE_REG;
14723                                         }
14724
14725                                         ins->dreg = alloc_dreg (cfg, stacktypes [regtype]);
14726
14727 #if SIZEOF_REGISTER != 8
14728                                         if (regtype == 'l') {
14729                                                 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));
14730                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
14731                                                 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));
14732                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
14733                                                 def_ins = store_ins;
14734                                         }
14735                                         else
14736 #endif
14737                                         {
14738                                                 g_assert (store_opcode != OP_STOREV_MEMBASE);
14739
14740                                                 /* Try to fuse the store into the instruction itself */
14741                                                 /* FIXME: Add more instructions */
14742                                                 if (!lvreg && ((ins->opcode == OP_ICONST) || ((ins->opcode == OP_I8CONST) && (ins->inst_c0 == 0)))) {
14743                                                         ins->opcode = store_membase_reg_to_store_membase_imm (store_opcode);
14744                                                         ins->inst_imm = ins->inst_c0;
14745                                                         ins->inst_destbasereg = var->inst_basereg;
14746                                                         ins->inst_offset = var->inst_offset;
14747                                                         spec = INS_INFO (ins->opcode);
14748                                                 } else if (!lvreg && ((ins->opcode == OP_MOVE) || (ins->opcode == OP_FMOVE) || (ins->opcode == OP_LMOVE) || (ins->opcode == OP_RMOVE))) {
14749                                                         ins->opcode = store_opcode;
14750                                                         ins->inst_destbasereg = var->inst_basereg;
14751                                                         ins->inst_offset = var->inst_offset;
14752
14753                                                         no_lvreg = TRUE;
14754
14755                                                         tmp_reg = ins->dreg;
14756                                                         ins->dreg = ins->sreg2;
14757                                                         ins->sreg2 = tmp_reg;
14758                                                         store = TRUE;
14759
14760                                                         spec2 [MONO_INST_DEST] = ' ';
14761                                                         spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
14762                                                         spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
14763                                                         spec2 [MONO_INST_SRC3] = ' ';
14764                                                         spec = spec2;
14765                                                 } else if (!lvreg && (op_to_op_store_membase (store_opcode, ins->opcode) != -1)) {
14766                                                         // FIXME: The backends expect the base reg to be in inst_basereg
14767                                                         ins->opcode = op_to_op_store_membase (store_opcode, ins->opcode);
14768                                                         ins->dreg = -1;
14769                                                         ins->inst_basereg = var->inst_basereg;
14770                                                         ins->inst_offset = var->inst_offset;
14771                                                         spec = INS_INFO (ins->opcode);
14772                                                 } else {
14773                                                         /* printf ("INS: "); mono_print_ins (ins); */
14774                                                         /* Create a store instruction */
14775                                                         NEW_STORE_MEMBASE (cfg, store_ins, store_opcode, var->inst_basereg, var->inst_offset, ins->dreg);
14776
14777                                                         /* Insert it after the instruction */
14778                                                         mono_bblock_insert_after_ins (bb, ins, store_ins);
14779
14780                                                         def_ins = store_ins;
14781
14782                                                         /* 
14783                                                          * We can't assign ins->dreg to var->dreg here, since the
14784                                                          * sregs could use it. So set a flag, and do it after
14785                                                          * the sregs.
14786                                                          */
14787                                                         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)))
14788                                                                 dest_has_lvreg = TRUE;
14789                                                 }
14790                                         }
14791                                 }
14792
14793                                 if (def_ins && !live_range_start [dreg]) {
14794                                         live_range_start [dreg] = def_ins;
14795                                         live_range_start_bb [dreg] = bb;
14796                                 }
14797
14798                                 if (cfg->compute_gc_maps && def_ins && (var->flags & MONO_INST_GC_TRACK)) {
14799                                         MonoInst *tmp;
14800
14801                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_DEF);
14802                                         tmp->inst_c1 = dreg;
14803                                         mono_bblock_insert_after_ins (bb, def_ins, tmp);
14804                                 }
14805                         }
14806
14807                         /************/
14808                         /*  SREGS   */
14809                         /************/
14810                         num_sregs = mono_inst_get_src_registers (ins, sregs);
14811                         for (srcindex = 0; srcindex < 3; ++srcindex) {
14812                                 regtype = spec [MONO_INST_SRC1 + srcindex];
14813                                 sreg = sregs [srcindex];
14814
14815                                 g_assert (((sreg == -1) && (regtype == ' ')) || ((sreg != -1) && (regtype != ' ')));
14816                                 if ((sreg != -1) && get_vreg_to_inst (cfg, sreg)) {
14817                                         MonoInst *var = get_vreg_to_inst (cfg, sreg);
14818                                         MonoInst *use_ins = ins;
14819                                         MonoInst *load_ins;
14820                                         guint32 load_opcode;
14821
14822                                         if (var->opcode == OP_REGVAR) {
14823                                                 sregs [srcindex] = var->dreg;
14824                                                 //mono_inst_set_src_registers (ins, sregs);
14825                                                 live_range_end [sreg] = use_ins;
14826                                                 live_range_end_bb [sreg] = bb;
14827
14828                                                 if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
14829                                                         MonoInst *tmp;
14830
14831                                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
14832                                                         /* var->dreg is a hreg */
14833                                                         tmp->inst_c1 = sreg;
14834                                                         mono_bblock_insert_after_ins (bb, ins, tmp);
14835                                                 }
14836
14837                                                 continue;
14838                                         }
14839
14840                                         g_assert (var->opcode == OP_REGOFFSET);
14841                                                 
14842                                         load_opcode = mono_type_to_load_membase (cfg, var->inst_vtype);
14843
14844                                         g_assert (load_opcode != OP_LOADV_MEMBASE);
14845
14846                                         if (vreg_to_lvreg [sreg]) {
14847                                                 g_assert (vreg_to_lvreg [sreg] != -1);
14848
14849                                                 /* The variable is already loaded to an lvreg */
14850                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
14851                                                         printf ("\t\tUse lvreg R%d for R%d.\n", vreg_to_lvreg [sreg], sreg);
14852                                                 sregs [srcindex] = vreg_to_lvreg [sreg];
14853                                                 //mono_inst_set_src_registers (ins, sregs);
14854                                                 continue;
14855                                         }
14856
14857                                         /* Try to fuse the load into the instruction */
14858                                         if ((srcindex == 0) && (op_to_op_src1_membase (cfg, load_opcode, ins->opcode) != -1)) {
14859                                                 ins->opcode = op_to_op_src1_membase (cfg, load_opcode, ins->opcode);
14860                                                 sregs [0] = var->inst_basereg;
14861                                                 //mono_inst_set_src_registers (ins, sregs);
14862                                                 ins->inst_offset = var->inst_offset;
14863                                         } else if ((srcindex == 1) && (op_to_op_src2_membase (cfg, load_opcode, ins->opcode) != -1)) {
14864                                                 ins->opcode = op_to_op_src2_membase (cfg, load_opcode, ins->opcode);
14865                                                 sregs [1] = var->inst_basereg;
14866                                                 //mono_inst_set_src_registers (ins, sregs);
14867                                                 ins->inst_offset = var->inst_offset;
14868                                         } else {
14869                                                 if (MONO_IS_REAL_MOVE (ins)) {
14870                                                         ins->opcode = OP_NOP;
14871                                                         sreg = ins->dreg;
14872                                                 } else {
14873                                                         //printf ("%d ", srcindex); mono_print_ins (ins);
14874
14875                                                         sreg = alloc_dreg (cfg, stacktypes [regtype]);
14876
14877                                                         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) {
14878                                                                 if (var->dreg == prev_dreg) {
14879                                                                         /*
14880                                                                          * sreg refers to the value loaded by the load
14881                                                                          * emitted below, but we need to use ins->dreg
14882                                                                          * since it refers to the store emitted earlier.
14883                                                                          */
14884                                                                         sreg = ins->dreg;
14885                                                                 }
14886                                                                 g_assert (sreg != -1);
14887                                                                 vreg_to_lvreg [var->dreg] = sreg;
14888                                                                 g_assert (lvregs_len < 1024);
14889                                                                 lvregs [lvregs_len ++] = var->dreg;
14890                                                         }
14891                                                 }
14892
14893                                                 sregs [srcindex] = sreg;
14894                                                 //mono_inst_set_src_registers (ins, sregs);
14895
14896 #if SIZEOF_REGISTER != 8
14897                                                 if (regtype == 'l') {
14898                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, MONO_LVREG_MS (sreg), var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET);
14899                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14900                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, MONO_LVREG_LS (sreg), var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET);
14901                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14902                                                         use_ins = load_ins;
14903                                                 }
14904                                                 else
14905 #endif
14906                                                 {
14907 #if SIZEOF_REGISTER == 4
14908                                                         g_assert (load_opcode != OP_LOADI8_MEMBASE);
14909 #endif
14910                                                         NEW_LOAD_MEMBASE (cfg, load_ins, load_opcode, sreg, var->inst_basereg, var->inst_offset);
14911                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14912                                                         use_ins = load_ins;
14913                                                 }
14914                                         }
14915
14916                                         if (var->dreg < orig_next_vreg) {
14917                                                 live_range_end [var->dreg] = use_ins;
14918                                                 live_range_end_bb [var->dreg] = bb;
14919                                         }
14920
14921                                         if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
14922                                                 MonoInst *tmp;
14923
14924                                                 MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
14925                                                 tmp->inst_c1 = var->dreg;
14926                                                 mono_bblock_insert_after_ins (bb, ins, tmp);
14927                                         }
14928                                 }
14929                         }
14930                         mono_inst_set_src_registers (ins, sregs);
14931
14932                         if (dest_has_lvreg) {
14933                                 g_assert (ins->dreg != -1);
14934                                 vreg_to_lvreg [prev_dreg] = ins->dreg;
14935                                 g_assert (lvregs_len < 1024);
14936                                 lvregs [lvregs_len ++] = prev_dreg;
14937                                 dest_has_lvreg = FALSE;
14938                         }
14939
14940                         if (store) {
14941                                 tmp_reg = ins->dreg;
14942                                 ins->dreg = ins->sreg2;
14943                                 ins->sreg2 = tmp_reg;
14944                         }
14945
14946                         if (MONO_IS_CALL (ins)) {
14947                                 /* Clear vreg_to_lvreg array */
14948                                 for (i = 0; i < lvregs_len; i++)
14949                                         vreg_to_lvreg [lvregs [i]] = 0;
14950                                 lvregs_len = 0;
14951                         } else if (ins->opcode == OP_NOP) {
14952                                 ins->dreg = -1;
14953                                 MONO_INST_NULLIFY_SREGS (ins);
14954                         }
14955
14956                         if (cfg->verbose_level > 2)
14957                                 mono_print_ins_index (1, ins);
14958                 }
14959
14960                 /* Extend the live range based on the liveness info */
14961                 if (cfg->compute_precise_live_ranges && bb->live_out_set && bb->code) {
14962                         for (i = 0; i < cfg->num_varinfo; i ++) {
14963                                 MonoMethodVar *vi = MONO_VARINFO (cfg, i);
14964
14965                                 if (vreg_is_volatile (cfg, vi->vreg))
14966                                         /* The liveness info is incomplete */
14967                                         continue;
14968
14969                                 if (mono_bitset_test_fast (bb->live_in_set, i) && !live_range_start [vi->vreg]) {
14970                                         /* Live from at least the first ins of this bb */
14971                                         live_range_start [vi->vreg] = bb->code;
14972                                         live_range_start_bb [vi->vreg] = bb;
14973                                 }
14974
14975                                 if (mono_bitset_test_fast (bb->live_out_set, i)) {
14976                                         /* Live at least until the last ins of this bb */
14977                                         live_range_end [vi->vreg] = bb->last_ins;
14978                                         live_range_end_bb [vi->vreg] = bb;
14979                                 }
14980                         }
14981                 }
14982         }
14983         
14984         /*
14985          * Emit LIVERANGE_START/LIVERANGE_END opcodes, the backend will implement them
14986          * by storing the current native offset into MonoMethodVar->live_range_start/end.
14987          */
14988         if (cfg->backend->have_liverange_ops && cfg->compute_precise_live_ranges && cfg->comp_done & MONO_COMP_LIVENESS) {
14989                 for (i = 0; i < cfg->num_varinfo; ++i) {
14990                         int vreg = MONO_VARINFO (cfg, i)->vreg;
14991                         MonoInst *ins;
14992
14993                         if (live_range_start [vreg]) {
14994                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_START);
14995                                 ins->inst_c0 = i;
14996                                 ins->inst_c1 = vreg;
14997                                 mono_bblock_insert_after_ins (live_range_start_bb [vreg], live_range_start [vreg], ins);
14998                         }
14999                         if (live_range_end [vreg]) {
15000                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_END);
15001                                 ins->inst_c0 = i;
15002                                 ins->inst_c1 = vreg;
15003                                 if (live_range_end [vreg] == live_range_end_bb [vreg]->last_ins)
15004                                         mono_add_ins_to_end (live_range_end_bb [vreg], ins);
15005                                 else
15006                                         mono_bblock_insert_after_ins (live_range_end_bb [vreg], live_range_end [vreg], ins);
15007                         }
15008                 }
15009         }
15010
15011         if (cfg->gsharedvt_locals_var_ins) {
15012                 /* Nullify if unused */
15013                 cfg->gsharedvt_locals_var_ins->opcode = OP_PCONST;
15014                 cfg->gsharedvt_locals_var_ins->inst_imm = 0;
15015         }
15016
15017         g_free (live_range_start);
15018         g_free (live_range_end);
15019         g_free (live_range_start_bb);
15020         g_free (live_range_end_bb);
15021 }
15022
15023 /**
15024  * FIXME:
15025  * - use 'iadd' instead of 'int_add'
15026  * - handling ovf opcodes: decompose in method_to_ir.
15027  * - unify iregs/fregs
15028  *   -> partly done, the missing parts are:
15029  *   - a more complete unification would involve unifying the hregs as well, so
15030  *     code wouldn't need if (fp) all over the place. but that would mean the hregs
15031  *     would no longer map to the machine hregs, so the code generators would need to
15032  *     be modified. Also, on ia64 for example, niregs + nfregs > 256 -> bitmasks
15033  *     wouldn't work any more. Duplicating the code in mono_local_regalloc () into
15034  *     fp/non-fp branches speeds it up by about 15%.
15035  * - use sext/zext opcodes instead of shifts
15036  * - add OP_ICALL
15037  * - get rid of TEMPLOADs if possible and use vregs instead
15038  * - clean up usage of OP_P/OP_ opcodes
15039  * - cleanup usage of DUMMY_USE
15040  * - cleanup the setting of ins->type for MonoInst's which are pushed on the 
15041  *   stack
15042  * - set the stack type and allocate a dreg in the EMIT_NEW macros
15043  * - get rid of all the <foo>2 stuff when the new JIT is ready.
15044  * - make sure handle_stack_args () is called before the branch is emitted
15045  * - when the new IR is done, get rid of all unused stuff
15046  * - COMPARE/BEQ as separate instructions or unify them ?
15047  *   - keeping them separate allows specialized compare instructions like
15048  *     compare_imm, compare_membase
15049  *   - most back ends unify fp compare+branch, fp compare+ceq
15050  * - integrate mono_save_args into inline_method
15051  * - get rid of the empty bblocks created by MONO_EMIT_NEW_BRACH_BLOCK2
15052  * - handle long shift opts on 32 bit platforms somehow: they require 
15053  *   3 sregs (2 for arg1 and 1 for arg2)
15054  * - make byref a 'normal' type.
15055  * - use vregs for bb->out_stacks if possible, handle_global_vreg will make them a
15056  *   variable if needed.
15057  * - do not start a new IL level bblock when cfg->cbb is changed by a function call
15058  *   like inline_method.
15059  * - remove inlining restrictions
15060  * - fix LNEG and enable cfold of INEG
15061  * - generalize x86 optimizations like ldelema as a peephole optimization
15062  * - add store_mem_imm for amd64
15063  * - optimize the loading of the interruption flag in the managed->native wrappers
15064  * - avoid special handling of OP_NOP in passes
15065  * - move code inserting instructions into one function/macro.
15066  * - try a coalescing phase after liveness analysis
15067  * - add float -> vreg conversion + local optimizations on !x86
15068  * - figure out how to handle decomposed branches during optimizations, ie.
15069  *   compare+branch, op_jump_table+op_br etc.
15070  * - promote RuntimeXHandles to vregs
15071  * - vtype cleanups:
15072  *   - add a NEW_VARLOADA_VREG macro
15073  * - the vtype optimizations are blocked by the LDADDR opcodes generated for 
15074  *   accessing vtype fields.
15075  * - get rid of I8CONST on 64 bit platforms
15076  * - dealing with the increase in code size due to branches created during opcode
15077  *   decomposition:
15078  *   - use extended basic blocks
15079  *     - all parts of the JIT
15080  *     - handle_global_vregs () && local regalloc
15081  *   - avoid introducing global vregs during decomposition, like 'vtable' in isinst
15082  * - sources of increase in code size:
15083  *   - vtypes
15084  *   - long compares
15085  *   - isinst and castclass
15086  *   - lvregs not allocated to global registers even if used multiple times
15087  * - call cctors outside the JIT, to make -v output more readable and JIT timings more
15088  *   meaningful.
15089  * - check for fp stack leakage in other opcodes too. (-> 'exceptions' optimization)
15090  * - add all micro optimizations from the old JIT
15091  * - put tree optimizations into the deadce pass
15092  * - decompose op_start_handler/op_endfilter/op_endfinally earlier using an arch
15093  *   specific function.
15094  * - unify the float comparison opcodes with the other comparison opcodes, i.e.
15095  *   fcompare + branchCC.
15096  * - create a helper function for allocating a stack slot, taking into account 
15097  *   MONO_CFG_HAS_SPILLUP.
15098  * - merge r68207.
15099  * - merge the ia64 switch changes.
15100  * - optimize mono_regstate2_alloc_int/float.
15101  * - fix the pessimistic handling of variables accessed in exception handler blocks.
15102  * - need to write a tree optimization pass, but the creation of trees is difficult, i.e.
15103  *   parts of the tree could be separated by other instructions, killing the tree
15104  *   arguments, or stores killing loads etc. Also, should we fold loads into other
15105  *   instructions if the result of the load is used multiple times ?
15106  * - make the REM_IMM optimization in mini-x86.c arch-independent.
15107  * - LAST MERGE: 108395.
15108  * - when returning vtypes in registers, generate IR and append it to the end of the
15109  *   last bb instead of doing it in the epilog.
15110  * - change the store opcodes so they use sreg1 instead of dreg to store the base register.
15111  */
15112
15113 /*
15114
15115 NOTES
15116 -----
15117
15118 - When to decompose opcodes:
15119   - earlier: this makes some optimizations hard to implement, since the low level IR
15120   no longer contains the neccessary information. But it is easier to do.
15121   - later: harder to implement, enables more optimizations.
15122 - Branches inside bblocks:
15123   - created when decomposing complex opcodes. 
15124     - branches to another bblock: harmless, but not tracked by the branch 
15125       optimizations, so need to branch to a label at the start of the bblock.
15126     - branches to inside the same bblock: very problematic, trips up the local
15127       reg allocator. Can be fixed by spitting the current bblock, but that is a
15128       complex operation, since some local vregs can become global vregs etc.
15129 - Local/global vregs:
15130   - local vregs: temporary vregs used inside one bblock. Assigned to hregs by the
15131     local register allocator.
15132   - global vregs: used in more than one bblock. Have an associated MonoMethodVar
15133     structure, created by mono_create_var (). Assigned to hregs or the stack by
15134     the global register allocator.
15135 - When to do optimizations like alu->alu_imm:
15136   - earlier -> saves work later on since the IR will be smaller/simpler
15137   - later -> can work on more instructions
15138 - Handling of valuetypes:
15139   - When a vtype is pushed on the stack, a new temporary is created, an 
15140     instruction computing its address (LDADDR) is emitted and pushed on
15141     the stack. Need to optimize cases when the vtype is used immediately as in
15142     argument passing, stloc etc.
15143 - Instead of the to_end stuff in the old JIT, simply call the function handling
15144   the values on the stack before emitting the last instruction of the bb.
15145 */
15146
15147 #endif /* DISABLE_JIT */